Skip to content

Commit 82ea467

Browse files
authored
Add some redirect webdriver tests (#4589)
* Add some redirect webdriver tests * Formatting * Fix linter issue * PR feedback
1 parent b6caa3f commit 82ea467

File tree

7 files changed

+194
-3
lines changed

7 files changed

+194
-3
lines changed

packages-exp/auth-exp/scripts/run-node-tests.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ var argv = yargs.options({
3535
}).argv;
3636
var nyc = path_1.resolve(__dirname, '../../../node_modules/.bin/nyc');
3737
var mocha = path_1.resolve(__dirname, '../../../node_modules/.bin/mocha');
38-
process.env.TS_NODE_COMPILER_OPTIONS = '{"module":"commonjs"}';
38+
process.env.TS_NODE_COMPILER_OPTIONS = '{"module":"commonjs", "target": "es6"}';
3939
var testConfig = [
4040
'src/!(platform_browser|platform_react_native|platform_cordova)/**/*.test.ts',
4141
'--file',

packages-exp/auth-exp/scripts/run-node-tests.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const argv = yargs.options({
3535
const nyc = resolve(__dirname, '../../../node_modules/.bin/nyc');
3636
const mocha = resolve(__dirname, '../../../node_modules/.bin/mocha');
3737

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

4040
let testConfig = [
4141
'src/!(platform_browser|platform_react_native|platform_cordova)/**/*.test.ts',
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* @license
3+
* Copyright 2021 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
// eslint-disable-next-line import/no-extraneous-dependencies
19+
import { OperationType, UserCredential } from '@firebase/auth-exp';
20+
import { expect } from 'chai';
21+
import { TestFunction } from './util/auth_driver';
22+
import { IdPPage } from './util/idp_page';
23+
import { browserDescribe } from './util/test_runner';
24+
25+
browserDescribe('WebDriver redirect IdP test', driver => {
26+
it('allows users to sign in', async () => {
27+
await driver.pause(200); // Race condition on auth init
28+
await driver.callNoWait(TestFunction.IDP_REDIRECT);
29+
const widget = new IdPPage(driver.webDriver);
30+
31+
// We're now on the widget page; wait for load
32+
await widget.pageLoad();
33+
await widget.clickAddAccount();
34+
await widget.fillEmail('[email protected]');
35+
await widget.fillDisplayName('Bob Test');
36+
await widget.fillScreenName('bob.test');
37+
await widget.fillProfilePhoto('http://bob.test/bob.png');
38+
await widget.clickSignIn();
39+
40+
await driver.reinitOnRedirect();
41+
42+
const currentUser = await driver.getUserSnapshot();
43+
expect(currentUser.email).to.eq('[email protected]');
44+
expect(currentUser.displayName).to.eq('Bob Test');
45+
expect(currentUser.photoURL).to.eq('http://bob.test/bob.png');
46+
47+
const redirectResult: UserCredential = await driver.call(
48+
TestFunction.REDIRECT_RESULT
49+
);
50+
expect(redirectResult.operationType).to.eq(OperationType.SIGN_IN);
51+
expect(redirectResult.user).to.eql(currentUser);
52+
});
53+
});

packages-exp/auth-exp/test/integration/webdriver/static/index.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
import { initializeApp } from '@firebase/app-exp';
1919
import {
2020
getAuth,
21+
getRedirectResult,
22+
GoogleAuthProvider,
2123
signInAnonymously,
24+
signInWithRedirect,
2225
useAuthEmulator
2326
} from '@firebase/auth-exp';
2427

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

5356
window.authSnap = async () => auth;
5457

58+
window.idpRedirect = () => {
59+
signInWithRedirect(auth, new GoogleAuthProvider());
60+
};
61+
62+
window.redirectResult = () => {
63+
return getRedirectResult(auth);
64+
};
65+
5566
// The config and emulator URL are injected by the test. The test framework
5667
// calls this function after that injection.
5768
window.startAuth = async () => {

packages-exp/auth-exp/test/integration/webdriver/util/auth_driver.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
PROJECT_ID,
2525
USE_EMULATOR
2626
} from '../../../helpers/integration/settings';
27+
import { JsLoadCondition } from './js_load_condition';
2728
import { authTestServer } from './test_server';
2829

2930
/** Available functions within the browser. See static/index.js */
@@ -33,7 +34,9 @@ export enum TestFunction {
3334
AWAIT_AUTH_INIT = 'authInit',
3435
USER_SNAPSHOT = 'userSnap',
3536
AUTH_SNAPSHOT = 'authSnap',
36-
START_AUTH = 'startAuth'
37+
START_AUTH = 'startAuth',
38+
IDP_REDIRECT = 'idpRedirect',
39+
REDIRECT_RESULT = 'redirectResult'
3740
}
3841

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

73+
async callNoWait(fn: TestFunction): Promise<void> {
74+
return this.webDriver.executeScript(`${fn}()`);
75+
}
76+
7077
async getAuthSnapshot(): Promise<Auth> {
7178
return this.call(TestFunction.AUTH_SNAPSHOT);
7279
}
@@ -85,6 +92,21 @@ export class AuthDriver {
8592
return this.call(TestFunction.AWAIT_AUTH_INIT);
8693
}
8794

95+
async reinitOnRedirect(): Promise<void> {
96+
// In this unique case we don't know when the page is back; check for the
97+
// presence of the init function
98+
// await this.webDriver.wait(this.webDriver.executeScript('typeof authInit !== "undefined"'));
99+
await this.webDriver.wait(new JsLoadCondition(TestFunction.START_AUTH));
100+
await this.injectConfigAndInitAuth();
101+
await this.waitForAuthInit();
102+
}
103+
104+
pause(ms: number): Promise<void> {
105+
return new Promise(resolve => {
106+
setTimeout(() => resolve(), ms);
107+
});
108+
}
109+
88110
async refresh(): Promise<void> {
89111
await this.webDriver.navigate().refresh();
90112
await this.injectConfigAndInitAuth();
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import { By, until, WebDriver } from 'selenium-webdriver';
19+
import { JsLoadCondition } from './js_load_condition';
20+
21+
const ADD_ACCOUNT_BUTTON = By.css('.js-new-account');
22+
const SIGN_IN_BUTTON = By.id('sign-in');
23+
const EMAIL_INPUT = By.id('email-input');
24+
const DISPLAY_NAME_INPUT = By.id('display-name-input');
25+
const SCREEN_NAME_INPUT = By.id('screen-name-input');
26+
const PROFILE_PHOTO_INPUT = By.id('profile-photo-input');
27+
28+
export class IdPPage {
29+
static PAGE_TITLE = 'Auth Emulator IDP Login Widget';
30+
31+
constructor(private readonly driver: WebDriver) {}
32+
33+
async pageLoad(): Promise<void> {
34+
await this.driver.wait(until.titleContains('Auth Emulator'));
35+
await this.driver.wait(new JsLoadCondition('toggleForm'));
36+
}
37+
38+
async clickAddAccount(): Promise<void> {
39+
await this.driver.wait(until.elementLocated(ADD_ACCOUNT_BUTTON));
40+
await this.driver.findElement(ADD_ACCOUNT_BUTTON).click();
41+
}
42+
43+
async clickSignIn(): Promise<void> {
44+
await this.driver.wait(until.elementLocated(SIGN_IN_BUTTON));
45+
const button = await this.driver.findElement(SIGN_IN_BUTTON);
46+
await this.driver.wait(until.elementIsEnabled(button));
47+
await button.click();
48+
}
49+
50+
fillEmail(email: string): Promise<void> {
51+
return this.fillInput(EMAIL_INPUT, email);
52+
}
53+
54+
fillDisplayName(displayName: string): Promise<void> {
55+
return this.fillInput(DISPLAY_NAME_INPUT, displayName);
56+
}
57+
58+
fillScreenName(screenName: string): Promise<void> {
59+
return this.fillInput(SCREEN_NAME_INPUT, screenName);
60+
}
61+
62+
fillProfilePhoto(prophilePhoto: string): Promise<void> {
63+
return this.fillInput(PROFILE_PHOTO_INPUT, prophilePhoto);
64+
}
65+
66+
private async fillInput(input: By, text: string): Promise<void> {
67+
await this.driver.wait(until.elementLocated(input));
68+
const el = await this.driver.findElement(input);
69+
await el.click();
70+
await el.sendKeys(text);
71+
}
72+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import { Condition } from 'selenium-webdriver';
19+
20+
/**
21+
* A condition that looks for the presence of a specified function. This is
22+
* used with WebDriver .wait() as a proxy for determining when the JS has
23+
* finished loading in a page.
24+
*/
25+
export class JsLoadCondition extends Condition<boolean> {
26+
constructor(globalValue: string) {
27+
super(`Waiting for global value ${globalValue}`, driver => {
28+
return driver.executeScript(
29+
`return typeof ${globalValue} !== 'undefined';`
30+
);
31+
});
32+
}
33+
}

0 commit comments

Comments
 (0)