@@ -13,6 +13,7 @@ import {
1313 RecoveryNumberNotSupportedError ,
1414 RecoveryPhoneNotEnabled ,
1515 RecoveryNumberRemoveMissingBackupCodes ,
16+ RecoveryPhoneRegistrationLimitReached ,
1617} from './recovery-phone.errors' ;
1718import { LOGGER_PROVIDER } from '@fxa/shared/log' ;
1819import { StatsDService } from '@fxa/shared/metrics/statsd' ;
@@ -49,6 +50,7 @@ describe('RecoveryPhoneService', () => {
4950 getConfirmedPhoneNumber : jest . fn ( ) ,
5051 hasRecoveryCodes : jest . fn ( ) ,
5152 removeCode : jest . fn ( ) ,
53+ getCountByPhoneNumber : jest . fn ( ) ,
5254 } ;
5355
5456 const mockOtpManager = {
@@ -58,6 +60,7 @@ describe('RecoveryPhoneService', () => {
5860 const mockRecoveryPhoneConfig : RecoveryPhoneConfig = {
5961 enabled : true ,
6062 allowedRegions : [ 'US' ] ,
63+ maxRegistrationsPerNumber : 5 ,
6164 sms : {
6265 validNumberPrefixes : [ '+1500' ] ,
6366 smsPumpingRiskThreshold : 75 ,
@@ -116,7 +119,7 @@ describe('RecoveryPhoneService', () => {
116119 expect ( service ) . toBeInstanceOf ( RecoveryPhoneService ) ;
117120 } ) ;
118121
119- it ( 'Should setup a phone number' , async ( ) => {
122+ it ( 'Should set up a phone number' , async ( ) => {
120123 mockOtpManager . generateCode . mockReturnValue ( code ) ;
121124
122125 const result = await service . setupPhoneNumber ( uid , phoneNumber ) ;
@@ -134,10 +137,9 @@ describe('RecoveryPhoneService', () => {
134137 true
135138 ) ;
136139 expect ( mockRecoveryPhoneManager . getAllUnconfirmed ) . toBeCalledWith ( uid ) ;
137- expect ( result ) . toBeTruthy ( ) ;
138140 } ) ;
139141
140- it ( 'Should send new code for setup phone number' , async ( ) => {
142+ it ( 'Should send new code to set up a phone number' , async ( ) => {
141143 mockOtpManager . generateCode . mockReturnValue ( code ) ;
142144 mockRecoveryPhoneManager . getAllUnconfirmed . mockResolvedValue ( [
143145 'this:is:the:code123' ,
@@ -163,7 +165,7 @@ describe('RecoveryPhoneService', () => {
163165 expect ( mockRecoveryPhoneManager . getAllUnconfirmed ) . toBeCalledWith ( uid ) ;
164166 } ) ;
165167
166- it ( 'handles message template when provided to setup phone number' , async ( ) => {
168+ it ( 'handles message template when provided to set up phone number' , async ( ) => {
167169 mockOtpManager . generateCode . mockReturnValue ( code ) ;
168170 const getFormattedMessage = jest . fn ( ) . mockResolvedValue ( 'message' ) ;
169171
@@ -195,6 +197,14 @@ describe('RecoveryPhoneService', () => {
195197 ) ;
196198 } ) ;
197199
200+ it ( 'Will reject a phone number if it has been used for too many accounts' , async ( ) => {
201+ mockRecoveryPhoneManager . getCountByPhoneNumber . mockReturnValue ( 5 ) ;
202+
203+ await expect ( service . setupPhoneNumber ( uid , phoneNumber ) ) . rejects . toEqual (
204+ new RecoveryPhoneRegistrationLimitReached ( phoneNumber )
205+ ) ;
206+ } ) ;
207+
198208 it ( 'Throws error during send sms' , async ( ) => {
199209 mockSmsManager . sendSMS . mockRejectedValueOnce ( mockError ) ;
200210 await expect ( service . setupPhoneNumber ( uid , phoneNumber ) ) . rejects . toEqual (
@@ -311,6 +321,19 @@ describe('RecoveryPhoneService', () => {
311321 ) ;
312322 } ) ;
313323
324+ it ( 'rejects phone number that has been used for too many accounts' , async ( ) => {
325+ const phoneNumber = '+15005550000' ;
326+ mockRecoveryPhoneManager . getUnconfirmed . mockReturnValue ( {
327+ isSetup : true ,
328+ phoneNumber,
329+ } ) ;
330+ mockRecoveryPhoneManager . getCountByPhoneNumber . mockResolvedValue ( 5 ) ;
331+
332+ await expect ( service . confirmSetupCode ( uid , code ) ) . rejects . toThrow (
333+ new RecoveryPhoneRegistrationLimitReached ( phoneNumber )
334+ ) ;
335+ } ) ;
336+
314337 it ( 'can handle failed lookup by throwing PhoneNumberNotSupported error' , async ( ) => {
315338 mockRecoveryPhoneManager . getUnconfirmed . mockReturnValue ( {
316339 isSetup : true ,
0 commit comments