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
62 changes: 62 additions & 0 deletions assets/js/form_helper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
export const UsStatesTerritories: [string, string][] = [
Comment thread
gina-yamada marked this conversation as resolved.
['Alabama', 'AL'],
['Alaska', 'AK'],
['American Samoa', 'AS'],
['Arizona', 'AZ'],
['Arkansas', 'AR'],
['Armed Forces Americas', 'AA'],
['Armed Forces Others', 'AE'],
['Armed Forces Pacific', 'AP'],
['California', 'CA'],
['Colorado', 'CO'],
['Connecticut', 'CT'],
['Delaware', 'DE'],
['District of Columbia', 'DC'],
['Florida', 'FL'],
['Georgia', 'GA'],
['Guam', 'GU'],
['Hawaii', 'HI'],
['Idaho', 'ID'],
['Illinois', 'IL'],
['Indiana', 'IN'],
['Iowa', 'IA'],
['Kansas', 'KS'],
['Kentucky', 'KY'],
['Louisiana', 'LA'],
['Maine', 'ME'],
['Maryland', 'MD'],
['Massachusetts', 'MA'],
['Michigan', 'MI'],
['Minnesota', 'MN'],
['Mississippi', 'MS'],
['Missouri', 'MO'],
['Montana', 'MT'],
['Nebraska', 'NE'],
['Nevada', 'NV'],
['New Hampshire', 'NH'],
['New Jersey', 'NJ'],
['New Mexico', 'NM'],
['New York', 'NY'],
['North Carolina', 'NC'],
['North Dakota', 'ND'],
['Northern Mariana Islands', 'MP'],
['Ohio', 'OH'],
['Oklahoma', 'OK'],
['Oregon', 'OR'],
['Pennsylvania', 'PA'],
['Puerto Rico', 'PR'],
['Rhode Island', 'RI'],
['South Carolina', 'SC'],
['South Dakota', 'SD'],
['Tennessee', 'TN'],
['Texas', 'TX'],
['United States Minor Outlying Islands', 'UM'],
['Utah', 'UT'],
['Vermont', 'VT'],
['Virgin Islands', 'VI'],
['Virginia', 'VA'],
['Washington', 'WA'],
['West Virginia', 'WV'],
['Wisconsin', 'WI'],
['Wyoming', 'WY'],
];
16 changes: 10 additions & 6 deletions assets/js/post_office_search.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
import { createRoot } from 'react-dom/client';
// @ts-ignore
import AddressSearch from '@18f/identity-address-search';

import { FullAddressSearch } from '@18f/identity-address-search';
// @ts-ignore
import { Alert } from '@18f/identity-components';

// @ts-ignore
import { t } from '@18f/identity-i18n';
import NoInPersonLocationsDisplay from './no_in_person_locations_display';
import { UsStatesTerritories } from './form_helper';

const elem = document.getElementById('post-office-search')!;
const root = createRoot(elem);
const { addressSearchUrl, locationsSearchUrl } = elem.dataset;
const { locationsSearchUrl } = elem.dataset;

root.render(
<AddressSearch
addressSearchURL={addressSearchUrl}
<FullAddressSearch
disabled={false}
handleLocationSelect={null}
locationsURL={locationsSearchUrl}
noInPersonLocationsDisplay={NoInPersonLocationsDisplay}
onFoundLocations={() => {}}
registerField={() => {}}
resultsHeaderComponent={() => (
<Alert type="info" className="margin-bottom-4">
<strong>
Expand All @@ -29,5 +32,6 @@ root.render(
</a>
</Alert>
)}
usStatesTerritories={UsStatesTerritories}
/>,
);
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@
"vnu-jar": "^21.10.12"
},
"dependencies": {
"@18f/identity-address-search": "^3.0.0",
"@18f/identity-address-search": "^3.1.1",
"@18f/identity-build-sass": "^1.3.0",
"@18f/identity-components": "^2.0.0",
"@18f/identity-design-system": "^7.1.0",
"@18f/identity-i18n": "^1.0.1",
"@18f/identity-components": "^2.0.0",
"@babel/core": "^7.12.9",
"@babel/preset-env": "^7.12.7",
"@babel/preset-react": "^7.22.5",
Expand Down
89 changes: 64 additions & 25 deletions spec/js/post_office_search_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @jest-environment jsdom
*/

import { getByLabelText, getByRole, waitFor } from '@testing-library/dom';
import { getByLabelText, getByRole, waitFor, getAllByText } from '@testing-library/dom';
import '@testing-library/jest-dom';
import { act } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
Expand All @@ -11,7 +11,6 @@ import { setImmediate } from 'timers/promises';
describe('Post Office Search', () => {
// This is simulated since the test env doesn't support fetch
const testServerPort = 9835;
const addressSearchUrl = `http://127.0.0.1:${testServerPort}/api/address_search`;
const locationsSearchUrl = `http://127.0.0.1:${testServerPort}/api/usps_locations`;

beforeEach(() => {
Expand All @@ -34,12 +33,12 @@ describe('Post Office Search', () => {

let container: HTMLDivElement;
let user: ReturnType<typeof userEvent['setup']>;

beforeEach(async () => {
user = userEvent.setup();
await act(async () => {
container = document.createElement('div');
container.id = 'post-office-search';
container.dataset.addressSearchUrl = addressSearchUrl;
container.dataset.locationsSearchUrl = locationsSearchUrl;
document.body.appendChild(container);
jest.isolateModules(() => {
Expand All @@ -60,52 +59,84 @@ describe('Post Office Search', () => {
}
});

const getField = function () {
return getByLabelText(
document.body,
'in_person_proofing.body.location.po_search.address_search_label',
);
const getField = function (labelName: string) {
return getByLabelText(document.body, `in_person_proofing.body.location.po_search.${labelName}`);
};

const getButton = function () {
const getSearchButton = function () {
return getByRole(container, 'button', {
name: 'in_person_proofing.body.location.po_search.search_button',
});
};

it('renders a post office search component', () => {
const field = getField();
expect(field).toBeEnabled();
expect(field).toBeVisible();
const testData = {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit but does this ever change? seems like a constant. const TEST_DATA or const SAMPLE_ADDRESS

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want this data to change so used const. If we need more data, we can create another const and/or nest it in different blocks. I preferred having one object with keys rather than having 4 different variables for each key. I went with lowerCamelCase to be consistent with the file.

address: '1600 W Pennsylvania Ave',
city: 'Washington',
state: 'DC',
zipcode: '20500',
};

function getFormElements() {
const addressField = getField('address_label');
const cityField = getField('city_label');
const stateField = getField('state_label');
const zipcodeField = getField('zipcode_label');
const searchButton = getSearchButton();
return { addressField, cityField, stateField, zipcodeField, searchButton };
}

it('renders post office search form fields that are enabled', () => {
const { addressField, cityField, stateField, zipcodeField, searchButton } = getFormElements();

expect(addressField).toBeEnabled();
expect(cityField).toBeEnabled();
expect(stateField).toBeEnabled();
expect(zipcodeField).toBeEnabled();

expect(addressField).toBeVisible();
expect(cityField).toBeVisible();
expect(stateField).toBeVisible();
expect(zipcodeField).toBeVisible();
expect(searchButton).toBeVisible();
});

describe('when searching', () => {
const testAddress = '1600 W Pennsylvania Ave, Washington, DC 20500';

it('allows search field input', async () => {
const field = getField();
const { addressField, cityField, stateField, zipcodeField } = getFormElements();

await act(async () => {
await user.clear(field);
await user.type(field, testAddress);
await user.clear(addressField);
await user.clear(cityField);
await user.clear(zipcodeField);

await user.type(addressField, testData.address);
await user.type(cityField, testData.city);
await user.selectOptions(stateField, testData.state);
await user.type(zipcodeField, testData.zipcode);
});

await waitFor(() => {
expect(field).toHaveValue(testAddress);
expect(addressField).toHaveValue(testData.address);
expect(cityField).toHaveValue(testData.city);
expect(stateField).toHaveValue(testData.state);
expect(zipcodeField).toHaveValue(testData.zipcode);
});
});

describe('submitting', () => {
describe('invalid input', () => {
beforeEach(async () => {
const button = getButton();
const button = getSearchButton();
await act(async () => {
await user.click(button);
});
});

it('shows an error', () => {
const errorMessage = 'in_person_proofing.body.location.inline_error';
const errorMessage = 'simple_form.required.text';
const requiredErrorMessages = getAllByText(document.body, 'simple_form.required.text');
expect(container).toHaveTextContent(errorMessage);
expect(requiredErrorMessages).toHaveLength(4);
});

it('does not result in any fetch requests', () => {
Expand All @@ -115,11 +146,19 @@ describe('Post Office Search', () => {

describe('valid input with no results', () => {
beforeEach(async () => {
const field = getField();
const button = getButton();
const { addressField, cityField, stateField, zipcodeField } = getFormElements();

const button = getSearchButton();
await act(async () => {
await user.clear(field);
await user.type(field, testAddress);
await user.clear(addressField);
await user.clear(cityField);
await user.clear(zipcodeField);

await user.type(addressField, testData.address);
await user.type(cityField, testData.city);
await user.selectOptions(stateField, testData.state);
await user.type(zipcodeField, testData.zipcode);

await user.click(button);
});
});
Expand Down