Skip to content
Merged
Show file tree
Hide file tree
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
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,14 @@ describe('Deduction', () => {
});

// 12% of $10,000 = $1,200
// 8% of $10,000 = $800
// 8% of ($10,000 - $1,200) = 8% of $8,800 = $704
await waitFor(() => {
expect(
getByLabelText('Calculated traditional deduction amount'),
).toHaveTextContent('$1,200.00');
expect(
getByLabelText('Calculated roth deduction amount'),
).toHaveTextContent('$800.00');
).toHaveTextContent('$704.00');
});
});

Expand Down Expand Up @@ -213,21 +213,22 @@ describe('Deduction', () => {
// Wait for GraphQL data to load
await findByText(/12%/);

// 12% of ($10,000 + $3,000 + $2,000) = $1,800
// 8% of ($10,000 + $3,000 + $2,000) = $1,200
// 403b contributions excluded from base: totalWithout403b = $10,000
// 12% of $10,000 = $1,200
// 8% of ($10,000 - $1,200) = 8% of $8,800 = $704
await waitFor(() => {
expect(
getByLabelText('Calculated traditional deduction amount'),
).toHaveTextContent('$1,800.00');
).toHaveTextContent('$1,200.00');
expect(
getByLabelText('Calculated roth deduction amount'),
).toHaveTextContent('$1,200.00');
).toHaveTextContent('$704.00');
});

// Total should be $3,000 + ($3,000 + $2,000) = $8,000
// Total should be ($1,200 + $704) + ($3,000 + $2,000) = $6,904
await waitFor(() => {
expect(getByLabelText('Total requested amount')).toHaveTextContent(
'$8,000.00',
'$6,904.00',
);
});
});
Expand All @@ -254,14 +255,14 @@ describe('Deduction', () => {
await findByText(/12%/);

// 12% of ($5,000 + $2,000 + $3,000) = 12% of $10,000 = $1,200
// 8% of ($5,000 + $2,000 + $3,000) = 8% of $10,000 = $800
// 8% of ($10,000 - $1,200) = 8% of $8,800 = $704
await waitFor(() => {
expect(
getByLabelText('Calculated traditional deduction amount'),
).toHaveTextContent('$1,200.00');
expect(
getByLabelText('Calculated roth deduction amount'),
).toHaveTextContent('$800.00');
).toHaveTextContent('$704.00');
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,10 @@ describe('NetAdditionalSalary', () => {
/>,
);

// Net = $10,000 - (12% of $10,000 + 8% of $10,000) = $10,000 - $1,200 - $800 = $8,000
expect(await findByText('$8,000')).toBeInTheDocument();
// Traditional = 12% of $10,000 = $1,200
// Roth = 8% of ($10,000 - $1,200) = 8% of $8,800 = $704
// Net = $10,000 - $1,200 - $704 = $8,096
expect(await findByText('$8,096')).toBeInTheDocument();
});

it('calculates net salary with both percentage and traditional403b deductions', async () => {
Expand All @@ -139,10 +141,12 @@ describe('NetAdditionalSalary', () => {
);

// Total = $10,000 + $1,000 + $100 = $11,100
// Calculated deduction = 12% of $11,100 + 8% of $11,100 = $1,332 + $888 = $2,220
// Total deduction = $2,220 + $1,000 + $100 = $3,320
// Net = $11,100 - $3,320 = $7,780
expect(await findByText('$7,780')).toBeInTheDocument();
// totalWithout403b = $10,000
// Traditional = 12% of $10,000 = $1,200
// Roth = 8% of ($10,000 - $1,200) = 8% of $8,800 = $704
// Total deduction = ($1,200 + $704) + ($1,000 + $100) = $3,004
// Net = $11,100 - $3,004 = $8,096
expect(await findByText('$8,096')).toBeInTheDocument();
});

it('includes all salary fields in the total calculation', async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defaultCompleteFormValues } from '../CompleteForm.mock';
import { getTotal } from './getTotal';
import { getTotal, getTotalWithout403b } from './getTotal';

describe('getTotal', () => {
it('returns correct number', () => {
Expand All @@ -12,3 +12,31 @@ describe('getTotal', () => {
).toBe(20123);
});
});

describe('getTotalWithout403b', () => {
it('excludes 403b contributions from total', () => {
expect(
getTotalWithout403b({
...defaultCompleteFormValues,
autoPurchase: '20000',
movingExpense: '123',
traditional403bContribution: '5000',
roth403bContribution: '3000',
}),
).toBe(20123);
});

it('returns same result as getTotal when 403b contributions are zero', () => {
const values = {
...defaultCompleteFormValues,
currentYearSalaryNotReceived: '1000',
adoption: '500',
};

expect(getTotalWithout403b(values)).toBe(getTotal(values));
});

it('returns zero when all fields are zero', () => {
expect(getTotalWithout403b(defaultCompleteFormValues)).toBe(0);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,14 @@ export const getTotal = (values: TotalableValues): number => {
return sum + Number(values[key] || 0);
}, 0);
};

const fieldsWithout403b = numericFields.filter(
(field) =>
field !== 'traditional403bContribution' && field !== 'roth403bContribution',
);

export const getTotalWithout403b = (values: TotalableValues): number => {
return fieldsWithout403b.reduce((sum, key) => {
return sum + Number(values[key] || 0);
}, 0);
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { createElement } from 'react';

Check notice on line 1 in src/components/Reports/AdditionalSalaryRequest/Shared/useSalaryCalculations.test.ts

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

✅ Getting better: Code Duplication

reduced similar code in: 'calculates all salary values correctly with default percentage enabled'. Avoid duplicated, aka copy-pasted, code inside the module. More duplication lowers the code health.
import { renderHook } from '@testing-library/react';
import { Formik } from 'formik';
import { CompleteFormValues } from '../AdditionalSalaryRequest';
Expand Down Expand Up @@ -76,11 +76,13 @@
});

expect(result.current.total).toBe(11100); // 5000 + 3000 + 2000 + 1000 + 100
expect(result.current.calculatedTraditionalDeduction).toBe(1332); // 11100 * 0.12
expect(result.current.calculatedRothDeduction).toBe(1110); // 11100 * 0.10
// Deductions are based on totalWithout403b (10000 = 5000 + 3000 + 2000)
expect(result.current.calculatedTraditionalDeduction).toBe(1200); // 10000 * 0.12
// Roth is based on totalWithout403b minus traditional deduction: (10000 - 1200) * 0.10
expect(result.current.calculatedRothDeduction).toBe(880); // 8800 * 0.10
expect(result.current.contribution403b).toBe(1100);
expect(result.current.totalDeduction).toBe(3542); // (1332 + 1110) + 1100
expect(result.current.netSalary).toBe(7558); // 11100 - 3542
expect(result.current.totalDeduction).toBe(3180); // (1200 + 880) + 1100
expect(result.current.netSalary).toBe(7920); // 11100 - 3180
expect(result.current.totalAnnualSalary).toBe(11100); // No calculations data, so just total
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useMemo } from 'react';
import { CompleteFormValues } from '../AdditionalSalaryRequest';
import { useAdditionalSalaryRequest } from './AdditionalSalaryRequestContext';
import { getTotal } from './Helper/getTotal';
import { getTotal, getTotalWithout403b } from './Helper/getTotal';

export interface SalaryCalculations {
total: number;
Expand Down Expand Up @@ -59,12 +59,14 @@ export const useSalaryCalculations = ({
return useMemo(() => {
const total = getTotal(values);

const totalWithout403b = getTotalWithout403b(values);

const calculatedTraditionalDeduction = values.deductTaxDeferredPercent
? total * traditional403bPercentage
? totalWithout403b * traditional403bPercentage
: 0;

const calculatedRothDeduction = values.deductRothPercent
? total * roth403bPercentage
? (totalWithout403b - calculatedTraditionalDeduction) * roth403bPercentage
: 0;

const calculatedDeduction =
Expand Down
Loading