import { act, fireEvent, render } from '@testing-library/react-native' import * as React from 'react' import { BIOMETRY_TYPE } from 'react-native-keychain' import { Provider } from 'react-redux' import { setPincodeSuccess } from 'src/account/actions' import { PincodeType } from 'src/account/reducer' import { OnboardingEvents } from 'src/analytics/Events' import AppAnalytics from 'src/analytics/AppAnalytics' import { Screens } from 'src/navigator/Screens' import EnableBiometry from 'src/onboarding/registration/EnableBiometry' import { goToNextOnboardingScreen } from 'src/onboarding/steps' import { setPincodeWithBiometry } from 'src/pincode/authentication' import Logger from 'src/utils/Logger' import MockedNavigator from 'test/MockedNavigator' import { createMockStore } from 'test/utils' import { mockOnboardingProps } from 'test/values' const mockOnboardingPropsSelector = jest.fn(() => mockOnboardingProps) jest.mock('src/onboarding/steps', () => ({ goToNextOnboardingScreen: jest.fn(), getOnboardingStepValues: () => ({ step: 1, totalSteps: 2 }), onboardingPropsSelector: () => mockOnboardingPropsSelector(), })) const mockedSetPincodeWithBiometry = jest.mocked(setPincodeWithBiometry) const loggerErrorSpy = jest.spyOn(Logger, 'error') const analyticsSpy = jest.spyOn(AppAnalytics, 'track') const store = createMockStore({ app: { supportedBiometryType: BIOMETRY_TYPE.FACE_ID, activeScreen: Screens.EnableBiometry, }, account: { choseToRestoreAccount: false, }, }) const renderComponent = () => { return render( ) } describe('EnableBiometry', () => { beforeEach(() => { jest.clearAllMocks() store.clearActions() }) it('should render the correct elements', () => { const { getByText, getByTestId } = renderComponent() expect(getByText('enableBiometry.title')).toBeTruthy() expect( getByText('enableBiometry.guideDescription, {"biometryType":"biometryType.FaceID"}') ).toBeTruthy() expect(getByText('enableBiometry.cta, {"biometryType":"biometryType.FaceID"}')).toBeTruthy() expect(getByTestId('FaceIDBiometryIcon')).toBeTruthy() expect(getByTestId('Image/FaceID')).toBeTruthy() }) it('should enable biometry', async () => { const { getByText } = renderComponent() await act(() => { fireEvent.press(getByText('enableBiometry.cta, {"biometryType":"biometryType.FaceID"}')) }) expect(setPincodeWithBiometry).toHaveBeenCalled() expect(store.getActions()).toEqual([setPincodeSuccess(PincodeType.PhoneAuth)]) expect(goToNextOnboardingScreen).toHaveBeenCalledWith({ firstScreenInCurrentStep: Screens.EnableBiometry, onboardingProps: mockOnboardingProps, }) expect(analyticsSpy).toHaveBeenNthCalledWith(1, OnboardingEvents.biometry_opt_in_start) expect(analyticsSpy).toHaveBeenNthCalledWith(2, OnboardingEvents.biometry_opt_in_approve) expect(analyticsSpy).toHaveBeenNthCalledWith(3, OnboardingEvents.biometry_opt_in_complete) }) it('should call goToNextOnboardingScreen', async () => { const store = createMockStore({ app: { supportedBiometryType: BIOMETRY_TYPE.FACE_ID, activeScreen: Screens.EnableBiometry, }, account: { choseToRestoreAccount: false, }, }) const { getByText } = render( ) await act(() => { fireEvent.press(getByText('enableBiometry.cta, {"biometryType":"biometryType.FaceID"}')) }) expect(setPincodeWithBiometry).toHaveBeenCalled() expect(goToNextOnboardingScreen).toHaveBeenCalledWith({ firstScreenInCurrentStep: Screens.EnableBiometry, onboardingProps: mockOnboardingProps, }) }) it('should log error and not navigate if biometry enable fails', async () => { mockedSetPincodeWithBiometry.mockRejectedValue('some error') const { getByText } = renderComponent() await act(() => { fireEvent.press(getByText('enableBiometry.cta, {"biometryType":"biometryType.FaceID"}')) }) expect(setPincodeWithBiometry).toHaveBeenCalled() expect(store.getActions()).toEqual([]) expect(goToNextOnboardingScreen).not.toHaveBeenCalled() expect(loggerErrorSpy).toHaveBeenCalled() expect(analyticsSpy).toHaveBeenCalledWith(OnboardingEvents.biometry_opt_in_error) }) it('should not log error if user cancels biometry validation, and not navigate', async () => { mockedSetPincodeWithBiometry.mockRejectedValue('user canceled the operation') const { getByText } = renderComponent() await act(() => { fireEvent.press(getByText('enableBiometry.cta, {"biometryType":"biometryType.FaceID"}')) }) expect(setPincodeWithBiometry).toHaveBeenCalled() expect(store.getActions()).toEqual([]) expect(goToNextOnboardingScreen).not.toHaveBeenCalled() expect(loggerErrorSpy).not.toHaveBeenCalled() }) it('should allow skip and navigate to next screen', () => { const { getByText } = renderComponent() fireEvent.press(getByText('skip')) expect(goToNextOnboardingScreen).toHaveBeenCalledWith({ firstScreenInCurrentStep: Screens.EnableBiometry, onboardingProps: mockOnboardingProps, }) }) it('should show guided onboarding explaining faceid when enabled to do so', () => { const store = createMockStore({ app: { supportedBiometryType: BIOMETRY_TYPE.FACE_ID, activeScreen: Screens.EnableBiometry, }, }) const { getByText, getByTestId } = render( ) expect(getByText('enableBiometry.title')).toBeTruthy() expect( getByText('enableBiometry.guideDescription, {"biometryType":"biometryType.FaceID"}') ).toBeTruthy() expect(getByTestId('Image/FaceID')).toBeTruthy() }) })