quodolores
Version:
Monorepo for the Firebase JavaScript SDK
353 lines (302 loc) • 12.3 kB
text/typescript
/**
* @license
* Copyright 2021 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 {
OperationType,
UserCredential,
User,
OAuthCredential
// eslint-disable-next-line import/no-extraneous-dependencies
} from '@firebase/auth-exp';
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,
EmailFunction,
RedirectFunction
} from './util/functions';
use(chaiAsPromised);
browserDescribe('WebDriver redirect IdP test', driver => {
beforeEach(async () => {
await driver.pause(200); // Race condition on auth init
});
it('allows users to sign in', async () => {
await driver.callNoWait(RedirectFunction.IDP_REDIRECT);
const widget = new IdPPage(driver.webDriver);
// We're now on the widget page; wait for load
await widget.pageLoad();
await widget.clickAddAccount();
await widget.fillEmail('bob@bob.test');
await widget.fillDisplayName('Bob Test');
await widget.fillScreenName('bob.test');
await widget.fillProfilePhoto('http://bob.test/bob.png');
await widget.clickSignIn();
await driver.reinitOnRedirect();
const currentUser = await driver.getUserSnapshot();
expect(currentUser.email).to.eq('bob@bob.test');
expect(currentUser.displayName).to.eq('Bob Test');
expect(currentUser.photoURL).to.eq('http://bob.test/bob.png');
const redirectResult: UserCredential = await driver.call(
RedirectFunction.REDIRECT_RESULT
);
expect(redirectResult.operationType).to.eq(OperationType.SIGN_IN);
expect(redirectResult.user).to.eql(currentUser);
});
it('can link with another account account', async () => {
// First, sign in anonymously
const { user: anonUser }: UserCredential = await driver.call(
AnonFunction.SIGN_IN_ANONYMOUSLY
);
// Then, link with redirect
await driver.callNoWait(RedirectFunction.IDP_LINK_REDIRECT);
const widget = new IdPPage(driver.webDriver);
await widget.pageLoad();
await widget.clickAddAccount();
await widget.fillEmail('bob@bob.test');
await widget.clickSignIn();
await driver.reinitOnRedirect();
// Back on page; check for the current user matching the anonymous account
// as well as the new IdP account
const user: User = await driver.getUserSnapshot();
expect(user.uid).to.eq(anonUser.uid);
expect(user.email).to.eq('bob@bob.test');
});
it('can be converted to a credential', async () => {
// Start with redirect
await driver.callNoWait(RedirectFunction.IDP_REDIRECT);
const widget = new IdPPage(driver.webDriver);
await widget.pageLoad();
await widget.clickAddAccount();
await widget.fillEmail('bob@bob.test');
await widget.clickSignIn();
// Generate a credential, then store it on the window before logging out
await driver.reinitOnRedirect();
const first = await driver.getUserSnapshot();
const cred: OAuthCredential = await driver.call(
RedirectFunction.GENERATE_CREDENTIAL_FROM_RESULT
);
expect(cred.accessToken).to.be.a('string');
expect(cred.idToken).to.be.a('string');
expect(cred.signInMethod).to.eq('google.com');
// We've now generated that credential. Sign out and sign back in using it
await driver.call(CoreFunction.SIGN_OUT);
const { user: second }: UserCredential = await driver.call(
RedirectFunction.SIGN_IN_WITH_REDIRECT_CREDENTIAL
);
expect(second.uid).to.eq(first.uid);
expect(second.providerData).to.eql(first.providerData);
});
it('handles account exists different credential errors', async () => {
// Start with redirect and a verified account
await driver.callNoWait(RedirectFunction.IDP_REDIRECT);
const widget = new IdPPage(driver.webDriver);
await widget.pageLoad();
await widget.clickAddAccount();
await widget.fillEmail('bob@bob.test');
await widget.clickSignIn();
await driver.reinitOnRedirect();
const original = await driver.getUserSnapshot();
expect(original.emailVerified).to.be.true;
// Try to sign in with an unverified Facebook account
// TODO: Convert this to the widget once unverified accounts work
// Come back and verify error / prepare for link
await expect(
driver.call(RedirectFunction.TRY_TO_SIGN_IN_UNVERIFIED, 'bob@bob.test')
).to.be.rejected.and.eventually.have.property(
'code',
'auth/account-exists-with-different-credential'
);
// Now do the link
await driver.call(RedirectFunction.LINK_WITH_ERROR_CREDENTIAL);
// Check the user for both providers
const user = await driver.getUserSnapshot();
expect(user.uid).to.eq(original.uid);
expect(user.providerData.map(d => d.providerId)).to.have.members([
'google.com',
'facebook.com'
]);
});
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('bob@bob.test');
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('bob@bob.test');
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,
'user@test.test'
);
// 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('other-user@test.test');
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,
'same@test.test'
);
// 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('same@test.test');
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;
beforeEach(async () => {
// Create a couple existing users
let cred: UserCredential = await driver.call(
RedirectFunction.CREATE_FAKE_GOOGLE_USER,
'bob@bob.test'
);
user1 = cred.user;
cred = await driver.call(
RedirectFunction.CREATE_FAKE_GOOGLE_USER,
'sally@sally.test'
);
user2 = cred.user;
await driver.call(CoreFunction.SIGN_OUT);
});
it('a user can sign in again', async () => {
// Sign in using pre-poulated user
await driver.callNoWait(RedirectFunction.IDP_REDIRECT);
// This time, select an existing account
const widget = new IdPPage(driver.webDriver);
await widget.pageLoad();
await widget.selectExistingAccountByEmail(user1.email!);
// Double check the new sign in matches the old
await driver.reinitOnRedirect();
const user = await driver.getUserSnapshot();
expect(user.uid).to.eq(user1.uid);
expect(user.email).to.eq(user1.email);
});
it('reauthenticate works for the correct user', async () => {
// Sign in using pre-poulated user
await driver.callNoWait(RedirectFunction.IDP_REDIRECT);
const widget = new IdPPage(driver.webDriver);
await widget.pageLoad();
await widget.selectExistingAccountByEmail(user1.email!);
// Double check the new sign in matches the old
await driver.reinitOnRedirect();
let user = await driver.getUserSnapshot();
expect(user.uid).to.eq(user1.uid);
expect(user.email).to.eq(user1.email);
// Reauthenticate specifically
await driver.callNoWait(RedirectFunction.IDP_REAUTH_REDIRECT);
await widget.pageLoad();
await widget.selectExistingAccountByEmail(user1.email!);
await driver.reinitOnRedirect();
user = await driver.getUserSnapshot();
expect(user.uid).to.eq(user1.uid);
expect(user.email).to.eq(user1.email);
});
it('reauthenticate throws for wrong user', async () => {
// Sign in using pre-poulated user
await driver.callNoWait(RedirectFunction.IDP_REDIRECT);
const widget = new IdPPage(driver.webDriver);
await widget.pageLoad();
await widget.selectExistingAccountByEmail(user1.email!);
// Immediately reauth but with the wrong user
await driver.reinitOnRedirect();
await driver.callNoWait(RedirectFunction.IDP_REAUTH_REDIRECT);
await widget.pageLoad();
await widget.selectExistingAccountByEmail(user2.email!);
await driver.reinitOnRedirect();
await expect(
driver.call(RedirectFunction.REDIRECT_RESULT)
).to.be.rejected.and.eventually.have.property(
'code',
'auth/user-mismatch'
);
});
it('handles aborted sign ins', async () => {
await driver.callNoWait(RedirectFunction.IDP_REDIRECT);
const widget = new IdPPage(driver.webDriver);
// Don't actually sign in; go back to the previous page
await widget.pageLoad();
await driver.goToTestPage();
await driver.reinitOnRedirect();
expect(await driver.getUserSnapshot()).to.be.null;
// Now do sign in
await driver.callNoWait(RedirectFunction.IDP_REDIRECT);
// Use user1
await widget.pageLoad();
await widget.selectExistingAccountByEmail(user1.email!);
// Ensure the user was signed in...
await driver.reinitOnRedirect();
let user = await driver.getUserSnapshot();
expect(user.uid).to.eq(user1.uid);
expect(user.email).to.eq(user1.email);
// Now open another sign in, but return
await driver.callNoWait(RedirectFunction.IDP_REAUTH_REDIRECT);
await widget.pageLoad();
await driver.goToTestPage();
await driver.reinitOnRedirect();
// Make sure state remained
user = await driver.getUserSnapshot();
expect(user.uid).to.eq(user1.uid);
expect(user.email).to.eq(user1.email);
});
});
});