Skip to content

Commit 73e0ad2

Browse files
committed
Add password reset methods to auth-next
1 parent ad23bb9 commit 73e0ad2

File tree

4 files changed

+384
-1
lines changed

4 files changed

+384
-1
lines changed

packages-exp/auth-exp/src/core/strategies/email.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@
1818
import { FirebaseError } from '@firebase/util';
1919
import { expect, use } from 'chai';
2020
import * as chaiAsPromised from 'chai-as-promised';
21+
import { restore, SinonStub, stub } from 'sinon';
2122
import * as sinonChai from 'sinon-chai';
22-
import { SinonStub, stub, restore } from 'sinon';
2323
import { mockEndpoint } from '../../../test/api/helper';
2424
import { mockAuth, testUser } from '../../../test/mock_auth';
2525
import * as mockFetch from '../../../test/mock_fetch';
2626
import { Endpoint } from '../../api';
2727
import { ServerError } from '../../api/errors';
28+
import { Operation } from '../../model/action_code_info';
2829
import { ProviderId } from '../providers';
2930
import * as location from '../util/location';
3031
import { fetchSignInMethodsForEmail, sendEmailVerification } from './email';

packages-exp/auth-exp/src/core/strategies/email.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { ActionCodeSettings, setActionCodeSettingsOnRequest } from '../../model/
2222
import { Auth } from '../../model/auth';
2323
import { User } from '../../model/user';
2424
import { getCurrentUrl, isHttpOrHttps } from '../util/location';
25+
import { Operation } from '../../model/action_code_info';
2526

2627
export async function fetchSignInMethodsForEmail(
2728
auth: Auth,
Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
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 { FirebaseError } from '@firebase/util';
19+
import { expect, use } from 'chai';
20+
import * as chaiAsPromised from 'chai-as-promised';
21+
import * as sinonChai from 'sinon-chai';
22+
// import { SinonStub, stub, restore } from 'sinon';
23+
import { mockEndpoint } from '../../../test/api/helper';
24+
import { mockAuth } from '../../../test/mock_auth';
25+
import * as mockFetch from '../../../test/mock_fetch';
26+
import { Endpoint } from '../../api';
27+
import { ServerError } from '../../api/errors';
28+
import { Operation } from '../../model/action_code_info';
29+
// import * as location from '../util/location';
30+
import { checkActionCode, confirmPasswordReset, sendPasswordResetEmail, verifyPasswordResetCode } from './email_and_password';
31+
32+
use(chaiAsPromised);
33+
use(sinonChai);
34+
35+
describe('sendPasswordResetEmail', () => {
36+
const email = '[email protected]';
37+
38+
beforeEach(mockFetch.setUp);
39+
afterEach(mockFetch.tearDown);
40+
41+
it('should send a password reset email', async () => {
42+
const mock = mockEndpoint(Endpoint.SEND_OOB_CODE, {
43+
email
44+
});
45+
await sendPasswordResetEmail(mockAuth, email);
46+
expect(mock.calls[0].request).to.eql({
47+
requestType: Operation.PASSWORD_RESET,
48+
email
49+
});
50+
});
51+
52+
it('should surface errors', async () => {
53+
const mock = mockEndpoint(
54+
Endpoint.SEND_OOB_CODE,
55+
{
56+
error: {
57+
code: 400,
58+
message: ServerError.INVALID_EMAIL
59+
}
60+
},
61+
400
62+
);
63+
await expect(
64+
sendPasswordResetEmail(mockAuth, email)
65+
).to.be.rejectedWith(
66+
FirebaseError,
67+
'Firebase: The email address is badly formatted. (auth/invalid-email).'
68+
);
69+
expect(mock.calls.length).to.eq(1);
70+
});
71+
72+
context('on iOS', () => {
73+
it('should pass action code parameters', async () => {
74+
const mock = mockEndpoint(Endpoint.SEND_OOB_CODE, {
75+
email
76+
});
77+
await sendPasswordResetEmail(mockAuth, email, {
78+
handleCodeInApp: true,
79+
iOS: {
80+
bundleId: 'my-bundle',
81+
appStoreId: 'my-appstore-id'
82+
},
83+
url: 'my-url',
84+
dynamicLinkDomain: 'fdl-domain'
85+
});
86+
87+
expect(mock.calls[0].request).to.eql({
88+
requestType: Operation.PASSWORD_RESET,
89+
email,
90+
continueUrl: 'my-url',
91+
dynamicLinkDomain: 'fdl-domain',
92+
canHandleCodeInApp: true,
93+
iosBundleId: 'my-bundle',
94+
iosAppStoreId: 'my-appstore-id'
95+
});
96+
});
97+
});
98+
99+
context('on Android', () => {
100+
it('should pass action code parameters', async () => {
101+
const mock = mockEndpoint(Endpoint.SEND_OOB_CODE, {
102+
email
103+
});
104+
await sendPasswordResetEmail(mockAuth, email, {
105+
handleCodeInApp: true,
106+
android: {
107+
installApp: false,
108+
minimumVersion: 'my-version',
109+
packageName: 'my-package'
110+
},
111+
url: 'my-url',
112+
dynamicLinkDomain: 'fdl-domain'
113+
});
114+
expect(mock.calls[0].request).to.eql({
115+
requestType: Operation.PASSWORD_RESET,
116+
email,
117+
continueUrl: 'my-url',
118+
dynamicLinkDomain: 'fdl-domain',
119+
canHandleCodeInApp: true,
120+
androidInstallApp: false,
121+
androidMinimumVersionCode: 'my-version',
122+
androidPackageName: 'my-package'
123+
});
124+
});
125+
});
126+
});
127+
128+
129+
describe('confirmPasswordReset', () => {
130+
const oobCode = 'oob-code';
131+
const newPassword = 'new-password';
132+
133+
beforeEach(mockFetch.setUp);
134+
afterEach(mockFetch.tearDown);
135+
136+
it('should confirm the password reset and not return the email', async () => {
137+
const mock = mockEndpoint(Endpoint.RESET_PASSWORD, {
138+
139+
});
140+
const response = await confirmPasswordReset(mockAuth, oobCode, newPassword);
141+
expect(response).to.be.undefined;
142+
expect(mock.calls[0].request).to.eql({
143+
oobCode,
144+
newPassword
145+
});
146+
});
147+
148+
it('should surface errors', async () => {
149+
const mock = mockEndpoint(
150+
Endpoint.RESET_PASSWORD,
151+
{
152+
error: {
153+
code: 400,
154+
message: ServerError.INVALID_OOB_CODE
155+
}
156+
},
157+
400
158+
);
159+
await expect(
160+
confirmPasswordReset(mockAuth, oobCode, newPassword)
161+
).to.be.rejectedWith(
162+
FirebaseError,
163+
'Firebase: The action code is invalid. This can happen if the code is malformed]: expired]: or has already been used. (auth/invalid-action-code).'
164+
);
165+
expect(mock.calls.length).to.eq(1);
166+
});
167+
});
168+
169+
describe('checkActionCode', () => {
170+
const oobCode = 'oob-code';
171+
const email = '[email protected]';
172+
const newEmail = '[email protected]';
173+
174+
beforeEach(mockFetch.setUp);
175+
afterEach(mockFetch.tearDown);
176+
177+
it('should verify the oob code', async () => {
178+
const mock = mockEndpoint(Endpoint.RESET_PASSWORD, {
179+
requestType: Operation.PASSWORD_RESET,
180+
181+
});
182+
const response = await checkActionCode(mockAuth, oobCode);
183+
expect(response).to.eql({
184+
data: {
185+
email,
186+
fromEmail: null
187+
},
188+
operation: Operation.PASSWORD_RESET
189+
});
190+
expect(mock.calls[0].request).to.eql({
191+
oobCode
192+
});
193+
});
194+
195+
it('should return the newEmail', async () => {
196+
const mock = mockEndpoint(Endpoint.RESET_PASSWORD, {
197+
requestType: Operation.PASSWORD_RESET,
198+
email,
199+
newEmail
200+
});
201+
const response = await checkActionCode(mockAuth, oobCode);
202+
expect(response).to.eql({
203+
data: {
204+
email,
205+
fromEmail: newEmail
206+
},
207+
operation: Operation.PASSWORD_RESET
208+
});
209+
expect(mock.calls[0].request).to.eql({
210+
oobCode
211+
});
212+
});
213+
214+
it('should expect a requestType', async () => {
215+
const mock = mockEndpoint(Endpoint.RESET_PASSWORD, {
216+
email
217+
});
218+
await expect(
219+
checkActionCode(mockAuth, oobCode)
220+
).to.be.rejectedWith(
221+
FirebaseError,
222+
'Firebase: An internal AuthError has occurred. (auth/internal-error).'
223+
);
224+
expect(mock.calls.length).to.eq(1);
225+
});
226+
227+
it('should surface errors', async () => {
228+
const mock = mockEndpoint(
229+
Endpoint.RESET_PASSWORD,
230+
{
231+
error: {
232+
code: 400,
233+
message: ServerError.INVALID_OOB_CODE
234+
}
235+
},
236+
400
237+
);
238+
await expect(
239+
checkActionCode(mockAuth, oobCode)
240+
).to.be.rejectedWith(
241+
FirebaseError,
242+
'Firebase: The action code is invalid. This can happen if the code is malformed]: expired]: or has already been used. (auth/invalid-action-code).'
243+
);
244+
expect(mock.calls.length).to.eq(1);
245+
});
246+
});
247+
248+
describe('verifyPasswordResetCode', () => {
249+
const oobCode = 'oob-code';
250+
const email = '[email protected]';
251+
252+
beforeEach(mockFetch.setUp);
253+
afterEach(mockFetch.tearDown);
254+
255+
it('should verify the oob code', async () => {
256+
const mock = mockEndpoint(Endpoint.RESET_PASSWORD, {
257+
requestType: Operation.PASSWORD_RESET,
258+
259+
});
260+
const response = await verifyPasswordResetCode(mockAuth, oobCode);
261+
expect(response).to.eq(email);
262+
expect(mock.calls[0].request).to.eql({
263+
oobCode
264+
});
265+
});
266+
267+
it('should expect a requestType', async () => {
268+
const mock = mockEndpoint(Endpoint.RESET_PASSWORD, {
269+
email
270+
});
271+
await expect(
272+
verifyPasswordResetCode(mockAuth, oobCode)
273+
).to.be.rejectedWith(
274+
FirebaseError,
275+
'Firebase: An internal AuthError has occurred. (auth/internal-error).'
276+
);
277+
expect(mock.calls.length).to.eq(1);
278+
});
279+
280+
it('should surface errors', async () => {
281+
const mock = mockEndpoint(
282+
Endpoint.RESET_PASSWORD,
283+
{
284+
error: {
285+
code: 400,
286+
message: ServerError.INVALID_OOB_CODE
287+
}
288+
},
289+
400
290+
);
291+
await expect(
292+
verifyPasswordResetCode(mockAuth, oobCode)
293+
).to.be.rejectedWith(
294+
FirebaseError,
295+
'Firebase: The action code is invalid. This can happen if the code is malformed]: expired]: or has already been used. (auth/invalid-action-code).'
296+
);
297+
expect(mock.calls.length).to.eq(1);
298+
});
299+
});
300+

0 commit comments

Comments
 (0)