Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions app/stacks/InsideStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,7 @@ const ProfileViewScreen: ComponentType<StaticScreenProps<undefined>> = withNavig
const ChangePasswordViewScreen: ComponentType<StaticScreenProps<undefined>> = withNavigation(ChangePasswordView as any) as any;
const UserPreferencesViewScreen: ComponentType<StaticScreenProps<undefined>> = withNavigation(UserPreferencesView as any) as any;
const SecurityPrivacyViewScreen: ComponentType<StaticScreenProps<undefined>> = withNavigation(SecurityPrivacyView as any) as any;
const ScreenLockConfigViewScreen: ComponentType<StaticScreenProps<undefined>> = withNavigation(
ScreenLockConfigView as any
) as any;
const ScreenLockConfigViewScreen: ComponentType<StaticScreenProps<undefined>> = ScreenLockConfigView;
const CreateDiscussionViewScreen = withNavigation(CreateDiscussionView as any) as any;
const E2EEnterYourPasswordViewScreen: ComponentType<StaticScreenProps<undefined>> = withNavigation(
E2EEnterYourPasswordView as any
Expand Down Expand Up @@ -239,10 +237,7 @@ const SettingsStack = createNativeStackNavigator({
MediaAutoDownloadView: MediaAutoDownloadViewScreen,
GetHelpView: GetHelpViewScreen,
LegalView: LegalViewScreen,
ScreenLockConfigView: createNativeStackScreen({
screen: ScreenLockConfigViewScreen,
options: (): NativeStackNavigationOptions => (ScreenLockConfigView as any).navigationOptions()
})
ScreenLockConfigView: ScreenLockConfigViewScreen
}
}).with(({ Navigator }) => {
'use memo';
Expand Down
8 changes: 1 addition & 7 deletions app/stacks/MasterDetailStack/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,6 @@ const TeamChannelsViewScreen: ComponentType<StaticScreenProps<ModalStackParamLis
const ReadReceiptsViewScreen: ComponentType<StaticScreenProps<ModalStackParamList['ReadReceiptsView']>> = withNavigation(
ReadReceiptsView as any
) as any;
const ScreenLockConfigViewScreen: ComponentType<StaticScreenProps<ModalStackParamList['ScreenLockConfigView']>> = withNavigation(
ScreenLockConfigView as any
) as any;

const RoomInfoEditViewScreen: ComponentType<StaticScreenProps<ModalStackParamList['RoomInfoEditView']>> = withNavigation(
RoomInfoEditView as any
Expand Down Expand Up @@ -225,10 +222,7 @@ const ModalStack = createNativeStackNavigator({
LanguageView,
ThemeView,
DefaultBrowserView,
ScreenLockConfigView: createNativeStackScreen({
screen: ScreenLockConfigViewScreen,
options: ScreenLockConfigView.navigationOptions
}),
ScreenLockConfigView,
StatusView,
ProfileView: ProfileViewScreen,
ChangePasswordView: ChangePasswordViewScreen,
Expand Down
163 changes: 163 additions & 0 deletions app/views/ScreenLockConfigView.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import { fireEvent, render, waitFor } from '@testing-library/react-native';

import ScreenLockConfigView from './ScreenLockConfigView';
import { BIOMETRY_ENABLED_KEY, DEFAULT_AUTO_LOCK } from '../lib/constants/localAuthentication';

const mockSetOptions = jest.fn();

jest.mock('@react-navigation/native', () => ({
useNavigation: () => ({ setOptions: mockSetOptions })
}));

jest.mock('../theme', () => ({
useTheme: () => ({ theme: 'light', colors: {} })
}));

jest.mock('../lib/hooks/useAppSelector', () => ({
useAppSelector: (selector: (state: any) => unknown) =>
selector({
server: { server: 'srv' },
settings: { Force_Screen_Lock: false, Force_Screen_Lock_After: 0 }
})
}));
Comment thread
diegolmello marked this conversation as resolved.

const update = jest.fn(cb => cb({ autoLock: false, autoLockTime: null }));
const fakeRecord = { autoLock: false, autoLockTime: null, update };

const mockWrite = jest.fn(fn => fn());
const mockFind = jest.fn(() => Promise.resolve(fakeRecord));

jest.mock('../lib/database', () => ({
__esModule: true,
default: {
servers: {
get: () => ({ find: mockFind }),
write: (fn: () => Promise<void>) => mockWrite(fn)
}
}
}));

const mockSupportedBiometryLabel = jest.fn(() => Promise.resolve('Face ID'));
const mockCheckHasPasscode = jest.fn();

jest.mock('../lib/methods/helpers/localAuthentication', () => ({
supportedBiometryLabel: () => mockSupportedBiometryLabel(),
checkHasPasscode: (args: any) => mockCheckHasPasscode(args),
changePasscode: jest.fn(),
handleLocalAuthentication: jest.fn()
}));

const mockGetBool = jest.fn((_key: string) => false as boolean | null);
const mockSetBool = jest.fn((_key: string, _value: boolean) => {});

jest.mock('../lib/methods/userPreferences', () => ({
__esModule: true,
default: {
getBool: (key: string) => mockGetBool(key),
setBool: (key: string, value: boolean) => mockSetBool(key, value)
}
}));

jest.mock('../lib/methods/helpers/log', () => ({
events: {
SLC_SAVE_SCREEN_LOCK: 'SLC_SAVE_SCREEN_LOCK',
SLC_TOGGLE_AUTOLOCK: 'SLC_TOGGLE_AUTOLOCK',
SLC_TOGGLE_BIOMETRY: 'SLC_TOGGLE_BIOMETRY',
SLC_CHANGE_AUTOLOCK_TIME: 'SLC_CHANGE_AUTOLOCK_TIME',
SLC_CHANGE_PASSCODE: 'SLC_CHANGE_PASSCODE'
},
logEvent: jest.fn()
}));

jest.mock('../containers/SafeAreaView', () => {
const { View } = require('react-native');
return ({ children }: any) => <View>{children}</View>;
});

describe('ScreenLockConfigView', () => {
beforeEach(() => {
jest.clearAllMocks();
mockFind.mockResolvedValue(fakeRecord);
mockSupportedBiometryLabel.mockResolvedValue('Face ID');
mockGetBool.mockReturnValue(false);
});

it('renders the auto-lock list item after init', async () => {
const { findByText } = render(<ScreenLockConfigView />);

await findByText('Unlock with passcode');
});

it('enable auto-lock persists true — stale-state guard', async () => {
mockCheckHasPasscode.mockResolvedValue(undefined);

const { findByTestId } = render(<ScreenLockConfigView />);
const autoLockSwitch = await findByTestId('screen-lock-config-auto-lock-switch');
fireEvent(autoLockSwitch, 'onValueChange', true);

await waitFor(() => expect(mockWrite).toHaveBeenCalled());

expect(update).toHaveBeenCalled();
const recordArg: any = {};
const cb = update.mock.calls[update.mock.calls.length - 1][0];
cb(recordArg);
expect(recordArg.autoLock).toBe(true);
expect(recordArg.autoLockTime).toBe(DEFAULT_AUTO_LOCK);
});

it('passcode-cancel undo — ends with autoLock false persisted', async () => {
mockCheckHasPasscode.mockRejectedValue(new Error('cancelled'));

const { findByTestId } = render(<ScreenLockConfigView />);
const autoLockSwitch = await findByTestId('screen-lock-config-auto-lock-switch');
fireEvent(autoLockSwitch, 'onValueChange', true);

await waitFor(() => expect(mockWrite).toHaveBeenCalled());

expect(update).toHaveBeenCalled();
const recordArg: any = {};
const cb = update.mock.calls[update.mock.calls.length - 1][0];
cb(recordArg);
expect(recordArg.autoLock).toBe(false);
expect(recordArg.autoLockTime).toBe(DEFAULT_AUTO_LOCK);
});
Comment thread
coderabbitai[bot] marked this conversation as resolved.

it('toggle biometry calls userPreferences.setBool with flipped value', async () => {
mockCheckHasPasscode.mockResolvedValue(undefined);

const { findByTestId } = render(<ScreenLockConfigView />);
const autoLockSwitch = await findByTestId('screen-lock-config-auto-lock-switch');
fireEvent(autoLockSwitch, 'onValueChange', true);
await waitFor(() => expect(mockWrite).toHaveBeenCalled());

mockWrite.mockClear();

const biometrySwitch = await findByTestId('screen-lock-config-biometry-switch');
fireEvent(biometrySwitch, 'onValueChange', true);

await waitFor(() => expect(mockSetBool).toHaveBeenCalledWith(BIOMETRY_ENABLED_KEY, true));
});

it('change auto-lock time persists selected value with current autoLock', async () => {
mockCheckHasPasscode.mockResolvedValue(undefined);

const { findByTestId, findByText } = render(<ScreenLockConfigView />);
const autoLockSwitch = await findByTestId('screen-lock-config-auto-lock-switch');
fireEvent(autoLockSwitch, 'onValueChange', true);
await waitFor(() => expect(mockWrite).toHaveBeenCalled());

mockWrite.mockClear();
update.mockClear();

const timeOption = await findByText('After 1 minute');
fireEvent.press(timeOption.parent!);

await waitFor(() => expect(mockWrite).toHaveBeenCalled());

expect(update).toHaveBeenCalled();
const recordArg: any = {};
const cb = update.mock.calls[update.mock.calls.length - 1][0];
cb(recordArg);
expect(recordArg.autoLockTime).toBe(60);
});
});
Loading
Loading