Skip to content

Commit

Permalink
Add some tests/ignores for seeminly-uncovered code
Browse files Browse the repository at this point in the history
It looks like c8 is now inconsistent in what it reports as
uncovered, but these additions are probably still a good idea.
  • Loading branch information
Vinnl committed Feb 19, 2024
1 parent 2acab6b commit eec01f2
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ it("passes the axe accessibility test suite for the security recommendations cel
expect(await axe(container)).toHaveNoViolations();
});

it("marks the security recommendations step as the current one", () => {
const ComposedComponent = composeStory(PhoneStory, Meta);

render(<ComposedComponent />);

const stepIndicator = screen
.getAllByRole("listitem")
.find((el) => el.textContent?.match(/Security recommendations/));
expect(stepIndicator).toBeInTheDocument();
expect(stepIndicator).toHaveAttribute("aria-current", "step");
});

it("shows the security recommendations celebration view", () => {
const ComposedComponent = composeStory(DoneStory, Meta);

Expand Down
36 changes: 35 additions & 1 deletion src/app/components/client/ComboBox.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import { it, expect } from "@jest/globals";
import { render } from "@testing-library/react";
import { render, screen } from "@testing-library/react";
import { userEvent } from "@testing-library/user-event";
import { composeStory } from "@storybook/react";
import { axe } from "jest-axe";
import Meta, {
Expand All @@ -22,3 +23,36 @@ it("passes the axe accessibility test suite if required", async () => {
const { container } = render(<ComposedTextComboBox />);
expect(await axe(container)).toHaveNoViolations();
});

it("shows suggestions when typing", async () => {
const user = userEvent.setup();
const ComposedTextComboBox = composeStory(TextComboBoxRequired, Meta);
render(<ComposedTextComboBox />);

const comboBox = screen.getByRole("combobox");
await user.type(comboBox, "one");

const suggestions = screen.getByRole("listbox");
expect(suggestions).toBeInTheDocument();
});

it("hides suggestions when clearing the input field", async () => {
const user = userEvent.setup();
const ComposedTextComboBox = composeStory(TextComboBoxRequired, Meta);
render(<ComposedTextComboBox />);

const comboBox = screen.getByRole("combobox");
await user.type(comboBox, "one");
await user.type(comboBox, "[Backspace][Backspace][Backspace]");

const suggestions = screen.queryByRole("listbox");
expect(suggestions).not.toBeInTheDocument();
});

it("shows error messages", () => {
const ComposedTextComboBox = composeStory(TextComboBoxRequired, Meta);
render(<ComposedTextComboBox isInvalid errorMessage="Input invalid" />);

const errorMessage = screen.getByText("Input invalid");
expect(errorMessage).toBeInTheDocument();
});
84 changes: 31 additions & 53 deletions src/app/components/client/ComboBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,16 @@ function ComboBox(props: ComboBoxProps) {
const listBoxRef = useRef(null);
const popoverRef = useRef(null);
const state = useComboBoxState({ ...props });
const {
inputProps,
listBoxProps,
labelProps,
errorMessageProps,
validationErrors,
} = useComboBox(
{
...props,
inputRef,
listBoxRef,
popoverRef,
},
state,
);
const { inputProps, listBoxProps, labelProps, errorMessageProps } =
useComboBox(
{
...props,
inputRef,
listBoxRef,
popoverRef,
},
state,
);

useEffect(() => {
if (inputProps.value === "") {
Expand All @@ -49,13 +44,7 @@ function ComboBox(props: ComboBoxProps) {
<div className={styles.comboBox}>
<label {...labelProps} className={styles.inputLabel}>
{label}
{isRequired ? (
<span aria-hidden="true">*</span>
) : (
// TODO: Add unit test when changing this code:
/* c8 ignore next */
""
)}
{isRequired ? <span aria-hidden="true">*</span> : ""}
</label>
<input
{...inputProps}
Expand All @@ -64,41 +53,30 @@ function ComboBox(props: ComboBoxProps) {
!inputProps.value ? styles.noValue : ""
} ${isInvalid ? styles.hasError : ""}`}
/>
{isInvalid && (
{isInvalid && typeof errorMessage === "string" && (
<div {...errorMessageProps} className={styles.inputMessage}>
{
// We always pass in a string at the time of writing, so we can't
// hit the "else" path with tests:
/* c8 ignore next 3 */
typeof errorMessage === "string"
? errorMessage
: validationErrors.join(" ")
}
{errorMessage}
</div>
)}
</div>
{
// TODO: Add unit test when changing this code:
/* c8 ignore next */
state.isOpen && (
<Popover
offset={8}
popoverRef={popoverRef}
state={state}
triggerRef={inputRef}
>
<div className={styles.popoverList}>
<ListBox
{...listBoxProps}
listBoxRef={listBoxRef}
listPlaceholder={listPlaceholder}
parentRef={inputRef}
state={state}
/>
</div>
</Popover>
)
}
{state.isOpen && (
<Popover
offset={8}
popoverRef={popoverRef}
state={state}
triggerRef={inputRef}
>
<div className={styles.popoverList}>
<ListBox
{...listBoxProps}
listBoxRef={listBoxRef}
listPlaceholder={listPlaceholder}
parentRef={inputRef}
state={state}
/>
</div>
</Popover>
)}
</>
);
}
Expand Down
6 changes: 3 additions & 3 deletions src/app/functions/server/getRelevantGuidedSteps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,15 @@ export function getNextGuidedStep(
return stepLink.eligible && !stepLink.completed;
});

// We don't have a way to trigger an invalid state without skipping a
// valid one during tests:
/* c8 ignore next 16 */
if (!nextStep) {
// In practice, there should always be a next step (at least "Done").
// If for any reason there is not, `href` will be undefined, in which case
// links will just not do anything.
console.error(
`Could not determine the relevant next guided step for the user. Skipping step: [${
// We don't have a way to trigger an invalid state without skipping a
// valid one during tests:
/* c8 ignore next */
afterStep ?? "Not skipping any steps"
}]. Is \`data.user\` defined: [${!!data.user}]. Country code: [${
data.countryCode
Expand Down
3 changes: 3 additions & 0 deletions src/app/functions/universal/getLocale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import { LocaleData } from "../server/l10n";
export function getLocale(
localeData: LocaleData[] | ReactLocalization,
): string {
// In tests, we only load "en", always (see <TestComponentWrapper>), so our
// tests will never hit the other test cases, hence the `c8 ignore`:
/* c8 ignore next 5 */
return (
(Array.isArray(localeData)
? localeData[0]?.locale
Expand Down

0 comments on commit eec01f2

Please sign in to comment.