Skip to content

Commit 732aaba

Browse files
committed
Get webdriver tests working
1 parent 16ea044 commit 732aaba

File tree

12 files changed

+285
-37
lines changed

12 files changed

+285
-37
lines changed

packages-exp/auth-compat-exp/scripts/run_node_tests.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,14 @@ const nyc = resolve(__dirname, '../../../node_modules/.bin/nyc');
3333
const mocha = resolve(__dirname, '../../../node_modules/.bin/mocha');
3434

3535
process.env.TS_NODE_COMPILER_OPTIONS = '{"module":"commonjs", "target": "es6"}';
36+
process.env.COMPAT_LAYER = 'true';
3637

3738
let testConfig = ['src/**/*.test.ts'];
3839

3940
if (argv.integration) {
4041
testConfig = ['test/integration/flows/**.test.ts'];
4142
} else if (argv.webdriver) {
42-
testConfig = ['../auth-exp/test/integration/webdriver/anonymous.test.ts', '--delay'];
43+
testConfig = ['../auth-exp/test/integration/webdriver/*.test.ts', '--delay'];
4344
}
4445

4546
let args = [

packages-exp/auth-compat-exp/src/auth.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ export class Auth
219219
break;
220220
case Persistence.LOCAL:
221221
// Not using isIndexedDBAvailable() since it only checks if indexedDB is defined.
222-
const isIndexedDBFullySupported = await (exp.indexedDBLocalPersistence as exp.PersistenceInternal)._isAvailable();
222+
const isIndexedDBFullySupported = await exp._getInstance<exp.PersistenceInternal>(exp.indexedDBLocalPersistence)._isAvailable();
223223
converted = isIndexedDBFullySupported
224224
? exp.indexedDBLocalPersistence
225225
: exp.browserLocalPersistence;

packages-exp/auth-compat-exp/src/popup_redirect.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,23 +39,17 @@ export class CompatPopupRedirectResolver
3939
) => Promise<exp.UserCredential | null> = exp._getRedirectResult;
4040

4141
async _initialize(auth: exp.AuthImpl): Promise<exp.EventManager> {
42-
if (this.underlyingResolver) {
43-
return this.underlyingResolver._initialize(auth);
44-
}
45-
46-
// We haven't yet determined whether or not we're in Cordova; go ahead
47-
// and determine that state now.
48-
const isCordova = await _isCordova();
49-
this.underlyingResolver = isCordova ? CORDOVA_RESOLVER : BROWSER_RESOLVER;
42+
await this.selectUnderlyingResolver();
5043
return this.assertedUnderlyingResolver._initialize(auth);
5144
}
5245

53-
_openPopup(
46+
async _openPopup(
5447
auth: exp.AuthImpl,
5548
provider: exp.AuthProvider,
5649
authType: exp.AuthEventType,
5750
eventId?: string
5851
): Promise<exp.AuthPopup> {
52+
await this.selectUnderlyingResolver();
5953
return this.assertedUnderlyingResolver._openPopup(
6054
auth,
6155
provider,
@@ -64,12 +58,13 @@ export class CompatPopupRedirectResolver
6458
);
6559
}
6660

67-
_openRedirect(
61+
async _openRedirect(
6862
auth: exp.AuthImpl,
6963
provider: exp.AuthProvider,
7064
authType: exp.AuthEventType,
7165
eventId?: string
7266
): Promise<void> {
67+
await this.selectUnderlyingResolver();
7368
return this.assertedUnderlyingResolver._openRedirect(
7469
auth,
7570
provider,
@@ -97,4 +92,15 @@ export class CompatPopupRedirectResolver
9792
_assert(this.underlyingResolver, exp.AuthErrorCode.INTERNAL_ERROR);
9893
return this.underlyingResolver;
9994
}
95+
96+
private async selectUnderlyingResolver(): Promise<void> {
97+
if (this.underlyingResolver) {
98+
return;
99+
}
100+
101+
// We haven't yet determined whether or not we're in Cordova; go ahead
102+
// and determine that state now.
103+
const isCordova = await _isCordova();
104+
this.underlyingResolver = isCordova ? CORDOVA_RESOLVER : BROWSER_RESOLVER;
105+
}
100106
}

packages-exp/auth-compat-exp/test/integration/webdriver/static/anonymous.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,5 @@
1616
*/
1717

1818
export async function anonymousSignIn() {
19-
console.error('hi');
20-
return firebase.auth().signInAnonymously();
19+
return compat.auth().signInAnonymously();
2120
}

packages-exp/auth-compat-exp/test/integration/webdriver/static/core.js

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,30 @@ export function reset() {
2222

2323
export function authInit() {
2424
return new Promise(resolve => {
25-
firebase.auth().onAuthStateChanged(user => {
26-
console.error('Init resolution', user);
25+
compat.auth().onAuthStateChanged(user => {
2726
resolve();
2827
});
2928
});
3029
}
3130

31+
export function legacyAuthInit() {
32+
return new Promise(resolve => {
33+
legacyAuth.onAuthStateChanged(() => resolve());
34+
});
35+
}
36+
3237
export async function userSnap() {
33-
console.error('User snap', firebase.auth().currentUser);
34-
return firebase.auth().currentUser;
38+
return compat.auth().currentUser;
39+
}
40+
41+
export async function legacyUserSnap() {
42+
return legacyAuth.currentUser;
3543
}
3644

3745
export async function authSnap() {
38-
return firebase.auth();
46+
return compat.auth();
3947
}
4048

4149
export function signOut() {
42-
return firebase.auth().signOut();
50+
return compat.auth().signOut();
4351
}

packages-exp/auth-compat-exp/test/integration/webdriver/static/email.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,5 @@
1818
const TEST_PASSWORD = 'password';
1919

2020
export function createUser(email) {
21-
return firebase.auth().createUserWithEmailAndPassword(email, TEST_PASSWORD);
21+
return compat.auth().createUserWithEmailAndPassword(email, TEST_PASSWORD);
2222
}

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

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,31 +15,63 @@
1515
* limitations under the License.
1616
*/
1717

18-
// import * as redirect from './redirect';
18+
import * as redirect from './redirect';
1919
import firebase from '@firebase/app-compat';
2020
import '@firebase/auth-compat';
2121
import * as anonymous from './anonymous';
2222
import * as core from './core';
23-
// import * as popup from './popup';
23+
import * as popup from './popup';
2424
import * as email from './email';
25-
// import * as persistence from './persistence';
26-
// import { initializeApp } from '@firebase/app-exp';
27-
// import { getAuth, useAuthEmulator } from '@firebase/auth-exp';
25+
import * as persistence from './persistence';
2826

2927
window.core = core;
3028
window.anonymous = anonymous;
31-
// window.redirect = redirect;
32-
// window.popup = popup;
29+
window.redirect = redirect;
30+
window.popup = popup;
3331
window.email = email;
34-
// window.persistence = persistence;
32+
window.persistence = persistence;
3533

36-
// window.auth = null;
34+
window.compat = null;
35+
window.legacyAuth = null;
3736

3837
// The config and emulator URL are injected by the test. The test framework
3938
// calls this function after that injection.
4039
window.startAuth = async () => {
41-
console.warn('Starting auth...');
40+
// Make sure we haven't confused our firebase with the old firebase
41+
if (!firebase.SDK_VERSION.startsWith('0.9')) {
42+
throw new Error('Using legacy SDK version instead of compat version ' + firebase.SDK_VERSION);
43+
}
4244
firebase.initializeApp(firebaseConfig);
4345
firebase.auth().useEmulator(emulatorUrl);
44-
window.firebase = firebase;
46+
window.compat = firebase;
4547
};
48+
49+
50+
window.startLegacySDK = async persistence => {
51+
return new Promise((resolve, reject) => {
52+
const appScript = document.createElement('script');
53+
// TODO: Find some way to make the tests work without Internet.
54+
appScript.src = 'https://www.gstatic.com/firebasejs/8.3.0/firebase-app.js';
55+
appScript.onerror = reject;
56+
document.head.appendChild(appScript);
57+
58+
const authScript = document.createElement('script');
59+
authScript.src =
60+
'https://www.gstatic.com/firebasejs/8.3.0/firebase-auth.js';
61+
authScript.onerror = reject;
62+
authScript.onload = function () {
63+
window.firebase.initializeApp(firebaseConfig);
64+
// Make sure the firebase variable here is the legacy SDK
65+
if (window.firebase.SDK_VERSION !== '8.3.0') {
66+
reject(new Error('Not using correct legacy version; using ' + window.firebase.SDK_VERSION));
67+
}
68+
const legacyAuth = window.firebase.auth();
69+
legacyAuth.useEmulator(emulatorUrl);
70+
legacyAuth.setPersistence(persistence.toLowerCase());
71+
window.legacyAuth = legacyAuth;
72+
resolve();
73+
};
74+
document.head.appendChild(authScript);
75+
});
76+
};
77+

packages-exp/auth-compat-exp/test/integration/webdriver/static/persistence.js

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,14 @@ const sessionStorage = window.sessionStorage;
2525
export async function clearPersistence() {
2626
sessionStorage.clear();
2727
localStorage.clear();
28-
return dbPromise(indexedDB.deleteDatabase(INDEXED_DB_NAME)).catch(
29-
() => undefined
30-
);
28+
// HACK: Deleting databases in Firefox sometimes take a few seconds. Let's just return early.
29+
return withTimeout(
30+
1000,
31+
dbPromise(indexedDB.deleteDatabase(INDEXED_DB_NAME))
32+
).catch(e => {
33+
console.error(e);
34+
return;
35+
});
3136
}
3237

3338
export async function localStorageSnap() {
@@ -64,6 +69,22 @@ export async function indexedDBSnap() {
6469
return result;
6570
}
6671

72+
export async function setPersistenceMemory() {
73+
return compat.auth().setPersistence('none');
74+
}
75+
76+
export async function setPersistenceSession() {
77+
return compat.auth().setPersistence('session');
78+
}
79+
80+
export async function setPersistenceLocalStorage() {
81+
return compat.auth().setPersistence('local');
82+
}
83+
84+
export async function setPersistenceIndexedDB() {
85+
return compat.auth().setPersistence('local');
86+
}
87+
6788
// Mock functions for testing edge cases
6889
export async function makeIndexedDBReadonly() {
6990
IDBObjectStore.prototype.add = IDBObjectStore.prototype.put = () => {
@@ -111,3 +132,12 @@ function dbPromise(dbRequest) {
111132
});
112133
});
113134
}
135+
136+
function withTimeout(ms, promise) {
137+
return Promise.race([
138+
new Promise((_, reject) =>
139+
setTimeout(() => reject(new Error('operation timed out')), ms)
140+
),
141+
promise
142+
]);
143+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
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+
// These functions are a little funky: WebDriver relies on callbacks to
19+
// pass data back to the main Node process. Because of that setup, we can't
20+
// return the popup tasks as pending promises as they won't resolve until
21+
// the WebDriver is allowed to do other stuff. Instead, we'll store the
22+
// promises in variables and provide a way to retrieve them later, unblocking
23+
// the WebDriver process.
24+
let popupPromise = null;
25+
let popupCred = null;
26+
let errorCred = null;
27+
28+
export function idpPopup(optProvider) {
29+
const provider = optProvider
30+
? new compat.auth.OAuthProvider(optProvider)
31+
: new compat.auth.GoogleAuthProvider();
32+
popupPromise = compat.auth().signInWithPopup(provider);
33+
}
34+
35+
export function idpReauthPopup() {
36+
popupPromise = compat.auth().currentUser.reauthenticateWithPopup(
37+
new compat.auth.GoogleAuthProvider()
38+
);
39+
}
40+
41+
export function idpLinkPopup() {
42+
popupPromise = compat.auth().currentUser.linkWithPopup(new compat.auth.GoogleAuthProvider());
43+
}
44+
45+
export function popupResult() {
46+
return popupPromise;
47+
}
48+
49+
export async function generateCredentialFromResult() {
50+
const result = await popupPromise;
51+
popupCred = result.credential;
52+
return popupCred;
53+
}
54+
55+
export async function signInWithPopupCredential() {
56+
return compat.auth().signInWithCredential(popupCred);
57+
}
58+
59+
export async function linkWithErrorCredential() {
60+
await compat.auth().currentUser.linkWithCredential(errorCred);
61+
}
62+
63+
// These below are not technically popup functions but they're helpers for
64+
// the popup tests.
65+
66+
export function createFakeGoogleUser(email) {
67+
return compat.auth().signInWithCredential(
68+
compat.auth.GoogleAuthProvider.credential(
69+
`{"sub": "__${email}__", "email": "${email}", "email_verified": true}`
70+
)
71+
);
72+
}
73+
74+
export async function tryToSignInUnverified(email) {
75+
try {
76+
await compat.auth().signInWithCredential(
77+
compat.auth.FacebookAuthProvider.credential(
78+
`{"sub": "$$${email}$$", "email": "${email}", "email_verified": false}`
79+
)
80+
);
81+
} catch (e) {
82+
errorCred = e.credential;
83+
throw e;
84+
}
85+
}

0 commit comments

Comments
 (0)