Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[No QA] Add unit test for getSubmitToAccountID and getApprovalChain #55062

Merged
merged 12 commits into from
Jan 15, 2025
317 changes: 316 additions & 1 deletion tests/unit/PolicyUtilsTest.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,146 @@
/* eslint-disable @typescript-eslint/naming-convention */
import Onyx from 'react-native-onyx';
import * as PolicyUtils from '@libs/PolicyUtils';

Check failure on line 3 in tests/unit/PolicyUtilsTest.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Namespace imports from @libs are not allowed. Use named imports instead. Example: import { method } from "@libs/module"
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Policy} from '@src/types/onyx';
import type {PersonalDetailsList, Policy, PolicyEmployeeList, Report, Transaction} from '@src/types/onyx';
import createCollection from '../utils/collections/createCollection';
import createRandomPolicy from '../utils/collections/policies';
import createRandomReport from '../utils/collections/reports';
import createRandomTransaction from '../utils/collections/transaction';
import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct';
import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates';

function toLocaleDigitMock(dot: string): string {
return dot;
}

const employeeList: PolicyEmployeeList = {
'owner@test.com': {
email: 'admin@test.com',
role: 'admin',
submitsTo: '',
},
'admin@test.com': {
email: 'admin@test.com',
role: 'admin',
submitsTo: '',
},
'employee@test.com': {
email: 'employee@test.com',
role: 'user',
submitsTo: 'admin@test.com',
},
'categoryapprover1@test.com': {
email: 'categoryapprover1@test.com',
role: 'user',
submitsTo: 'admin@test.com',
},
'categoryapprover2@test.com': {
email: 'categoryapprover2@test.com',
role: 'user',
submitsTo: 'admin@test.com',
},
'tagapprover1@test.com': {
email: 'tagapprover1@test.com',
role: 'user',
submitsTo: 'admin@test.com',
},
'tagapprover2@test.com': {
email: 'tagapprover2@test.com',
role: 'user',
submitsTo: 'admin@test.com',
},
};

const personalDetails: PersonalDetailsList = {
'1': {
accountID: 1,
login: 'admin@test.com',
},
'2': {
accountID: 2,
login: 'employee@test.com',
},
'3': {
accountID: 3,
login: 'categoryapprover1@test.com',
},
'4': {
accountID: 4,
login: 'categoryapprover2@test.com',
},
'5': {
accountID: 5,
login: 'tagapprover1@test.com',
},
'6': {
accountID: 6,
login: 'tagapprover2@test.com',
},
'7': {
accountID: 7,
login: 'owner@test.com',
},
};

const rules = {
approvalRules: [
{
applyWhen: [
{
condition: 'matches',
field: 'category',
value: 'cat1',
},
],
approver: 'categoryapprover1@test.com',
id: '1',
},
{
applyWhen: [
{
condition: 'matches',
field: 'tag',
value: 'tag1',
},
],
approver: 'tagapprover1@test.com',
id: '2',
},
{
applyWhen: [
{
condition: 'matches',
field: 'category',
value: 'cat2',
},
],
approver: 'categoryapprover2@test.com',
id: '3',
},
{
applyWhen: [
{
condition: 'matches',
field: 'tag',
value: 'tag2',
},
],
approver: 'tagapprover2@test.com',
id: '4',
},
],
};

const ownerAccountID = 7;
const adminAccountID = 1;
const employeeAccountID = 2;
const categoryapprover1AccountID = 3;
const categoryapprover2AccountID = 4;
const tagapprover1AccountID = 5;
const tagapprover2AccountID = 6;

describe('PolicyUtils', () => {
describe('getActivePolicies', () => {
it("getActivePolicies should filter out policies that the current user doesn't belong to", () => {
Expand Down Expand Up @@ -95,4 +228,186 @@
});
});
});

describe('getSubmitToAccountID', () => {
beforeEach(() => {
wrapOnyxWithWaitForBatchedUpdates(Onyx);
Onyx.set(ONYXKEYS.PERSONAL_DETAILS_LIST, personalDetails);
});
afterEach(async () => {
await Onyx.clear();
await waitForBatchedUpdatesWithAct();
});
describe('Has no rule approver', () => {
it('should return the policy approver/owner if the policy use the optional or basic workflow', () => {
const policy: Policy = {
...createRandomPolicy(0),
approver: 'owner@test.com',
owner: 'owner@test.com',
type: 'team',
approvalMode: CONST.POLICY.APPROVAL_MODE.BASIC,
};
const expenseReport: Report = {
...createRandomReport(0),
ownerAccountID: employeeAccountID,
type: CONST.REPORT.TYPE.EXPENSE,
};
expect(PolicyUtils.getSubmitToAccountID(policy, expenseReport)).toBe(ownerAccountID);
});
it('should return the employee submitsTo if the policy use the advance workflow', () => {
const policy: Policy = {
...createRandomPolicy(0),
approver: 'owner@test.com',
owner: 'owner@test.com',
employeeList,
type: 'team',
approvalMode: CONST.POLICY.APPROVAL_MODE.ADVANCED,
};
const expenseReport: Report = {
...createRandomReport(0),
ownerAccountID: employeeAccountID,
type: CONST.REPORT.TYPE.EXPENSE,
};
expect(PolicyUtils.getSubmitToAccountID(policy, expenseReport)).toBe(adminAccountID);
});
});
describe('Has category/tag approver', () => {
it('should return the first category approver if has any transaction category match with category approver rule', async () => {
const policy: Policy = {
...createRandomPolicy(0),
approver: 'owner@test.com',
owner: 'owner@test.com',
type: 'team',
employeeList,
rules,
approvalMode: CONST.POLICY.APPROVAL_MODE.ADVANCED,
};
const expenseReport: Report = {
...createRandomReport(0),
ownerAccountID: employeeAccountID,
type: CONST.REPORT.TYPE.EXPENSE,
};
const transaction1: Transaction = {
...createRandomTransaction(0),
category: 'cat1',
reportID: expenseReport.reportID,
};
const transaction2: Transaction = {
...createRandomTransaction(1),
category: '',
reportID: expenseReport.reportID,
};
await Onyx.set(ONYXKEYS.COLLECTION.TRANSACTION, {
[transaction1.transactionID]: transaction1,
[transaction2.transactionID]: transaction2,
});
expect(PolicyUtils.getSubmitToAccountID(policy, expenseReport)).toBe(categoryapprover1AccountID);
});
it('should return the category approver of the first transaction sorted by created if we have many transaction categories match with the category approver rule', async () => {
const policy: Policy = {
...createRandomPolicy(0),
approver: 'owner@test.com',
owner: 'owner@test.com',
type: 'team',
employeeList,
rules,
approvalMode: CONST.POLICY.APPROVAL_MODE.ADVANCED,
};
const expenseReport: Report = {
...createRandomReport(0),
ownerAccountID: employeeAccountID,
type: CONST.REPORT.TYPE.EXPENSE,
};
const transaction1: Transaction = {
...createRandomTransaction(0),
category: 'cat1',
created: '3',
reportID: expenseReport.reportID,
};
const transaction2: Transaction = {
...createRandomTransaction(1),
category: 'cat2',
created: '2',
reportID: expenseReport.reportID,
};
await Onyx.set(ONYXKEYS.COLLECTION.TRANSACTION, {
[transaction1.transactionID]: transaction1,
[transaction2.transactionID]: transaction2,
});
expect(PolicyUtils.getSubmitToAccountID(policy, expenseReport)).toBe(categoryapprover2AccountID);
});
describe('Has no transaction match with the category approver rule', () => {
it('should return the first tag approver if has any transaction tag match with with the tag approver rule ', async () => {
const policy: Policy = {
...createRandomPolicy(0),
approver: 'owner@test.com',
owner: 'owner@test.com',
type: 'team',
employeeList,
rules,
approvalMode: CONST.POLICY.APPROVAL_MODE.ADVANCED,
};
const expenseReport: Report = {
...createRandomReport(0),
ownerAccountID: employeeAccountID,
type: CONST.REPORT.TYPE.EXPENSE,
};
const transaction1: Transaction = {
...createRandomTransaction(0),
category: '',
tag: 'tag1',
created: '3',
reportID: expenseReport.reportID,
};
const transaction2: Transaction = {
...createRandomTransaction(1),
category: '',
tag: '',
created: '2',
reportID: expenseReport.reportID,
};
await Onyx.set(ONYXKEYS.COLLECTION.TRANSACTION, {
[transaction1.transactionID]: transaction1,
[transaction2.transactionID]: transaction2,
});
expect(PolicyUtils.getSubmitToAccountID(policy, expenseReport)).toBe(tagapprover1AccountID);
});
it('should return the tag approver of the first transaction sorted by created if we have many transaction tags match with the tag approver rule', async () => {
const policy: Policy = {
...createRandomPolicy(0),
approver: 'owner@test.com',
owner: 'owner@test.com',
type: 'team',
employeeList,
rules,
approvalMode: CONST.POLICY.APPROVAL_MODE.ADVANCED,
};
const expenseReport: Report = {
...createRandomReport(0),
ownerAccountID: employeeAccountID,
type: CONST.REPORT.TYPE.EXPENSE,
};
const transaction1: Transaction = {
...createRandomTransaction(0),
category: '',
tag: 'tag1',
created: '3',
reportID: expenseReport.reportID,
};
const transaction2: Transaction = {
...createRandomTransaction(1),
category: '',
tag: 'tag2',
created: '2',
reportID: expenseReport.reportID,
};
await Onyx.set(ONYXKEYS.COLLECTION.TRANSACTION, {
[transaction1.transactionID]: transaction1,
[transaction2.transactionID]: transaction2,
});
expect(PolicyUtils.getSubmitToAccountID(policy, expenseReport)).toBe(tagapprover2AccountID);
});
});
});
});
});
Loading
Loading