veritatisdoloremque
Version:
Monorepo for the Firebase JavaScript SDK
317 lines (282 loc) • 9.31 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 { restore, SinonStub, stub } from 'sinon';
import * as sinonChai from 'sinon-chai';
import { ActionCodeOperation, ProviderId } from '../../model/public_types';
import { FirebaseError, isNode } from '@firebase/util';
import { mockEndpoint } from '../../../test/helpers/api/helper';
import { testAuth, TestAuth, testUser } from '../../../test/helpers/mock_auth';
import * as mockFetch from '../../../test/helpers/mock_fetch';
import { Endpoint } from '../../api';
import { ServerError } from '../../api/errors';
import { UserInternal } from '../../model/user';
import {
fetchSignInMethodsForEmail,
sendEmailVerification,
verifyBeforeUpdateEmail
} from './email';
use(chaiAsPromised);
use(sinonChai);
describe('core/strategies/fetchSignInMethodsForEmail', () => {
const email = 'foo@bar.com';
const expectedSignInMethods = [ProviderId.PASSWORD, ProviderId.GOOGLE];
let auth: TestAuth;
beforeEach(async () => {
auth = await testAuth();
mockFetch.setUp();
});
afterEach(mockFetch.tearDown);
if (isNode()) {
context('node', () => {
it('should use localhost for the continueUri', async () => {
const mock = mockEndpoint(Endpoint.CREATE_AUTH_URI, {
signinMethods: expectedSignInMethods
});
const response = await fetchSignInMethodsForEmail(auth, email);
expect(response).to.eql(expectedSignInMethods);
expect(mock.calls[0].request).to.eql({
identifier: email,
continueUri: 'http://localhost'
});
});
});
} else {
it('should return the sign in methods', async () => {
const mock = mockEndpoint(Endpoint.CREATE_AUTH_URI, {
signinMethods: expectedSignInMethods
});
const response = await fetchSignInMethodsForEmail(auth, email);
expect(response).to.eql(expectedSignInMethods);
const request = mock.calls[0].request as Record<string, string>;
expect(request['identifier']).to.eq(email);
// We can't rely on a fixed port number
expect(request['continueUri']).to.match(
/http:\/\/localhost:[0-9]+\/context\.html/
);
});
}
it('should surface errors', async () => {
const mock = mockEndpoint(
Endpoint.CREATE_AUTH_URI,
{
error: {
code: 400,
message: ServerError.INVALID_EMAIL
}
},
400
);
await expect(fetchSignInMethodsForEmail(auth, email)).to.be.rejectedWith(
FirebaseError,
'Firebase: The email address is badly formatted. (auth/invalid-email).'
);
expect(mock.calls.length).to.eq(1);
});
});
describe('core/strategies/sendEmailVerification', () => {
const email = 'foo@bar.com';
const idToken = 'access-token';
let user: UserInternal;
let auth: TestAuth;
let reloadStub: SinonStub;
beforeEach(async () => {
auth = await testAuth();
user = testUser(auth, 'my-user-uid', email, true);
mockFetch.setUp();
reloadStub = stub(user, 'reload');
});
afterEach(() => {
mockFetch.tearDown();
restore();
});
it('should send the email verification', async () => {
const mock = mockEndpoint(Endpoint.SEND_OOB_CODE, {
requestType: ActionCodeOperation.VERIFY_EMAIL,
email
});
await sendEmailVerification(user);
expect(reloadStub).to.not.have.been.called;
expect(mock.calls[0].request).to.eql({
requestType: ActionCodeOperation.VERIFY_EMAIL,
idToken
});
});
it('should reload the user if the API returns a different email', async () => {
const mock = mockEndpoint(Endpoint.SEND_OOB_CODE, {
requestType: ActionCodeOperation.VERIFY_EMAIL,
email: 'other@email.com'
});
await sendEmailVerification(user);
expect(reloadStub).to.have.been.calledOnce;
expect(mock.calls[0].request).to.eql({
requestType: ActionCodeOperation.VERIFY_EMAIL,
idToken
});
});
context('on iOS', () => {
it('should pass action code parameters', async () => {
const mock = mockEndpoint(Endpoint.SEND_OOB_CODE, {
requestType: ActionCodeOperation.VERIFY_EMAIL,
email
});
await sendEmailVerification(user, {
handleCodeInApp: true,
iOS: {
bundleId: 'my-bundle'
},
url: 'my-url',
dynamicLinkDomain: 'fdl-domain'
});
expect(mock.calls[0].request).to.eql({
requestType: ActionCodeOperation.VERIFY_EMAIL,
idToken,
continueUrl: 'my-url',
dynamicLinkDomain: 'fdl-domain',
canHandleCodeInApp: true,
iosBundleId: 'my-bundle'
});
});
});
context('on Android', () => {
it('should pass action code parameters', async () => {
const mock = mockEndpoint(Endpoint.SEND_OOB_CODE, {
requestType: ActionCodeOperation.VERIFY_EMAIL,
email
});
await sendEmailVerification(user, {
handleCodeInApp: true,
android: {
installApp: false,
minimumVersion: 'my-version',
packageName: 'my-package'
},
url: 'my-url',
dynamicLinkDomain: 'fdl-domain'
});
expect(mock.calls[0].request).to.eql({
requestType: ActionCodeOperation.VERIFY_EMAIL,
idToken,
continueUrl: 'my-url',
dynamicLinkDomain: 'fdl-domain',
canHandleCodeInApp: true,
androidInstallApp: false,
androidMinimumVersionCode: 'my-version',
androidPackageName: 'my-package'
});
});
});
});
describe('core/strategies/verifyBeforeUpdateEmail', () => {
const email = 'foo@bar.com';
const newEmail = 'newemail@bar.com';
const idToken = 'access-token';
let user: UserInternal;
let auth: TestAuth;
let reloadStub: SinonStub;
beforeEach(async () => {
auth = await testAuth();
user = testUser(auth, 'my-user-uid', email, true);
mockFetch.setUp();
reloadStub = stub(user, 'reload');
});
afterEach(() => {
mockFetch.tearDown();
restore();
});
it('should send the email verification', async () => {
const mock = mockEndpoint(Endpoint.SEND_OOB_CODE, {
requestType: ActionCodeOperation.VERIFY_AND_CHANGE_EMAIL,
email
});
await verifyBeforeUpdateEmail(user, newEmail);
expect(reloadStub).to.not.have.been.called;
expect(mock.calls[0].request).to.eql({
requestType: ActionCodeOperation.VERIFY_AND_CHANGE_EMAIL,
idToken,
newEmail
});
});
it('should reload the user if the API returns a different email', async () => {
const mock = mockEndpoint(Endpoint.SEND_OOB_CODE, {
requestType: ActionCodeOperation.VERIFY_AND_CHANGE_EMAIL,
email: 'other@email.com'
});
await verifyBeforeUpdateEmail(user, newEmail);
expect(reloadStub).to.have.been.calledOnce;
expect(mock.calls[0].request).to.eql({
requestType: ActionCodeOperation.VERIFY_AND_CHANGE_EMAIL,
idToken,
newEmail
});
});
context('on iOS', () => {
it('should pass action code parameters', async () => {
const mock = mockEndpoint(Endpoint.SEND_OOB_CODE, {
requestType: ActionCodeOperation.VERIFY_AND_CHANGE_EMAIL,
email
});
await verifyBeforeUpdateEmail(user, newEmail, {
handleCodeInApp: true,
iOS: {
bundleId: 'my-bundle'
},
url: 'my-url',
dynamicLinkDomain: 'fdl-domain'
});
expect(mock.calls[0].request).to.eql({
requestType: ActionCodeOperation.VERIFY_AND_CHANGE_EMAIL,
idToken,
newEmail,
continueUrl: 'my-url',
dynamicLinkDomain: 'fdl-domain',
canHandleCodeInApp: true,
iosBundleId: 'my-bundle'
});
});
});
context('on Android', () => {
it('should pass action code parameters', async () => {
const mock = mockEndpoint(Endpoint.SEND_OOB_CODE, {
requestType: ActionCodeOperation.VERIFY_AND_CHANGE_EMAIL,
email
});
await verifyBeforeUpdateEmail(user, newEmail, {
handleCodeInApp: true,
android: {
installApp: false,
minimumVersion: 'my-version',
packageName: 'my-package'
},
url: 'my-url',
dynamicLinkDomain: 'fdl-domain'
});
expect(mock.calls[0].request).to.eql({
requestType: ActionCodeOperation.VERIFY_AND_CHANGE_EMAIL,
idToken,
newEmail,
continueUrl: 'my-url',
dynamicLinkDomain: 'fdl-domain',
canHandleCodeInApp: true,
androidInstallApp: false,
androidMinimumVersionCode: 'my-version',
androidPackageName: 'my-package'
});
});
});
});