Skip to content

Add some redirect webdriver tests #4589

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 4 commits into from
Mar 8, 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
2 changes: 1 addition & 1 deletion packages-exp/auth-exp/scripts/run-node-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ var argv = yargs.options({
}).argv;
var nyc = path_1.resolve(__dirname, '../../../node_modules/.bin/nyc');
var mocha = path_1.resolve(__dirname, '../../../node_modules/.bin/mocha');
process.env.TS_NODE_COMPILER_OPTIONS = '{"module":"commonjs"}';
process.env.TS_NODE_COMPILER_OPTIONS = '{"module":"commonjs", "target": "es6"}';
var testConfig = [
'src/!(platform_browser|platform_react_native|platform_cordova)/**/*.test.ts',
'--file',
Expand Down
2 changes: 1 addition & 1 deletion packages-exp/auth-exp/scripts/run-node-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const argv = yargs.options({
const nyc = resolve(__dirname, '../../../node_modules/.bin/nyc');
const mocha = resolve(__dirname, '../../../node_modules/.bin/mocha');

process.env.TS_NODE_COMPILER_OPTIONS = '{"module":"commonjs"}';
process.env.TS_NODE_COMPILER_OPTIONS = '{"module":"commonjs", "target": "es6"}';

let testConfig = [
'src/!(platform_browser|platform_react_native|platform_cordova)/**/*.test.ts',
Expand Down
53 changes: 53 additions & 0 deletions packages-exp/auth-exp/test/integration/webdriver/redirect.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* @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.
*/

// eslint-disable-next-line import/no-extraneous-dependencies
import { OperationType, UserCredential } from '@firebase/auth-exp';
import { expect } from 'chai';
import { TestFunction } from './util/auth_driver';
import { IdPPage } from './util/idp_page';
import { browserDescribe } from './util/test_runner';

browserDescribe('WebDriver redirect IdP test', driver => {
it('allows users to sign in', async () => {
await driver.pause(200); // Race condition on auth init
await driver.callNoWait(TestFunction.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('[email protected]');
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('[email protected]');
expect(currentUser.displayName).to.eq('Bob Test');
expect(currentUser.photoURL).to.eq('http://bob.test/bob.png');

const redirectResult: UserCredential = await driver.call(
TestFunction.REDIRECT_RESULT
);
expect(redirectResult.operationType).to.eq(OperationType.SIGN_IN);
expect(redirectResult.user).to.eql(currentUser);
});
});
11 changes: 11 additions & 0 deletions packages-exp/auth-exp/test/integration/webdriver/static/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@
import { initializeApp } from '@firebase/app-exp';
import {
getAuth,
getRedirectResult,
GoogleAuthProvider,
signInAnonymously,
signInWithRedirect,
useAuthEmulator
} from '@firebase/auth-exp';

Expand Down Expand Up @@ -52,6 +55,14 @@ window.userSnap = async () => auth.currentUser;

window.authSnap = async () => auth;

window.idpRedirect = () => {
signInWithRedirect(auth, new GoogleAuthProvider());
};

window.redirectResult = () => {
return getRedirectResult(auth);
};

// The config and emulator URL are injected by the test. The test framework
// calls this function after that injection.
window.startAuth = async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
PROJECT_ID,
USE_EMULATOR
} from '../../../helpers/integration/settings';
import { JsLoadCondition } from './js_load_condition';
import { authTestServer } from './test_server';

/** Available functions within the browser. See static/index.js */
Expand All @@ -33,7 +34,9 @@ export enum TestFunction {
AWAIT_AUTH_INIT = 'authInit',
USER_SNAPSHOT = 'userSnap',
AUTH_SNAPSHOT = 'authSnap',
START_AUTH = 'startAuth'
START_AUTH = 'startAuth',
IDP_REDIRECT = 'idpRedirect',
REDIRECT_RESULT = 'redirectResult'
}

/** Helper wraper around the WebDriver object */
Expand Down Expand Up @@ -67,6 +70,10 @@ export class AuthDriver {
return JSON.parse(result as string) as T;
}

async callNoWait(fn: TestFunction): Promise<void> {
return this.webDriver.executeScript(`${fn}()`);
}

async getAuthSnapshot(): Promise<Auth> {
return this.call(TestFunction.AUTH_SNAPSHOT);
}
Expand All @@ -85,6 +92,21 @@ export class AuthDriver {
return this.call(TestFunction.AWAIT_AUTH_INIT);
}

async reinitOnRedirect(): Promise<void> {
// In this unique case we don't know when the page is back; check for the
// presence of the init function
// await this.webDriver.wait(this.webDriver.executeScript('typeof authInit !== "undefined"'));
await this.webDriver.wait(new JsLoadCondition(TestFunction.START_AUTH));
await this.injectConfigAndInitAuth();
await this.waitForAuthInit();
}

pause(ms: number): Promise<void> {
return new Promise(resolve => {
setTimeout(() => resolve(), ms);
});
}

async refresh(): Promise<void> {
await this.webDriver.navigate().refresh();
await this.injectConfigAndInitAuth();
Expand Down
72 changes: 72 additions & 0 deletions packages-exp/auth-exp/test/integration/webdriver/util/idp_page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* @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 { By, until, WebDriver } from 'selenium-webdriver';
import { JsLoadCondition } from './js_load_condition';

const ADD_ACCOUNT_BUTTON = By.css('.js-new-account');
const SIGN_IN_BUTTON = By.id('sign-in');
const EMAIL_INPUT = By.id('email-input');
const DISPLAY_NAME_INPUT = By.id('display-name-input');
const SCREEN_NAME_INPUT = By.id('screen-name-input');
const PROFILE_PHOTO_INPUT = By.id('profile-photo-input');

export class IdPPage {
static PAGE_TITLE = 'Auth Emulator IDP Login Widget';

constructor(private readonly driver: WebDriver) {}

async pageLoad(): Promise<void> {
await this.driver.wait(until.titleContains('Auth Emulator'));
await this.driver.wait(new JsLoadCondition('toggleForm'));
}

async clickAddAccount(): Promise<void> {
await this.driver.wait(until.elementLocated(ADD_ACCOUNT_BUTTON));
await this.driver.findElement(ADD_ACCOUNT_BUTTON).click();
}

async clickSignIn(): Promise<void> {
await this.driver.wait(until.elementLocated(SIGN_IN_BUTTON));
const button = await this.driver.findElement(SIGN_IN_BUTTON);
await this.driver.wait(until.elementIsEnabled(button));
await button.click();
}

fillEmail(email: string): Promise<void> {
return this.fillInput(EMAIL_INPUT, email);
}

fillDisplayName(displayName: string): Promise<void> {
return this.fillInput(DISPLAY_NAME_INPUT, displayName);
}

fillScreenName(screenName: string): Promise<void> {
return this.fillInput(SCREEN_NAME_INPUT, screenName);
}

fillProfilePhoto(prophilePhoto: string): Promise<void> {
return this.fillInput(PROFILE_PHOTO_INPUT, prophilePhoto);
}

private async fillInput(input: By, text: string): Promise<void> {
await this.driver.wait(until.elementLocated(input));
const el = await this.driver.findElement(input);
await el.click();
await el.sendKeys(text);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* @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 { Condition } from 'selenium-webdriver';

/**
* A condition that looks for the presence of a specified function. This is
* used with WebDriver .wait() as a proxy for determining when the JS has
* finished loading in a page.
*/
export class JsLoadCondition extends Condition<boolean> {
constructor(globalValue: string) {
super(`Waiting for global value ${globalValue}`, driver => {
return driver.executeScript(
`return typeof ${globalValue} !== 'undefined';`
);
});
}
}