Skip to content

[Auth] Update and add integration tests to bring us closer to parity with the existing tests #4605

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions packages-exp/auth-exp/test/integration/flows/custom.local.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
Auth,
createUserWithEmailAndPassword,
EmailAuthProvider,
getAdditionalUserInfo,
linkWithCredential,
OperationType,
reload,
Expand Down Expand Up @@ -73,6 +74,9 @@ describe('Integration test: custom auth', () => {
'some-claim'
);
expect(user.providerId).to.eq('firebase');
const additionalUserInfo = await getAdditionalUserInfo(cred)!;
expect(additionalUserInfo.providerId).to.be.null;
expect(additionalUserInfo.isNewUser).to.be.true;
});

it('uid will overwrite existing user, joining accounts', async () => {
Expand Down Expand Up @@ -128,6 +132,20 @@ describe('Integration test: custom auth', () => {
expect(user.photoURL).to.eq('photo-url');
});

it('token can be refreshed', async () => {
const { user } = await signInWithCustomToken(auth, customToken);
const origToken = await user.getIdToken();
await new Promise(resolve => setTimeout(resolve, 1000));
expect(await user.getIdToken(true)).not.to.eq(origToken);
});

it('signing in will not override anonymous user', async () => {
const { user: anonUser } = await signInAnonymously(auth);
const { user: customUser } = await signInWithCustomToken(auth, customToken);
expect(auth.currentUser).to.eql(customUser);
expect(customUser.uid).not.to.eql(anonUser.uid);
});

context('email/password interaction', () => {
let email: string;
let customToken: string;
Expand Down
16 changes: 15 additions & 1 deletion packages-exp/auth-exp/test/integration/flows/email.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ import {
updateProfile,
Auth,
OperationType,
UserCredential
UserCredential,
getAdditionalUserInfo
// eslint-disable-next-line import/no-extraneous-dependencies
} from '@firebase/auth-exp';
import { FirebaseError } from '@firebase/util';
Expand Down Expand Up @@ -64,6 +65,13 @@ describe('Integration test: email/password auth', () => {
expect(user.uid).to.be.a('string');
expect(user.email).to.eq(email);
expect(user.emailVerified).to.be.false;
expect(user.providerData.length).to.eq(1);
expect(user.providerData[0].providerId).to.eq('password');
expect(user.providerData[0].email).to.eq(email);

const additionalUserInfo = getAdditionalUserInfo(userCred)!;
expect(additionalUserInfo.isNewUser).to.be.true;
expect(additionalUserInfo.providerId).to.eq('password');
});

it('errors when createUser called twice', async () => {
Expand Down Expand Up @@ -95,6 +103,9 @@ describe('Integration test: email/password auth', () => {

expect(signInCred.operationType).to.eq(OperationType.SIGN_IN);
expect(signInCred.user.uid).to.eq(signUpCred.user.uid);
const additionalUserInfo = getAdditionalUserInfo(signInCred)!;
expect(additionalUserInfo.isNewUser).to.be.false;
expect(additionalUserInfo.providerId).to.eq('password');
});

it('allows the user to sign in with signInWithCredential', async () => {
Expand All @@ -104,6 +115,9 @@ describe('Integration test: email/password auth', () => {

expect(signInCred.operationType).to.eq(OperationType.SIGN_IN);
expect(signInCred.user.uid).to.eq(signUpCred.user.uid);
const additionalUserInfo = getAdditionalUserInfo(signInCred)!;
expect(additionalUserInfo.isNewUser).to.be.false;
expect(additionalUserInfo.providerId).to.eq('password');
});

it('allows the user to update profile', async () => {
Expand Down
50 changes: 41 additions & 9 deletions packages-exp/auth-exp/test/integration/flows/phone.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,15 @@ describe('Integration test: phone auth', () => {
document.body.removeChild(fakeRecaptchaContainer);
});

function resetVerifier(): void {
verifier.clear();
verifier = new RecaptchaVerifier(
fakeRecaptchaContainer,
undefined as any,
auth
);
}

/** If in the emulator, search for the code in the API */
async function code(
crOrId: ConfirmationResult | string,
Expand Down Expand Up @@ -126,18 +135,41 @@ describe('Integration test: phone auth', () => {
expect(auth.currentUser!.phoneNumber).to.be.null;
});

it('anonymous users can upgrade using phone number', async () => {
const { user } = await signInAnonymously(auth);
const { uid: anonId } = user;

const provider = new PhoneAuthProvider(auth);
const verificationId = await provider.verifyPhoneNumber(
PHONE_B.phoneNumber,
verifier
);

await updatePhoneNumber(
user,
PhoneAuthProvider.credential(
verificationId,
await code(verificationId, PHONE_B.code)
)
);
expect(user.phoneNumber).to.eq(PHONE_B.phoneNumber);

await auth.signOut();
resetVerifier();

const cr = await signInWithPhoneNumber(auth, PHONE_B.phoneNumber, verifier);
const { user: secondSignIn } = await cr.confirm(
await code(cr, PHONE_B.code)
);
expect(secondSignIn.uid).to.eq(anonId);
expect(secondSignIn.isAnonymous).to.be.false;
expect(secondSignIn.providerData[0].phoneNumber).to.eq(PHONE_B.phoneNumber);
expect(secondSignIn.providerData[0].providerId).to.eq('phone');
});

context('with already-created user', () => {
let signUpCred: UserCredential;

function resetVerifier(): void {
verifier.clear();
verifier = new RecaptchaVerifier(
fakeRecaptchaContainer,
undefined as any,
auth
);
}

beforeEach(async () => {
const cr = await signInWithPhoneNumber(
auth,
Expand Down
90 changes: 89 additions & 1 deletion packages-exp/auth-exp/test/integration/webdriver/popup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ import { expect, use } from 'chai';
import { IdPPage } from './util/idp_page';
import * as chaiAsPromised from 'chai-as-promised';
import { browserDescribe } from './util/test_runner';
import { AnonFunction, CoreFunction, PopupFunction } from './util/functions';
import {
AnonFunction,
CoreFunction,
EmailFunction,
PopupFunction
} from './util/functions';

use(chaiAsPromised);

Expand Down Expand Up @@ -146,6 +151,89 @@ browserDescribe('Popup IdP tests', driver => {
]);
});

it('does not auto-upgrade anon accounts', async () => {
const { user: anonUser }: UserCredential = await driver.call(
AnonFunction.SIGN_IN_ANONYMOUSLY
);
await driver.callNoWait(PopupFunction.IDP_POPUP);
await driver.selectPopupWindow();
const widget = new IdPPage(driver.webDriver);
await widget.pageLoad();
await widget.clickAddAccount();
await widget.fillEmail('[email protected]');
await widget.clickSignIn();

// On redirect, check that the signed in user is different
await driver.selectMainWindow();
const curUser = await driver.getUserSnapshot();
expect(curUser.uid).not.to.eq(anonUser.uid);
});

it('linking with anonymous user upgrades account', async () => {
const { user: anonUser }: UserCredential = await driver.call(
AnonFunction.SIGN_IN_ANONYMOUSLY
);
await driver.callNoWait(PopupFunction.IDP_LINK_POPUP);
await driver.selectPopupWindow();
const widget = new IdPPage(driver.webDriver);
await widget.pageLoad();
await widget.clickAddAccount();
await widget.fillEmail('[email protected]');
await widget.clickSignIn();

// On redirect, check that the signed in user is upgraded
await driver.selectMainWindow();
const curUser = await driver.getUserSnapshot();
expect(curUser.uid).to.eq(anonUser.uid);
expect(curUser.isAnonymous).to.be.false;
});

it('is possible to link with different email', async () => {
const { user: emailUser }: UserCredential = await driver.call(
EmailFunction.CREATE_USER,
'[email protected]'
);

// Link using pre-poulated user
await driver.callNoWait(PopupFunction.IDP_LINK_POPUP);
await driver.selectPopupWindow();
const widget = new IdPPage(driver.webDriver);
await widget.pageLoad();
await widget.clickAddAccount();
await widget.fillEmail('[email protected]');
await widget.clickSignIn();

// Check the linked account
await driver.selectMainWindow();
const curUser = await driver.getUserSnapshot();
expect(curUser.uid).to.eq(emailUser.uid);
expect(curUser.emailVerified).to.be.false;
expect(curUser.providerData.length).to.eq(2);
});

it('is possible to link with the same email', async () => {
const { user: emailUser }: UserCredential = await driver.call(
EmailFunction.CREATE_USER,
'[email protected]'
);

// Link using pre-poulated user
await driver.callNoWait(PopupFunction.IDP_LINK_POPUP);
await driver.selectPopupWindow();
const widget = new IdPPage(driver.webDriver);
await widget.pageLoad();
await widget.clickAddAccount();
await widget.fillEmail('[email protected]');
await widget.clickSignIn();

// Check the linked account
await driver.selectMainWindow();
const curUser = await driver.getUserSnapshot();
expect(curUser.uid).to.eq(emailUser.uid);
expect(curUser.emailVerified).to.be.true;
expect(curUser.providerData.length).to.eq(2);
});

context('with existing user', () => {
let user1: User;
let user2: User;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ import { expect, use } from 'chai';
import { IdPPage } from './util/idp_page';
import * as chaiAsPromised from 'chai-as-promised';
import { browserDescribe } from './util/test_runner';
import { AnonFunction, CoreFunction, RedirectFunction } from './util/functions';
import {
AnonFunction,
CoreFunction,
EmailFunction,
RedirectFunction
} from './util/functions';

use(chaiAsPromised);

Expand Down Expand Up @@ -146,6 +151,87 @@ browserDescribe('WebDriver redirect IdP test', driver => {
]);
});

it('does not auto-upgrade anon accounts', async () => {
const { user: anonUser }: UserCredential = await driver.call(
AnonFunction.SIGN_IN_ANONYMOUSLY
);
await driver.callNoWait(RedirectFunction.IDP_REDIRECT);
const widget = new IdPPage(driver.webDriver);
await widget.pageLoad();
await widget.clickAddAccount();
await widget.fillEmail('[email protected]');
await widget.clickSignIn();

// On redirect, check that the signed in user is different
await driver.reinitOnRedirect();
const curUser = await driver.getUserSnapshot();
expect(curUser.uid).not.to.eq(anonUser.uid);
});

it('linking with anonymous user upgrades account', async () => {
const { user: anonUser }: UserCredential = await driver.call(
AnonFunction.SIGN_IN_ANONYMOUSLY
);
await driver.callNoWait(RedirectFunction.IDP_LINK_REDIRECT);
const widget = new IdPPage(driver.webDriver);
await widget.pageLoad();
await widget.clickAddAccount();
await widget.fillEmail('[email protected]');
await widget.clickSignIn();

// On redirect, check that the signed in user is upgraded
await driver.reinitOnRedirect();
const curUser = await driver.getUserSnapshot();
expect(curUser.uid).to.eq(anonUser.uid);
expect(curUser.isAnonymous).to.be.false;
});

it('is possible to link with different email', async () => {
const { user: emailUser }: UserCredential = await driver.call(
EmailFunction.CREATE_USER,
'[email protected]'
);

// Link using pre-poulated user
await driver.callNoWait(RedirectFunction.IDP_LINK_REDIRECT);

const widget = new IdPPage(driver.webDriver);
await widget.pageLoad();
await widget.clickAddAccount();
await widget.fillEmail('[email protected]');
await widget.clickSignIn();

// Check the linked account
await driver.reinitOnRedirect();
const curUser = await driver.getUserSnapshot();
expect(curUser.uid).to.eq(emailUser.uid);
expect(curUser.emailVerified).to.be.false;
expect(curUser.providerData.length).to.eq(2);
});

it('is possible to link with the same email', async () => {
const { user: emailUser }: UserCredential = await driver.call(
EmailFunction.CREATE_USER,
'[email protected]'
);

// Link using pre-poulated user
await driver.callNoWait(RedirectFunction.IDP_LINK_REDIRECT);

const widget = new IdPPage(driver.webDriver);
await widget.pageLoad();
await widget.clickAddAccount();
await widget.fillEmail('[email protected]');
await widget.clickSignIn();

// Check the linked account
await driver.reinitOnRedirect();
const curUser = await driver.getUserSnapshot();
expect(curUser.uid).to.eq(emailUser.uid);
expect(curUser.emailVerified).to.be.true;
expect(curUser.providerData.length).to.eq(2);
});

context('with existing user', () => {
let user1: User;
let user2: User;
Expand Down
24 changes: 24 additions & 0 deletions packages-exp/auth-exp/test/integration/webdriver/static/email.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* @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 { createUserWithEmailAndPassword } from '@firebase/auth-exp';

const TEST_PASSWORD = 'password';

export function createUser(email) {
return createUserWithEmailAndPassword(auth, email, TEST_PASSWORD);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ import * as redirect from './redirect';
import * as anonymous from './anonymous';
import * as core from './core';
import * as popup from './popup';
import * as email from './email';
import { initializeApp } from '@firebase/app-exp';
import { getAuth, useAuthEmulator } from '@firebase/auth-exp';

window.core = { ...core };
window.anonymous = { ...anonymous };
window.redirect = { ...redirect };
window.popup = { ...popup };
window.email = { ...email };

// The config and emulator URL are injected by the test. The test framework
// calls this function after that injection.
Expand Down
Loading