Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 161 additions & 1 deletion tests/unit/TransactionUtilsTest.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import type {OnyxCollection} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import {shouldShowBrokenConnectionViolation} from '@libs/TransactionUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Attendee} from '@src/types/onyx/IOU';
import type {ReportCollectionDataSet} from '@src/types/onyx/Report';
import * as TransactionUtils from '../../src/libs/TransactionUtils';
import type {Policy, Transaction} from '../../src/types/onyx';
import type {Policy, Transaction, TransactionViolation} from '../../src/types/onyx';
import createRandomPolicy, {createCategoryTaxExpenseRules} from '../utils/collections/policies';

function generateTransaction(values: Partial<Transaction> = {}): Transaction {
Expand All @@ -25,7 +30,56 @@ function generateTransaction(values: Partial<Transaction> = {}): Transaction {
return {...baseValues, ...values};
}

const CURRENT_USER_ID = 1;
const SECOND_USER_ID = 2;
const FAKE_OPEN_REPORT_ID = 'FAKE_OPEN_REPORT_ID';
const FAKE_OPEN_REPORT_SECOND_USER_ID = 'FAKE_OPEN_REPORT_SECOND_USER_ID';
const FAKE_PROCESSING_REPORT_ID = 'FAKE_PROCESSING_REPORT_ID';
const FAKE_APPROVED_REPORT_ID = 'FAKE_APPROVED_REPORT_ID';
const openReport = {
reportID: FAKE_OPEN_REPORT_ID,
ownerAccountID: CURRENT_USER_ID,
type: CONST.REPORT.TYPE.EXPENSE,
stateNum: CONST.REPORT.STATE_NUM.OPEN,
statusNum: CONST.REPORT.STATUS_NUM.OPEN,
};
const processingReport = {
reportID: FAKE_PROCESSING_REPORT_ID,
ownerAccountID: CURRENT_USER_ID,
type: CONST.REPORT.TYPE.EXPENSE,
stateNum: CONST.REPORT.STATE_NUM.SUBMITTED,
};
const approvedReport = {
reportID: FAKE_APPROVED_REPORT_ID,
ownerAccountID: SECOND_USER_ID,
type: CONST.REPORT.TYPE.EXPENSE,
stateNum: CONST.REPORT.STATE_NUM.APPROVED,
};
const secondUserOpenReport = {
reportID: FAKE_OPEN_REPORT_SECOND_USER_ID,
ownerAccountID: SECOND_USER_ID,
type: CONST.REPORT.TYPE.EXPENSE,
stateNum: CONST.REPORT.STATE_NUM.OPEN,
statusNum: CONST.REPORT.STATUS_NUM.OPEN,
};
const reportCollectionDataSet: ReportCollectionDataSet = {
[`${ONYXKEYS.COLLECTION.REPORT}${FAKE_OPEN_REPORT_ID}`]: openReport,
[`${ONYXKEYS.COLLECTION.REPORT}${FAKE_PROCESSING_REPORT_ID}`]: processingReport,
[`${ONYXKEYS.COLLECTION.REPORT}${FAKE_APPROVED_REPORT_ID}`]: approvedReport,
[`${ONYXKEYS.COLLECTION.REPORT}${FAKE_OPEN_REPORT_SECOND_USER_ID}`]: secondUserOpenReport,
};

describe('TransactionUtils', () => {
beforeAll(() => {
Onyx.init({
keys: ONYXKEYS,
initialKeyStates: {
[ONYXKEYS.SESSION]: {accountID: CURRENT_USER_ID},
...reportCollectionDataSet,
},
});
});

describe('getCreated', () => {
describe('when the transaction property "modifiedCreated" has value', () => {
const transaction = generateTransaction({
Expand Down Expand Up @@ -279,4 +333,110 @@ describe('TransactionUtils', () => {
expect(result).toBe(9.09);
});
});

describe('shouldShowBrokenConnectionViolation', () => {
it('should return false when the provided transaction is undefined', () => {
const transaction = undefined;
const transactionViolations = [{type: CONST.VIOLATION_TYPES.VIOLATION, name: CONST.VIOLATIONS.RTER}];
const showBrokenConnectionViolation = shouldShowBrokenConnectionViolation(transaction, undefined, undefined, transactionViolations);

expect(showBrokenConnectionViolation).toBe(false);
});

it('should throw an error when both transactionIDs and transactionViolations are arrays', () => {
const transactionIDs = ['FAKE_1', 'FAKE_2'];
const transactionViolations: TransactionViolation[] = [{type: CONST.VIOLATION_TYPES.VIOLATION, name: CONST.VIOLATIONS.RTER}];

expect(() => {
shouldShowBrokenConnectionViolation(transactionIDs, undefined, undefined, transactionViolations);
}).toThrow('Invalid argument combination. If a transactionIDList is passed in, then an OnyxCollection of violations is expected');
});

it('should throw an error when only one transaction is provided and transactionViolations are not an array', () => {
const transaction = generateTransaction();
const transactionViolations: OnyxCollection<TransactionViolation[]> = {
violationID: [{type: CONST.VIOLATION_TYPES.VIOLATION, name: CONST.VIOLATIONS.RTER}],
};

expect(() => {
shouldShowBrokenConnectionViolation(transaction, undefined, undefined, transactionViolations);
}).toThrow('Invalid argument combination. If a single transaction is passed in, then an array of violations for that transaction is expected');
});

it('should return false when no broken connection violations are found for the provided transaction', () => {
const transaction = generateTransaction();
const transactionViolations = [{type: CONST.VIOLATION_TYPES.VIOLATION, name: CONST.VIOLATIONS.DUPLICATED_TRANSACTION}];
const showBrokenConnectionViolation = shouldShowBrokenConnectionViolation(transaction, undefined, undefined, transactionViolations);

expect(showBrokenConnectionViolation).toBe(false);
});

it('should return true when a broken connection violation exists for one transaction and the user is the policy member', () => {
const policy = {role: CONST.POLICY.ROLE.USER} as Policy;
const transaction = generateTransaction();
const transactionViolations = [{type: CONST.VIOLATION_TYPES.VIOLATION, name: CONST.VIOLATIONS.RTER, data: {rterType: CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION}}];
const showBrokenConnectionViolation = shouldShowBrokenConnectionViolation(transaction, undefined, policy, transactionViolations);

expect(showBrokenConnectionViolation).toBe(true);
});

it('should return true when a broken connection violation exists for any of the provided transactions and the user is the policy member', () => {
const policy = {role: CONST.POLICY.ROLE.USER} as Policy;
const transaction1 = generateTransaction();
const transaction2 = generateTransaction();
const transactionIDs = [transaction1.transactionID, transaction2.transactionID];
const transactionViolations = {
[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction1.transactionID}`]: [
{
type: CONST.VIOLATION_TYPES.VIOLATION,
name: CONST.VIOLATIONS.RTER,
data: {rterType: CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION},
},
],
};
const showBrokenConnectionViolation = shouldShowBrokenConnectionViolation(transactionIDs, undefined, policy, transactionViolations);

expect(showBrokenConnectionViolation).toBe(true);
});

it('should return true when a broken connection violation exists and the user is the policy admin and the expense submitter', () => {
const policy = {role: CONST.POLICY.ROLE.ADMIN} as Policy;
const report = processingReport;
const transaction = generateTransaction();
const transactionViolations = [{type: CONST.VIOLATION_TYPES.VIOLATION, name: CONST.VIOLATIONS.RTER, data: {rterType: CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION}}];
const showBrokenConnectionViolation = shouldShowBrokenConnectionViolation(transaction, report, policy, transactionViolations);

expect(showBrokenConnectionViolation).toBe(true);
});

it('should return true when a broken connection violation exists, the user is the policy admin and the expense report is in the open state', () => {
const policy = {role: CONST.POLICY.ROLE.ADMIN} as Policy;
const report = secondUserOpenReport;
const transaction = generateTransaction();
const transactionViolations = [{type: CONST.VIOLATION_TYPES.VIOLATION, name: CONST.VIOLATIONS.RTER, data: {rterType: CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION}}];
const showBrokenConnectionViolation = shouldShowBrokenConnectionViolation(transaction, report, policy, transactionViolations);

expect(showBrokenConnectionViolation).toBe(true);
});

it('should return true when a broken connection violation exists, the user is the policy admin, the expense report is in the processing state and instant submit is enabled', () => {
const policy = {role: CONST.POLICY.ROLE.ADMIN, autoReporting: true, autoReportingFrequency: CONST.POLICY.AUTO_REPORTING_FREQUENCIES.INSTANT} as Policy;
const report = processingReport;
const transaction = generateTransaction();
const transactionViolations = [{type: CONST.VIOLATION_TYPES.VIOLATION, name: CONST.VIOLATIONS.RTER, data: {rterType: CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION}}];
const showBrokenConnectionViolation = shouldShowBrokenConnectionViolation(transaction, report, policy, transactionViolations);

expect(showBrokenConnectionViolation).toBe(true);
});

it('should return false when a broken connection violation exists, the user is the policy admin but the expense report is in the approved state', () => {
const policy = {role: CONST.POLICY.ROLE.ADMIN} as Policy;
const report = approvedReport;
const transaction = generateTransaction();
const transactionViolations = [{type: CONST.VIOLATION_TYPES.VIOLATION, name: CONST.VIOLATIONS.RTER, data: {rterType: CONST.RTER_VIOLATION_TYPES.BROKEN_CARD_CONNECTION}}];
const showBrokenConnectionViolation = shouldShowBrokenConnectionViolation(transaction, report, policy, transactionViolations);

expect(showBrokenConnectionViolation).toBe(false);
});
});
});