Skip to content

Commit fbb1526

Browse files
authored
fix storage event handling (#1400)
1 parent dc0bc35 commit fbb1526

File tree

5 files changed

+125
-26
lines changed

5 files changed

+125
-26
lines changed

addon/session-stores/local-storage.js

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Ember from 'ember';
33
import BaseStore from './base';
44
import objectsAreEqual from '../utils/objects-are-equal';
55

6-
const { RSVP, $: jQuery, computed, getOwner } = Ember;
6+
const { RSVP, computed, getOwner, run: { bind } } = Ember;
77

88
/**
99
Session store that persists data in the browser's `localStorage`.
@@ -45,7 +45,13 @@ export default BaseStore.extend({
4545
this._super(...arguments);
4646

4747
if (!this.get('_isFastBoot')) {
48-
this._bindToStorageEvents();
48+
window.addEventListener('storage', bind(this, this._handleStorageEvent));
49+
}
50+
},
51+
52+
willDestroy() {
53+
if (!this.get('_isFastBoot')) {
54+
window.removeEventListener('storage', bind(this, this._handleStorageEvent));
4955
}
5056
},
5157

@@ -94,16 +100,14 @@ export default BaseStore.extend({
94100
return RSVP.resolve();
95101
},
96102

97-
_bindToStorageEvents() {
98-
jQuery(window).on('storage', (e) => {
99-
if (e.originalEvent.key === this.key) {
100-
this.restore().then((data) => {
101-
if (!objectsAreEqual(data, this._lastData)) {
102-
this._lastData = data;
103-
this.trigger('sessionDataUpdated', data);
104-
}
105-
});
106-
}
107-
});
103+
_handleStorageEvent(e) {
104+
if (e.key === this.get('key')) {
105+
this.restore().then((data) => {
106+
if (!objectsAreEqual(data, this._lastData)) {
107+
this._lastData = data;
108+
this.trigger('sessionDataUpdated', data);
109+
}
110+
});
111+
}
108112
}
109113
});

addon/session-stores/session-storage.js

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Ember from 'ember';
33
import BaseStore from './base';
44
import objectsAreEqual from '../utils/objects-are-equal';
55

6-
const { RSVP, $: jQuery, computed, getOwner } = Ember;
6+
const { RSVP, computed, getOwner, run: { bind } } = Ember;
77

88
/**
99
Session store that persists data in the browser's `sessionStorage`.
@@ -41,7 +41,13 @@ export default BaseStore.extend({
4141
this._super(...arguments);
4242

4343
if (!this.get('_isFastBoot')) {
44-
this._bindToStorageEvents();
44+
window.addEventListener('storage', bind(this, this._handleStorageEvent));
45+
}
46+
},
47+
48+
willDestroy() {
49+
if (!this.get('_isFastBoot')) {
50+
window.removeEventListener('storage', bind(this, this._handleStorageEvent));
4551
}
4652
},
4753

@@ -90,16 +96,14 @@ export default BaseStore.extend({
9096
return RSVP.resolve();
9197
},
9298

93-
_bindToStorageEvents() {
94-
jQuery(window).on('storage', (e) => {
95-
if (e.originalEvent.key === this.key) {
96-
this.restore().then((data) => {
97-
if (!objectsAreEqual(data, this._lastData)) {
98-
this._lastData = data;
99-
this.trigger('sessionDataUpdated', data);
100-
}
101-
});
102-
}
103-
});
99+
_handleStorageEvent(e) {
100+
if (e.key === this.get('key')) {
101+
this.restore().then((data) => {
102+
if (!objectsAreEqual(data, this._lastData)) {
103+
this._lastData = data;
104+
this.trigger('sessionDataUpdated', data);
105+
}
106+
});
107+
}
104108
}
105109
});

tests/unit/session-stores/local-storage-test.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { describe } from 'mocha';
22
import LocalStorage from 'ember-simple-auth/session-stores/local-storage';
33
import itBehavesLikeAStore from './shared/store-behavior';
4+
import itBehavesLikeAStorageEventHandler from './shared/storage-event-handler-behavior';
45

56
describe('LocalStorageStore', function() {
67
itBehavesLikeAStore({
@@ -10,4 +11,12 @@ describe('LocalStorageStore', function() {
1011
});
1112
}
1213
});
14+
15+
itBehavesLikeAStorageEventHandler({
16+
store() {
17+
return LocalStorage.create({
18+
_isFastBoot: false
19+
});
20+
}
21+
});
1322
});

tests/unit/session-stores/session-storage-test.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { describe } from 'mocha';
22
import SessionStorage from 'ember-simple-auth/session-stores/session-storage';
33
import itBehavesLikeAStore from './shared/store-behavior';
4+
import itBehavesLikeAStorageEventHandler from './shared/storage-event-handler-behavior';
45

56
describe('SessionStorageStore', function() {
67
itBehavesLikeAStore({
@@ -10,4 +11,12 @@ describe('SessionStorageStore', function() {
1011
});
1112
}
1213
});
14+
15+
itBehavesLikeAStorageEventHandler({
16+
store() {
17+
return SessionStorage.create({
18+
_isFastBoot: false
19+
});
20+
}
21+
});
1322
});
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import Ember from 'ember';
2+
import { describe, beforeEach, it } from 'mocha';
3+
import { expect } from 'chai';
4+
import sinon from 'sinon';
5+
6+
const { run } = Ember;
7+
8+
export default function(options) {
9+
let store;
10+
11+
// eslint-disable-next-line mocha/no-top-level-hooks
12+
beforeEach(function() {
13+
store = options.store();
14+
});
15+
16+
describe('storage events', function() {
17+
beforeEach(function() {
18+
sinon.spy(window, 'addEventListener');
19+
sinon.spy(window, 'removeEventListener');
20+
});
21+
22+
afterEach(function() {
23+
window.addEventListener.restore();
24+
window.removeEventListener.restore();
25+
});
26+
27+
it('binds to "storage" events on the window when created', function() {
28+
store = options.store();
29+
30+
expect(window.addEventListener).to.have.been.called.once;
31+
});
32+
33+
it('triggers the "sessionDataUpdated" event when the data in the browser storage has changed', function() {
34+
let triggered = false;
35+
store.on('sessionDataUpdated', () => {
36+
triggered = true;
37+
});
38+
39+
window.dispatchEvent(new StorageEvent('storage', { key: store.get('key') }));
40+
41+
expect(triggered).to.be.true;
42+
});
43+
44+
it('does not trigger the "sessionDataUpdated" event when the data in the browser storage has not changed', function() {
45+
let triggered = false;
46+
store.on('sessionDataUpdated', () => {
47+
triggered = true;
48+
});
49+
50+
store.persist({ key: 'value' }); // this data will be read again when the event is handled so that no change will be detected
51+
window.dispatchEvent(new StorageEvent('storage', { key: store.get('key') }));
52+
53+
expect(triggered).to.be.false;
54+
});
55+
56+
it('does not trigger the "sessionDataUpdated" event when the data in the browser storage has changed for a different key', function() {
57+
let triggered = false;
58+
store.on('sessionDataUpdated', () => {
59+
triggered = true;
60+
});
61+
62+
window.dispatchEvent(new StorageEvent('storage', { key: 'another key' }));
63+
64+
expect(triggered).to.be.false;
65+
});
66+
67+
it('unbinds from "storage" events on the window when destroyed', function() {
68+
run(() => store.destroy());
69+
70+
expect(window.removeEventListener).to.have.been.called.once;
71+
});
72+
});
73+
}

0 commit comments

Comments
 (0)