Skip to content

Commit 7eea870

Browse files
committed
Add some tests & fix a couple issues with local storage events
1 parent cddc280 commit 7eea870

File tree

3 files changed

+161
-38
lines changed

3 files changed

+161
-38
lines changed

packages-exp/auth-exp/src/core/user/reload.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import {
3131
ProviderUserInfo
3232
} from '../../api/account_management/account';
3333
import { _reloadWithoutSaving, reload } from './reload';
34-
import { UserMetadata } from './user_impl';
34+
import { UserMetadata } from './user_metadata';
3535

3636
use(chaiAsPromised);
3737
use(sinonChai);

packages-exp/auth-exp/src/platform_browser/persistence/local_storage.test.ts

Lines changed: 158 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { expect } from 'chai';
18+
import { expect, use } from 'chai';
1919
import * as sinon from 'sinon';
20+
import * as sinonChai from 'sinon-chai';
2021
import { testAuth, testUser } from '../../../test/helpers/mock_auth';
2122
import {
2223
PersistedBlob,
@@ -26,53 +27,175 @@ import {
2627
import { _getInstance } from '../../core/util/instantiator';
2728
import { browserLocalPersistence } from './local_storage';
2829

29-
describe('core/persistence/browser', () => {
30+
use(sinonChai);
31+
32+
describe('browserLocalPersistence', () => {
33+
const persistence: Persistence = _getInstance(browserLocalPersistence);
34+
3035
beforeEach(() => {
3136
localStorage.clear();
32-
sessionStorage.clear();
3337
});
3438

3539
afterEach(() => sinon.restore());
36-
describe('browserLocalPersistence', () => {
37-
const persistence: Persistence = _getInstance(browserLocalPersistence);
38-
39-
it('should work with persistence type', async () => {
40-
const key = 'my-super-special-persistence-type';
41-
const value = PersistenceType.LOCAL;
42-
expect(await persistence.get(key)).to.be.null;
43-
await persistence.set(key, value);
44-
expect(await persistence.get(key)).to.be.eq(value);
45-
expect(await persistence.get('other-key')).to.be.null;
46-
await persistence.remove(key);
47-
expect(await persistence.get(key)).to.be.null;
40+
41+
it('should work with persistence type', async () => {
42+
const key = 'my-super-special-persistence-type';
43+
const value = PersistenceType.LOCAL;
44+
expect(await persistence.get(key)).to.be.null;
45+
await persistence.set(key, value);
46+
expect(await persistence.get(key)).to.be.eq(value);
47+
expect(await persistence.get('other-key')).to.be.null;
48+
await persistence.remove(key);
49+
expect(await persistence.get(key)).to.be.null;
50+
});
51+
52+
it('should return persistedblob from user', async () => {
53+
const key = 'my-super-special-user';
54+
const auth = await testAuth();
55+
const value = testUser(auth, 'some-uid');
56+
57+
expect(await persistence.get(key)).to.be.null;
58+
await persistence.set(key, value.toJSON());
59+
const out = await persistence.get<PersistedBlob>(key);
60+
expect(out!['uid']).to.eql(value.uid);
61+
await persistence.remove(key);
62+
expect(await persistence.get(key)).to.be.null;
63+
});
64+
65+
describe('#isAvailable', () => {
66+
it('should emit false if localStorage setItem throws', async () => {
67+
sinon.stub(localStorage, 'setItem').throws(new Error('nope'));
68+
expect(await persistence.isAvailable()).to.be.false;
69+
});
70+
71+
it('should emit false if localStorage removeItem throws', async () => {
72+
sinon.stub(localStorage, 'removeItem').throws(new Error('nope'));
73+
expect(await persistence.isAvailable()).to.be.false;
74+
});
75+
76+
it('should emit true if everything works properly', async () => {
77+
expect(await persistence.isAvailable()).to.be.true;
78+
});
79+
});
80+
81+
describe('#addEventListener', () => {
82+
const key = 'my-key';
83+
const newValue = 'new-value';
84+
85+
let callback: sinon.SinonSpy;
86+
87+
beforeEach(() => {
88+
callback = sinon.spy();
89+
persistence.addListener(key, callback);
90+
});
91+
92+
afterEach(() => {
93+
persistence.removeListener(key, callback);
94+
});
95+
96+
context('with multiple listeners', () => {
97+
let otherCallback: sinon.SinonSpy;
98+
99+
beforeEach(() => {
100+
otherCallback = sinon.spy();
101+
persistence.addListener(key, otherCallback);
102+
localStorage.setItem(key, JSON.stringify(newValue));
103+
});
104+
105+
afterEach(() => {
106+
persistence.removeListener(key, otherCallback);
107+
});
108+
109+
it('should trigger both listeners if multiple listeners are registered', () => {
110+
window.dispatchEvent(
111+
new StorageEvent('storage', {
112+
key,
113+
oldValue: null,
114+
newValue: JSON.stringify(newValue)
115+
})
116+
);
117+
118+
expect(callback).to.have.been.calledWith(newValue);
119+
expect(otherCallback).to.have.been.calledWith(newValue);
120+
});
48121
});
49122

50-
it('should return persistedblob from user', async () => {
51-
const key = 'my-super-special-user';
52-
const auth = await testAuth();
53-
const value = testUser(auth, 'some-uid');
54-
55-
expect(await persistence.get(key)).to.be.null;
56-
await persistence.set(key, value.toJSON());
57-
const out = await persistence.get<PersistedBlob>(key);
58-
expect(out!['uid']).to.eql(value.uid);
59-
await persistence.remove(key);
60-
expect(await persistence.get(key)).to.be.null;
123+
context('with a change in the underlying storage', () => {
124+
beforeEach(() => {
125+
localStorage.setItem(key, JSON.stringify(newValue));
126+
});
127+
128+
it('should trigger on storage event for the same key', () => {
129+
window.dispatchEvent(
130+
new StorageEvent('storage', {
131+
key,
132+
oldValue: null,
133+
newValue: JSON.stringify(newValue)
134+
})
135+
);
136+
137+
expect(callback).to.have.been.calledWith(newValue);
138+
});
139+
140+
it('should not trigger after unsubscribe', () => {
141+
persistence.removeListener(key, callback);
142+
window.dispatchEvent(
143+
new StorageEvent('storage', {
144+
key,
145+
oldValue: null,
146+
newValue: JSON.stringify(newValue)
147+
})
148+
);
149+
150+
expect(callback).not.to.have.been.called;
151+
});
152+
153+
it('should trigger even if the event had no key', () => {
154+
window.dispatchEvent(new StorageEvent('storage', {}));
155+
156+
expect(callback).to.have.been.calledWith(newValue);
157+
});
61158
});
62159

63-
describe('#isAvailable', () => {
64-
it('should emit false if localStorage setItem throws', async () => {
65-
sinon.stub(localStorage, 'setItem').throws(new Error('nope'));
66-
expect(await persistence.isAvailable()).to.be.false;
160+
context('without a change in the underlying storage', () => {
161+
it('should not trigger', () => {
162+
window.dispatchEvent(
163+
new StorageEvent('storage', {
164+
key,
165+
oldValue: null,
166+
newValue: JSON.stringify(newValue)
167+
})
168+
);
169+
170+
expect(callback).not.to.have.been.called;
67171
});
68172

69-
it('should emit false if localStorage removeItem throws', async () => {
70-
sinon.stub(localStorage, 'removeItem').throws(new Error('nope'));
71-
expect(await persistence.isAvailable()).to.be.false;
173+
it('should not trigger on storage event for a different key', () => {
174+
localStorage.setItem('other-key', JSON.stringify(newValue));
175+
window.dispatchEvent(
176+
new StorageEvent('storage', {
177+
key: 'other-key',
178+
oldValue: null,
179+
newValue: JSON.stringify(newValue)
180+
})
181+
);
182+
183+
expect(callback).not.to.have.been.called;
72184
});
73185

74-
it('should emit true if everything works properly', async () => {
75-
expect(await persistence.isAvailable()).to.be.true;
186+
it('should not trigger if the listener was added after the storage was updated', () => {
187+
const otherCallback = sinon.spy();
188+
persistence.addListener(key, otherCallback);
189+
190+
window.dispatchEvent(
191+
new StorageEvent('storage', {
192+
key,
193+
oldValue: null,
194+
newValue: JSON.stringify(newValue)
195+
})
196+
);
197+
198+
expect(otherCallback).not.to.have.been.called;
76199
});
77200
});
78201
});

packages-exp/auth-exp/src/platform_browser/persistence/local_storage.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ class BrowserLocalPersistence extends BrowserPersistenceClass
192192
}
193193

194194
private _attachListener(): void {
195-
window.addEventListener('storage', this._onStorageEvent);
195+
window.addEventListener('storage', this._onStorageEvent.bind(this));
196196
}
197197

198198
private _detachListener(): void {
@@ -212,7 +212,7 @@ class BrowserLocalPersistence extends BrowserPersistenceClass
212212
this._attachListener();
213213
}
214214
}
215-
this.listeners[key] = this.listeners[key] || [];
215+
this.listeners[key] = this.listeners[key] || new Set();
216216
this.listeners[key].add(listener);
217217
}
218218

0 commit comments

Comments
 (0)