Skip to content

Commit 56030a0

Browse files
authored
Add more redirect tests so that almost all the main use cases are covered (#4597)
* Flesh out the redirect tests to cover the main use cases as well as error cases * Formatting, licenses * Linter * PR feedback * Formatting * PR feedback
1 parent b6080a8 commit 56030a0

File tree

9 files changed

+485
-86
lines changed

9 files changed

+485
-86
lines changed

packages-exp/auth-exp/test/integration/webdriver/anonymous.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
// eslint-disable-next-line import/no-extraneous-dependencies
1919
import { OperationType, UserCredential } from '@firebase/auth-exp';
2020
import { expect } from 'chai';
21-
import { TestFunction } from './util/auth_driver';
21+
import { AnonFunction } from './util/functions';
2222
import { browserDescribe } from './util/test_runner';
2323

2424
/**
@@ -29,7 +29,7 @@ import { browserDescribe } from './util/test_runner';
2929
browserDescribe('WebDriver anonymous auth test', driver => {
3030
it('basic sign in is possible', async () => {
3131
const cred: UserCredential = await driver.call(
32-
TestFunction.SIGN_IN_ANONYMOUSLY
32+
AnonFunction.SIGN_IN_ANONYMOUSLY
3333
);
3434
expect(cred).not.to.be.null;
3535
expect(cred.user.isAnonymous).to.be.true;
@@ -39,7 +39,7 @@ browserDescribe('WebDriver anonymous auth test', driver => {
3939

4040
it('same user persists after refresh and sign in', async () => {
4141
const { user: before }: UserCredential = await driver.call(
42-
TestFunction.SIGN_IN_ANONYMOUSLY
42+
AnonFunction.SIGN_IN_ANONYMOUSLY
4343
);
4444
await driver.refresh();
4545

@@ -48,7 +48,7 @@ browserDescribe('WebDriver anonymous auth test', driver => {
4848

4949
// Then, sign in again and check
5050
const { user: after }: UserCredential = await driver.call(
51-
TestFunction.SIGN_IN_ANONYMOUSLY
51+
AnonFunction.SIGN_IN_ANONYMOUSLY
5252
);
5353
expect(after.uid).to.eq(before.uid);
5454
});

packages-exp/auth-exp/test/integration/webdriver/redirect.test.ts

Lines changed: 221 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,28 @@
1515
* limitations under the License.
1616
*/
1717

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';
18+
import {
19+
OperationType,
20+
UserCredential,
21+
User,
22+
OAuthCredential
23+
// eslint-disable-next-line import/no-extraneous-dependencies
24+
} from '@firebase/auth-exp';
25+
import { expect, use } from 'chai';
2226
import { IdPPage } from './util/idp_page';
27+
import * as chaiAsPromised from 'chai-as-promised';
2328
import { browserDescribe } from './util/test_runner';
29+
import { AnonFunction, CoreFunction, RedirectFunction } from './util/functions';
30+
31+
use(chaiAsPromised);
2432

2533
browserDescribe('WebDriver redirect IdP test', driver => {
26-
it('allows users to sign in', async () => {
34+
beforeEach(async () => {
2735
await driver.pause(200); // Race condition on auth init
28-
await driver.callNoWait(TestFunction.IDP_REDIRECT);
36+
});
37+
38+
it('allows users to sign in', async () => {
39+
await driver.callNoWait(RedirectFunction.IDP_REDIRECT);
2940
const widget = new IdPPage(driver.webDriver);
3041

3142
// We're now on the widget page; wait for load
@@ -38,16 +49,218 @@ browserDescribe('WebDriver redirect IdP test', driver => {
3849
await widget.clickSignIn();
3950

4051
await driver.reinitOnRedirect();
41-
4252
const currentUser = await driver.getUserSnapshot();
4353
expect(currentUser.email).to.eq('[email protected]');
4454
expect(currentUser.displayName).to.eq('Bob Test');
4555
expect(currentUser.photoURL).to.eq('http://bob.test/bob.png');
4656

4757
const redirectResult: UserCredential = await driver.call(
48-
TestFunction.REDIRECT_RESULT
58+
RedirectFunction.REDIRECT_RESULT
4959
);
5060
expect(redirectResult.operationType).to.eq(OperationType.SIGN_IN);
5161
expect(redirectResult.user).to.eql(currentUser);
5262
});
63+
64+
it('can link with another account account', async () => {
65+
// First, sign in anonymously
66+
const { user: anonUser }: UserCredential = await driver.call(
67+
AnonFunction.SIGN_IN_ANONYMOUSLY
68+
);
69+
70+
// Then, link with redirect
71+
await driver.callNoWait(RedirectFunction.IDP_LINK_REDIRECT);
72+
const widget = new IdPPage(driver.webDriver);
73+
await widget.pageLoad();
74+
await widget.clickAddAccount();
75+
await widget.fillEmail('[email protected]');
76+
await widget.clickSignIn();
77+
78+
await driver.reinitOnRedirect();
79+
// Back on page; check for the current user matching the anonymous account
80+
// as well as the new IdP account
81+
const user: User = await driver.getUserSnapshot();
82+
expect(user.uid).to.eq(anonUser.uid);
83+
expect(user.email).to.eq('[email protected]');
84+
});
85+
86+
it('can be converted to a credential', async () => {
87+
// Start with redirect
88+
await driver.callNoWait(RedirectFunction.IDP_REDIRECT);
89+
const widget = new IdPPage(driver.webDriver);
90+
await widget.pageLoad();
91+
await widget.clickAddAccount();
92+
await widget.fillEmail('[email protected]');
93+
await widget.clickSignIn();
94+
95+
// Generate a credential, then store it on the window before logging out
96+
await driver.reinitOnRedirect();
97+
const first = await driver.getUserSnapshot();
98+
const cred: OAuthCredential = await driver.call(
99+
RedirectFunction.GENERATE_CREDENTIAL_FROM_RESULT
100+
);
101+
expect(cred.accessToken).to.be.a('string');
102+
expect(cred.idToken).to.be.a('string');
103+
expect(cred.signInMethod).to.eq('google.com');
104+
105+
// We've now generated that credential. Sign out and sign back in using it
106+
await driver.call(CoreFunction.SIGN_OUT);
107+
const { user: second }: UserCredential = await driver.call(
108+
RedirectFunction.SIGN_IN_WITH_REDIRECT_CREDENTIAL
109+
);
110+
expect(second.uid).to.eq(first.uid);
111+
expect(second.providerData).to.eql(first.providerData);
112+
});
113+
114+
it('handles account exists different credential errors', async () => {
115+
// Start with redirect and a verified account
116+
await driver.callNoWait(RedirectFunction.IDP_REDIRECT);
117+
const widget = new IdPPage(driver.webDriver);
118+
await widget.pageLoad();
119+
await widget.clickAddAccount();
120+
await widget.fillEmail('[email protected]');
121+
await widget.clickSignIn();
122+
await driver.reinitOnRedirect();
123+
124+
const original = await driver.getUserSnapshot();
125+
expect(original.emailVerified).to.be.true;
126+
127+
// Try to sign in with an unverified Facebook account
128+
// TODO: Convert this to the widget once unverified accounts work
129+
// Come back and verify error / prepare for link
130+
await expect(
131+
driver.call(RedirectFunction.TRY_TO_SIGN_IN_UNVERIFIED, '[email protected]')
132+
).to.be.rejected.and.eventually.have.property(
133+
'code',
134+
'auth/account-exists-with-different-credential'
135+
);
136+
137+
// Now do the link
138+
await driver.call(RedirectFunction.LINK_WITH_ERROR_CREDENTIAL);
139+
140+
// Check the user for both providers
141+
const user = await driver.getUserSnapshot();
142+
expect(user.uid).to.eq(original.uid);
143+
expect(user.providerData.map(d => d.providerId)).to.have.members([
144+
'google.com',
145+
'facebook.com'
146+
]);
147+
});
148+
149+
context('with existing user', () => {
150+
let user1: User;
151+
let user2: User;
152+
153+
beforeEach(async () => {
154+
// Create a couple existing users
155+
let cred: UserCredential = await driver.call(
156+
RedirectFunction.CREATE_FAKE_GOOGLE_USER,
157+
158+
);
159+
user1 = cred.user;
160+
cred = await driver.call(
161+
RedirectFunction.CREATE_FAKE_GOOGLE_USER,
162+
163+
);
164+
user2 = cred.user;
165+
await driver.call(CoreFunction.SIGN_OUT);
166+
});
167+
168+
it('a user can sign in again', async () => {
169+
// Sign in using pre-poulated user
170+
await driver.callNoWait(RedirectFunction.IDP_REDIRECT);
171+
172+
// This time, select an existing account
173+
const widget = new IdPPage(driver.webDriver);
174+
await widget.pageLoad();
175+
await widget.selectExistingAccountByEmail(user1.email!);
176+
177+
// Double check the new sign in matches the old
178+
await driver.reinitOnRedirect();
179+
const user = await driver.getUserSnapshot();
180+
expect(user.uid).to.eq(user1.uid);
181+
expect(user.email).to.eq(user1.email);
182+
});
183+
184+
it('reauthenticate works for the correct user', async () => {
185+
// Sign in using pre-poulated user
186+
await driver.callNoWait(RedirectFunction.IDP_REDIRECT);
187+
188+
const widget = new IdPPage(driver.webDriver);
189+
await widget.pageLoad();
190+
await widget.selectExistingAccountByEmail(user1.email!);
191+
192+
// Double check the new sign in matches the old
193+
await driver.reinitOnRedirect();
194+
let user = await driver.getUserSnapshot();
195+
expect(user.uid).to.eq(user1.uid);
196+
expect(user.email).to.eq(user1.email);
197+
198+
// Reauthenticate specifically
199+
await driver.callNoWait(RedirectFunction.IDP_REAUTH_REDIRECT);
200+
await widget.pageLoad();
201+
await widget.selectExistingAccountByEmail(user1.email!);
202+
203+
await driver.reinitOnRedirect();
204+
user = await driver.getUserSnapshot();
205+
expect(user.uid).to.eq(user1.uid);
206+
expect(user.email).to.eq(user1.email);
207+
});
208+
209+
it('reauthenticate throws for wrong user', async () => {
210+
// Sign in using pre-poulated user
211+
await driver.callNoWait(RedirectFunction.IDP_REDIRECT);
212+
213+
const widget = new IdPPage(driver.webDriver);
214+
await widget.pageLoad();
215+
await widget.selectExistingAccountByEmail(user1.email!);
216+
217+
// Immediately reauth but with the wrong user
218+
await driver.reinitOnRedirect();
219+
await driver.callNoWait(RedirectFunction.IDP_REAUTH_REDIRECT);
220+
await widget.pageLoad();
221+
await widget.selectExistingAccountByEmail(user2.email!);
222+
223+
await driver.reinitOnRedirect();
224+
await expect(
225+
driver.call(RedirectFunction.REDIRECT_RESULT)
226+
).to.be.rejected.and.eventually.have.property(
227+
'code',
228+
'auth/user-mismatch'
229+
);
230+
});
231+
232+
it('handles aborted sign ins', async () => {
233+
await driver.callNoWait(RedirectFunction.IDP_REDIRECT);
234+
const widget = new IdPPage(driver.webDriver);
235+
236+
// Don't actually sign in; go back to the previous page
237+
await widget.pageLoad();
238+
await driver.goToTestPage();
239+
await driver.reinitOnRedirect();
240+
expect(await driver.getUserSnapshot()).to.be.null;
241+
242+
// Now do sign in
243+
await driver.callNoWait(RedirectFunction.IDP_REDIRECT);
244+
// Use user1
245+
await widget.pageLoad();
246+
await widget.selectExistingAccountByEmail(user1.email!);
247+
248+
// Ensure the user was signed in...
249+
await driver.reinitOnRedirect();
250+
let user = await driver.getUserSnapshot();
251+
expect(user.uid).to.eq(user1.uid);
252+
expect(user.email).to.eq(user1.email);
253+
254+
// Now open another sign in, but return
255+
await driver.callNoWait(RedirectFunction.IDP_REAUTH_REDIRECT);
256+
await widget.pageLoad();
257+
await driver.goToTestPage();
258+
await driver.reinitOnRedirect();
259+
260+
// Make sure state remained
261+
user = await driver.getUserSnapshot();
262+
expect(user.uid).to.eq(user1.uid);
263+
expect(user.email).to.eq(user1.email);
264+
});
265+
});
53266
});
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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 { signInAnonymously } from '@firebase/auth-exp';
19+
20+
export async function anonymousSignIn() {
21+
const userCred = await signInAnonymously(auth);
22+
return userCred;
23+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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+
export function reset() {
19+
sessionStorage.clear();
20+
localStorage.clear();
21+
const del = indexedDB.deleteDatabase('firebaseLocalStorageDb');
22+
23+
return new Promise(resolve => {
24+
del.addEventListener('success', () => resolve());
25+
del.addEventListener('error', () => resolve());
26+
del.addEventListener('blocked', () => resolve());
27+
});
28+
}
29+
30+
export function authInit() {
31+
return new Promise(resolve => {
32+
auth.onAuthStateChanged(() => resolve());
33+
});
34+
}
35+
36+
export async function userSnap() {
37+
return auth.currentUser;
38+
}
39+
40+
export async function authSnap() {
41+
return auth;
42+
}
43+
44+
export function signOut() {
45+
return auth.signOut();
46+
}

0 commit comments

Comments
 (0)