-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathLockScreen.test.tsx
More file actions
143 lines (116 loc) · 4.43 KB
/
Copy pathLockScreen.test.tsx
File metadata and controls
143 lines (116 loc) · 4.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import { NativeStackScreenProps } from "@react-navigation/native-stack";
import { waitFor } from "@testing-library/react-native";
import { LockScreen } from "components/screens/LockScreen";
import { LoginType } from "config/constants";
import { ROOT_NAVIGATOR_ROUTES, RootStackParamList } from "config/routes";
import { useAuthenticationStore } from "ducks/auth";
import { usePreferencesStore } from "ducks/preferences";
import { renderWithProviders } from "helpers/testUtils";
import React from "react";
import { AppState } from "react-native";
jest.mock("ducks/auth", () => {
const actual = jest.requireActual("ducks/auth");
return {
...actual,
getActiveAccountPublicKey: jest.fn().mockResolvedValue(null),
};
});
jest.mock("services/autoLock", () => ({
persistAutoLockTimer: jest.fn().mockResolvedValue(undefined),
applyAutoLockTimerToHashKey: jest.fn().mockResolvedValue(undefined),
}));
type LockScreenNavigationProp = NativeStackScreenProps<
RootStackParamList,
typeof ROOT_NAVIGATOR_ROUTES.LOCK_SCREEN
>["navigation"];
type LockScreenRouteProp = NativeStackScreenProps<
RootStackParamList,
typeof ROOT_NAVIGATOR_ROUTES.LOCK_SCREEN
>["route"];
const mockNavigation = {
replace: jest.fn(),
goBack: jest.fn(),
setOptions: jest.fn(),
} as unknown as LockScreenNavigationProp;
const mockRoute = {
key: "lock-screen",
name: ROOT_NAVIGATOR_ROUTES.LOCK_SCREEN,
} as unknown as LockScreenRouteProp;
describe("LockScreen", () => {
const mockSignIn = jest.fn();
const mockVerifyActionWithBiometrics = jest.fn(
(callback: (password?: string) => Promise<unknown>) =>
callback("biometric-password"),
);
const previousAppState = AppState.currentState;
beforeEach(() => {
jest.clearAllMocks();
(AppState as { currentState: string }).currentState = "active";
useAuthenticationStore.setState({
signIn: mockSignIn,
verifyActionWithBiometrics:
mockVerifyActionWithBiometrics as unknown as ReturnType<
typeof useAuthenticationStore.getState
>["verifyActionWithBiometrics"],
signInMethod: LoginType.FACE,
isLoading: false,
error: null,
});
usePreferencesStore.setState({ isBiometricsEnabled: true });
});
afterAll(() => {
(AppState as { currentState: typeof previousAppState }).currentState =
previousAppState;
});
const renderLockScreen = () =>
renderWithProviders(
<LockScreen navigation={mockNavigation} route={mockRoute} />,
);
it("auto-prompts biometrics on mount and unlocks with the stored password", async () => {
renderLockScreen();
await waitFor(() => {
expect(mockVerifyActionWithBiometrics).toHaveBeenCalledTimes(1);
});
expect(mockSignIn).toHaveBeenCalledWith({
password: "biometric-password",
});
});
it("does not auto-prompt when biometrics are disabled", async () => {
usePreferencesStore.setState({ isBiometricsEnabled: false });
useAuthenticationStore.setState({ signInMethod: LoginType.PASSWORD });
renderLockScreen();
await waitFor(() => {
expect(mockVerifyActionWithBiometrics).not.toHaveBeenCalled();
});
expect(mockSignIn).not.toHaveBeenCalled();
});
it("re-prompts biometrics when the app returns from the background", async () => {
renderLockScreen();
await waitFor(() => {
expect(mockVerifyActionWithBiometrics).toHaveBeenCalledTimes(1);
});
// Simulate the app going to the background and returning to the foreground
const appStateHandlers = (
AppState.addEventListener as jest.Mock
).mock.calls.map(([, handler]) => handler as (state: string) => void);
appStateHandlers.forEach((handler) => handler("background"));
appStateHandlers.forEach((handler) => handler("active"));
await waitFor(() => {
expect(mockVerifyActionWithBiometrics).toHaveBeenCalledTimes(2);
});
});
it("does not re-prompt on inactive-to-active transitions (e.g. the biometric overlay itself)", async () => {
renderLockScreen();
await waitFor(() => {
expect(mockVerifyActionWithBiometrics).toHaveBeenCalledTimes(1);
});
const appStateHandlers = (
AppState.addEventListener as jest.Mock
).mock.calls.map(([, handler]) => handler as (state: string) => void);
appStateHandlers.forEach((handler) => handler("inactive"));
appStateHandlers.forEach((handler) => handler("active"));
await waitFor(() => {
expect(mockVerifyActionWithBiometrics).toHaveBeenCalledTimes(1);
});
});
});