Skip to content

Commit

Permalink
Merge pull request #34228 from gedu/edu/reassure_sign_in
Browse files Browse the repository at this point in the history
[No QA] [Reassure] Sign in base perf flow
  • Loading branch information
mountiny authored Jan 24, 2024
2 parents e6f5254 + a0c1445 commit 864e697
Show file tree
Hide file tree
Showing 8 changed files with 185 additions and 2 deletions.
5 changes: 5 additions & 0 deletions src/components/MagicCodeInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ const propTypes = {

/** Last pressed digit on BigDigitPad */
lastPressedDigit: PropTypes.string,

/** TestID for test */
testID: PropTypes.string,
};

const defaultProps = {
Expand All @@ -77,6 +80,7 @@ const defaultProps = {
maxLength: CONST.MAGIC_CODE_LENGTH,
isDisableKeyboard: false,
lastPressedDigit: '',
testID: '',
};

/**
Expand Down Expand Up @@ -394,6 +398,7 @@ function MagicCodeInput(props) {
role={CONST.ACCESSIBILITY_ROLE.TEXT}
style={[styles.inputTransparent]}
textInputContainerStyles={[styles.borderNone]}
testID={props.testID}
/>
</View>
</GestureDetector>
Expand Down
1 change: 1 addition & 0 deletions src/pages/signin/LoginForm/BaseLoginForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ function LoginForm(props) {
textContentType="username"
id="username"
name="username"
testID="username"
onBlur={() => {
if (firstBlurred.current || !Visibility.isVisible() || !Visibility.hasFocus()) {
return;
Expand Down
5 changes: 4 additions & 1 deletion src/pages/signin/SignInPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,10 @@ function SignInPageInner({credentials, account, isInModal, activeClients, prefer
return (
// Bottom SafeAreaView is removed so that login screen svg displays correctly on mobile.
// The SVG should flow under the Home Indicator on iOS.
<View style={[styles.signInPage, StyleUtils.getSafeAreaPadding({...safeAreaInsets, bottom: 0, top: isInModal ? 0 : safeAreaInsets.top}, 1)]}>
<View
style={[styles.signInPage, StyleUtils.getSafeAreaPadding({...safeAreaInsets, bottom: 0, top: isInModal ? 0 : safeAreaInsets.top}, 1)]}
testID={SignInPageInner.displayName}
>
<SignInPageLayout
welcomeHeader={welcomeHeader}
welcomeText={welcomeText}
Expand Down
1 change: 1 addition & 0 deletions src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ function BaseValidateCodeForm(props) {
hasError={hasError}
autoFocus
key="validateCode"
testID="validateCode"
/>
{hasError && <FormHelpMessage message={ErrorUtils.getLatestErrorMessage(props.account)} />}
<View style={[styles.alignItemsStart]}>
Expand Down
2 changes: 1 addition & 1 deletion src/types/onyx/Account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ type Account = {
/** The active policy ID. Initiating a SmartScan will create an expense on this policy by default. */
activePolicyID?: string;

errors?: OnyxCommon.Errors;
errors?: OnyxCommon.Errors | null;
success?: string;
codesAreCopied?: boolean;
twoFactorAuthStep?: TwoFactorAuthStep;
Expand Down
148 changes: 148 additions & 0 deletions tests/perf-test/SignInPage.perf-test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import type * as NativeNavigation from '@react-navigation/native';
import {fireEvent, screen} from '@testing-library/react-native';
import React from 'react';
import Onyx from 'react-native-onyx';
import {measurePerformance} from 'reassure';
import ComposeProviders from '@components/ComposeProviders';
import {LocaleContextProvider} from '@components/LocaleContextProvider';
import OnyxProvider from '@components/OnyxProvider';
import {WindowDimensionsProvider} from '@components/withWindowDimensions';
import * as Localize from '@libs/Localize';
import type * as Navigation from '@libs/Navigation/Navigation';
import ONYXKEYS from '@src/ONYXKEYS';
import SignInPage from '@src/pages/signin/SignInPage';
import getValidCodeCredentials from '../utils/collections/getValidCodeCredentials';
import userAccount, {getValidAccount} from '../utils/collections/userAccount';
import PusherHelper from '../utils/PusherHelper';
import * as TestHelper from '../utils/TestHelper';
import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates';

jest.mock('../../src/libs/Navigation/Navigation', () => {
const actualNav = jest.requireActual('../../src/libs/Navigation/Navigation');
return {
...actualNav,
navigationRef: {
addListener: () => jest.fn(),
removeListener: () => jest.fn(),
},
} as typeof Navigation;
});

const mockedNavigate = jest.fn();
jest.mock('@react-navigation/native', () => {
const actualNav = jest.requireActual('@react-navigation/native');
return {
...actualNav,
useFocusEffect: jest.fn(),
useIsFocused: () => ({
navigate: mockedNavigate,
}),
useRoute: () => jest.fn(),
useNavigation: () => ({
navigate: jest.fn(),
addListener: () => jest.fn(),
}),
createNavigationContainerRef: jest.fn(),
} as typeof NativeNavigation;
});

type Props = Partial<typeof SignInPage> & {navigation: Partial<typeof Navigation.navigationRef>};

function SignInPageWrapper(args: Props) {
return (
<ComposeProviders components={[OnyxProvider, WindowDimensionsProvider, LocaleContextProvider]}>
<SignInPage
// eslint-disable-next-line react/jsx-props-no-spreading
{...args}
navigation={args.navigation}
/>
</ComposeProviders>
);
}

const login = '[email protected]';

describe('SignInPage', () => {
beforeAll(() => {
Onyx.init({
keys: ONYXKEYS,
safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS],
});
});

// Initialize the network key for OfflineWithFeedback
beforeEach(() => {
global.fetch = TestHelper.getGlobalFetchMock() as typeof fetch;
wrapOnyxWithWaitForBatchedUpdates(Onyx);
Onyx.merge(ONYXKEYS.NETWORK, {isOffline: false});
});

// Clear out Onyx after each test so that each test starts with a clean state
afterEach(() => {
Onyx.clear();
PusherHelper.teardown();
});

test('[SignInPage] should add username and click continue button', () => {
const addListener = jest.fn();
const scenario = async () => {
// Checking the SignInPage is mounted
await screen.findByTestId('SignInPage');

const usernameInput = screen.getByTestId('username');

fireEvent.changeText(usernameInput, login);

const hintContinueButtonText = Localize.translateLocal('common.continue');

const continueButton = await screen.findByText(hintContinueButtonText);

fireEvent.press(continueButton);
};

const navigation = {addListener};

return waitForBatchedUpdates()
.then(() =>
Onyx.multiSet({
[ONYXKEYS.ACCOUNT]: userAccount,
[ONYXKEYS.IS_SIDEBAR_LOADED]: false,
}),
)
.then(() => measurePerformance(<SignInPageWrapper navigation={navigation} />, {scenario}));
});

test('[SignInPage] should add magic code and click Sign In button', () => {
const addListener = jest.fn();
const scenario = async () => {
// Checking the SignInPage is mounted
await screen.findByTestId('SignInPage');

const welcomeBackText = Localize.translateLocal('welcomeText.welcomeBack');
const enterMagicCodeText = Localize.translateLocal('welcomeText.welcomeEnterMagicCode', {login});

await screen.findByText(`${welcomeBackText} ${enterMagicCodeText}`);
const magicCodeInput = screen.getByTestId('validateCode');

fireEvent.changeText(magicCodeInput, '123456');

const signInButtonText = Localize.translateLocal('common.signIn');
const signInButton = await screen.findByText(signInButtonText);

fireEvent.press(signInButton);
};

const navigation = {addListener};

return waitForBatchedUpdates()
.then(() =>
Onyx.multiSet({
[ONYXKEYS.ACCOUNT]: getValidAccount(login),
[ONYXKEYS.CREDENTIALS]: getValidCodeCredentials(login),
[ONYXKEYS.IS_SIDEBAR_LOADED]: false,
}),
)
.then(() => measurePerformance(<SignInPageWrapper navigation={navigation} />, {scenario}));
});
});
11 changes: 11 additions & 0 deletions tests/utils/collections/getValidCodeCredentials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {randEmail, randNumber} from '@ngneat/falso';
import type {Credentials} from '@src/types/onyx';

function getValidCodeCredentials(login = randEmail()): Credentials {
return {
login,
validateCode: `${randNumber()}`,
};
}

export default getValidCodeCredentials;
14 changes: 14 additions & 0 deletions tests/utils/collections/userAccount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import CONST from '@src/CONST';
import type {Account} from '@src/types/onyx';

function getValidAccount(credentialLogin = ''): Account {
return {
validated: true,
primaryLogin: credentialLogin,
isLoading: false,
requiresTwoFactorAuth: false,
};
}

export default CONST.DEFAULT_ACCOUNT_DATA;
export {getValidAccount};

0 comments on commit 864e697

Please sign in to comment.