1fa5bc561SWill Schurmanimport { asMock } from '../../../__tests__/asMock'; 28d307f52SEvan Baconimport { promptAsync } from '../../../utils/prompts'; 38d307f52SEvan Baconimport { ApiV2Error } from '../../rest/client'; 48d307f52SEvan Baconimport { showLoginPromptAsync } from '../actions'; 58d307f52SEvan Baconimport { retryUsernamePasswordAuthWithOTPAsync, UserSecondFactorDeviceMethod } from '../otp'; 6*d88ac65dSlzkbimport { loginAsync, ssoLoginAsync } from '../user'; 78d307f52SEvan Bacon 84c50faceSEvan Baconjest.mock('../../../log'); 98d307f52SEvan Baconjest.mock('../../../utils/prompts'); 108d307f52SEvan Baconjest.mock('../../rest/client', () => { 118d307f52SEvan Bacon const { ApiV2Error } = jest.requireActual('../../rest/client'); 128d307f52SEvan Bacon return { 138d307f52SEvan Bacon ApiV2Error, 148d307f52SEvan Bacon }; 158d307f52SEvan Bacon}); 168d307f52SEvan Baconjest.mock('../otp'); 178d307f52SEvan Baconjest.mock('../user'); 188d307f52SEvan Bacon 198d307f52SEvan BaconbeforeEach(() => { 208d307f52SEvan Bacon asMock(promptAsync).mockClear(); 218d307f52SEvan Bacon asMock(promptAsync).mockImplementation(() => { 228d307f52SEvan Bacon throw new Error('Should not be called'); 238d307f52SEvan Bacon }); 248d307f52SEvan Bacon 258d307f52SEvan Bacon asMock(loginAsync).mockClear(); 26*d88ac65dSlzkb asMock(ssoLoginAsync).mockClear(); 278d307f52SEvan Bacon}); 288d307f52SEvan Bacon 298d307f52SEvan Bacondescribe(showLoginPromptAsync, () => { 308d307f52SEvan Bacon it('prompts for OTP when 2FA is enabled', async () => { 318d307f52SEvan Bacon asMock(promptAsync) 32fa5bc561SWill Schurman .mockImplementationOnce(async () => ({ username: 'hello', password: 'world' })) 33fa5bc561SWill Schurman .mockImplementationOnce(async () => ({ otp: '123456' })) 348d307f52SEvan Bacon .mockImplementation(() => { 358d307f52SEvan Bacon throw new Error("shouldn't happen"); 368d307f52SEvan Bacon }); 378d307f52SEvan Bacon asMock(loginAsync) 388d307f52SEvan Bacon .mockImplementationOnce(async () => { 398d307f52SEvan Bacon throw new ApiV2Error({ 408d307f52SEvan Bacon message: 'An OTP is required', 418d307f52SEvan Bacon code: 'ONE_TIME_PASSWORD_REQUIRED', 428d307f52SEvan Bacon metadata: { 438d307f52SEvan Bacon secondFactorDevices: [ 448d307f52SEvan Bacon { 458d307f52SEvan Bacon id: 'p0', 468d307f52SEvan Bacon is_primary: true, 478d307f52SEvan Bacon method: UserSecondFactorDeviceMethod.SMS, 488d307f52SEvan Bacon sms_phone_number: 'testphone', 498d307f52SEvan Bacon }, 508d307f52SEvan Bacon ], 518d307f52SEvan Bacon smsAutomaticallySent: true, 528d307f52SEvan Bacon }, 538d307f52SEvan Bacon }); 548d307f52SEvan Bacon }) 55fa5bc561SWill Schurman .mockImplementation(async () => {}); 568d307f52SEvan Bacon 578d307f52SEvan Bacon await showLoginPromptAsync(); 588d307f52SEvan Bacon 598d307f52SEvan Bacon expect(retryUsernamePasswordAuthWithOTPAsync).toHaveBeenCalledWith('hello', 'world', { 608d307f52SEvan Bacon secondFactorDevices: [ 618d307f52SEvan Bacon { 628d307f52SEvan Bacon id: 'p0', 638d307f52SEvan Bacon is_primary: true, 648d307f52SEvan Bacon method: UserSecondFactorDeviceMethod.SMS, 658d307f52SEvan Bacon sms_phone_number: 'testphone', 668d307f52SEvan Bacon }, 678d307f52SEvan Bacon ], 688d307f52SEvan Bacon smsAutomaticallySent: true, 698d307f52SEvan Bacon }); 708d307f52SEvan Bacon }); 718d307f52SEvan Bacon 728d307f52SEvan Bacon it('does not prompt if all required credentials are provided', async () => { 738d307f52SEvan Bacon asMock(promptAsync).mockImplementation(() => { 748d307f52SEvan Bacon throw new Error("shouldn't happen"); 758d307f52SEvan Bacon }); 76fa5bc561SWill Schurman asMock(loginAsync).mockImplementation(async () => {}); 778d307f52SEvan Bacon 788d307f52SEvan Bacon await showLoginPromptAsync({ username: 'hello', password: 'world' }); 798d307f52SEvan Bacon }); 80*d88ac65dSlzkb 81*d88ac65dSlzkb it('calls regular login if the sso flag is false', async () => { 82*d88ac65dSlzkb asMock(promptAsync).mockImplementationOnce(async () => ({ 83*d88ac65dSlzkb username: 'USERNAME', 84*d88ac65dSlzkb password: 'PASSWORD', 85*d88ac65dSlzkb })); 86*d88ac65dSlzkb 87*d88ac65dSlzkb await showLoginPromptAsync({ username: 'hello', password: 'world', sso: false }); 88*d88ac65dSlzkb 89*d88ac65dSlzkb expect(loginAsync).toHaveBeenCalledTimes(1); 90*d88ac65dSlzkb }); 91*d88ac65dSlzkb 92*d88ac65dSlzkb it('calls regular login if the sso flag is undefined', async () => { 93*d88ac65dSlzkb asMock(promptAsync) 94*d88ac65dSlzkb .mockImplementationOnce(async () => ({ username: 'USERNAME', password: 'PASSWORD' })) 95*d88ac65dSlzkb .mockImplementation(() => { 96*d88ac65dSlzkb throw new Error("shouldn't happen"); 97*d88ac65dSlzkb }); 98*d88ac65dSlzkb 99*d88ac65dSlzkb await showLoginPromptAsync({ username: 'hello', password: 'world' }); 100*d88ac65dSlzkb 101*d88ac65dSlzkb expect(loginAsync).toHaveBeenCalledTimes(1); 102*d88ac65dSlzkb }); 103*d88ac65dSlzkb 104*d88ac65dSlzkb it('calls SSO login if the sso flag is true', async () => { 105*d88ac65dSlzkb asMock(promptAsync); 106*d88ac65dSlzkb await showLoginPromptAsync({ username: 'hello', password: 'world', sso: true }); 107*d88ac65dSlzkb 108*d88ac65dSlzkb expect(ssoLoginAsync).toHaveBeenCalledTimes(1); 109*d88ac65dSlzkb }); 1108d307f52SEvan Bacon}); 111