Skip to content

Commit

Permalink
Merge pull request #36867 from HezekielT/migrate/36135
Browse files Browse the repository at this point in the history
  • Loading branch information
cead22 authored Mar 18, 2024
2 parents ed6fbbc + aaad266 commit 4f2ec61
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 135 deletions.
2 changes: 1 addition & 1 deletion src/types/onyx/PolicyCategory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/types/onyx/PolicyTag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
82 changes: 43 additions & 39 deletions tests/actions/PolicyTest.js → tests/actions/PolicyTest.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -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();
Expand All @@ -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<PolicyType> = await new Promise((resolve) => {
const connectionID = Onyx.connect({
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
waitForCollectionCallback: true,
Expand All @@ -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<PolicyMembers> = await new Promise((resolve) => {
const connectionID = Onyx.connect({
key: `${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${policyID}`,
waitForCollectionCallback: true,
Expand All @@ -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<Report> = await new Promise((resolve) => {
const connectionID = Onyx.connect({
key: ONYXKEYS.COLLECTION.REPORT,
waitForCollectionCallback: true,
Expand All @@ -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;
Expand All @@ -107,7 +110,7 @@ describe('actions/Policy', () => {
}
});

let reportActions = await new Promise((resolve) => {
let reportActions: OnyxCollection<ReportActions> = await new Promise((resolve) => {
const connectionID = Onyx.connect({
key: ONYXKEYS.COLLECTION.REPORT_ACTIONS,
waitForCollectionCallback: true,
Expand All @@ -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();

Expand All @@ -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({
Expand All @@ -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) => {
Expand All @@ -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();
});
});
Expand Down
Original file line number Diff line number Diff line change
@@ -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<WithLocalizeProps>) => {
function WrappedComponent(props: WithLocalizeProps) {
return (
<Component
// eslint-disable-next-line react/jsx-props-no-spreading
Expand All @@ -19,8 +22,8 @@ jest.mock('../../src/components/withLocalize', () => (Component) => {
return WrappedComponent;
});

jest.mock('../../src/components/withNavigationFocus', () => (Component) => {
function WithNavigationFocus(props) {
jest.mock('@src/components/withNavigationFocus', () => (Component: ComponentType<WithNavigationFocusProps>) => {
function WithNavigationFocus(props: WithNavigationFocusProps) {
return (
<Component
// eslint-disable-next-line react/jsx-props-no-spreading
Expand All @@ -35,25 +38,27 @@ jest.mock('../../src/components/withNavigationFocus', () => (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}`,
})),
indexOffset,
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 (
<OptionsSelector
value="test"
Expand All @@ -65,12 +70,12 @@ function OptionsSelectorWrapper(args) {
}

test('[OptionsSelector] should render text input with interactions', () => {
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<void>>;

measurePerformance(<OptionsSelectorWrapper />, {scenario});
});
Expand All @@ -85,22 +90,22 @@ 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<void>>;

measurePerformance(<OptionsSelectorWrapper />, {scenario});
});

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,
Expand All @@ -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'));
Expand Down
Loading

0 comments on commit 4f2ec61

Please sign in to comment.