Skip to content

Commit

Permalink
feat: when List schema sets max: 1, don't display add another butto…
Browse files Browse the repository at this point in the history
…n or index in card header (#3265)
  • Loading branch information
jessicamcinchak authored Jun 12, 2024
1 parent 85af90a commit f936014
Show file tree
Hide file tree
Showing 13 changed files with 445 additions and 242 deletions.
47 changes: 18 additions & 29 deletions editor.planx.uk/src/@planx/components/List/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,49 +13,38 @@ import InputRowLabel from "ui/shared/InputRowLabel";

import { EditorProps, ICONS, InternalNotes, MoreInformation } from "../ui";
import { List, parseContent } from "./model";
import { ProposedAdvertisements } from "./schemas/Adverts";
import { BuildingDetailsGLA } from "./schemas/GLA/BuildingDetails";
import { CommunalSpaceGLA } from "./schemas/GLA/CommunalSpace";
import { ExistingAndProposedUsesGLA } from "./schemas/GLA/ExistingAndProposedUses";
import { OpenSpaceGLA } from "./schemas/GLA/OpenSpace";
import { ProtectedSpaceGLA } from "./schemas/GLA/ProtectedSpace";
import { ResidentialUnitsExisting } from "./schemas/ResidentialUnits/Existing";
import { ResidentialUnitsProposed } from "./schemas/ResidentialUnits/Proposed";
// import { ResidentialUnitsGLANew } from "./schemas/ResidentialUnits/GLA/New";
// import { ResidentialUnitsGLARebuilt } from "./schemas/ResidentialUnits/GLA/Rebuilt";
// import { ResidentialUnitsGLARemoved } from "./schemas/ResidentialUnits/GLA/Removed";
// import { ResidentialUnitsGLARetained } from "./schemas/ResidentialUnits/GLA/Retained";
import { ResidentialUnitsGLAGained } from "./schemas/ResidentialUnits/GLA/Gained";
import { ResidentialUnitsGLALost } from "./schemas/ResidentialUnits/GLA/Lost";
import { ExistingAndProposedUsesGLA } from "./schemas/GLA/ExistingAndProposedUses";
import { CommunalSpaceGLA } from "./schemas/GLA/CommunalSpace";
import { BuildingDetailsGLA } from "./schemas/GLA/BuildingDetails";
import { ProtectedSpaceGLA } from "./schemas/GLA/ProtectedSpace";
import { OpenSpaceGLA } from "./schemas/GLA/OpenSpace";
import { Zoo } from "./schemas/Zoo";
import { ProposedAdvertisements } from "./schemas/Adverts";
import { ResidentialUnitsProposed } from "./schemas/ResidentialUnits/Proposed";
import { Zoo } from "./schemas/Tests/Zoo";

type Props = EditorProps<TYPES.List, List>;

export const SCHEMAS = [
{ name: "Residential units - Existing", schema: ResidentialUnitsExisting },
{ name: "Residential units - Proposed", schema: ResidentialUnitsProposed },
{ name: "Residential units (GLA) - Gained", schema: ResidentialUnitsGLAGained },
{
name: "Residential units (GLA) - Gained",
schema: ResidentialUnitsGLAGained,
},
{ name: "Residential units (GLA) - Lost", schema: ResidentialUnitsGLALost },
{ name: "Existing and proposed uses (GLA)", schema: ExistingAndProposedUsesGLA },
{ name: "Communal spaces (GLA)", schema: CommunalSpaceGLA },
{
name: "Existing and proposed uses (GLA)",
schema: ExistingAndProposedUsesGLA,
},
{ name: "Building details (GLA)", schema: BuildingDetailsGLA },
{ name: "Communal spaces (GLA)", schema: CommunalSpaceGLA },
{ name: "Protected spaces (GLA)", schema: ProtectedSpaceGLA },
{ name: "Open spaces (GLA)", schema: OpenSpaceGLA },
// { name: "Residential units (GLA) - New", schema: ResidentialUnitsGLANew },
// {
// name: "Residential units (GLA) - Rebuilt",
// schema: ResidentialUnitsGLARebuilt,
// },
// {
// name: "Residentail units (GLA) - Removed",
// schema: ResidentialUnitsGLARemoved,
// },
// {
// name: "Residential units (GLA) - Retained",
// schema: ResidentialUnitsGLARetained,
// },
{ name: "Zoo (test)", schema: Zoo },
{ name: "Proposed advertisements", schema: ProposedAdvertisements },
{ name: "(Test only) Zoo", schema: Zoo },
];

function ListComponent(props: Props) {
Expand Down
144 changes: 39 additions & 105 deletions editor.planx.uk/src/@planx/components/List/Public/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,114 +1,30 @@
import { screen, within } from "@testing-library/react";
import { getByText, screen, within } from "@testing-library/react";
import { UserEvent } from "@testing-library/user-event/dist/types/setup/setup";
import { cloneDeep, merge } from "lodash";
import React from "react";
import { axe, setup } from "testUtils";

import { UserResponse } from "../model";
import ListComponent, { Props } from "../Public";
import { GenericUnitsTest } from "../schemas/GenericUnitsTest";
import { Zoo } from "../schemas/Zoo";
import ListComponent from "../Public";
import {
flatten,
sumIdenticalUnits,
sumIdenticalUnitsByDevelopmentType,
} from "../utils";

const mockProps: Props = {
fn: "mockFn",
schema: Zoo,
schemaName: "Zoo",
title: "Mock Title",
description: "Mock description",
};

const mockPayload = {
data: {
mockFn: [
{
age: 10,
cuteness: "Very",
email: "richard.parker@pi.com",
name: "Richard Parker",
size: "Medium",
},
{
age: 10,
cuteness: "Very",
email: "richard.parker@pi.com",
name: "Richard Parker",
size: "Medium",
},
],
"mockFn.one.age": 10,
"mockFn.one.cuteness": "Very",
"mockFn.one.email": "richard.parker@pi.com",
"mockFn.one.name": "Richard Parker",
"mockFn.one.size": "Medium",
"mockFn.two.age": 10,
"mockFn.two.cuteness": "Very",
"mockFn.two.email": "richard.parker@pi.com",
"mockFn.two.name": "Richard Parker",
"mockFn.two.size": "Medium",
"mockFn.total.listItems": 2,
},
};

const mockPropsUnits: Props = {
fn: "proposal.units.residential",
schema: GenericUnitsTest,
schemaName: "Generic residential units",
title: "Describe residential units",
};

const mockPayloadUnits = {
data: {
"proposal.units.residential": [
{
development: "newBuild",
garden: "Yes",
identicalUnits: 1,
},
{
development: "newBuild",
garden: "No",
identicalUnits: 2,
},
{
development: "changeOfUseTo",
garden: "No",
identicalUnits: 2,
},
],
"proposal.units.residential.one.development": "newBuild",
"proposal.units.residential.one.garden": "Yes",
"proposal.units.residential.one.identicalUnits": 1,
"proposal.units.residential.two.development": "newBuild",
"proposal.units.residential.two.garden": "No",
"proposal.units.residential.two.identicalUnits": 2,
"proposal.units.residential.three.development": "changeOfUseTo",
"proposal.units.residential.three.garden": "No",
"proposal.units.residential.three.identicalUnits": 2,
"proposal.units.residential.total.listItems": 3,
"proposal.units.residential.total.units": 5,
"proposal.units.residential.total.units.newBuid": 3,
"proposal.units.residential.total.units.changeOfUseTo": 2,
},
};
mockUnitsPayload,
mockUnitsProps,
} from "../schemas/Tests/GenericUnits";
import { mockMaxOneProps } from "../schemas/Tests/MaxOne";
import { mockZooPayload, mockZooProps } from "../schemas/Tests/Zoo";

jest.setTimeout(20_000);

describe("Basic UI", () => {
it("renders correctly", () => {
const { getByText } = setup(<ListComponent {...mockProps} />);
const { getByText } = setup(<ListComponent {...mockZooProps} />);

expect(getByText(/Mock Title/)).toBeInTheDocument();
expect(getByText(/Mock description/)).toBeInTheDocument();
});

it("parses provided schema to render expected form", async () => {
const { getByLabelText, getByText, user, getByRole, queryAllByRole } =
setup(<ListComponent {...mockProps} />);
setup(<ListComponent {...mockZooProps} />);

// Text inputs are generated from schema...
const textInput = getByLabelText(/What's their name?/) as HTMLInputElement;
Expand Down Expand Up @@ -174,15 +90,17 @@ describe("Basic UI", () => {
});

it("should not have any accessibility violations", async () => {
const { container } = setup(<ListComponent {...mockProps} />);
const { container } = setup(<ListComponent {...mockZooProps} />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
});

describe("Building a list", () => {
it("does not display a default item if the schema has no required minimum", () => {
const mockWithMinZero = merge(cloneDeep(mockProps), { schema: { min: 0 } });
const mockWithMinZero = merge(cloneDeep(mockZooProps), {
schema: { min: 0 },
});
const { queryByRole, getByTestId } = setup(
<ListComponent {...mockWithMinZero} />,
);
Expand All @@ -202,7 +120,7 @@ describe("Building a list", () => {

it("displays a default item if the schema has a required minimum", () => {
const { getByRole, queryByLabelText } = setup(
<ListComponent {...mockProps} />,
<ListComponent {...mockZooProps} />,
);

// Card present...
Expand All @@ -218,9 +136,22 @@ describe("Building a list", () => {
expect(inputField).not.toBeDisabled();
});

it("hides the index number in the card header and the 'add another' button if the schema has a max of 1", () => {
const { getAllByTestId, queryByTestId } = setup(
<ListComponent {...mockMaxOneProps} />,
);

const cards = getAllByTestId(/list-card/);
expect(cards).toHaveLength(1);
expect(cards[0]).toHaveTextContent("Parking spaces");

const addItemButton = queryByTestId("list-add-button");
expect(addItemButton).not.toBeInTheDocument();
});

test("Adding an item", async () => {
const { getAllByTestId, getByTestId, user } = setup(
<ListComponent {...mockProps} />,
<ListComponent {...mockZooProps} />,
);

let cards = getAllByTestId(/list-card/);
Expand Down Expand Up @@ -252,7 +183,7 @@ describe("Building a list", () => {
test("Editing an item", async () => {
// Setup three cards
const { getAllByTestId, getByTestId, user } = setup(
<ListComponent {...mockProps} />,
<ListComponent {...mockZooProps} />,
);

await fillInResponse(user);
Expand Down Expand Up @@ -308,7 +239,7 @@ describe("Building a list", () => {
user,
getByLabelText,
queryAllByTestId,
} = setup(<ListComponent {...mockProps} />);
} = setup(<ListComponent {...mockZooProps} />);

await fillInResponse(user);

Expand Down Expand Up @@ -378,7 +309,7 @@ describe("Building a list", () => {
test("Removing an item when another card is active", async () => {
// Setup two cards
const { getAllByTestId, getByTestId, user } = setup(
<ListComponent {...mockProps} />,
<ListComponent {...mockZooProps} />,
);

await fillInResponse(user);
Expand Down Expand Up @@ -430,7 +361,7 @@ describe("Payload generation", () => {
it("generates a valid payload on submission (Zoo)", async () => {
const handleSubmit = jest.fn();
const { getByTestId, user } = setup(
<ListComponent {...mockProps} handleSubmit={handleSubmit} />,
<ListComponent {...mockZooProps} handleSubmit={handleSubmit} />,
);
const addItemButton = getByTestId("list-add-button");

Expand All @@ -442,13 +373,13 @@ describe("Payload generation", () => {
await user.click(screen.getByTestId("continue-button"));

expect(handleSubmit).toHaveBeenCalled();
expect(handleSubmit.mock.calls[0][0]).toMatchObject(mockPayload);
expect(handleSubmit.mock.calls[0][0]).toMatchObject(mockZooPayload);
});

it.skip("generates a valid payload with summary stats on submission (Units)", async () => {
const handleSubmit = jest.fn();
const { getByTestId, user } = setup(
<ListComponent {...mockPropsUnits} handleSubmit={handleSubmit} />,
<ListComponent {...mockUnitsProps} handleSubmit={handleSubmit} />,
);

const saveButton = screen.getByRole("button", { name: /Save/ });
Expand Down Expand Up @@ -486,14 +417,17 @@ describe("Payload generation", () => {
await user.click(screen.getByTestId("continue-button"));

expect(handleSubmit).toHaveBeenCalled();
expect(handleSubmit.mock.calls[0][0]).toMatchObject(mockPayloadUnits);
expect(handleSubmit.mock.calls[0][0]).toMatchObject(mockUnitsPayload);
});
});

describe("Navigating back", () => {
test("it pre-populates list correctly", async () => {
const { getAllByText, queryByLabelText, getAllByTestId } = setup(
<ListComponent {...mockProps} previouslySubmittedData={mockPayload} />,
<ListComponent
{...mockZooProps}
previouslySubmittedData={mockZooPayload}
/>,
);

const cards = getAllByTestId(/list-card/);
Expand Down
Loading

0 comments on commit f936014

Please sign in to comment.