Skip to content

Commit c473b17

Browse files
authored
Merge pull request #30833 from adhorodyski/chore/testing-utils
[NoQA] chore(tests): unified utilities for mocking collections
2 parents e1c98cb + 56a1e16 commit c473b17

File tree

6 files changed

+111
-0
lines changed

6 files changed

+111
-0
lines changed

package-lock.json

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@
189189
"@dword-design/eslint-plugin-import-alias": "^4.0.8",
190190
"@electron/notarize": "^2.1.0",
191191
"@jest/globals": "^29.5.0",
192+
"@ngneat/falso": "^7.1.1",
192193
"@octokit/core": "4.0.4",
193194
"@octokit/plugin-paginate-rest": "3.1.0",
194195
"@octokit/plugin-throttling": "4.1.0",

tests/README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,36 @@
1515
- To simulate a network request succeeding or failing we can mock the expected response first and then manually trigger the action that calls that API command.
1616
- [Mocking the response of `HttpUtils.xhr()`](https://github.com/Expensify/App/blob/ca2fa88a5789b82463d35eddc3d57f70a7286868/tests/actions/SessionTest.js#L25-L32) is the best way to simulate various API conditions so we can verify whether a result occurs or not.
1717

18+
## Mocking collections / collection items
19+
20+
When unit testing an interface with Jest/performance testing with Reassure you might need to work with collections of data. These often get tricky to generate and maintain. To help with this we have a few helper methods located in `tests/utils/collections/`.
21+
22+
- `createCollection()` - Creates a collection of data (`Record<string, T>`) with a given number of items (default=500). This is useful for eg. testing the performance of a component with a large number of items. You can use it to populate Onyx.
23+
- `createRandom*()` - like `createRandomPolicy`, these functions are responsible for generating a randomised object of the given type. You can use them as your defaults when calling `createCollection()` or as standalone utilities.
24+
25+
Basic example:
26+
```ts
27+
const policies = createCollection<Policy>(item => `policies_${item.id}`, createRandomPolicy);
28+
29+
/**
30+
Output:
31+
{
32+
"policies_0": policyItem0,
33+
"policies_1": policyItem1,
34+
...
35+
}
36+
*/
37+
```
38+
39+
Example with overrides:
40+
41+
```ts
42+
const policies = createCollection<Policy>(
43+
item => `policies_${item.id}`,
44+
index => ({ ...createRandomPolicy(index), isPinned: true })
45+
);
46+
```
47+
1848
## Mocking `node_modules`, user modules, and what belongs in `jest/setup.js`
1949

2050
If you need to mock a library that exists in `node_modules` then add it to the `__mocks__` folder in the root of the project. More information about this [here](https://jestjs.io/docs/manual-mocks#mocking-node-modules). If you need to mock an individual library you should create a mock module in a `__mocks__` subdirectory adjacent to the library as explained [here](https://jestjs.io/docs/manual-mocks#mocking-user-modules). However, keep in mind that when you do this you also must manually require the mock by calling something like `jest.mock('../../src/libs/Log');` at the top of an individual test file. If every test in the app will need something to be mocked that's a good case for adding it to `jest/setup.js`, but we should generally avoid adding user mocks or `node_modules` mocks to this file. Please use the `__mocks__` subdirectories wherever appropriate.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export default function createCollection<T>(createKey: (item: T, index: number) => string, createItem: (index: number) => T, length = 500): Record<string, T> {
2+
const map: Record<string, T> = {};
3+
4+
for (let i = 0; i < length; i++) {
5+
const item = createItem(i);
6+
const itemKey = createKey(item, i);
7+
map[itemKey] = item;
8+
}
9+
10+
return map;
11+
}

tests/utils/collections/policies.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import {rand, randAvatar, randBoolean, randCurrencyCode, randEmail, randPastDate, randWord} from '@ngneat/falso';
2+
import CONST from '@src/CONST';
3+
import type {Policy} from '@src/types/onyx';
4+
5+
export default function createRandomPolicy(index: number): Policy {
6+
return {
7+
id: index.toString(),
8+
name: randWord(),
9+
type: rand(Object.values(CONST.POLICY.TYPE)),
10+
areChatRoomsEnabled: randBoolean(),
11+
autoReporting: randBoolean(),
12+
isPolicyExpenseChatEnabled: randBoolean(),
13+
autoReportingFrequency: rand(Object.values(CONST.POLICY.AUTO_REPORTING_FREQUENCIES)),
14+
outputCurrency: randCurrencyCode(),
15+
role: rand(Object.values(CONST.POLICY.ROLE)),
16+
owner: randEmail(),
17+
ownerAccountID: index,
18+
avatar: randAvatar(),
19+
isFromFullPolicy: randBoolean(),
20+
lastModified: randPastDate().toISOString(),
21+
pendingAction: rand(Object.values(CONST.RED_BRICK_ROAD_PENDING_ACTION)),
22+
errors: {},
23+
customUnits: {},
24+
errorFields: {},
25+
};
26+
}

tests/utils/collections/reports.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import {rand, randBoolean, randCurrencyCode, randEmail, randWord} from '@ngneat/falso';
2+
import CONST from '@src/CONST';
3+
import type {Report} from '@src/types/onyx';
4+
5+
export default function createRandomReport(index: number): Report {
6+
return {
7+
reportID: index.toString(),
8+
chatType: rand(Object.values(CONST.REPORT.CHAT_TYPE)),
9+
currency: randCurrencyCode(),
10+
displayName: randWord(),
11+
hasDraft: randBoolean(),
12+
ownerEmail: randEmail(),
13+
ownerAccountID: index,
14+
isPinned: randBoolean(),
15+
isOptimisticReport: randBoolean(),
16+
isOwnPolicyExpenseChat: randBoolean(),
17+
isWaitingOnBankAccount: randBoolean(),
18+
isLastMessageDeletedParentAction: randBoolean(),
19+
policyID: index.toString(),
20+
reportName: randWord(),
21+
};
22+
}

0 commit comments

Comments
 (0)