Skip to content

Commit

Permalink
Merge pull request Expensify#38551 from brandonhenry/38166-reassure-a…
Browse files Browse the repository at this point in the history
…dd-measureFunction-test-for-formatSectionsFromSearchTerm

[Reassure] Add measureFunction test for formatSectionsFromSearchTerm
  • Loading branch information
mountiny authored Apr 8, 2024
2 parents 1b6c993 + a830536 commit 89b9cef
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 0 deletions.
102 changes: 102 additions & 0 deletions tests/perf-test/OptionsListUtils.perf-test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import {rand} from '@ngneat/falso';
import type * as NativeNavigation from '@react-navigation/native';
import Onyx from 'react-native-onyx';
import {measureFunction} from 'reassure';
import * as OptionsListUtils from '@libs/OptionsListUtils';
import type {OptionData} from '@libs/ReportUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {PersonalDetails} from '@src/types/onyx';
import type Report from '@src/types/onyx/Report';
import {formatSectionsFromSearchTerm} from '../../src/libs/OptionsListUtils';
import createCollection from '../utils/collections/createCollection';
import createRandomOptionData from '../utils/collections/optionData';
import createPersonalDetails from '../utils/collections/personalDetails';
import {getRandomDate} from '../utils/collections/reportActions';
import createRandomReport from '../utils/collections/reports';
Expand All @@ -16,6 +20,10 @@ const REPORTS_COUNT = 5000;
const PERSONAL_DETAILS_LIST_COUNT = 1000;
const SEARCH_VALUE = 'TestingValue';

const PERSONAL_DETAILS_COUNT = 1000;
const SELECTED_OPTIONS_COUNT = 1000;
const RECENT_REPORTS_COUNT = 100;

const reports = createCollection<Report>(
(item) => `${ONYXKEYS.COLLECTION.REPORT}${item.reportID}`,
(index) => ({
Expand All @@ -32,6 +40,27 @@ const personalDetails = createCollection<PersonalDetails>(
PERSONAL_DETAILS_LIST_COUNT,
);

const getMockedReports = (length = 500) =>
createCollection<Report>(
(item) => `${ONYXKEYS.COLLECTION.REPORT}${item.reportID}`,
(index) => ({
...createRandomReport(index),
type: rand(Object.values(CONST.REPORT.TYPE)),
lastVisibleActionCreated: getRandomDate(),
}),
length,
);

const getMockedPersonalDetails = (length = 500) =>
createCollection<PersonalDetails>(
(item) => item.accountID,
(index) => createPersonalDetails(index),
length,
);

const mockedReportsMap = getMockedReports(REPORTS_COUNT) as Record<`${typeof ONYXKEYS.COLLECTION.REPORT}`, Report>;
const mockedPersonalDetailsMap = getMockedPersonalDetails(PERSONAL_DETAILS_LIST_COUNT);

const mockedBetas = Object.values(CONST.BETAS);

jest.mock('@react-navigation/native', () => {
Expand All @@ -48,6 +77,21 @@ const options = OptionsListUtils.createOptionList(personalDetails, reports);

/* GetOption is the private function and is never called directly, we are testing the functions which call getOption with different params */
describe('OptionsListUtils', () => {
beforeAll(() => {
Onyx.init({
keys: ONYXKEYS,
});

Onyx.multiSet({
...mockedReportsMap,
...mockedPersonalDetailsMap,
});
});

afterAll(() => {
Onyx.clear();
});

/* Testing getSearchOptions */
test('[OptionsListUtils] getSearchOptions with search value', async () => {
await waitForBatchedUpdates();
Expand Down Expand Up @@ -77,4 +121,62 @@ describe('OptionsListUtils', () => {
await waitForBatchedUpdates();
await measureFunction(() => OptionsListUtils.getMemberInviteOptions(options.personalDetails, mockedBetas, SEARCH_VALUE));
});

test('[OptionsListUtils] worst case scenario with a search term that matches a subset of selectedOptions, filteredRecentReports, and filteredPersonalDetails', async () => {
const SELECTED_OPTION_TEXT = 'Selected Option';
const RECENT_REPORT_TEXT = 'Recent Report';
const PERSONAL_DETAIL_TEXT = 'Personal Detail';

const SELECTED_OPTIONS_MATCH_FREQUENCY = 2;
const RECENT_REPORTS_MATCH_FREQUENCY = 3;
const PERSONAL_DETAILS_MATCH_FREQUENCY = 5;

const selectedOptions = createCollection<OptionData>(
(item) => item.reportID,
(index) => ({
...createRandomOptionData(index),
searchText: index % SELECTED_OPTIONS_MATCH_FREQUENCY === 0 ? SEARCH_VALUE : `${SELECTED_OPTION_TEXT} ${index}`,
}),
SELECTED_OPTIONS_COUNT,
);
const filteredRecentReports = createCollection<OptionData>(
(item) => item.reportID,
(index) => ({
...createRandomOptionData(index + SELECTED_OPTIONS_COUNT),
searchText: index % RECENT_REPORTS_MATCH_FREQUENCY === 0 ? SEARCH_VALUE : `${RECENT_REPORT_TEXT} ${index}`,
}),
RECENT_REPORTS_COUNT,
);
const filteredPersonalDetails = createCollection<OptionData>(
(item) => item.reportID,
(index) => ({
...createRandomOptionData(index + SELECTED_OPTIONS_COUNT + RECENT_REPORTS_COUNT),
searchText: index % PERSONAL_DETAILS_MATCH_FREQUENCY === 0 ? SEARCH_VALUE : `${PERSONAL_DETAIL_TEXT} ${index}`,
}),
PERSONAL_DETAILS_COUNT,
);

const mockedPersonalDetails = getMockedPersonalDetails(PERSONAL_DETAILS_COUNT);

await measureFunction(() =>
formatSectionsFromSearchTerm(
SEARCH_VALUE,
Object.values(selectedOptions),
Object.values(filteredRecentReports),
Object.values(filteredPersonalDetails),
false,
mockedPersonalDetails,
true,
),
);
});

test('[OptionsListUtils] empty search term with selected options and mocked personal details', async () => {
const selectedOptions = createCollection<OptionData>((item) => item.reportID, createRandomOptionData, SELECTED_OPTIONS_COUNT);

const mockedPersonalDetails = getMockedPersonalDetails(PERSONAL_DETAILS_COUNT);

await waitForBatchedUpdates();
await measureFunction(() => formatSectionsFromSearchTerm('', Object.values(selectedOptions), [], [], true, mockedPersonalDetails, true));
});
});
57 changes: 57 additions & 0 deletions tests/utils/collections/optionData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import {rand, randBoolean, randEmail, randNumber, randPhoneNumber, randWord} from '@ngneat/falso';
import type {OptionData} from '@libs/ReportUtils';
import CONST from '@src/CONST';

export default function createRandomOptionData(index: number): OptionData {
return {
login: randEmail(),
searchText: randWord(),
reportID: `report_${index}`,
text: randWord(),
alternateText: randWord(),
tooltipText: randWord(),
keyForList: `option_${index}`,
descriptiveText: randWord(),
isUnread: randBoolean(),
isPinned: randBoolean(),
isSelected: randBoolean(),
phoneNumber: randPhoneNumber(),
policyName: randWord(),
policyID: `policy_${index}`,
accountID: randNumber(),
isArchivedRoom: randBoolean(),
isPolicyExpenseChat: randBoolean(),
chatType: rand(Object.values(CONST.REPORT.CHAT_TYPE)),
hasOutstandingChildRequest: randBoolean(),
isOwnPolicyExpenseChat: randBoolean(),
lastMessageText: randWord(),
lastMessageTimestamp: Date.now(),
lastVisibleActionCreated: new Date().toISOString(),
lastReadCreated: new Date().toISOString(),
lastReadTime: new Date().toISOString(),
lastReadSequenceNumber: randNumber(),
lastMentionedTime: randBoolean() ? new Date().toISOString() : null,
notificationPreference: rand(Object.values(CONST.REPORT.NOTIFICATION_PREFERENCE)),
oldPolicyName: randWord(),
hasParentAccess: randBoolean(),
description: randWord(),
isDeletedParentAction: randBoolean(),
reportName: randWord(),
reportActionID: `reportAction_${index}`,
chatReportID: `chatReport_${index}`,
stateNum: rand(Object.values(CONST.REPORT.STATE_NUM)),
statusNum: rand(Object.values(CONST.REPORT.STATUS_NUM)),
type: rand(Object.values(CONST.REPORT.TYPE)),
visibility: rand(Object.values(CONST.REPORT.VISIBILITY)),
isLastMessageDeletedParentAction: randBoolean(),
isCancelledIOU: randBoolean(),
iouReportID: `iou_${index}`,
iouReportAmount: randNumber({min: 0, max: 1000}),
currency: randWord(),
isWaitingOnBankAccount: randBoolean(),
lastVisibleActionLastModified: new Date().toISOString(),
lastActorAccountID: randNumber(),
ownerAccountID: randNumber(),
ownerEmail: randEmail(),
};
}

0 comments on commit 89b9cef

Please sign in to comment.