-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #32093 from OlimpiaZurek/feat/30569/ReportActionsU…
…tils-reassure-tests [NoQA] add perf tests for ReportActionsUtils
- Loading branch information
Showing
5 changed files
with
244 additions
and
96 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
import Onyx from 'react-native-onyx'; | ||
import {measureFunction} from 'reassure'; | ||
import * as ReportActionsUtils from '@libs/ReportActionsUtils'; | ||
import CONST from '@src/CONST'; | ||
import ONYXKEYS from '@src/ONYXKEYS'; | ||
import ReportAction, {ReportActions} from '@src/types/onyx/ReportAction'; | ||
import createCollection from '../utils/collections/createCollection'; | ||
import createRandomReportAction from '../utils/collections/reportActions'; | ||
import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; | ||
|
||
beforeAll(() => | ||
Onyx.init({ | ||
keys: ONYXKEYS, | ||
safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS], | ||
}), | ||
); | ||
|
||
// Clear out Onyx after each test so that each test starts with a clean slate | ||
afterEach(() => { | ||
Onyx.clear(); | ||
}); | ||
|
||
const getMockedReportActionsMap = (reportsLength = 10, actionsPerReportLength = 100) => { | ||
const mockReportActions = Array.from({length: actionsPerReportLength}, (v, i) => { | ||
const reportActionKey = i + 1; | ||
const reportAction = createRandomReportAction(reportActionKey); | ||
|
||
return {[reportActionKey]: reportAction}; | ||
}); | ||
|
||
const reportKeysMap = Array.from({length: reportsLength}, (v, i) => { | ||
const key = i + 1; | ||
|
||
return {[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${key}`]: Object.assign({}, ...mockReportActions)}; | ||
}); | ||
|
||
return Object.assign({}, ...reportKeysMap) as Partial<ReportAction>; | ||
}; | ||
|
||
const mockedReportActionsMap = getMockedReportActionsMap(2, 10000); | ||
|
||
const reportActions = createCollection<ReportAction>( | ||
(item) => `${item.reportActionID}`, | ||
(index) => createRandomReportAction(index), | ||
); | ||
|
||
const reportId = '1'; | ||
|
||
const runs = CONST.PERFORMANCE_TESTS.RUNS; | ||
|
||
/** | ||
* This function will be executed 20 times and the average time will be used on the comparison. | ||
* It will fail based on the CI configuration around Reassure: | ||
* @see /.github/workflows/reassurePerformanceTests.yml | ||
* | ||
* Max deviation on the duration is set to 20% at the time of writing. | ||
* | ||
* More on the measureFunction API: | ||
* @see https://callstack.github.io/reassure/docs/api#measurefunction-function | ||
*/ | ||
test('getLastVisibleAction on 10k reportActions', async () => { | ||
await Onyx.multiSet({ | ||
...mockedReportActionsMap, | ||
}); | ||
|
||
await waitForBatchedUpdates(); | ||
await measureFunction(() => ReportActionsUtils.getLastVisibleAction(reportId), {runs}); | ||
}); | ||
|
||
test('getLastVisibleAction on 10k reportActions with actionsToMerge', async () => { | ||
const parentReportActionId = '1'; | ||
const fakeParentAction = reportActions[parentReportActionId]; | ||
const actionsToMerge = { | ||
[parentReportActionId]: { | ||
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, | ||
previousMessage: fakeParentAction.message, | ||
message: [ | ||
{ | ||
translationKey: '', | ||
type: 'COMMENT', | ||
html: '', | ||
text: '', | ||
isEdited: true, | ||
isDeletedParentAction: true, | ||
}, | ||
], | ||
errors: null, | ||
linkMetaData: [], | ||
}, | ||
} as unknown as ReportActions; | ||
|
||
await Onyx.multiSet({ | ||
...mockedReportActionsMap, | ||
}); | ||
await waitForBatchedUpdates(); | ||
await measureFunction(() => ReportActionsUtils.getLastVisibleAction(reportId, actionsToMerge), {runs}); | ||
}); | ||
|
||
test('getMostRecentIOURequestActionID on 10k ReportActions', async () => { | ||
const reportActionsArray = ReportActionsUtils.getSortedReportActionsForDisplay(reportActions); | ||
await Onyx.multiSet({ | ||
...mockedReportActionsMap, | ||
}); | ||
await waitForBatchedUpdates(); | ||
await measureFunction(() => ReportActionsUtils.getMostRecentIOURequestActionID(reportActionsArray), {runs}); | ||
}); | ||
|
||
test('getLastVisibleMessage on 10k ReportActions', async () => { | ||
await Onyx.multiSet({ | ||
...mockedReportActionsMap, | ||
}); | ||
await waitForBatchedUpdates(); | ||
await measureFunction(() => ReportActionsUtils.getLastVisibleMessage(reportId), {runs}); | ||
}); | ||
|
||
test('getLastVisibleMessage on 10k ReportActions with actionsToMerge', async () => { | ||
const parentReportActionId = '1'; | ||
const fakeParentAction = reportActions[parentReportActionId]; | ||
const actionsToMerge = { | ||
[parentReportActionId]: { | ||
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, | ||
previousMessage: fakeParentAction.message, | ||
message: [ | ||
{ | ||
translationKey: '', | ||
type: 'COMMENT', | ||
html: '', | ||
text: '', | ||
isEdited: true, | ||
isDeletedParentAction: true, | ||
}, | ||
], | ||
errors: null, | ||
linkMetaData: [], | ||
}, | ||
} as unknown as ReportActions; | ||
|
||
await Onyx.multiSet({ | ||
...mockedReportActionsMap, | ||
}); | ||
await waitForBatchedUpdates(); | ||
await measureFunction(() => ReportActionsUtils.getLastVisibleMessage(reportId, actionsToMerge), {runs}); | ||
}); | ||
|
||
test('getSortedReportActionsForDisplay on 10k ReportActions', async () => { | ||
await Onyx.multiSet({ | ||
...mockedReportActionsMap, | ||
}); | ||
await waitForBatchedUpdates(); | ||
await measureFunction(() => ReportActionsUtils.getSortedReportActionsForDisplay(reportActions), {runs}); | ||
}); | ||
|
||
test('getLastClosedReportAction on 10k ReportActions', async () => { | ||
await Onyx.multiSet({ | ||
...mockedReportActionsMap, | ||
}); | ||
await waitForBatchedUpdates(); | ||
await measureFunction(() => ReportActionsUtils.getLastClosedReportAction(reportActions), {runs}); | ||
}); | ||
|
||
test('getMostRecentReportActionLastModified', async () => { | ||
await Onyx.multiSet({ | ||
...mockedReportActionsMap, | ||
}); | ||
await waitForBatchedUpdates(); | ||
await measureFunction(() => ReportActionsUtils.getMostRecentReportActionLastModified(), {runs}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import {rand, randAggregation, randBoolean, randPastDate, randWord} from '@ngneat/falso'; | ||
import CONST from '@src/CONST'; | ||
import {ReportAction} from '@src/types/onyx'; | ||
|
||
type ActionType = keyof typeof CONST.REPORT.ACTIONS.TYPE; | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const flattenActionNamesValues = (actionNames: any) => { | ||
let result = [] as ActionType[]; | ||
Object.keys(actionNames).forEach((key) => { | ||
if (typeof actionNames[key] === 'object') { | ||
result = result.concat(flattenActionNamesValues(actionNames[key])); | ||
} else { | ||
result.push(actionNames[key]); | ||
} | ||
}); | ||
return result; | ||
}; | ||
|
||
export default function createRandomReportAction(index: number): ReportAction { | ||
return { | ||
// we need to add any here because of the way we are generating random values | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
actionName: rand(flattenActionNamesValues(CONST.REPORT.ACTIONS.TYPE)) as any, | ||
reportActionID: index.toString(), | ||
previousReportActionID: index.toString(), | ||
actorAccountID: index, | ||
person: [ | ||
{ | ||
type: randWord(), | ||
style: randWord(), | ||
text: randWord(), | ||
}, | ||
], | ||
created: randPastDate().toISOString(), | ||
message: [ | ||
{ | ||
type: randWord(), | ||
html: randWord(), | ||
style: randWord(), | ||
text: randWord(), | ||
isEdited: randBoolean(), | ||
isDeletedParentAction: randBoolean(), | ||
whisperedTo: randAggregation(), | ||
reactions: [ | ||
{ | ||
emoji: randWord(), | ||
users: [ | ||
{ | ||
accountID: index, | ||
skinTone: index, | ||
}, | ||
], | ||
}, | ||
], | ||
}, | ||
], | ||
originalMessage: { | ||
html: randWord(), | ||
type: rand(Object.values(CONST.IOU.REPORT_ACTION_TYPE)), | ||
}, | ||
whisperedToAccountIDs: randAggregation(), | ||
avatar: randWord(), | ||
automatic: randBoolean(), | ||
shouldShow: randBoolean(), | ||
lastModified: randPastDate().toISOString(), | ||
pendingAction: rand(Object.values(CONST.RED_BRICK_ROAD_PENDING_ACTION)), | ||
delegateAccountID: index.toString(), | ||
errors: {}, | ||
isAttachment: randBoolean(), | ||
}; | ||
} |