diff --git a/src/types/onyx/PolicyCategory.ts b/src/types/onyx/PolicyCategory.ts index 0fd498632dbc..b42bceec0468 100644 --- a/src/types/onyx/PolicyCategory.ts +++ b/src/types/onyx/PolicyCategory.ts @@ -15,7 +15,7 @@ type PolicyCategory = OnyxCommon.OnyxValueWithOfflineFeedback<{ /** "General Ledger code" that corresponds to this category in an accounting system. Similar to an ID. */ // eslint-disable-next-line @typescript-eslint/naming-convention - 'GL Code': string; + 'GL Code'?: string; /** An ID for this category from an external accounting system */ externalID: string; diff --git a/src/types/onyx/PolicyTag.ts b/src/types/onyx/PolicyTag.ts index 70a0884c30bd..8066b85d1e44 100644 --- a/src/types/onyx/PolicyTag.ts +++ b/src/types/onyx/PolicyTag.ts @@ -9,7 +9,7 @@ type PolicyTag = { /** "General Ledger code" that corresponds to this tag in an accounting system. Similar to an ID. */ // eslint-disable-next-line @typescript-eslint/naming-convention - 'GL Code': string; + 'GL Code'?: string; /** A list of errors keyed by microtime */ errors?: OnyxCommon.Errors | null; diff --git a/tests/actions/PolicyTest.js b/tests/actions/PolicyTest.ts similarity index 59% rename from tests/actions/PolicyTest.js rename to tests/actions/PolicyTest.ts index 5a994aaf600e..e59fec068d65 100644 --- a/tests/actions/PolicyTest.js +++ b/tests/actions/PolicyTest.ts @@ -1,9 +1,10 @@ -import _ from 'lodash'; import Onyx from 'react-native-onyx'; +import type {OnyxCollection} from 'react-native-onyx'; import CONST from '@src/CONST'; -import OnyxUpdateManager from '../../src/libs/actions/OnyxUpdateManager'; -import * as Policy from '../../src/libs/actions/Policy'; -import ONYXKEYS from '../../src/ONYXKEYS'; +import OnyxUpdateManager from '@src/libs/actions/OnyxUpdateManager'; +import * as Policy from '@src/libs/actions/Policy'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {PolicyMembers, Policy as PolicyType, Report, ReportAction, ReportActions} from '@src/types/onyx'; import * as TestHelper from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; @@ -20,12 +21,14 @@ describe('actions/Policy', () => { }); beforeEach(() => { + // @ts-expect-error TODO: Remove this once TestHelper (https://github.com/Expensify/App/issues/25318) is migrated to TypeScript. global.fetch = TestHelper.getGlobalFetchMock(); return Onyx.clear().then(waitForBatchedUpdates); }); describe('createWorkspace', () => { it('creates a new workspace', async () => { + // @ts-expect-error TODO: Remove this once TestHelper (https://github.com/Expensify/App/issues/25318) is migrated to TypeScript. fetch.pause(); Onyx.set(ONYXKEYS.SESSION, {email: ESH_EMAIL, accountID: ESH_ACCOUNT_ID}); await waitForBatchedUpdates(); @@ -38,7 +41,7 @@ describe('actions/Policy', () => { Policy.createWorkspace(ESH_EMAIL, true, WORKSPACE_NAME, policyID); await waitForBatchedUpdates(); - let policy = await new Promise((resolve) => { + let policy: OnyxCollection = await new Promise((resolve) => { const connectionID = Onyx.connect({ key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, waitForCollectionCallback: true, @@ -50,15 +53,15 @@ describe('actions/Policy', () => { }); // check if policy was created with correct values - expect(policy.id).toBe(policyID); - expect(policy.name).toBe(WORKSPACE_NAME); - expect(policy.type).toBe(CONST.POLICY.TYPE.FREE); - expect(policy.role).toBe(CONST.POLICY.ROLE.ADMIN); - expect(policy.owner).toBe(ESH_EMAIL); - expect(policy.isPolicyExpenseChatEnabled).toBe(true); - expect(policy.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); - - const policyMembers = await new Promise((resolve) => { + expect(policy?.id).toBe(policyID); + expect(policy?.name).toBe(WORKSPACE_NAME); + expect(policy?.type).toBe(CONST.POLICY.TYPE.FREE); + expect(policy?.role).toBe(CONST.POLICY.ROLE.ADMIN); + expect(policy?.owner).toBe(ESH_EMAIL); + expect(policy?.isPolicyExpenseChatEnabled).toBe(true); + expect(policy?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); + + const policyMembers: OnyxCollection = await new Promise((resolve) => { const connectionID = Onyx.connect({ key: `${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${policyID}`, waitForCollectionCallback: true, @@ -70,9 +73,9 @@ describe('actions/Policy', () => { }); // check if the user was added as an admin to the policy - expect(policyMembers[ESH_ACCOUNT_ID].role).toBe(CONST.POLICY.ROLE.ADMIN); + expect(policyMembers?.[ESH_ACCOUNT_ID]?.role).toBe(CONST.POLICY.ROLE.ADMIN); - let allReports = await new Promise((resolve) => { + let allReports: OnyxCollection = await new Promise((resolve) => { const connectionID = Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT, waitForCollectionCallback: true, @@ -84,12 +87,12 @@ describe('actions/Policy', () => { }); // Three reports should be created: #announce, #admins and expense report - const workspaceReports = _.filter(allReports, (report) => report.policyID === policyID); - expect(_.size(workspaceReports)).toBe(3); - _.forEach(workspaceReports, (report) => { - expect(report.pendingFields.addWorkspaceRoom).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); - expect(report.participantAccountIDs).toEqual([ESH_ACCOUNT_ID]); - switch (report.chatType) { + const workspaceReports = Object.values(allReports ?? {}).filter((report) => report?.policyID === policyID); + expect(workspaceReports.length).toBe(3); + workspaceReports.forEach((report) => { + expect(report?.pendingFields?.addWorkspaceRoom).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); + expect(report?.participantAccountIDs).toEqual([ESH_ACCOUNT_ID]); + switch (report?.chatType) { case CONST.REPORT.CHAT_TYPE.POLICY_ADMINS: { adminReportID = report.reportID; break; @@ -107,7 +110,7 @@ describe('actions/Policy', () => { } }); - let reportActions = await new Promise((resolve) => { + let reportActions: OnyxCollection = await new Promise((resolve) => { const connectionID = Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT_ACTIONS, waitForCollectionCallback: true, @@ -119,20 +122,21 @@ describe('actions/Policy', () => { }); // Each of the three reports should have a a `CREATED` action. - let adminReportActions = _.values(reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${adminReportID}`]); - let announceReportActions = _.values(reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${announceReportID}`]); - let expenseReportActions = _.values(reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReportID}`]); - let workspaceReportActions = _.concat(adminReportActions, announceReportActions, expenseReportActions); - _.forEach([adminReportActions, announceReportActions, expenseReportActions], (actions) => { - expect(_.size(actions)).toBe(1); + let adminReportActions: ReportAction[] = Object.values(reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${adminReportID}`] ?? {}); + let announceReportActions: ReportAction[] = Object.values(reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${announceReportID}`] ?? {}); + let expenseReportActions: ReportAction[] = Object.values(reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReportID}`] ?? {}); + let workspaceReportActions: ReportAction[] = adminReportActions.concat(announceReportActions, expenseReportActions); + [adminReportActions, announceReportActions, expenseReportActions].forEach((actions) => { + expect(actions.length).toBe(1); }); - _.forEach([...adminReportActions, ...announceReportActions, ...expenseReportActions], (reportAction) => { + [...adminReportActions, ...announceReportActions, ...expenseReportActions].forEach((reportAction) => { expect(reportAction.actionName).toBe(CONST.REPORT.ACTIONS.TYPE.CREATED); expect(reportAction.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); expect(reportAction.actorAccountID).toBe(ESH_ACCOUNT_ID); }); // Check for success data + // @ts-expect-error TODO: Remove this once TestHelper (https://github.com/Expensify/App/issues/25318) is migrated to TypeScript. fetch.resume(); await waitForBatchedUpdates(); @@ -148,7 +152,7 @@ describe('actions/Policy', () => { }); // Check if the policy pending action was cleared - expect(policy.pendingAction).toBeFalsy(); + expect(policy?.pendingAction).toBeFalsy(); allReports = await new Promise((resolve) => { const connectionID = Onyx.connect({ @@ -162,9 +166,9 @@ describe('actions/Policy', () => { }); // Check if the report pending action and fields were cleared - _.forEach(allReports, (report) => { - expect(report.pendingAction).toBeFalsy(); - expect(report.pendingFields.addWorkspaceRoom).toBeFalsy(); + Object.values(allReports ?? {}).forEach((report) => { + expect(report?.pendingAction).toBeFalsy(); + expect(report?.pendingFields?.addWorkspaceRoom).toBeFalsy(); }); reportActions = await new Promise((resolve) => { @@ -179,11 +183,11 @@ describe('actions/Policy', () => { }); // Check if the report action pending action was cleared - adminReportActions = _.values(reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${adminReportID}`]); - announceReportActions = _.values(reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${announceReportID}`]); - expenseReportActions = _.values(reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReportID}`]); - workspaceReportActions = _.concat(adminReportActions, announceReportActions, expenseReportActions); - _.forEach(workspaceReportActions, (reportAction) => { + adminReportActions = Object.values(reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${adminReportID}`] ?? {}); + announceReportActions = Object.values(reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${announceReportID}`] ?? {}); + expenseReportActions = Object.values(reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReportID}`] ?? {}); + workspaceReportActions = adminReportActions.concat(announceReportActions, expenseReportActions); + workspaceReportActions.forEach((reportAction) => { expect(reportAction.pendingAction).toBeFalsy(); }); }); diff --git a/tests/perf-test/OptionsSelector.perf-test.js b/tests/perf-test/OptionsSelector.perf-test.tsx similarity index 67% rename from tests/perf-test/OptionsSelector.perf-test.js rename to tests/perf-test/OptionsSelector.perf-test.tsx index 6104ded05c6a..835e2a15673c 100644 --- a/tests/perf-test/OptionsSelector.perf-test.js +++ b/tests/perf-test/OptionsSelector.perf-test.tsx @@ -1,12 +1,15 @@ import {fireEvent} from '@testing-library/react-native'; +import type {RenderResult} from '@testing-library/react-native'; import React from 'react'; +import type {ComponentType} from 'react'; import {measurePerformance} from 'reassure'; -import _ from 'underscore'; +import type {WithLocalizeProps} from '@components/withLocalize'; +import type {WithNavigationFocusProps} from '@components/withNavigationFocus'; import OptionsSelector from '@src/components/OptionsSelector'; import variables from '@src/styles/variables'; -jest.mock('../../src/components/withLocalize', () => (Component) => { - function WrappedComponent(props) { +jest.mock('@src/components/withLocalize', () => (Component: ComponentType) => { + function WrappedComponent(props: WithLocalizeProps) { return ( (Component) => { return WrappedComponent; }); -jest.mock('../../src/components/withNavigationFocus', () => (Component) => { - function WithNavigationFocus(props) { +jest.mock('@src/components/withNavigationFocus', () => (Component: ComponentType) => { + function WithNavigationFocus(props: WithNavigationFocusProps) { return ( (Component) => { return WithNavigationFocus; }); -const generateSections = (sectionConfigs) => - _.map(sectionConfigs, ({numItems, indexOffset, shouldShow = true}) => ({ - data: Array.from({length: numItems}, (_v, i) => ({ +type GenerateSectionsProps = Array<{numberOfItems: number; indexOffset: number; shouldShow?: boolean}>; + +const generateSections = (sections: GenerateSectionsProps) => + sections.map(({numberOfItems, indexOffset, shouldShow = true}) => ({ + data: Array.from({length: numberOfItems}, (v, i) => ({ text: `Item ${i + indexOffset}`, keyForList: `item-${i + indexOffset}`, })), @@ -45,15 +50,15 @@ const generateSections = (sectionConfigs) => shouldShow, })); -const singleSectionSConfig = [{numItems: 1000, indexOffset: 0}]; +const singleSectionsConfig = [{numberOfItems: 1000, indexOffset: 0}]; const mutlipleSectionsConfig = [ - {numItems: 1000, indexOffset: 0}, - {numItems: 100, indexOffset: 70}, + {numberOfItems: 1000, indexOffset: 0}, + {numberOfItems: 100, indexOffset: 70}, ]; - +// @ts-expect-error TODO: Remove this once OptionsSelector is migrated to TypeScript. function OptionsSelectorWrapper(args) { - const sections = generateSections(singleSectionSConfig); + const sections = generateSections(singleSectionsConfig); return ( { - const scenario = (screen) => { + const scenario = ((screen: RenderResult) => { const textInput = screen.getByTestId('options-selector-input'); fireEvent.changeText(textInput, 'test'); fireEvent.changeText(textInput, 'test2'); fireEvent.changeText(textInput, 'test3'); - }; + }) as Awaited<(screen: RenderResult) => Promise>; measurePerformance(, {scenario}); }); @@ -85,11 +90,11 @@ test('[OptionsSelector] should render multiple sections', () => { }); test('[OptionsSelector] should press a list items', () => { - const scenario = (screen) => { + const scenario = ((screen: RenderResult) => { fireEvent.press(screen.getByText('Item 1')); fireEvent.press(screen.getByText('Item 5')); fireEvent.press(screen.getByText('Item 10')); - }; + }) as Awaited<(screen: RenderResult) => Promise>; measurePerformance(, {scenario}); }); @@ -97,10 +102,10 @@ test('[OptionsSelector] should press a list items', () => { test('[OptionsSelector] should scroll and press few items', () => { const sections = generateSections(mutlipleSectionsConfig); - const generateEventData = (numOptions, optionRowHeight) => ({ + const generateEventData = (numberOfOptions: number, optionRowHeight: number) => ({ nativeEvent: { contentOffset: { - y: optionRowHeight * numOptions, + y: optionRowHeight * numberOfOptions, }, contentSize: { height: optionRowHeight * 10, @@ -115,7 +120,7 @@ test('[OptionsSelector] should scroll and press few items', () => { const eventData = generateEventData(100, variables.optionRowHeight); const eventData2 = generateEventData(200, variables.optionRowHeight); - const scenario = async (screen) => { + const scenario = async (screen: RenderResult) => { fireEvent.press(screen.getByText('Item 10')); fireEvent.scroll(screen.getByTestId('options-list'), eventData); fireEvent.press(await screen.findByText('Item 100')); diff --git a/tests/perf-test/SearchPage.perf-test.js b/tests/perf-test/SearchPage.perf-test.tsx similarity index 50% rename from tests/perf-test/SearchPage.perf-test.js rename to tests/perf-test/SearchPage.perf-test.tsx index be6b6a5d78f9..3f3395092b26 100644 --- a/tests/perf-test/SearchPage.perf-test.js +++ b/tests/perf-test/SearchPage.perf-test.tsx @@ -1,14 +1,22 @@ +import type * as NativeNavigation from '@react-navigation/native'; +import type {StackScreenProps} from '@react-navigation/stack'; import {fireEvent, screen, waitFor} from '@testing-library/react-native'; +import type {TextMatch} from '@testing-library/react-native/build/matches'; import React from 'react'; +import type {ComponentType} from 'react'; import Onyx from 'react-native-onyx'; +import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import {measurePerformance} from 'reassure'; -import _ from 'underscore'; import {LocaleContextProvider} from '@components/LocaleContextProvider'; +import type {WithNavigationFocusProps} from '@components/withNavigationFocus'; +import type {RootStackParamList} from '@libs/Navigation/types'; import SearchPage from '@pages/SearchPage'; -import ComposeProviders from '../../src/components/ComposeProviders'; -import OnyxProvider from '../../src/components/OnyxProvider'; -import CONST from '../../src/CONST'; -import ONYXKEYS from '../../src/ONYXKEYS'; +import ComposeProviders from '@src/components/ComposeProviders'; +import OnyxProvider from '@src/components/OnyxProvider'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type SCREENS from '@src/SCREENS'; +import type {Beta, PersonalDetails, Report} from '@src/types/onyx'; import createCollection from '../utils/collections/createCollection'; import createPersonalDetails from '../utils/collections/personalDetails'; import createRandomReport from '../utils/collections/reports'; @@ -18,22 +26,22 @@ import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates'; jest.mock('lodash/debounce', () => - jest.fn((fn) => { + jest.fn((fn: Record>) => { // eslint-disable-next-line no-param-reassign fn.cancel = jest.fn(); return fn; }), ); -jest.mock('../../src/libs/Log'); +jest.mock('@src/libs/Log'); -jest.mock('../../src/libs/API', () => ({ +jest.mock('@src/libs/API', () => ({ write: jest.fn(), makeRequestWithSideEffects: jest.fn(), read: jest.fn(), })); -jest.mock('../../src/libs/Navigation/Navigation'); +jest.mock('@src/libs/Navigation/Navigation'); const mockedNavigate = jest.fn(); jest.mock('@react-navigation/native', () => { @@ -50,11 +58,11 @@ jest.mock('@react-navigation/native', () => { addListener: () => jest.fn(), }), createNavigationContainerRef: jest.fn(), - }; + } as typeof NativeNavigation; }); -jest.mock('../../src/components/withNavigationFocus', () => (Component) => { - function WithNavigationFocus(props) { +jest.mock('@src/components/withNavigationFocus', () => (Component: ComponentType) => { + function WithNavigationFocus(props: WithNavigationFocusProps) { return ( (Component) => { }); const getMockedReports = (length = 100) => - createCollection( + createCollection( (item) => `${ONYXKEYS.COLLECTION.REPORT}${item.reportID}`, (index) => createRandomReport(index), length, ); const getMockedPersonalDetails = (length = 100) => - createCollection( + createCollection( (item) => item.accountID, (index) => createPersonalDetails(index), length, ); const mockedReports = getMockedReports(600); -const mockedBetas = _.values(CONST.BETAS); +const mockedBetas = Object.values(CONST.BETAS); const mockedPersonalDetails = getMockedPersonalDetails(100); beforeAll(() => Onyx.init({ keys: ONYXKEYS, safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT], - registerStorageEventListener: () => {}, }), ); // Initialize the network key for OfflineWithFeedback beforeEach(() => { + // @ts-expect-error TODO: Remove this once TestHelper (https://github.com/Expensify/App/issues/25318) is migrated to TypeScript. global.fetch = TestHelper.getGlobalFetchMock(); wrapOnyxWithWaitForBatchedUpdates(Onyx); Onyx.merge(ONYXKEYS.NETWORK, {isOffline: false}); @@ -108,7 +116,13 @@ afterEach(() => { PusherHelper.teardown(); }); -function SearchPageWrapper(args) { +type SearchPageProps = StackScreenProps & { + betas: OnyxEntry; + reports: OnyxCollection; + isSearchingForReports: OnyxEntry; +}; + +function SearchPageWrapper(args: SearchPageProps) { return ( { + // @ts-expect-error TODO: Remove this once TestHelper (https://github.com/Expensify/App/issues/25318) is migrated to TypeScript. const {addListener} = TestHelper.createAddListenerMock(); const scenario = async () => { @@ -134,81 +149,93 @@ test('[Search Page] should interact when text input changes', async () => { const navigation = {addListener}; - return waitForBatchedUpdates() - .then(() => - Onyx.multiSet({ - ...mockedReports, - [ONYXKEYS.PERSONAL_DETAILS_LIST]: mockedPersonalDetails, - [ONYXKEYS.BETAS]: mockedBetas, - [ONYXKEYS.IS_SEARCHING_FOR_REPORTS]: true, - }), - ) - .then(() => measurePerformance(, {scenario})); + return ( + waitForBatchedUpdates() + .then(() => + Onyx.multiSet({ + ...mockedReports, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: mockedPersonalDetails, + [ONYXKEYS.BETAS]: mockedBetas, + [ONYXKEYS.IS_SEARCHING_FOR_REPORTS]: true, + }), + ) + // @ts-expect-error TODO: Remove this once TestHelper (https://github.com/Expensify/App/issues/25318) is migrated to TypeScript. + .then(() => measurePerformance(, {scenario})) + ); }); test('[Search Page] should render selection list', async () => { + // @ts-expect-error TODO: Remove this once TestHelper (https://github.com/Expensify/App/issues/25318) is migrated to TypeScript. const {triggerTransitionEnd, addListener} = TestHelper.createAddListenerMock(); const smallMockedPersonalDetails = getMockedPersonalDetails(5); const scenario = async () => { await screen.findByTestId('SearchPage'); - await waitFor(triggerTransitionEnd); + await waitFor(triggerTransitionEnd as Awaited<() => Promise>); await screen.findByTestId('selection-list'); - await screen.findByText(smallMockedPersonalDetails['1'].login); - await screen.findByText(smallMockedPersonalDetails['2'].login); + await screen.findByText(smallMockedPersonalDetails['1'].login as TextMatch); + await screen.findByText(smallMockedPersonalDetails['2'].login as TextMatch); }; const navigation = {addListener}; - return waitForBatchedUpdates() - .then(() => - Onyx.multiSet({ - ...mockedReports, - [ONYXKEYS.PERSONAL_DETAILS_LIST]: smallMockedPersonalDetails, - [ONYXKEYS.BETAS]: mockedBetas, - [ONYXKEYS.IS_SEARCHING_FOR_REPORTS]: true, - }), - ) - .then(() => measurePerformance(, {scenario})); + return ( + waitForBatchedUpdates() + .then(() => + Onyx.multiSet({ + ...mockedReports, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: smallMockedPersonalDetails, + [ONYXKEYS.BETAS]: mockedBetas, + [ONYXKEYS.IS_SEARCHING_FOR_REPORTS]: true, + }), + ) + // @ts-expect-error TODO: Remove this once TestHelper (https://github.com/Expensify/App/issues/25318) is migrated to TypeScript. + .then(() => measurePerformance(, {scenario})) + ); }); test('[Search Page] should search in selection list', async () => { + // @ts-expect-error TODO: Remove this once TestHelper (https://github.com/Expensify/App/issues/25318) is migrated to TypeScript. const {triggerTransitionEnd, addListener} = TestHelper.createAddListenerMock(); const scenario = async () => { await screen.findByTestId('SearchPage'); - await waitFor(triggerTransitionEnd); + await waitFor(triggerTransitionEnd as Awaited<() => Promise>); const input = screen.getByTestId('selection-list-text-input'); const searchValue = mockedPersonalDetails['88'].login; fireEvent.changeText(input, searchValue); - await screen.findByText(searchValue); + await screen.findByText(searchValue as TextMatch); }; const navigation = {addListener}; - return waitForBatchedUpdates() - .then(() => - Onyx.multiSet({ - ...mockedReports, - [ONYXKEYS.PERSONAL_DETAILS_LIST]: mockedPersonalDetails, - [ONYXKEYS.BETAS]: mockedBetas, - [ONYXKEYS.IS_SEARCHING_FOR_REPORTS]: true, - }), - ) - .then(() => measurePerformance(, {scenario})); + return ( + waitForBatchedUpdates() + .then(() => + Onyx.multiSet({ + ...mockedReports, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: mockedPersonalDetails, + [ONYXKEYS.BETAS]: mockedBetas, + [ONYXKEYS.IS_SEARCHING_FOR_REPORTS]: true, + }), + ) + // @ts-expect-error TODO: Remove this once TestHelper (https://github.com/Expensify/App/issues/25318) is migrated to TypeScript. + .then(() => measurePerformance(, {scenario})) + ); }); test('[Search Page] should click on list item', async () => { + // @ts-expect-error TODO: Remove this once TestHelper (https://github.com/Expensify/App/issues/25318) is migrated to TypeScript. const {triggerTransitionEnd, addListener} = TestHelper.createAddListenerMock(); const scenario = async () => { await screen.findByTestId('SearchPage'); const input = screen.getByTestId('selection-list-text-input'); - await waitFor(triggerTransitionEnd); + await waitFor(triggerTransitionEnd as Awaited<() => Promise>); - const searchValue = mockedPersonalDetails['4'].login; + const searchValue = mockedPersonalDetails['4'].login as TextMatch; fireEvent.changeText(input, searchValue); const optionButton = await screen.findByText(searchValue); @@ -216,14 +243,17 @@ test('[Search Page] should click on list item', async () => { }; const navigation = {addListener}; - return waitForBatchedUpdates() - .then(() => - Onyx.multiSet({ - ...mockedReports, - [ONYXKEYS.PERSONAL_DETAILS_LIST]: mockedPersonalDetails, - [ONYXKEYS.BETAS]: mockedBetas, - [ONYXKEYS.IS_SEARCHING_FOR_REPORTS]: true, - }), - ) - .then(() => measurePerformance(, {scenario})); + return ( + waitForBatchedUpdates() + .then(() => + Onyx.multiSet({ + ...mockedReports, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: mockedPersonalDetails, + [ONYXKEYS.BETAS]: mockedBetas, + [ONYXKEYS.IS_SEARCHING_FOR_REPORTS]: true, + }), + ) + // @ts-expect-error TODO: Remove this once TestHelper (https://github.com/Expensify/App/issues/25318) is migrated to TypeScript. + .then(() => measurePerformance(, {scenario})) + ); }); diff --git a/tests/unit/PhoneNumberTest.js b/tests/unit/PhoneNumberTest.ts similarity index 100% rename from tests/unit/PhoneNumberTest.js rename to tests/unit/PhoneNumberTest.ts diff --git a/tests/unit/UserUtilsTest.js b/tests/unit/UserUtilsTest.ts similarity index 86% rename from tests/unit/UserUtilsTest.js rename to tests/unit/UserUtilsTest.ts index f0f20fc6d4cb..f91f2a499e79 100644 --- a/tests/unit/UserUtilsTest.js +++ b/tests/unit/UserUtilsTest.ts @@ -1,4 +1,4 @@ -import * as UserUtils from '../../src/libs/UserUtils'; +import * as UserUtils from '@src/libs/UserUtils'; describe('UserUtils', () => { it('should return the default avatar from the avatar url', () => { diff --git a/tests/unit/ViolationUtilsTest.js b/tests/unit/ViolationUtilsTest.ts similarity index 93% rename from tests/unit/ViolationUtilsTest.js rename to tests/unit/ViolationUtilsTest.ts index 15a3a4f7de07..354a90802077 100644 --- a/tests/unit/ViolationUtilsTest.js +++ b/tests/unit/ViolationUtilsTest.ts @@ -2,6 +2,7 @@ import {beforeEach} from '@jest/globals'; import Onyx from 'react-native-onyx'; import ViolationsUtils from '@libs/Violations/ViolationsUtils'; import ONYXKEYS from '@src/ONYXKEYS'; +import type {PolicyCategories, PolicyTagList, Transaction, TransactionViolation} from '@src/types/onyx'; const categoryOutOfPolicyViolation = { name: 'categoryOutOfPolicy', @@ -24,15 +25,15 @@ const missingTagViolation = { }; describe('getViolationsOnyxData', () => { - let transaction; - let transactionViolations; - let policyRequiresTags; - let policyTags; - let policyRequiresCategories; - let policyCategories; + let transaction: Transaction; + let transactionViolations: TransactionViolation[]; + let policyRequiresTags: boolean; + let policyTags: PolicyTagList; + let policyRequiresCategories: boolean; + let policyCategories: PolicyCategories; beforeEach(() => { - transaction = {transactionID: '123'}; + transaction = {transactionID: '123', reportID: '1234', amount: 100, comment: {}, created: '2023-07-24 13:46:20', merchant: 'United Airlines', currency: 'USD'}; transactionViolations = []; policyRequiresTags = false; policyTags = {}; @@ -62,12 +63,12 @@ describe('getViolationsOnyxData', () => { describe('policyRequiresCategories', () => { beforeEach(() => { policyRequiresCategories = true; - policyCategories = {Food: {enabled: true}}; + policyCategories = {Food: {name: 'Food', unencodedName: '', enabled: true, areCommentsRequired: false, externalID: '1234', origin: '12345'}}; transaction.category = 'Food'; }); it('should add missingCategory violation if no category is included', () => { - transaction.category = null; + transaction.category = undefined; const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); expect(result.value).toEqual(expect.arrayContaining([missingCategoryViolation, ...transactionViolations])); }); @@ -132,6 +133,7 @@ describe('getViolationsOnyxData', () => { Lunch: {name: 'Lunch', enabled: true}, Dinner: {name: 'Dinner', enabled: true}, }, + orderWeight: 1, }, }; transaction.tag = 'Lunch'; @@ -209,6 +211,7 @@ describe('getViolationsOnyxData', () => { }, }, required: true, + orderWeight: 1, }, Region: { name: 'Region', @@ -218,6 +221,8 @@ describe('getViolationsOnyxData', () => { enabled: true, }, }, + required: true, + orderWeight: 2, }, Project: { name: 'Project', @@ -228,6 +233,7 @@ describe('getViolationsOnyxData', () => { }, }, required: true, + orderWeight: 3, }, }; });