Skip to content

Commit 14fbc8e

Browse files
authored
Update the phone tests to work with the emulator (#4574)
* Add custom auth test * Formatting * es lint * Update some stuff * Formatting * Allow phone tests to run against emulator as well * Formatting, license * es lint
1 parent 88a3b2e commit 14fbc8e

File tree

2 files changed

+100
-13
lines changed

2 files changed

+100
-13
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
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+
// eslint-disable-next-line import/no-extraneous-dependencies
19+
import { Auth } from '@firebase/auth-exp';
20+
import { getApps } from '@firebase/app-exp';
21+
22+
interface VerificationSession {
23+
code: string;
24+
phoneNumber: string;
25+
sessionInfo: string;
26+
}
27+
28+
interface VerificationCodesResponse {
29+
verificationCodes: VerificationSession[];
30+
}
31+
32+
export async function getPhoneVerificationCodes(
33+
auth: Auth
34+
): Promise<Record<string, VerificationSession>> {
35+
assertEmulator(auth);
36+
const url = getEmulatorUrl(auth, 'verificationCodes');
37+
const response: VerificationCodesResponse = await (await fetch(url)).json();
38+
39+
return response.verificationCodes.reduce((accum, session) => {
40+
accum[session.sessionInfo] = session;
41+
return accum;
42+
}, {} as Record<string, VerificationSession>);
43+
}
44+
45+
function getEmulatorUrl(auth: Auth, endpoint: string): string {
46+
const { host, port, protocol } = auth.emulatorConfig!;
47+
const projectId = getProjectId(auth);
48+
return `${protocol}://${host}:${port}/emulator/v1/projects/${projectId}/${endpoint}`;
49+
}
50+
51+
function getProjectId(auth: Auth): string {
52+
return getApps().find(app => app.name === auth.name)!.options.projectId!;
53+
}
54+
55+
function assertEmulator(auth: Auth): void {
56+
if (!auth.emulatorConfig) {
57+
throw new Error("Can't fetch OOB codes against prod API");
58+
}
59+
}

packages-exp/auth-exp/test/integration/flows/phone.test.ts

+41-13
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ import {
3030
Auth,
3131
OperationType,
3232
ProviderId,
33-
UserCredential
33+
UserCredential,
34+
ConfirmationResult
3435
// eslint-disable-next-line import/no-extraneous-dependencies
3536
} from '@firebase/auth-exp';
3637
import { FirebaseError } from '@firebase/util';
@@ -39,6 +40,7 @@ import {
3940
cleanUpTestInstance,
4041
getTestInstance
4142
} from '../../helpers/integration/helpers';
43+
import { getPhoneVerificationCodes } from '../../helpers/integration/emulator_rest_helpers';
4244

4345
use(chaiAsPromised);
4446

@@ -80,9 +82,23 @@ describe('Integration test: phone auth', () => {
8082
document.body.removeChild(fakeRecaptchaContainer);
8183
});
8284

85+
/** If in the emulator, search for the code in the API */
86+
async function code(
87+
crOrId: ConfirmationResult | string,
88+
fallback: string
89+
): Promise<string> {
90+
if (auth.emulatorConfig) {
91+
const codes = await getPhoneVerificationCodes(auth);
92+
const vid = typeof crOrId === 'string' ? crOrId : crOrId.verificationId;
93+
return codes[vid].code;
94+
}
95+
96+
return fallback;
97+
}
98+
8399
it('allows user to sign up', async () => {
84100
const cr = await signInWithPhoneNumber(auth, PHONE_A.phoneNumber, verifier);
85-
const userCred = await cr.confirm(PHONE_A.code);
101+
const userCred = await cr.confirm(await code(cr, PHONE_A.code));
86102

87103
expect(auth.currentUser).to.eq(userCred.user);
88104
expect(userCred.operationType).to.eq(OperationType.SIGN_IN);
@@ -98,7 +114,7 @@ describe('Integration test: phone auth', () => {
98114
const { uid: anonId } = user;
99115

100116
const cr = await linkWithPhoneNumber(user, PHONE_A.phoneNumber, verifier);
101-
const linkResult = await cr.confirm(PHONE_A.code);
117+
const linkResult = await cr.confirm(await code(cr, PHONE_A.code));
102118
expect(linkResult.operationType).to.eq(OperationType.LINK);
103119
expect(linkResult.user.uid).to.eq(user.uid);
104120
expect(linkResult.user.phoneNumber).to.eq(PHONE_A.phoneNumber);
@@ -128,7 +144,7 @@ describe('Integration test: phone auth', () => {
128144
PHONE_A.phoneNumber,
129145
verifier
130146
);
131-
signUpCred = await cr.confirm(PHONE_A.code);
147+
signUpCred = await cr.confirm(await code(cr, PHONE_A.code));
132148
resetVerifier();
133149
await auth.signOut();
134150
});
@@ -139,14 +155,14 @@ describe('Integration test: phone auth', () => {
139155
PHONE_A.phoneNumber,
140156
verifier
141157
);
142-
const signInCred = await cr.confirm(PHONE_A.code);
158+
const signInCred = await cr.confirm(await code(cr, PHONE_A.code));
143159

144160
expect(signInCred.user.uid).to.eq(signUpCred.user.uid);
145161
});
146162

147163
it('allows the user to update their phone number', async () => {
148164
let cr = await signInWithPhoneNumber(auth, PHONE_A.phoneNumber, verifier);
149-
const { user } = await cr.confirm(PHONE_A.code);
165+
const { user } = await cr.confirm(await code(cr, PHONE_A.code));
150166

151167
resetVerifier();
152168

@@ -158,38 +174,48 @@ describe('Integration test: phone auth', () => {
158174

159175
await updatePhoneNumber(
160176
user,
161-
PhoneAuthProvider.credential(verificationId, PHONE_B.code)
177+
PhoneAuthProvider.credential(
178+
verificationId,
179+
await code(verificationId, PHONE_B.code)
180+
)
162181
);
163182
expect(user.phoneNumber).to.eq(PHONE_B.phoneNumber);
164183

165184
await auth.signOut();
166185
resetVerifier();
167186

168187
cr = await signInWithPhoneNumber(auth, PHONE_B.phoneNumber, verifier);
169-
const { user: secondSignIn } = await cr.confirm(PHONE_B.code);
188+
const { user: secondSignIn } = await cr.confirm(
189+
await code(cr, PHONE_B.code)
190+
);
170191
expect(secondSignIn.uid).to.eq(user.uid);
171192
});
172193

173194
it('allows the user to reauthenticate with phone number', async () => {
174195
let cr = await signInWithPhoneNumber(auth, PHONE_A.phoneNumber, verifier);
175-
const { user } = await cr.confirm(PHONE_A.code);
196+
const { user } = await cr.confirm(await code(cr, PHONE_A.code));
176197
const oldToken = await user.getIdToken();
177198

178199
resetVerifier();
179200

201+
// Wait a bit to ensure the sign in time is different in the token
202+
await new Promise((resolve): void => {
203+
setTimeout(resolve, 1500);
204+
});
205+
180206
cr = await reauthenticateWithPhoneNumber(
181207
user,
182208
PHONE_A.phoneNumber,
183209
verifier
184210
);
185-
await cr.confirm(PHONE_A.code);
211+
await cr.confirm(await code(cr, PHONE_A.code));
186212

187213
expect(await user.getIdToken()).not.to.eq(oldToken);
188214
});
189215

190216
it('prevents reauthentication with wrong phone number', async () => {
191217
let cr = await signInWithPhoneNumber(auth, PHONE_A.phoneNumber, verifier);
192-
const { user } = await cr.confirm(PHONE_A.code);
218+
const { user } = await cr.confirm(await code(cr, PHONE_A.code));
193219

194220
resetVerifier();
195221

@@ -198,7 +224,7 @@ describe('Integration test: phone auth', () => {
198224
PHONE_B.phoneNumber,
199225
verifier
200226
);
201-
await expect(cr.confirm(PHONE_B.code)).to.be.rejectedWith(
227+
await expect(cr.confirm(await code(cr, PHONE_B.code))).to.be.rejectedWith(
202228
FirebaseError,
203229
'auth/user-mismatch'
204230
);
@@ -207,7 +233,9 @@ describe('Integration test: phone auth', () => {
207233
// reauthenticateWithPhoneNumber does not trigger a state change
208234
resetVerifier();
209235
cr = await signInWithPhoneNumber(auth, PHONE_B.phoneNumber, verifier);
210-
const { user: otherUser } = await cr.confirm(PHONE_B.code);
236+
const { user: otherUser } = await cr.confirm(
237+
await code(cr, PHONE_B.code)
238+
);
211239
await otherUser.delete();
212240
});
213241
});

0 commit comments

Comments
 (0)