Skip to content

Commit 7cd1086

Browse files
authored
chore: add contractor address tests (#360)
1 parent 86027c6 commit 7cd1086

File tree

6 files changed

+294
-9
lines changed

6 files changed

+294
-9
lines changed
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
import { beforeEach, describe, expect, it, vi } from 'vitest'
2+
import { screen } from '@testing-library/react'
3+
import userEvent from '@testing-library/user-event'
4+
import { HttpResponse } from 'msw'
5+
import { Address } from './Address'
6+
import { server } from '@/test/mocks/server'
7+
import {
8+
handleGetContractor,
9+
handleGetContractorAddress,
10+
handleUpdateContractorAddress,
11+
} from '@/test/mocks/apis/contractor_address'
12+
import { setupApiTestMocks } from '@/test/mocks/apiServer'
13+
import { contractorEvents } from '@/shared/constants'
14+
import { renderWithProviders } from '@/test-utils/renderWithProviders'
15+
16+
describe('Contractor/Address', () => {
17+
beforeEach(() => {
18+
setupApiTestMocks()
19+
})
20+
21+
describe('when API has minimal address details', () => {
22+
const exampleUpdatedAddress = {
23+
version: 'contractor-address-version-updated',
24+
country: 'USA',
25+
street_1: '123 Main St',
26+
street_2: 'Apt 4B',
27+
city: 'Denver',
28+
state: 'CO',
29+
zip: '80202',
30+
}
31+
32+
beforeEach(() => {
33+
server.use(
34+
handleGetContractorAddress(() =>
35+
HttpResponse.json({
36+
version: 'contractor-address-version',
37+
street_1: null,
38+
street_2: null,
39+
city: null,
40+
state: null,
41+
zip: null,
42+
country: 'USA',
43+
}),
44+
),
45+
handleUpdateContractorAddress(() => HttpResponse.json(exampleUpdatedAddress)),
46+
)
47+
})
48+
49+
it('should allow submitting the form', async () => {
50+
const user = userEvent.setup()
51+
const mockOnEvent = vi.fn()
52+
53+
renderWithProviders(<Address contractorId="contractor_id" onEvent={mockOnEvent} />)
54+
55+
await screen.findByText('Home address')
56+
57+
await user.type(screen.getByLabelText('Street 1'), '123 Main St')
58+
await user.type(screen.getByLabelText(/Street 2/i), 'Apt 4B')
59+
await user.type(screen.getByLabelText('City'), 'Denver')
60+
61+
const stateControl = screen.getByRole('button', {
62+
name: /Select state.../i,
63+
expanded: false,
64+
})
65+
await user.click(stateControl)
66+
const coloradoOption = screen.getByRole('option', {
67+
name: /Colorado/i,
68+
})
69+
await user.click(coloradoOption)
70+
71+
await user.type(screen.getByLabelText('Zip'), '80202')
72+
73+
const continueButton = screen.getByRole('button', {
74+
name: /Continue/i,
75+
})
76+
await user.click(continueButton)
77+
78+
expect(mockOnEvent).toHaveBeenNthCalledWith(
79+
1,
80+
contractorEvents.CONTRACTOR_ADDRESS_UPDATED,
81+
expect.objectContaining({
82+
version: exampleUpdatedAddress.version,
83+
street1: exampleUpdatedAddress.street_1,
84+
street2: exampleUpdatedAddress.street_2,
85+
city: exampleUpdatedAddress.city,
86+
state: exampleUpdatedAddress.state,
87+
zip: exampleUpdatedAddress.zip,
88+
country: exampleUpdatedAddress.country,
89+
}),
90+
)
91+
92+
expect(mockOnEvent).toHaveBeenNthCalledWith(2, contractorEvents.CONTRACTOR_ADDRESS_DONE)
93+
})
94+
95+
it('should allow setting default values', async () => {
96+
renderWithProviders(
97+
<Address
98+
contractorId="contractor_id"
99+
onEvent={() => {}}
100+
defaultValues={{
101+
street1: '999 Default St',
102+
street2: 'Apt 123',
103+
city: 'Default City',
104+
state: 'CO',
105+
zip: '80202',
106+
}}
107+
/>,
108+
)
109+
110+
await screen.findByText('Home address')
111+
112+
expect(screen.getByLabelText('Street 1')).toHaveValue('999 Default St')
113+
expect(screen.getByLabelText(/Street 2/i)).toHaveValue('Apt 123')
114+
expect(screen.getByLabelText('City')).toHaveValue('Default City')
115+
expect(
116+
screen.getByRole('button', {
117+
name: /Colorado/i,
118+
expanded: false,
119+
}),
120+
).toBeInTheDocument()
121+
expect(screen.getByLabelText('Zip')).toHaveValue('80202')
122+
})
123+
})
124+
125+
describe('when API has full address details', () => {
126+
beforeEach(() => {
127+
server.use(
128+
handleGetContractorAddress(() =>
129+
HttpResponse.json({
130+
version: 'contractor-address-version',
131+
street_1: '999 Kiera Stravenue',
132+
street_2: 'Suite 541',
133+
city: 'San Francisco',
134+
state: 'CA',
135+
zip: '94107',
136+
country: 'USA',
137+
}),
138+
),
139+
)
140+
})
141+
142+
it('should defer to values from API over default values', async () => {
143+
renderWithProviders(
144+
<Address
145+
contractorId="contractor_id"
146+
onEvent={() => {}}
147+
defaultValues={{
148+
street1: '999 Default St',
149+
street2: 'Apt 123',
150+
city: 'Default City',
151+
state: 'CO',
152+
zip: '80202',
153+
}}
154+
/>,
155+
)
156+
157+
await screen.findByText('Home address')
158+
159+
expect(screen.getByLabelText('Street 1')).toHaveValue('999 Kiera Stravenue')
160+
expect(screen.getByLabelText(/Street 2/i)).toHaveValue('Suite 541')
161+
expect(screen.getByLabelText('City')).toHaveValue('San Francisco')
162+
expect(
163+
screen.getByRole('button', {
164+
name: /California/i,
165+
expanded: false,
166+
}),
167+
).toBeInTheDocument()
168+
expect(screen.getByLabelText('Zip')).toHaveValue('94107')
169+
})
170+
})
171+
172+
describe('contractor type in heading', () => {
173+
it('should show individual text when contractorType is Individual', async () => {
174+
renderWithProviders(<Address contractorId="contractor_id" onEvent={() => {}} />)
175+
176+
expect(await screen.findByText('Home address')).toBeInTheDocument()
177+
expect(
178+
screen.getByText("Contractor's home mailing address, within the United States."),
179+
).toBeInTheDocument()
180+
})
181+
182+
it('should show business text when contractorType is Business', async () => {
183+
server.use(
184+
handleGetContractor(() => {
185+
return HttpResponse.json({
186+
type: 'Business',
187+
uuid: 'contractor_id',
188+
is_active: true,
189+
file_new_hire_report: false,
190+
})
191+
}),
192+
)
193+
194+
renderWithProviders(<Address contractorId="contractor_id" onEvent={() => {}} />)
195+
196+
expect(await screen.findByText('Business address')).toBeInTheDocument()
197+
expect(
198+
screen.getByText("Contractor's business address, within the United States."),
199+
).toBeInTheDocument()
200+
})
201+
})
202+
})

src/components/Contractor/Address/Form.tsx

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ export function Form() {
1313
isRequired
1414
errorMessage={t('validations.street1')}
1515
/>
16-
<TextInputField name="street2" label={t('street2', 'Street 2')} />
16+
<TextInputField name="street2" label={t('street2')} />
1717
<TextInputField
1818
name="city"
19-
label={t('city', 'City')}
19+
label={t('city')}
2020
isRequired
2121
errorMessage={t('validations.city')}
2222
/>
@@ -26,17 +26,12 @@ export function Form() {
2626
label: t(`statesHash.${stateAbbr}`, { ns: 'common', defaultValue: stateAbbr }),
2727
value: stateAbbr,
2828
}))}
29-
label={t('state', 'State')}
29+
label={t('state')}
3030
placeholder={t('statePlaceholder')}
3131
errorMessage={t('validations.state')}
3232
isRequired
3333
/>
34-
<TextInputField
35-
name="zip"
36-
label={t('zip', 'Zip')}
37-
isRequired
38-
errorMessage={t('validations.zip')}
39-
/>
34+
<TextInputField name="zip" label={t('zip')} isRequired errorMessage={t('validations.zip')} />
4035
</Grid>
4136
)
4237
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import type { HttpResponseResolver, PathParams } from 'msw'
2+
import { http, HttpResponse } from 'msw'
3+
import type { GetV1ContractorsContractorUuidRequest } from '@gusto/embedded-api/models/operations/getv1contractorscontractoruuid'
4+
import type { GetV1ContractorsContractorUuidAddressRequest } from '@gusto/embedded-api/models/operations/getv1contractorscontractoruuidaddress'
5+
import type { PutV1ContractorsContractorUuidAddressRequestBody } from '@gusto/embedded-api/models/operations/putv1contractorscontractoruuidaddress'
6+
import type { Contractor$Outbound } from '@gusto/embedded-api/models/components/contractor'
7+
import type { ContractorAddress$Outbound } from '@gusto/embedded-api/models/components/contractoraddress'
8+
import { getFixture } from '../fixtures/getFixture'
9+
import { API_BASE_URL } from '@/test/constants'
10+
11+
export function handleGetContractor(
12+
resolver: HttpResponseResolver<
13+
PathParams,
14+
GetV1ContractorsContractorUuidRequest,
15+
Contractor$Outbound
16+
>,
17+
) {
18+
return http.get(`${API_BASE_URL}/v1/contractors/:contractorUuid`, resolver)
19+
}
20+
21+
export const getContractor = handleGetContractor(async () => {
22+
const responseFixture = await getFixture('get-v1-contractors-contractor_id')
23+
return HttpResponse.json(responseFixture)
24+
})
25+
26+
export function handleGetContractorAddress(
27+
resolver: HttpResponseResolver<
28+
PathParams,
29+
GetV1ContractorsContractorUuidAddressRequest,
30+
ContractorAddress$Outbound
31+
>,
32+
) {
33+
return http.get(`${API_BASE_URL}/v1/contractors/:contractorUuid/address`, resolver)
34+
}
35+
36+
export const getContractorAddress = handleGetContractorAddress(async () => {
37+
const responseFixture = await getFixture('get-v1-contractors-contractor_id-address')
38+
return HttpResponse.json(responseFixture)
39+
})
40+
41+
export function handleUpdateContractorAddress(
42+
resolver: HttpResponseResolver<
43+
PathParams,
44+
PutV1ContractorsContractorUuidAddressRequestBody,
45+
ContractorAddress$Outbound
46+
>,
47+
) {
48+
return http.put(`${API_BASE_URL}/v1/contractors/:contractorUuid/address`, resolver)
49+
}
50+
51+
export const updateContractorAddress = handleUpdateContractorAddress(async ({ request }) => {
52+
const requestBody = await request.json()
53+
const responseFixture = await getFixture('put-v1-contractors-contractor_id-address')
54+
return HttpResponse.json({
55+
...responseFixture,
56+
...requestBody,
57+
})
58+
})
59+
60+
export default [getContractor, getContractorAddress, updateContractorAddress]
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"contractorAddress": {
3+
"version": "233230906da15e32d9785fadf1d388d",
4+
"contractor_uuid": "97f9767c-6044-48e0-8f68-ae6378bf",
5+
"street_1": "999 Kiera Stravenue",
6+
"street_2": "Suite 541",
7+
"city": "San Francisco",
8+
"state": "CA",
9+
"zip": "94107",
10+
"country": "USA",
11+
"active": true
12+
}
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"contractorAddress": {
3+
"version": "233230906da15e2d9785fadf1d388d-updated",
4+
"contractor_uuid": "97f9767c-6044-48e0-8f68-ae6378bf",
5+
"street_1": "999 Kiera Stravenue",
6+
"street_2": "Suite 541",
7+
"city": "San Francisco",
8+
"state": "CA",
9+
"zip": "94107",
10+
"country": "USA",
11+
"active": true
12+
}
13+
}

src/test/mocks/handlers.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import PayScheduleHandlers from './apis/payschedule'
1313
import CompanyStateTaxesHandlers from './apis/company_state_taxes'
1414
import ContractorPaymentMethodHandlers from './apis/contractor_payment_method'
1515
import ContractorNewHireReportHandlers from './apis/contractor_new_hire_report'
16+
import contractorAddressHandlers from './apis/contractor_address'
1617

1718
export const handlers = [
1819
...EmployeeHandlers,
@@ -30,4 +31,5 @@ export const handlers = [
3031
...CompanyStateTaxesHandlers,
3132
...ContractorPaymentMethodHandlers,
3233
...ContractorNewHireReportHandlers,
34+
...contractorAddressHandlers,
3335
]

0 commit comments

Comments
 (0)