quodolores
Version:
Monorepo for the Firebase JavaScript SDK
237 lines (213 loc) • 6.75 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 { ProviderId } from '../../model/public_types';
import { FirebaseError } from '@firebase/util';
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 } from '../../api/account_management/account';
import { UserInternal } from '../../model/user';
import { _assertLinkedStatus, unlink } from './link_unlink';
use(chaiAsPromised);
describe('core/user/link_unlink', () => {
let user: UserInternal;
let auth: TestAuth;
let getAccountInfoEndpoint: fetch.Route;
beforeEach(async () => {
auth = await testAuth();
user = testUser(auth, 'uid', '', true);
await auth._updateCurrentUser(user);
fetch.setUp();
});
afterEach(() => {
fetch.tearDown();
});
context('link', () => {
it('rejects if the provider is not linked', async () => {
mockEndpoint(Endpoint.GET_ACCOUNT_INFO, {
users: [
{
uid: 'uid'
}
]
});
await expect(unlink(user, ProviderId.PHONE)).to.be.rejectedWith(
FirebaseError,
'Firebase: User was not linked to an account with the given provider. (auth/no-such-provider).'
);
});
context('with properly linked account', () => {
let endpoint: fetch.Route;
beforeEach(() => {
mockEndpoint(Endpoint.GET_ACCOUNT_INFO, {
users: [
{
uid: 'uid',
providerUserInfo: [{ providerId: ProviderId.PHONE }]
}
]
});
endpoint = mockEndpoint(Endpoint.SET_ACCOUNT_INFO, {
providerUserInfo: [
{
providerId: ProviderId.GOOGLE
}
]
});
});
it('removes the phone provider from the list and persists', async () => {
user.phoneNumber = 'number!';
user.providerData = [
{
providerId: ProviderId.PHONE,
displayName: '',
phoneNumber: '',
email: '',
photoURL: '',
uid: ''
},
{
providerId: ProviderId.GOOGLE,
displayName: '',
phoneNumber: '',
email: '',
photoURL: '',
uid: ''
}
];
await unlink(user, ProviderId.PHONE);
expect(user.providerData).to.eql([
{
providerId: ProviderId.GOOGLE,
displayName: '',
phoneNumber: '',
email: '',
photoURL: '',
uid: ''
}
]);
expect(auth.persistenceLayer.lastObjectSet).to.eql(user.toJSON());
expect(user.phoneNumber).to.be.null;
});
it('removes non-phone provider from the list and persists', async () => {
user.providerData = [
{
providerId: ProviderId.GOOGLE,
displayName: '',
phoneNumber: '',
email: '',
photoURL: '',
uid: ''
},
{
providerId: ProviderId.TWITTER,
displayName: '',
phoneNumber: '',
email: '',
photoURL: '',
uid: ''
}
];
await unlink(user, ProviderId.TWITTER);
expect(user.providerData).to.eql([
{
providerId: ProviderId.GOOGLE,
displayName: '',
phoneNumber: '',
email: '',
photoURL: '',
uid: ''
}
]);
expect(auth.persistenceLayer.lastObjectSet).to.eql(user.toJSON());
});
it('calls the endpoint with the provider', async () => {
await unlink(user, ProviderId.PHONE);
expect(endpoint.calls[0].request).to.eql({
idToken: await user.getIdToken(),
deleteProvider: [ProviderId.PHONE]
});
});
});
});
describe('_assertLinkedStatus', () => {
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
};
beforeEach(() => {
getAccountInfoEndpoint = mockEndpoint(Endpoint.GET_ACCOUNT_INFO, {
users: [
{
uid: 'uid',
providerUserInfo: [{ providerId: ProviderId.PHONE }]
}
]
});
});
it('should error with already linked if expectation is true', async () => {
getAccountInfoEndpoint.response = {
users: [
{
...serverUser,
providerUserInfo: [{ providerId: ProviderId.GOOGLE }]
}
]
};
await expect(
_assertLinkedStatus(false, user, ProviderId.GOOGLE)
).to.be.rejectedWith(
FirebaseError,
'Firebase: User can only be linked to one identity for the given provider. (auth/provider-already-linked).'
);
});
it('should not error if provider is not linked', async () => {
await expect(_assertLinkedStatus(false, user, ProviderId.GOOGLE)).not.to
.be.rejected;
});
it('should error if provider is not linked but it was expected to be', async () => {
await expect(
_assertLinkedStatus(true, user, ProviderId.GOOGLE)
).to.be.rejectedWith(
FirebaseError,
'Firebase: User was not linked to an account with the given provider. (auth/no-such-provider).'
);
});
it('should not error if provider is linked and that is expected', async () => {
getAccountInfoEndpoint.response = {
users: [
{
...serverUser,
providerUserInfo: [{ providerId: ProviderId.GOOGLE }]
}
]
};
await expect(_assertLinkedStatus(true, user, ProviderId.GOOGLE)).not.to.be
.rejected;
});
});
});