Skip to content

Commit

Permalink
Merge branch 'main' into jh/playwright-public-pov
Browse files Browse the repository at this point in the history
  • Loading branch information
jamdelion committed Sep 17, 2024
2 parents 7da5771 + 8d42e6f commit 0bd1e43
Show file tree
Hide file tree
Showing 23 changed files with 525 additions and 307 deletions.
2 changes: 0 additions & 2 deletions api.planx.uk/.husky/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,3 @@
. "$(dirname -- "$0")/_/husky.sh"
cd api.planx.uk
pnpm dlx lint-staged
cd ../e2e
pnpm dlx lint-staged
245 changes: 175 additions & 70 deletions editor.planx.uk/src/@planx/components/MapAndLabel/Public/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,18 @@ import { setup } from "testUtils";
import { vi } from "vitest";
import { axe } from "vitest-axe";

import { point1, point2 } from "../test/mocks/geojson";
import { point1, point2, point3 } from "../test/mocks/geojson";
import { props } from "../test/mocks/Trees";
import { addFeaturesToMap, addMultipleFeatures } from "../test/utils";
import {
addFeaturesToMap,
addMultipleFeatures,
checkErrorMessagesEmpty,
checkErrorMessagesPopulated,
clickContinue,
fillOutFirstHalfOfForm,
fillOutForm,
fillOutSecondHalfOfForm,
} from "../test/utils";

beforeAll(() => {
if (!window.customElements.get("my-map")) {
Expand Down Expand Up @@ -40,7 +49,6 @@ describe("Basic UI", () => {
it("removes the prompt once a feature is added", async () => {
const { queryByText, getByTestId } = setup(<MapAndLabel {...props} />);
const map = getByTestId("map-and-label-map");
expect(map).toBeInTheDocument();

addFeaturesToMap(map, [point1]);

Expand All @@ -58,7 +66,6 @@ describe("Basic UI", () => {
expect(queryByText(/Tree 1/)).not.toBeInTheDocument();

const map = getByTestId("map-and-label-map");
expect(map).toBeInTheDocument();

addFeaturesToMap(map, [point1]);

Expand All @@ -73,7 +80,6 @@ describe("Basic UI", () => {
expect(queryByText(/Tree 1/)).not.toBeInTheDocument();

const map = getByTestId("map-and-label-map");
expect(map).toBeInTheDocument();

addFeaturesToMap(map, [point1]);

Expand All @@ -85,23 +91,26 @@ describe("Basic UI", () => {
// Schema and field validation is handled in both List and Schema folders - here we're only testing the MapAndLabel specific error handling
describe("validation and error handling", () => {
it("shows all fields are required", async () => {
const { getAllByTestId, getByTestId, getByRole, user } = setup(
const { getByTestId, user, queryByRole, getAllByTestId } = setup(
<MapAndLabel {...props} />,
);
const map = getByTestId("map-and-label-map");
expect(map).toBeInTheDocument();

addFeaturesToMap(map, [point1]);

expect(getByRole("tab", { name: /Tree 1/ })).toBeInTheDocument();
const tabOne = queryByRole("tab", { name: /Tree 1/ });
expect(tabOne).toBeInTheDocument();

const firstTabPanel = getByTestId("vertical-tabpanel-0");
const firstSpeciesInput = within(firstTabPanel).getByLabelText("Species");

const continueButton = getByRole("button", { name: /Continue/ });
expect(continueButton).toBeInTheDocument();
await user.click(continueButton);
// check input is empty
expect(firstSpeciesInput).toHaveDisplayValue("");

await clickContinue(user);

const errorMessages = getAllByTestId(/error-message-input/);

// Date field has been removed so only 4 inputs
expect(errorMessages).toHaveLength(4);

errorMessages.forEach((message) => {
Expand All @@ -111,119 +120,215 @@ describe("validation and error handling", () => {

// it shows all fields are required in a tab
it("should show all fields are required, for all feature tabs", async () => {
const { getByTestId, getByRole, user, debug } = setup(
<MapAndLabel {...props} />,
);
const map = getByTestId("map-and-label-map");
expect(map).toBeInTheDocument();
debug();
const { getByTestId, getByRole, user } = setup(<MapAndLabel {...props} />);

addMultipleFeatures([point1, point2]);

// vertical side tab query
const firstTab = getByRole("tab", { name: /Tree 1/ });
const secondTab = getByRole("tab", { name: /Tree 2/ });

// side tab validation
expect(firstTab).toBeInTheDocument();
expect(secondTab).toBeInTheDocument();

// form for each tab
const firstTabPanel = getByTestId("vertical-tabpanel-0");
const secondTabPanel = getByTestId("vertical-tabpanel-1");

// default is to start on seond tab panel since we add two points
// default is to start on second tab panel since we add two points
expect(firstTabPanel).not.toBeVisible();
expect(secondTabPanel).toBeVisible();

// Form is generate for secondTabPanel but not the first
expect(secondTabPanel.childElementCount).toBeGreaterThan(0);
expect(firstTabPanel.childElementCount).toBe(0);

const continueButton = getByRole("button", { name: /Continue/ });
await user.click(continueButton);
await clickContinue(user);

// error messages appear
const errorMessagesTabTwo =
within(secondTabPanel).getAllByTestId(/error-message-input/);
expect(errorMessagesTabTwo).toHaveLength(4);

// error messages are empty but visible before error state induced
// this ensures they contain the error message text
errorMessagesTabTwo.forEach((input) => {
expect(input).not.toBeEmptyDOMElement();
});
await checkErrorMessagesPopulated();

await user.click(firstTab);

expect(firstTabPanel).toBeVisible();

// error messages persist
const errorMessagesTabOne =
within(firstTabPanel).getAllByTestId(/error-message-input/);
expect(errorMessagesTabOne).toHaveLength(4);
await checkErrorMessagesPopulated();
});

// it shows all fields are required across different tabs
it("should show an error if the minimum number of items is not met", async () => {
const { getByTestId, getByRole, user } = setup(<MapAndLabel {...props} />);
const map = getByTestId("map-and-label-map");
expect(map).toBeInTheDocument();
const { getByTestId, user } = setup(<MapAndLabel {...props} />);

const continueButton = getByRole("button", { name: /Continue/ });

await user.click(continueButton);
await clickContinue(user);

const errorWrapper = getByTestId(/error-wrapper/);

const errorMessage = within(errorWrapper).getByText(/You must plot /);

expect(errorMessage).toBeInTheDocument();
expect(errorMessage).toBeVisible();
});
// ??
it("an error state is applied to a tabpanel button, when it's associated feature is invalid", async () => {
const { getByTestId, getByRole, user, getAllByTestId } = setup(
const { getByTestId, user, queryByRole } = setup(
<MapAndLabel {...props} />,
);
const map = getByTestId("map-and-label-map");
expect(map).toBeInTheDocument();

addFeaturesToMap(map, [point1]);

const tabOne = getByRole("tab", { name: /Tree 1/ });
const tabOne = queryByRole("tab", { name: /Tree 1/ });

expect(tabOne).toBeInTheDocument();

const continueButton = getByRole("button", { name: /Continue/ });
expect(continueButton).toBeInTheDocument();
await user.click(continueButton);
await clickContinue(user);

const errorMessages = getAllByTestId(/error-message-input/);

// check error messages are correct amount and contain info
expect(errorMessages).toHaveLength(4);

errorMessages.forEach((message) => {
expect(message).not.toBeEmptyDOMElement();
});
await checkErrorMessagesPopulated();

expect(tabOne).toHaveStyle("border-left: 5px solid #D4351C");
});
// shows the error state on a tab when it's invalid
});

it("does not trigger handleSubmit when errors exist", async () => {
const handleSubmit = vi.fn();
const { getByTestId, user } = setup(
<MapAndLabel {...props} handleSubmit={handleSubmit} />,
);
const map = getByTestId("map-and-label-map");

addFeaturesToMap(map, [point1]);

await clickContinue(user);

await checkErrorMessagesPopulated();

expect(handleSubmit).not.toBeCalled();
});
test.todo("an error displays if the maximum number of items is exceeded");

describe("basic interactions - happy path", () => {
test.todo("adding an item to the map adds a feature tab");
// add feature, see a tab (one feature only)
test.todo("a user can input details on a single feature and submit");
// only one feature, fill out form, submit
test.todo("adding multiple features to the map adds multiple feature tabs");
// add more than one feature, see multiple tabs
test.todo("a user can input details on multiple features and submit");
// add details to more than one tab, submit
test.todo("a user can input details on feature tabs in any order");
// ??
it("adding an item to the map adds a feature tab", async () => {
const { getByTestId } = setup(<MapAndLabel {...props} />);
const map = getByTestId("map-and-label-map");

addFeaturesToMap(map, [point1]);

const firstTabPanel = getByTestId("vertical-tabpanel-0");

expect(firstTabPanel).toBeVisible();
});

it("a user can input details on a single feature and submit", async () => {
const { getByTestId, user } = setup(<MapAndLabel {...props} />);

const map = getByTestId("map-and-label-map");

addFeaturesToMap(map, [point1]);

const firstTabPanel = getByTestId("vertical-tabpanel-0");

expect(firstTabPanel).toBeVisible();

await fillOutForm(user);

await clickContinue(user);

await checkErrorMessagesEmpty();
});

it("adding multiple features to the map adds multiple feature tabs", async () => {
const { queryByRole } = setup(<MapAndLabel {...props} />);

addMultipleFeatures([point1, point2, point3]);

// vertical side tab query
const firstTab = queryByRole("tab", { name: /Tree 1/ });
const secondTab = queryByRole("tab", { name: /Tree 2/ });
const thirdTab = queryByRole("tab", { name: /Tree 3/ });
const fourthTab = queryByRole("tab", { name: /Tree 4/ });

// check the right amount are in the document
expect(firstTab).toBeInTheDocument();
expect(secondTab).toBeInTheDocument();
expect(thirdTab).toBeInTheDocument();
expect(fourthTab).not.toBeInTheDocument();

expect(firstTab).toHaveAttribute("aria-selected", "false");
expect(secondTab).toHaveAttribute("aria-selected", "false");
expect(thirdTab).toHaveAttribute("aria-selected", "true");
});

it("a user can input details on multiple features and submit", async () => {
const { getByTestId, getByRole, user } = setup(<MapAndLabel {...props} />);
getByTestId("map-and-label-map");

addMultipleFeatures([point1, point2]);

// vertical side tab query
const firstTab = getByRole("tab", { name: /Tree 1/ });
const firstTabPanel = getByTestId("vertical-tabpanel-0");
const secondTabPanel = getByTestId("vertical-tabpanel-1");

await fillOutForm(user);
const secondSpeciesInput = within(secondTabPanel).getByLabelText("Species");

expect(secondSpeciesInput).toHaveDisplayValue("Larch");

await user.click(firstTab);

// check form on screen is reset
const firstSpeciesInput = within(firstTabPanel).getByLabelText("Species");
expect(secondSpeciesInput).not.toBeInTheDocument();
expect(firstSpeciesInput).not.toHaveDisplayValue("Larch");

await fillOutForm(user);

await clickContinue(user);

await checkErrorMessagesEmpty();
});
it("a user can input details on feature tabs in any order", async () => {
const { getByTestId, getByRole, user } = setup(<MapAndLabel {...props} />);

addMultipleFeatures([point1, point2]);

const firstTab = getByRole("tab", { name: /Tree 1/ });
const secondTab = getByRole("tab", { name: /Tree 2/ });

const firstTabPanel = getByTestId("vertical-tabpanel-0");
const secondTabPanel = getByTestId("vertical-tabpanel-1");

await user.click(firstTab);

const firstSpeciesInput = within(firstTabPanel).getByLabelText("Species");
expect(firstSpeciesInput).not.toHaveDisplayValue("Larch");

// partially fill out firstTabPanel
await fillOutFirstHalfOfForm(user);

await user.click(secondTab);
const secondSpeciesInput = within(secondTabPanel).getByLabelText("Species");
expect(secondSpeciesInput).not.toHaveDisplayValue("Larch");

// partially fill out secondTabPanel
await fillOutFirstHalfOfForm(user);

await user.click(firstTab);

// check that the data stays within the firstTabPanel
expect(firstSpeciesInput).toHaveDisplayValue("Larch");

// Complete the filling out of the firstTabPanel
await fillOutSecondHalfOfForm(user);

await user.click(secondTab);

// check that the data stays within the secondTabPanel
expect(secondSpeciesInput).toHaveDisplayValue("Larch");

// Complete the filling out of the secondTabPanel
await fillOutSecondHalfOfForm(user);

await clickContinue(user);

await checkErrorMessagesEmpty();
});
});

describe("copy feature select", () => {
Expand Down
Loading

0 comments on commit 0bd1e43

Please sign in to comment.