-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
CHAL-30 #DONE Voter registration form (#30)
* added register route * added checkbox component and story * added voter registration form and pages * added phone input * fixed select menu page overflow issue * refined eligibility page * added tests for phone input * refined names form * cleaned up addresses form * added tests for ZipCodeValidator, PhoneValidator, and useRedirectToFirstIncompletePage. Cleaned up modal tests. * fixed overflow issue on addresses page due to select component input width * fixed typos, added error alert and loading wheel to other details page, forms focus on first nonvalid input when submitted while invalid * added persistent fields, rendered voter registration form pages on the the client * installed latest version of fully-formed and audited npm packages * added address confirmation components and stories * added hook to prefetch other details page when home state and zip change * implemented address confirmation modal * added address validation service * added types for google address validation, updated components and stories, added validateAddresses client util * fixed false positive returned by shouldCreateReviewRecommendedAddressError * replaced google maps skd with calls to http api as the sdk uses eval internally * added function to apply caution validity to address form fields * added warning icons to input elements * added hook to check if any form elements are invalid * improved aria * fixed broken tests, added test for validateAddressesWithGoogleMaps * added tests for validateAddressesWithGoogleMaps * added more tests * added tests for addresses page * added focus functionality back to select component, fixed missing act() warnings, added tests for usePrefetch * added more tests for the combobox element * tested warning icon display in select component * test coverage outside of register route back up to 100% * added tests for names form * added tests for eligibility * added test for VoterRegistrationForm * completed tests for src/app/register/eligibility * added tests for other details page * added tests for addresses utils * addeed tests for usePrefetchOtherDetailsWithStateAndZip * added tests for address forms * added tests for address forms * added tests for FormattedAddress * added final tests, formatted, linted * small UI updates * exported PhoneInputGroup from index.tsx * removed superfluous files * removed superfluous files * fixed type errors, linted, and formatted
- Loading branch information
Showing
264 changed files
with
13,468 additions
and
259 deletions.
There are no files selected for viewing
This file contains 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 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 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
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains 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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions
5
public/static/images/components/shared/warning-icon-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
271 changes: 271 additions & 0 deletions
271
src/__tests__/unit/app/api/validate-addresses/route.test.tsx
This file contains 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,271 @@ | ||
import { POST } from '@/app/api/validate-addresses/route'; | ||
import { serverContainer } from '@/services/server/container'; | ||
import { SERVER_SERVICE_KEYS } from '@/services/server/keys'; | ||
import { saveActualImplementation } from '@/utils/test/save-actual-implementation'; | ||
import { NextRequest } from 'next/server'; | ||
import { AddressErrorTypes } from '@/model/types/addresses/address-error-types'; | ||
import { ServerError } from '@/errors/server-error'; | ||
import type { ValidateAddresses } from '@/services/server/validate-addresses/validate-addresses'; | ||
import type { AddressErrors } from '@/model/types/addresses/address-errors'; | ||
|
||
describe('POST', () => { | ||
const getActualService = saveActualImplementation(serverContainer, 'get'); | ||
|
||
it(`returns a response with a result.errors property containing an empty array | ||
if all addresses were valid.`, async () => { | ||
const containerSpy = jest | ||
.spyOn(serverContainer, 'get') | ||
.mockImplementation(key => { | ||
if (key.name === SERVER_SERVICE_KEYS.validateAddresses.name) { | ||
const validateAddresses: ValidateAddresses = () => { | ||
return Promise.resolve([] as AddressErrors[]); | ||
}; | ||
|
||
return validateAddresses; | ||
} | ||
|
||
return getActualService(key); | ||
}); | ||
|
||
const request = new NextRequest( | ||
'https://challenge.8by8.us/api/validate-addresses', | ||
{ | ||
method: 'POST', | ||
body: JSON.stringify({ | ||
homeAddress: { | ||
streetLine1: '1600 Amphitheatre Pkwy', | ||
city: 'Mountain View', | ||
state: 'CA', | ||
zip: '94043', | ||
}, | ||
}), | ||
}, | ||
); | ||
|
||
const response = await POST(request); | ||
const body = await response.json(); | ||
expect(body).toEqual({ | ||
result: { | ||
errors: [], | ||
}, | ||
}); | ||
|
||
containerSpy.mockRestore(); | ||
}); | ||
|
||
it(`returns a response with a result.errors property containing errors if any | ||
were detected.`, async () => { | ||
const addresses = { | ||
homeAddress: { | ||
streetLine1: '2930 Pearl Street', | ||
streetLine2: 'Suite 100', | ||
city: 'Boulder', | ||
state: 'CO', | ||
zip: '80301', | ||
}, | ||
mailingAddress: { | ||
streetLine1: '1600 Amphitheatre Pkwy', | ||
city: 'Montan View', | ||
state: 'CA', | ||
zip: '94043', | ||
}, | ||
previousAddress: { | ||
streetLine1: '500 W 2nd St', | ||
city: 'Austin', | ||
state: 'TX', | ||
zip: '78701', | ||
}, | ||
}; | ||
|
||
const errors: AddressErrors[] = [ | ||
{ | ||
type: AddressErrorTypes.UnconfirmedComponents, | ||
form: 'homeAddress', | ||
unconfirmedAddressComponents: { | ||
streetLine1: { | ||
value: addresses.homeAddress.streetLine1, | ||
hasIssue: false, | ||
}, | ||
streetLine2: { | ||
value: addresses.homeAddress.streetLine2, | ||
hasIssue: true, | ||
}, | ||
city: { | ||
value: addresses.homeAddress.city, | ||
hasIssue: false, | ||
}, | ||
state: { | ||
value: addresses.homeAddress.state, | ||
hasIssue: false, | ||
}, | ||
zip: { | ||
value: addresses.homeAddress.zip, | ||
hasIssue: false, | ||
}, | ||
}, | ||
}, | ||
{ | ||
type: AddressErrorTypes.ReviewRecommendedAddress, | ||
form: 'mailingAddress', | ||
enteredAddress: { | ||
streetLine1: { | ||
value: addresses.mailingAddress.streetLine1, | ||
hasIssue: false, | ||
}, | ||
city: { | ||
value: addresses.mailingAddress.city, | ||
hasIssue: true, | ||
}, | ||
state: { | ||
value: addresses.mailingAddress.state, | ||
hasIssue: false, | ||
}, | ||
zip: { | ||
value: addresses.mailingAddress.zip, | ||
hasIssue: false, | ||
}, | ||
}, | ||
recommendedAddress: { | ||
streetLine1: { | ||
value: addresses.mailingAddress.streetLine1, | ||
hasIssue: false, | ||
}, | ||
city: { | ||
value: addresses.mailingAddress.city, | ||
hasIssue: true, | ||
}, | ||
state: { | ||
value: addresses.mailingAddress.state, | ||
hasIssue: false, | ||
}, | ||
zip: { | ||
value: addresses.mailingAddress.zip, | ||
hasIssue: false, | ||
}, | ||
}, | ||
}, | ||
{ | ||
type: AddressErrorTypes.MissingSubpremise, | ||
form: 'previousAddress', | ||
}, | ||
]; | ||
|
||
const containerSpy = jest | ||
.spyOn(serverContainer, 'get') | ||
.mockImplementation(key => { | ||
if (key.name === SERVER_SERVICE_KEYS.validateAddresses.name) { | ||
const validateAddresses: ValidateAddresses = () => { | ||
return Promise.resolve(errors); | ||
}; | ||
|
||
return validateAddresses; | ||
} | ||
|
||
return getActualService(key); | ||
}); | ||
|
||
const request = new NextRequest( | ||
'https://challenge.8by8.us/api/validate-addresses', | ||
{ | ||
method: 'POST', | ||
body: JSON.stringify(addresses), | ||
}, | ||
); | ||
|
||
const response = await POST(request); | ||
const body = await response.json(); | ||
expect(body).toEqual({ | ||
result: { | ||
errors, | ||
}, | ||
}); | ||
|
||
containerSpy.mockRestore(); | ||
}); | ||
|
||
it(`returns a response with a status of 400 if the data sent in the body | ||
could not be parsed.`, async () => { | ||
const request = new NextRequest( | ||
'https://challenge.8by8.us/api/validate-addresses', | ||
{ | ||
method: 'POST', | ||
body: JSON.stringify({}), | ||
}, | ||
); | ||
|
||
const response = await POST(request); | ||
expect(response.status).toBe(400); | ||
}); | ||
|
||
it('returns a response with a status matching that of a caught ServerError.', async () => { | ||
const containerSpy = jest | ||
.spyOn(serverContainer, 'get') | ||
.mockImplementation(key => { | ||
if (key.name === SERVER_SERVICE_KEYS.validateAddresses.name) { | ||
const validateAddresses: ValidateAddresses = () => { | ||
throw new ServerError('Too many requests.', 429); | ||
}; | ||
|
||
return validateAddresses; | ||
} | ||
|
||
return getActualService(key); | ||
}); | ||
|
||
const request = new NextRequest( | ||
'https://challenge.8by8.us/api/validate-addresses', | ||
{ | ||
method: 'POST', | ||
body: JSON.stringify({ | ||
homeAddress: { | ||
streetLine1: '1600 Amphitheatre Pkwy', | ||
city: 'Mountain View', | ||
state: 'CA', | ||
zip: '94043', | ||
}, | ||
}), | ||
}, | ||
); | ||
|
||
const response = await POST(request); | ||
expect(response.status).toBe(429); | ||
|
||
containerSpy.mockRestore(); | ||
}); | ||
|
||
it(`returns a response with a status of 500 when an unknown error is encountered.`, async () => { | ||
const containerSpy = jest | ||
.spyOn(serverContainer, 'get') | ||
.mockImplementation(key => { | ||
if (key.name === SERVER_SERVICE_KEYS.validateAddresses.name) { | ||
const validateAddresses: ValidateAddresses = () => { | ||
throw new Error(); | ||
}; | ||
|
||
return validateAddresses; | ||
} | ||
|
||
return getActualService(key); | ||
}); | ||
|
||
const request = new NextRequest( | ||
'https://challenge.8by8.us/api/validate-addresses', | ||
{ | ||
method: 'POST', | ||
body: JSON.stringify({ | ||
homeAddress: { | ||
streetLine1: '1600 Amphitheatre Pkwy', | ||
city: 'Mountain View', | ||
state: 'CA', | ||
zip: '94043', | ||
}, | ||
}), | ||
}, | ||
); | ||
|
||
const response = await POST(request); | ||
expect(response.status).toBe(500); | ||
|
||
containerSpy.mockRestore(); | ||
}); | ||
}); |
This file contains 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
Oops, something went wrong.