UNPKG

voluptasmollitia

Version:
280 lines (243 loc) 10.1 kB
/** * @license * Copyright 2019 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import * as chai from 'chai'; import { expect } from 'chai'; import * as sinon from 'sinon'; import * as sinonChai from 'sinon-chai'; import { testAuth, testUser, TestAuth } from '../../../test/helpers/mock_auth'; import { UserImpl } from '../user/user_impl'; import { _getInstance } from '../util/instantiator'; import { PersistenceInternal, PersistenceType, PersistenceValue, StorageEventListener } from './'; import { inMemoryPersistence } from './in_memory'; import { KeyName, PersistenceUserManager } from './persistence_user_manager'; chai.use(sinonChai); function makePersistence( type = PersistenceType.NONE ): { persistence: PersistenceInternal; stub: sinon.SinonStubbedInstance<PersistenceInternal>; } { const persistence: PersistenceInternal = { type, _isAvailable: () => Promise.resolve(true), _set: async () => {}, _get() { return Promise.resolve(null); }, _remove: async () => {}, _addListener(_key: string, _listener: StorageEventListener) {}, _removeListener(_key: string, _listener: StorageEventListener) {} }; const stub = sinon.stub(persistence); return { persistence, stub }; } describe('core/persistence/persistence_user_manager', () => { let auth: TestAuth; beforeEach(async () => { auth = await testAuth(); }); describe('.create', () => { it('defaults to inMemory if no list provided', async () => { const manager = await PersistenceUserManager.create(auth, []); expect(manager.persistence).to.eq(_getInstance(inMemoryPersistence)); }); it('chooses the first one available', async () => { const a = makePersistence(); const b = makePersistence(); const c = makePersistence(); const search = [a.persistence, b.persistence, c.persistence]; const auth = await testAuth(); a.stub._isAvailable.resolves(false); a.stub._get.onFirstCall().resolves(testUser(auth, 'uid').toJSON()); b.stub._isAvailable.resolves(true); const out = await PersistenceUserManager.create(auth, search); expect(a.stub._isAvailable).to.have.been.calledOnce; expect(b.stub._isAvailable).to.have.been.calledOnce; expect(c.stub._isAvailable).to.not.have.been.called; // a should not be chosen since it is not available (despite having a user). expect(out.persistence).to.eq(b.persistence); }); it('searches in order for a user', async () => { const a = makePersistence(); const b = makePersistence(); const c = makePersistence(); const search = [a.persistence, b.persistence, c.persistence]; const auth = await testAuth(); const user = testUser(auth, 'uid'); a.stub._isAvailable.resolves(true); a.stub._get.resolves(user.toJSON()); b.stub._get.resolves(testUser(auth, 'wrong-uid').toJSON()); const out = await PersistenceUserManager.create(auth, search); expect(a.stub._get).to.have.been.calledOnce; expect(b.stub._get).not.to.have.been.called; expect(c.stub._get).not.to.have.been.called; expect(out.persistence).to.eq(a.persistence); expect((await out.getCurrentUser())!.uid).to.eq(user.uid); }); it('migrate found user to the selected persistence and clear others', async () => { const a = makePersistence(); const b = makePersistence(); const c = makePersistence(); const search = [a.persistence, b.persistence, c.persistence]; const auth = await testAuth(); const user = testUser(auth, 'uid'); a.stub._isAvailable.resolves(true); b.stub._get.resolves(user.toJSON()); c.stub._get.resolves(testUser(auth, 'wrong-uid').toJSON()); let persistedUserInA: PersistenceValue | null = null; a.stub._set.callsFake(async (_, value) => { persistedUserInA = value; }); a.stub._get.callsFake(async () => persistedUserInA); const out = await PersistenceUserManager.create(auth, search); expect(a.stub._set).to.have.been.calledOnceWith( 'firebase:authUser:test-api-key:test-app', user.toJSON() ); expect(b.stub._set).to.not.have.been.called; expect(c.stub._set).to.not.have.been.called; expect(b.stub._remove).to.have.been.calledOnceWith( 'firebase:authUser:test-api-key:test-app' ); expect(c.stub._remove).to.have.been.calledOnceWith( 'firebase:authUser:test-api-key:test-app' ); expect(out.persistence).to.eq(a.persistence); expect((await out.getCurrentUser())!.uid).to.eq(user.uid); }); it('uses default user key if none provided', async () => { const { stub, persistence } = makePersistence(); await PersistenceUserManager.create(auth, [persistence]); expect(stub._get).to.have.been.calledWith( 'firebase:authUser:test-api-key:test-app' ); }); it('uses user key if provided', async () => { const { stub, persistence } = makePersistence(); await PersistenceUserManager.create( auth, [persistence], KeyName.REDIRECT_USER ); expect(stub._get).to.have.been.calledWith( 'firebase:redirectUser:test-api-key:test-app' ); }); it('returns in-memory persistence if all else fails', async () => { const a = makePersistence(); const b = makePersistence(); const c = makePersistence(); const search = [a.persistence, b.persistence, c.persistence]; a.stub._isAvailable.resolves(false); b.stub._isAvailable.resolves(false); c.stub._isAvailable.resolves(false); const out = await PersistenceUserManager.create(auth, search); expect(out.persistence).to.eq(_getInstance(inMemoryPersistence)); expect(a.stub._get).to.have.been.calledOnce; expect(b.stub._get).to.have.been.calledOnce; expect(c.stub._get).to.have.been.called; }); }); describe('manager methods', () => { let persistenceStub: sinon.SinonStubbedInstance<PersistenceInternal>; let manager: PersistenceUserManager; beforeEach(async () => { const { persistence, stub } = makePersistence(PersistenceType.SESSION); stub._isAvailable.resolves(true); persistenceStub = stub; manager = await PersistenceUserManager.create(auth, [persistence]); }); it('#setCurrentUser calls underlying persistence w/ key', async () => { const user = testUser(auth, 'uid'); await manager.setCurrentUser(user); expect(persistenceStub._set).to.have.been.calledWith( 'firebase:authUser:test-api-key:test-app', user.toJSON() ); }); it('#removeCurrentUser calls underlying persistence', async () => { await manager.removeCurrentUser(); expect(persistenceStub._remove).to.have.been.calledWith( 'firebase:authUser:test-api-key:test-app' ); }); it('#getCurrentUser calls with instantiator', async () => { const rawObject = {}; const userImplStub = sinon.stub(UserImpl, '_fromJSON'); persistenceStub._get.returns(Promise.resolve(rawObject)); await manager.getCurrentUser(); expect(userImplStub).to.have.been.calledWith(auth, rawObject); userImplStub.restore(); }); it('#savePersistenceForRedirect calls through', async () => { await manager.savePersistenceForRedirect(); expect(persistenceStub._set).to.have.been.calledWith( 'firebase:persistence:test-api-key:test-app', 'SESSION' ); }); describe('#setPersistence', () => { it('returns immediately if persistence is not changed', async () => { const spy = sinon.spy(manager, 'getCurrentUser'); await manager.setPersistence(manager.persistence); expect(spy).not.to.have.been.called; spy.restore(); }); it('removes current user & sets it in the new persistene', async () => { const { persistence: nextPersistence, stub: nextStub } = makePersistence(); const auth = await testAuth(); const user = testUser(auth, 'uid'); persistenceStub._get.returns(Promise.resolve(user.toJSON())); await manager.setPersistence(nextPersistence); expect(persistenceStub._get).to.have.been.called; expect(persistenceStub._remove).to.have.been.called; expect(nextStub._set).to.have.been.calledWith( 'firebase:authUser:test-api-key:test-app', user.toJSON() ); }); it('migrates user for a different persistence even if .type matches', async () => { const { persistence, stub } = makePersistence(PersistenceType.LOCAL); await manager.setPersistence(persistence); const auth = await testAuth(); const user = testUser(auth, 'uid'); stub._get.returns(Promise.resolve(user.toJSON())); const { persistence: nextPersistence, stub: nextStub } = makePersistence(PersistenceType.LOCAL); // This should migrate the user even if both has type LOCAL. For example, developer may want // to switch from localStorage to indexedDB (both type LOCAL) and we should honor that. await manager.setPersistence(nextPersistence); expect(stub._get).to.have.been.called; expect(stub._remove).to.have.been.called; expect(nextStub._set).to.have.been.calledWith( 'firebase:authUser:test-api-key:test-app', user.toJSON() ); }); }); }); });