Skip to content

Commit

Permalink
Merge pull request #1965 from usdoj/develop
Browse files Browse the repository at this point in the history
Latest from develop
  • Loading branch information
ameshkin authored Jul 9, 2024
2 parents 32839ed + bab8f73 commit 99fe639
Show file tree
Hide file tree
Showing 49 changed files with 1,613 additions and 341 deletions.
19 changes: 19 additions & 0 deletions features/AgencySearch.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@agencysearch
Feature: Agency Search

As site visitor
I need to be able to search for an agency
So that I can find a particular agency

Background:
Given I am on "/agency-search.html"
And I wait 60 seconds

Scenario: The agency type-ahead works
Then I should see "Search an agency name or keyword"
And I enter "ENV" into the agency search box
And I wait 1 second
Then I should see "Council on Environmental Quality"
And I hard click on "the first agency suggestion"
And I wait 5 seconds
Then I should see "The Council on Environmental Quality oversees NEPA implementation"
18 changes: 18 additions & 0 deletions features/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# End-to-end Tests

## About the testing framework
- The framework used for e2e tests in this project is Cucumber-mink: https://cucumber-mink.js.org/.
- Additional reference: https://cucumber.io/docs/cucumber/api/?lang=javascript

## Running tests locally
When running the `.feature` tests locally, the API must be made available to the front end:
1. In one terminal window/tab, start the foia-api (`ddev start` or equivalent)
2. In another tab, start the foia.gov front-end in development mode: (`make serve.dev` or `npm run serve:dev`)
3. In another tab, launch the tests:
- To run all `.feature` tests, run `npx cucumber-js`
- To run specific `.feature` tests, run `npx cucumber-js features/AgencySearch.feature features/Wizard.feature` etc.
- The `--fail-fast` flag can be appended to make the test suite exit at any failure rather than attempting to complete the entire batch.

### Additional Notes
- When debugging tests, the browser automation can be switched to non-headless mode by adding `headless: false`, to the Mink config in `features/support/mink.js`.
- The entire test suite may take ~10 min to complete.
60 changes: 60 additions & 0 deletions features/Wizard.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
@wizard
Feature: wizard

As a site visitor
I need to use the wizard
So that I can be guided to the appropriate agency or information

Background:
Given I am on "/wizard.html"
And I wait 60 seconds

Scenario: The Wizard loads successfully
Then I should see "Hello,"
And I should see "The government hosts a vast amount of information,"
And I hard click on "the wizard primary button"
And I wait 1 second
Then I should see "Let's dive in..."

Scenario: The tax records journey can be navigated
Then I hard click on "the wizard primary button"
Then I wait 5 second
Then the "the wizard primary button" element should not exist
Then I hard click on "the Tax records topic button"
Then the "the wizard primary button" element should exist
Then I hard click on "the wizard primary button"
And I wait 5 seconds
Then I should see "Are you seeking your own records?"
And I select the radio option for the answer "Yes"
And I hard click on "the wizard primary button"
And I wait 1 second
Then I should see "Okay, you’re looking for:"
And I should see "Your own tax records"
And I hard click on "the wizard primary button"
And I wait 1 second
Then I select the radio option for the answer "Copy or transcript of tax return"
And I hard click on "the wizard primary button"
And I wait 1 second
Then I should see "Visit the Internal Revenue Service (IRS) website"
And I should see 1 "external link card" element
And I should see "Were these results helpful?"
Then I select the radio option for the answer "Yes"
And I hard click on "the wizard primary button"
Then I select the radio option for the answer "Yes, I would like to do another search."
And I hard click on "the wizard primary button"
And I wait 1 second

Scenario: A user query can be submitted and results are returned
Then I hard click on "the wizard primary button"
Then I wait 1 second
Then the "wizard primary button" element should not exist
Then I enter "John Lewis Voting Rights Act" into the wizard query box
Then the "the wizard primary button" element should exist
And I hard click on "the wizard primary button"
And I wait 5 seconds
Then I should see "Okay, you’re looking for:"
And I should see "John Lewis Voting Rights Act"
And I should see "We found the following public information:"
And the "external link card" element should exist
And I should see "If the information above is not what you're looking for, the following agencies may have it."
And I should see "Were these results helpful?"
10 changes: 5 additions & 5 deletions features/step_definitions/mink-gherkin.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const customSteps = [
async callback(value) {
const inputSelector = this.mink.getSelector(value);
const inputHandle = await this.mink.page.$(inputSelector);
await inputHandle.evaluate(b => b.click());
await inputHandle.evaluate((b) => b.click());
return inputHandle.dispose();
},
},
Expand Down Expand Up @@ -68,7 +68,7 @@ const customSteps = [
const inputSelector = `input[name="${value}"]`;
const inputHandle = await this.mink.page.$(inputSelector);
await Promise.delay(1 * 1000);
await inputHandle.evaluate(b => b.click());
await inputHandle.evaluate((b) => b.click());
return inputHandle.dispose();
},
},
Expand All @@ -78,7 +78,7 @@ const customSteps = [
const inputSelector = this.mink.getSelector('the first radio option');
const inputHandle = await this.mink.page.$(inputSelector);
await Promise.delay(1 * 1000);
await inputHandle.evaluate(b => b.click());
await inputHandle.evaluate((b) => b.click());
return inputHandle.dispose();
},
},
Expand All @@ -88,7 +88,7 @@ const customSteps = [
const inputSelector = this.mink.getSelector('the first radio option');
const inputHandle = await this.mink.page.$(inputSelector);
await Promise.delay(1 * 1000);
await inputHandle.evaluate(b => b.click());
await inputHandle.evaluate((b) => b.click());
return inputHandle.dispose();
},
},
Expand All @@ -98,7 +98,7 @@ const customSteps = [
const inputSelector = this.mink.getSelector('the first radio option');
const inputHandle = await this.mink.page.$(inputSelector);
await Promise.delay(1 * 1000);
await inputHandle.evaluate(b => b.click());
await inputHandle.evaluate((b) => b.click());
return inputHandle.dispose();
},
},
Expand Down
42 changes: 21 additions & 21 deletions features/support/mink.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,27 @@ const driver = new mink.Mink({
height: 768,
},
selectors: {
"homepage search button": ".usa-search-submit-text",
"the homepage search box": "#search-field-big",
"the agency search box": "#agency-search",
"the annual report search box": "#agency-component-search-1",
"the A-to-Z button": "button[aria-controls='a1']",
"the A button": "button[aria-controls='A']",
"the last item in the A section": "#A li:last-child span",
"the start request button": ".start-request",
"the first agency suggestion": ".foia-component-card:first-of-type",
"the first radio option": "input[type='radio']:first-of-type",
"the View Report button": "button[value='view']",
"the data type dropdown": "select[name='data_type']",
"the Select All Agencies button": ".select-all-agencies > a",
"the Hero image credit": "a[href='https://commons.wikimedia.org/wiki/File:Usdepartmentofjustice.jpg']",
"the justice.gov link": "a[href='http://www.justice.gov']",
"the external link script": "script[src='/assets/js/extlink.min.js']",
"the wizard primary button": "button.w-component-button.usa-button.usa-button-primary-alt.usa-button-big",
"the Tax records topic button": "div.w-component-pill-group > ul > li:nth-child(2) > button",
"the wizard query box": "textarea.w-component-form-item__element",
"external link card": "a.foia-component-card.foia-component-card--alt.foia-component-card--ext"
}
'homepage search button': '.usa-search-submit-text',
'the homepage search box': '#search-field-big',
'the agency search box': '#agency-search',
'the annual report search box': '#agency-component-search-1',
'the A-to-Z button': "button[aria-controls='a1']",
'the A button': "button[aria-controls='A']",
'the last item in the A section': '#A li:last-child span',
'the start request button': '.start-request',
'the first agency suggestion': '.foia-component-card:first-of-type',
'the first radio option': "input[type='radio']:first-of-type",
'the View Report button': "button[value='view']",
'the data type dropdown': "select[name='data_type']",
'the Select All Agencies button': '.select-all-agencies > a',
'the Hero image credit': "a[href='https://commons.wikimedia.org/wiki/File:Usdepartmentofjustice.jpg']",
'the justice.gov link': "a[href='http://www.justice.gov']",
'the external link script': "script[src='/assets/js/extlink.min.js']",
'the wizard primary button': 'button.w-component-button.usa-button.usa-button-primary-alt.usa-button-big',
'the Tax records topic button': 'div.w-component-pill-group > ul > li:nth-child(2) > button',
'the wizard query box': 'textarea.w-component-form-item__element',
'external link card': 'a.foia-component-card.foia-component-card--alt.foia-component-card--ext',
},
});

// Avoid timeout issues.
Expand Down
12 changes: 11 additions & 1 deletion js/components/wizard_component_body_text.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,24 @@ import PropTypes from 'prop-types';
/**
* @param {import('prop-types').InferProps<typeof BodyText.propTypes>} props
*/
function BodyText({ children }) {
function BodyText({ children, html = '' }) {
if (html) {
return (
<p
className="w-component-body-text"
/* eslint-disable-next-line react/no-danger */
dangerouslySetInnerHTML={{ __html: html }}
/>
);
}
return (
<p className="w-component-body-text">{children}</p>
);
}

BodyText.propTypes = {
children: PropTypes.string,
html: PropTypes.string,
};

export default BodyText;
19 changes: 19 additions & 0 deletions js/components/wizard_component_description.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import PropTypes from 'prop-types';

/**
* @param {import('prop-types').InferProps<typeof Description>} props
*/
function Description({ children }) {
return (
<div className="w-component-description">
{children}
</div>
);
}

Description.propTypes = {
children: PropTypes.node,
};

export default Description;
52 changes: 52 additions & 0 deletions js/components/wizard_component_feedback_radio.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import PropTypes from 'prop-types';
import React from 'react';
import FormItem from './wizard_component_form_item';

function FeedbackRadioSet({
name, prefix, suffix, options, onChange,
}) {
return (
<div className="w-component-feedback-option-set">
{prefix}
<div className="w-component-feedback-option-set__options">
{options.map(({ label, value }, index) => {
let ariaLabel;
if (index === 0) {
ariaLabel = `${prefix} ${value}`;
} else if (index === options.length - 1) {
ariaLabel = `${suffix} ${value}`;
} else {
ariaLabel = value;
}

return (
<FormItem
type="radio"
name={name}
key={label}
labelHtml={label}
value={value}
onChange={onChange}
ariaLabel={ariaLabel}
/>
);
})}
</div>
{suffix}
</div>
);
}

FeedbackRadioSet.propTypes = {
name: PropTypes.string.isRequired,
prefix: PropTypes.string,
suffix: PropTypes.string,
options: PropTypes.arrayOf(
PropTypes.shape({
label: PropTypes.node,
value: PropTypes.number,
}),
).isRequired,
onChange: PropTypes.func.isRequired,
};
export default FeedbackRadioSet;
Loading

0 comments on commit 99fe639

Please sign in to comment.