-
Notifications
You must be signed in to change notification settings - Fork 1
MPDX-9544 Frontend - Add validation to ensure the Requested Gross Salary for SOSA staff doesn't exceed their cap #1770
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
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
fd32b1d
Export OverCapPerson interface and include overUserCap in useCaps ret…
zweatshirt 0ed8b0f
Add useSosaBlockOverCap hook and corresponding tests
zweatshirt cce257b
Refactor AutosaveTextField to include external error handling and sav…
zweatshirt 98170b4
Add SOSA over-cap alert and autosave handling in RequestedSalaryCard
zweatshirt File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,8 @@ | ||
| import React from 'react'; | ||
| import { render, waitFor } from '@testing-library/react'; | ||
| import { DeepPartial } from 'ts-essentials'; | ||
| import { UserPersonTypeEnum } from 'pages/api/graphql-rest.page.generated'; | ||
| import { AutosaveForm } from 'src/components/Shared/Autosave/AutosaveForm'; | ||
| import { SalaryCalculationQuery } from '../../SalaryCalculatorContext/SalaryCalculation.generated'; | ||
| import { | ||
| SalaryCalculatorTestWrapper, | ||
|
|
@@ -33,7 +35,9 @@ const TestComponent: React.FC<SalaryCalculatorTestWrapperProps> = (props) => ( | |
| }} | ||
| {...props} | ||
| > | ||
| <RequestedSalaryCard /> | ||
| <AutosaveForm> | ||
| <RequestedSalaryCard /> | ||
| </AutosaveForm> | ||
| </SalaryCalculatorTestWrapper> | ||
| ); | ||
|
|
||
|
|
@@ -164,4 +168,56 @@ As you set your salary level, the amount you receive should reflect the amount o | |
| ); | ||
| }); | ||
| }); | ||
|
|
||
| describe('SOSA over-cap Alert', () => { | ||
| const sosaUser = { | ||
| staffInfo: { | ||
| userPersonType: UserPersonTypeEnum.EmployeeStaffNonRmoSpouse, | ||
| }, | ||
| }; | ||
| const overCapMock: DeepPartial<SalaryCalculationQuery['salaryRequest']> = { | ||
| calculations: { | ||
| minimumRequiredSalary: 10002, | ||
| minimumRequestedSalary: 10003, | ||
| effectiveCap: 10004, | ||
| requestedGross: 15000, | ||
| }, | ||
| }; | ||
|
|
||
| it('renders when the SOSA user is over their effective cap', async () => { | ||
| const { findByRole } = render( | ||
| <TestComponent | ||
| hasSpouse={false} | ||
| hcmUser={{ ...sosaUser, currentSalary: { grossSalaryAmount: 10001 } }} | ||
| salaryRequestMock={overCapMock} | ||
| />, | ||
| ); | ||
|
|
||
| expect(await findByRole('alert')).toHaveTextContent( | ||
| 'Your request requires additional approvals and cannot be submitted online. SOSA staff can have requests exceeding the $10,004.00 cap approved for certain geographic locations with the appropriate levels of approval.Please contact payroll@cru.org for further assistance.', | ||
| ); | ||
| expect( | ||
| await findByRole('link', { name: 'payroll@cru.org' }), | ||
| ).toHaveAttribute('href', 'mailto:payroll@cru.org'); | ||
| }); | ||
|
|
||
| it('does not render when the user is SOSA but under their cap', async () => { | ||
| const { queryByRole } = render( | ||
| <TestComponent | ||
| hasSpouse={false} | ||
| hcmUser={{ ...sosaUser, currentSalary: { grossSalaryAmount: 10001 } }} | ||
| />, | ||
| ); | ||
|
|
||
| await waitFor(() => expect(queryByRole('alert')).not.toBeInTheDocument()); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
[Suggestion] **Negative-Alert tests assert absence without anchoring to a positive render first.** The `waitFor(() => expect(queryByRole('alert')).not.toBeInTheDocument())` will pass on the first tick before the salary-calculation query resolves. A regression that delays the Alert past the initial render would slip through. Awaiting some other rendered element (e.g., a rowheader cell) before the absence assertion would catch that.
Flagged by Standards. |
||
| }); | ||
|
|
||
| it('does not render when the user is not SOSA, even if over cap', async () => { | ||
| const { queryByRole } = render( | ||
| <TestComponent hasSpouse={false} salaryRequestMock={overCapMock} />, | ||
| ); | ||
|
|
||
| await waitFor(() => expect(queryByRole('alert')).not.toBeInTheDocument()); | ||
| }); | ||
| }); | ||
| }); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 74 additions & 0 deletions
74
src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.test.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| import React from 'react'; | ||
| import { renderHook, waitFor } from '@testing-library/react'; | ||
| import { DeepPartial } from 'ts-essentials'; | ||
| import { UserPersonTypeEnum } from 'pages/api/graphql-rest.page.generated'; | ||
| import { SalaryCalculationQuery } from '../SalaryCalculatorContext/SalaryCalculation.generated'; | ||
| import { SalaryCalculatorTestWrapper } from '../SalaryCalculatorTestWrapper'; | ||
| import { useSosaBlockOverCap } from './useSosaBlockOverCap'; | ||
|
|
||
| const sosaUser = { | ||
| staffInfo: { userPersonType: UserPersonTypeEnum.EmployeeStaffNonRmoSpouse }, | ||
| }; | ||
|
|
||
| const overCapMock: DeepPartial<SalaryCalculationQuery['salaryRequest']> = { | ||
| calculations: { effectiveCap: 10004, requestedGross: 15000 }, | ||
| }; | ||
|
|
||
| const renderUseSosaBlockOverCap = ( | ||
| props: Parameters<typeof SalaryCalculatorTestWrapper>[0], | ||
| ) => | ||
| renderHook(() => useSosaBlockOverCap(), { | ||
| wrapper: ({ children }) => ( | ||
| <SalaryCalculatorTestWrapper {...props}> | ||
| {children} | ||
| </SalaryCalculatorTestWrapper> | ||
| ), | ||
| }); | ||
|
|
||
| describe('useSosaBlockOverCap', () => { | ||
| it('blocks when a SOSA user is over their cap', async () => { | ||
| const { result } = renderUseSosaBlockOverCap({ | ||
| hasSpouse: false, | ||
| hcmUser: sosaUser, | ||
| salaryRequestMock: overCapMock, | ||
| }); | ||
|
|
||
| await waitFor(() => expect(result.current.blockOnCap).toBe(true)); | ||
| }); | ||
|
|
||
| it('does not block when a SOSA user is under their cap', async () => { | ||
| const { result } = renderUseSosaBlockOverCap({ | ||
| hasSpouse: false, | ||
| hcmUser: sosaUser, | ||
| salaryRequestMock: { | ||
| calculations: { effectiveCap: 10004, requestedGross: 10003 }, | ||
| }, | ||
| }); | ||
|
|
||
| await waitFor(() => expect(result.current.isUserSosa).toBe(true)); | ||
| expect(result.current.blockOnCap).toBe(false); | ||
| }); | ||
|
|
||
| it('does not block when a SOSA user is exactly at their cap', async () => { | ||
| const { result } = renderUseSosaBlockOverCap({ | ||
| hasSpouse: false, | ||
| hcmUser: sosaUser, | ||
| salaryRequestMock: { | ||
| calculations: { effectiveCap: 10004, requestedGross: 10004 }, | ||
| }, | ||
| }); | ||
|
|
||
| await waitFor(() => expect(result.current.isUserSosa).toBe(true)); | ||
| expect(result.current.blockOnCap).toBe(false); | ||
| }); | ||
|
|
||
| it('does not block when the user is not SOSA, even if over cap', async () => { | ||
| const { result } = renderUseSosaBlockOverCap({ | ||
| hasSpouse: false, | ||
| salaryRequestMock: overCapMock, | ||
| }); | ||
|
|
||
| await waitFor(() => expect(result.current.isUserSosa).toBe(false)); | ||
| expect(result.current.blockOnCap).toBe(false); | ||
| }); | ||
| }); |
27 changes: 27 additions & 0 deletions
27
src/components/HrTools/SalaryCalculator/SalaryCalculation/useSosaBlockOverCap.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| import { UserPersonTypeEnum } from 'pages/api/graphql-rest.page.generated'; | ||
| import { useSalaryCalculator } from '../SalaryCalculatorContext/SalaryCalculatorContext'; | ||
| import { useCaps } from './useCaps'; | ||
|
|
||
| interface UseSosaBlockOverCapResult { | ||
| /** Whether the user is a SOSA employee (Employee Staff Non-RMO Spouse) */ | ||
| isUserSosa: boolean; | ||
|
|
||
| /** Whether the user is a SOSA employee whose saved gross exceeds their effective cap */ | ||
| blockOnCap: boolean; | ||
| } | ||
|
|
||
| /** | ||
| * Determine whether a SOSA user's requested gross salary exceeds their | ||
| * effective cap. Requests over their cap may not be submitted online. | ||
| */ | ||
| export const useSosaBlockOverCap = (): UseSosaBlockOverCapResult => { | ||
| const { hcmUser } = useSalaryCalculator(); | ||
| const { overUserCap } = useCaps(); | ||
|
|
||
| const isUserSosa = | ||
| hcmUser?.staffInfo.userPersonType === | ||
| UserPersonTypeEnum.EmployeeStaffNonRmoSpouse; | ||
| const blockOnCap = isUserSosa && overUserCap; | ||
|
|
||
| return { isUserSosa, blockOnCap }; | ||
| }; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.