1import { asMock } from '../../../__tests__/asMock'; 2import { promptAsync } from '../../../utils/prompts'; 3import { ApiV2Error } from '../../rest/client'; 4import { showLoginPromptAsync } from '../actions'; 5import { retryUsernamePasswordAuthWithOTPAsync, UserSecondFactorDeviceMethod } from '../otp'; 6import { loginAsync, ssoLoginAsync } from '../user'; 7 8jest.mock('../../../log'); 9jest.mock('../../../utils/prompts'); 10jest.mock('../../rest/client', () => { 11 const { ApiV2Error } = jest.requireActual('../../rest/client'); 12 return { 13 ApiV2Error, 14 }; 15}); 16jest.mock('../otp'); 17jest.mock('../user'); 18 19beforeEach(() => { 20 asMock(promptAsync).mockClear(); 21 asMock(promptAsync).mockImplementation(() => { 22 throw new Error('Should not be called'); 23 }); 24 25 asMock(loginAsync).mockClear(); 26 asMock(ssoLoginAsync).mockClear(); 27}); 28 29describe(showLoginPromptAsync, () => { 30 it('prompts for OTP when 2FA is enabled', async () => { 31 asMock(promptAsync) 32 .mockImplementationOnce(async () => ({ username: 'hello', password: 'world' })) 33 .mockImplementationOnce(async () => ({ otp: '123456' })) 34 .mockImplementation(() => { 35 throw new Error("shouldn't happen"); 36 }); 37 asMock(loginAsync) 38 .mockImplementationOnce(async () => { 39 throw new ApiV2Error({ 40 message: 'An OTP is required', 41 code: 'ONE_TIME_PASSWORD_REQUIRED', 42 metadata: { 43 secondFactorDevices: [ 44 { 45 id: 'p0', 46 is_primary: true, 47 method: UserSecondFactorDeviceMethod.SMS, 48 sms_phone_number: 'testphone', 49 }, 50 ], 51 smsAutomaticallySent: true, 52 }, 53 }); 54 }) 55 .mockImplementation(async () => {}); 56 57 await showLoginPromptAsync(); 58 59 expect(retryUsernamePasswordAuthWithOTPAsync).toHaveBeenCalledWith('hello', 'world', { 60 secondFactorDevices: [ 61 { 62 id: 'p0', 63 is_primary: true, 64 method: UserSecondFactorDeviceMethod.SMS, 65 sms_phone_number: 'testphone', 66 }, 67 ], 68 smsAutomaticallySent: true, 69 }); 70 }); 71 72 it('does not prompt if all required credentials are provided', async () => { 73 asMock(promptAsync).mockImplementation(() => { 74 throw new Error("shouldn't happen"); 75 }); 76 asMock(loginAsync).mockImplementation(async () => {}); 77 78 await showLoginPromptAsync({ username: 'hello', password: 'world' }); 79 }); 80 81 it('calls regular login if the sso flag is false', async () => { 82 asMock(promptAsync).mockImplementationOnce(async () => ({ 83 username: 'USERNAME', 84 password: 'PASSWORD', 85 })); 86 87 await showLoginPromptAsync({ username: 'hello', password: 'world', sso: false }); 88 89 expect(loginAsync).toHaveBeenCalledTimes(1); 90 }); 91 92 it('calls regular login if the sso flag is undefined', async () => { 93 asMock(promptAsync) 94 .mockImplementationOnce(async () => ({ username: 'USERNAME', password: 'PASSWORD' })) 95 .mockImplementation(() => { 96 throw new Error("shouldn't happen"); 97 }); 98 99 await showLoginPromptAsync({ username: 'hello', password: 'world' }); 100 101 expect(loginAsync).toHaveBeenCalledTimes(1); 102 }); 103 104 it('calls SSO login if the sso flag is true', async () => { 105 asMock(promptAsync); 106 await showLoginPromptAsync({ username: 'hello', password: 'world', sso: true }); 107 108 expect(ssoLoginAsync).toHaveBeenCalledTimes(1); 109 }); 110}); 111