voluptasmollitia
Version:
Monorepo for the Firebase JavaScript SDK
222 lines (197 loc) • 6.44 kB
text/typescript
/**
* @license
* Copyright 2020 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 { expect, use } from 'chai';
import * as chaiAsPromised from 'chai-as-promised';
import * as sinon from 'sinon';
import * as sinonChai from 'sinon-chai';
import { ProviderId, UserInfo } from '../../model/public_types';
import { mockEndpoint } from '../../../test/helpers/api/helper';
import { testAuth, TestAuth, testUser } from '../../../test/helpers/mock_auth';
import * as fetch from '../../../test/helpers/mock_fetch';
import { Endpoint } from '../../api';
import {
APIUserInfo,
ProviderUserInfo
} from '../../api/account_management/account';
import { _reloadWithoutSaving, reload } from './reload';
import { UserMetadata } from './user_metadata';
import { UserInternal } from '../../model/user';
use(chaiAsPromised);
use(sinonChai);
const BASIC_USER_INFO: UserInfo = {
providerId: ProviderId.FIREBASE,
uid: 'uid',
email: 'email',
displayName: 'display-name',
phoneNumber: 'phone-number',
photoURL: 'photo-url'
};
const BASIC_PROVIDER_USER_INFO: ProviderUserInfo = {
providerId: ProviderId.FIREBASE,
rawId: 'uid',
email: 'email',
displayName: 'display-name',
phoneNumber: 'phone-number',
photoUrl: 'photo-url'
};
describe('core/user/reload', () => {
let auth: TestAuth;
beforeEach(async () => {
auth = await testAuth();
fetch.setUp();
});
afterEach(fetch.tearDown);
it('sets all the new properties', async () => {
const serverUser: APIUserInfo = {
localId: 'local-id',
displayName: 'display-name',
photoUrl: 'photo-url',
email: 'email',
emailVerified: true,
phoneNumber: 'phone-number',
tenantId: 'tenant-id',
createdAt: 123,
lastLoginAt: 456
};
mockEndpoint(Endpoint.GET_ACCOUNT_INFO, {
users: [serverUser]
});
const user = testUser(auth, 'abc', '', true);
await _reloadWithoutSaving(user);
expect(user.uid).to.eq('local-id');
expect(user.displayName).to.eq('display-name');
expect(user.photoURL).to.eq('photo-url');
expect(user.email).to.eq('email');
expect(user.emailVerified).to.be.true;
expect(user.phoneNumber).to.eq('phone-number');
expect(user.tenantId).to.eq('tenant-id');
expect((user.metadata as UserMetadata).toJSON()).to.eql({
createdAt: 123,
lastLoginAt: 456
});
});
it('adds missing provider data', async () => {
const user = testUser(auth, 'abc', '', true);
user.providerData = [{ ...BASIC_USER_INFO }];
mockEndpoint(Endpoint.GET_ACCOUNT_INFO, {
users: [
{
providerUserInfo: [
{ ...BASIC_PROVIDER_USER_INFO, providerId: ProviderId.FACEBOOK }
]
}
]
});
await _reloadWithoutSaving(user);
expect(user.providerData).to.eql([
{ ...BASIC_USER_INFO },
{ ...BASIC_USER_INFO, providerId: ProviderId.FACEBOOK }
]);
});
it('merges provider data, using the new data for overlaps', async () => {
const user = testUser(auth, 'abc', '', true);
user.providerData = [
{
...BASIC_USER_INFO,
providerId: ProviderId.GITHUB,
uid: 'i-will-be-overwritten'
},
{
...BASIC_USER_INFO
}
];
mockEndpoint(Endpoint.GET_ACCOUNT_INFO, {
users: [
{
providerUserInfo: [
{
...BASIC_PROVIDER_USER_INFO,
providerId: ProviderId.GITHUB,
rawId: 'new-uid'
}
]
}
]
});
await _reloadWithoutSaving(user);
expect(user.providerData).to.eql([
{ ...BASIC_USER_INFO },
{
...BASIC_USER_INFO,
providerId: ProviderId.GITHUB,
uid: 'new-uid'
}
]);
});
it('reload persists the object and notifies listeners', async () => {
mockEndpoint(Endpoint.GET_ACCOUNT_INFO, {
users: [{}]
});
const user = testUser(auth, 'user', '', true);
user.auth.currentUser = user;
const cb = sinon.stub();
user.auth.onIdTokenChanged(cb);
await reload(user);
expect(cb).to.have.been.calledWith(user);
expect(auth.persistenceLayer.lastObjectSet).to.eql(user.toJSON());
});
context('anonymous carryover', () => {
let user: UserInternal;
beforeEach(() => {
user = testUser(auth, 'abc', '', true);
});
function setup(
isAnonStart: boolean,
emailStart: string,
passwordHash: string,
providerData: Array<{ providerId: string }>
): void {
// Get around readonly property
const mutUser = (user as unknown) as Record<string, unknown>;
mutUser.isAnonymous = isAnonStart;
mutUser.email = emailStart;
mockEndpoint(Endpoint.GET_ACCOUNT_INFO, {
users: [
{
providerUserInfo: [...providerData],
passwordHash
}
]
});
}
it('user stays not anonymous even if reload user is', async () => {
setup(false, '', '', []); // After reload the user would count as anon
await _reloadWithoutSaving(user);
expect(user.isAnonymous).to.be.false;
});
it('user stays anonymous if reload user is anonymous', async () => {
setup(true, '', '', []); // After reload the user would count as anon
await _reloadWithoutSaving(user);
expect(user.isAnonymous).to.be.true;
});
it('user becomes not anonymous if reload user is not', async () => {
setup(true, '', '', [{ providerId: 'google' }]); // After reload the user would count as anon
await _reloadWithoutSaving(user);
expect(user.isAnonymous).to.be.false;
});
it('user becomes not anonymous if password hash set', async () => {
setup(true, 'email', 'pass', [{ providerId: 'google' }]); // After reload the user would count as anon
await _reloadWithoutSaving(user);
expect(user.isAnonymous).to.be.false;
});
});
});