diff --git a/api.planx.uk/package.json b/api.planx.uk/package.json
index cf59ad7d0f..33042b0c16 100644
--- a/api.planx.uk/package.json
+++ b/api.planx.uk/package.json
@@ -11,7 +11,7 @@
},
"dependencies": {
"@airbrake/node": "^2.1.8",
- "@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#bea2192",
+ "@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#d47553e",
"@types/isomorphic-fetch": "^0.0.36",
"adm-zip": "^0.5.10",
"aws-sdk": "^2.1467.0",
diff --git a/api.planx.uk/pnpm-lock.yaml b/api.planx.uk/pnpm-lock.yaml
index 71459ce07a..4322bf9d5f 100644
--- a/api.planx.uk/pnpm-lock.yaml
+++ b/api.planx.uk/pnpm-lock.yaml
@@ -14,8 +14,8 @@ dependencies:
specifier: ^2.1.8
version: 2.1.8
'@opensystemslab/planx-core':
- specifier: git+https://github.com/theopensystemslab/planx-core#bea2192
- version: github.com/theopensystemslab/planx-core/bea2192
+ specifier: git+https://github.com/theopensystemslab/planx-core#d47553e
+ version: github.com/theopensystemslab/planx-core/d47553e
'@types/isomorphic-fetch':
specifier: ^0.0.36
version: 0.0.36
@@ -6137,8 +6137,8 @@ packages:
resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==}
dev: false
- github.com/theopensystemslab/planx-core/bea2192:
- resolution: {tarball: https://codeload.github.com/theopensystemslab/planx-core/tar.gz/bea2192}
+ github.com/theopensystemslab/planx-core/d47553e:
+ resolution: {tarball: https://codeload.github.com/theopensystemslab/planx-core/tar.gz/d47553e}
name: '@opensystemslab/planx-core'
version: 1.0.0
prepare: true
diff --git a/e2e/tests/api-driven/package.json b/e2e/tests/api-driven/package.json
index 73118cf07b..d5e27fd240 100644
--- a/e2e/tests/api-driven/package.json
+++ b/e2e/tests/api-driven/package.json
@@ -7,7 +7,7 @@
"packageManager": "pnpm@8.6.6",
"dependencies": {
"@cucumber/cucumber": "^9.3.0",
- "@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#bea2192",
+ "@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#d47553e",
"axios": "^1.7.4",
"dotenv": "^16.3.1",
"dotenv-expand": "^10.0.0",
diff --git a/e2e/tests/api-driven/pnpm-lock.yaml b/e2e/tests/api-driven/pnpm-lock.yaml
index 2a64be1400..31f0a8f970 100644
--- a/e2e/tests/api-driven/pnpm-lock.yaml
+++ b/e2e/tests/api-driven/pnpm-lock.yaml
@@ -9,8 +9,8 @@ dependencies:
specifier: ^9.3.0
version: 9.3.0
'@opensystemslab/planx-core':
- specifier: git+https://github.com/theopensystemslab/planx-core#bea2192
- version: github.com/theopensystemslab/planx-core/bea2192
+ specifier: git+https://github.com/theopensystemslab/planx-core#d47553e
+ version: github.com/theopensystemslab/planx-core/d47553e
axios:
specifier: ^1.7.4
version: 1.7.4
@@ -2932,8 +2932,8 @@ packages:
resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==}
dev: false
- github.com/theopensystemslab/planx-core/bea2192:
- resolution: {tarball: https://codeload.github.com/theopensystemslab/planx-core/tar.gz/bea2192}
+ github.com/theopensystemslab/planx-core/d47553e:
+ resolution: {tarball: https://codeload.github.com/theopensystemslab/planx-core/tar.gz/d47553e}
name: '@opensystemslab/planx-core'
version: 1.0.0
prepare: true
diff --git a/e2e/tests/ui-driven/package.json b/e2e/tests/ui-driven/package.json
index a337e13060..ed53dde709 100644
--- a/e2e/tests/ui-driven/package.json
+++ b/e2e/tests/ui-driven/package.json
@@ -8,7 +8,7 @@
"postinstall": "./install-dependencies.sh"
},
"dependencies": {
- "@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#bea2192",
+ "@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#d47553e",
"axios": "^1.7.4",
"dotenv": "^16.3.1",
"eslint": "^8.56.0",
diff --git a/e2e/tests/ui-driven/pnpm-lock.yaml b/e2e/tests/ui-driven/pnpm-lock.yaml
index 17fbb73582..aef5a7a65b 100644
--- a/e2e/tests/ui-driven/pnpm-lock.yaml
+++ b/e2e/tests/ui-driven/pnpm-lock.yaml
@@ -6,8 +6,8 @@ settings:
dependencies:
'@opensystemslab/planx-core':
- specifier: git+https://github.com/theopensystemslab/planx-core#bea2192
- version: github.com/theopensystemslab/planx-core/bea2192
+ specifier: git+https://github.com/theopensystemslab/planx-core#d47553e
+ version: github.com/theopensystemslab/planx-core/d47553e
axios:
specifier: ^1.7.4
version: 1.7.4
@@ -2674,8 +2674,8 @@ packages:
resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==}
dev: false
- github.com/theopensystemslab/planx-core/bea2192:
- resolution: {tarball: https://codeload.github.com/theopensystemslab/planx-core/tar.gz/bea2192}
+ github.com/theopensystemslab/planx-core/d47553e:
+ resolution: {tarball: https://codeload.github.com/theopensystemslab/planx-core/tar.gz/d47553e}
name: '@opensystemslab/planx-core'
version: 1.0.0
prepare: true
diff --git a/editor.planx.uk/package.json b/editor.planx.uk/package.json
index 622801495b..2cd00f4b21 100644
--- a/editor.planx.uk/package.json
+++ b/editor.planx.uk/package.json
@@ -15,7 +15,7 @@
"@mui/material": "^5.15.10",
"@mui/utils": "^5.15.11",
"@opensystemslab/map": "1.0.0-alpha.3",
- "@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#e6040d9",
+ "@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#d47553e",
"@tiptap/core": "^2.4.0",
"@tiptap/extension-bold": "^2.0.3",
"@tiptap/extension-bubble-menu": "^2.1.13",
diff --git a/editor.planx.uk/pnpm-lock.yaml b/editor.planx.uk/pnpm-lock.yaml
index 4d4a8b1c43..a0ee2beed6 100644
--- a/editor.planx.uk/pnpm-lock.yaml
+++ b/editor.planx.uk/pnpm-lock.yaml
@@ -47,8 +47,8 @@ dependencies:
specifier: 1.0.0-alpha.3
version: 1.0.0-alpha.3
'@opensystemslab/planx-core':
- specifier: git+https://github.com/theopensystemslab/planx-core#e6040d9
- version: github.com/theopensystemslab/planx-core/e6040d9(@types/react@18.2.45)
+ specifier: git+https://github.com/theopensystemslab/planx-core#d47553e
+ version: github.com/theopensystemslab/planx-core/d47553e(@types/react@18.2.45)
'@tiptap/core':
specifier: ^2.4.0
version: 2.4.0(@tiptap/pm@2.0.3)
@@ -21360,9 +21360,9 @@ packages:
use-sync-external-store: 1.2.0(react@18.2.0)
dev: false
- github.com/theopensystemslab/planx-core/e6040d9(@types/react@18.2.45):
- resolution: {tarball: https://codeload.github.com/theopensystemslab/planx-core/tar.gz/e6040d9}
- id: github.com/theopensystemslab/planx-core/e6040d9
+ github.com/theopensystemslab/planx-core/d47553e(@types/react@18.2.45):
+ resolution: {tarball: https://codeload.github.com/theopensystemslab/planx-core/tar.gz/d47553e}
+ id: github.com/theopensystemslab/planx-core/d47553e
name: '@opensystemslab/planx-core'
version: 1.0.0
prepare: true
diff --git a/editor.planx.uk/src/@planx/components/Page/Public.test.tsx b/editor.planx.uk/src/@planx/components/Page/Public.test.tsx
index 27a23409ba..fca2c24dd8 100644
--- a/editor.planx.uk/src/@planx/components/Page/Public.test.tsx
+++ b/editor.planx.uk/src/@planx/components/Page/Public.test.tsx
@@ -1 +1,191 @@
-test.todo("coming soon!");
+import React from "react";
+import { setup } from "testUtils";
+import { vi } from "vitest";
+import { axe } from "vitest-axe";
+
+import PageComponent from "./Public";
+import { ProposedAdvertisements } from "./schema/AdvertConsent";
+
+it("renders correctly", async () => {
+ const { getByRole } = setup(
+ ,
+ );
+
+ const title = getByRole("heading", {
+ level: 1,
+ name: "Tell us about your proposed advertisements",
+ });
+ expect(title).toBeVisible();
+});
+
+it("has no accessibility violations", async () => {
+ const { container } = setup(
+ ,
+ );
+
+ const results = await axe(container);
+ expect(results).toHaveNoViolations();
+});
+
+it("displays the supplied Page schema", () => {
+ const { getByLabelText } = setup(
+ ,
+ );
+
+ // Each PageSchema field is displayed
+ ProposedAdvertisements.fields.forEach(({ data }) => {
+ const input = getByLabelText(data.title);
+ expect(input).toBeVisible();
+ });
+});
+
+it("handles PageSchema errors", async () => {
+ const handleSubmit = vi.fn();
+ const {
+ user,
+ queryAllByTestId,
+ getAllByTestId,
+ getByTestId,
+ queryByText,
+ getAllByText,
+ } = setup(
+ ,
+ );
+
+ // No error messages present initially
+ let errorMessages = queryAllByTestId(/error-message-input-number/);
+ expect(queryByText("Enter your answer before continuing")).toBeNull();
+ errorMessages.forEach((message) => expect(message).toBeEmptyDOMElement());
+
+ // User hits "Continue" without populating fields
+ const continueButton = getByTestId("continue-button");
+ await user.click(continueButton);
+
+ // Error messages present, per field
+ errorMessages = getAllByTestId(/error-message-input-number/);
+ errorMessages.forEach((message) => expect(message).not.toBeEmptyDOMElement());
+ expect(getAllByText("Enter your answer before continuing")).toHaveLength(
+ ProposedAdvertisements.fields.length,
+ );
+
+ // Due to errors, component has not submitted data
+ expect(handleSubmit).not.toHaveBeenCalled();
+});
+
+it("submits a valid payload", async () => {
+ const handleSubmit = vi.fn();
+ const { user, getAllByLabelText, getByTestId } = setup(
+ ,
+ );
+
+ const inputs = getAllByLabelText(/How many/);
+ expect(inputs).toHaveLength(ProposedAdvertisements.fields.length);
+
+ // Populate each field
+ for (const input of inputs) {
+ await user.type(input, "1");
+ }
+
+ const continueButton = getByTestId("continue-button");
+ await user.click(continueButton);
+
+ expect(handleSubmit).toHaveBeenCalled();
+
+ const expectedFlattenedData = expect.objectContaining({
+ data: expect.objectContaining({
+ "testFn.fascia": 1,
+ "testFn.hoarding": 1,
+ "testFn.other": 1,
+ "testFn.projecting": 1,
+ }),
+ });
+ expect(handleSubmit).toHaveBeenCalledWith(expectedFlattenedData);
+
+ const expectedDefaultData = expect.objectContaining({
+ data: expect.objectContaining({
+ testFn: [
+ {
+ fascia: 1,
+ hoarding: 1,
+ other: 1,
+ projecting: 1,
+ },
+ ],
+ }),
+ });
+ expect(handleSubmit).toHaveBeenCalledWith(expectedDefaultData);
+});
+
+it("handles back navigation", () => {
+ const previousData = {
+ data: {
+ testFn: [
+ {
+ fascia: 1,
+ hoarding: 2,
+ other: 3,
+ projecting: 4,
+ },
+ ],
+ "testFn.fascia": 1,
+ "testFn.hoarding": 2,
+ "testFn.other": 3,
+ "testFn.projecting": 4,
+ },
+ };
+
+ const handleSubmit = vi.fn();
+ const { getByLabelText } = setup(
+ ,
+ );
+
+ // Each input is correctly pre-populated
+ const fasciaInput = getByLabelText(/fascia/);
+ expect(fasciaInput).toHaveValue(1);
+
+ const hoardingInput = getByLabelText(/hoarding/);
+ expect(hoardingInput).toHaveValue(2);
+
+ const otherInput = getByLabelText(/other/);
+ expect(otherInput).toHaveValue(3);
+
+ const projectingInput = getByLabelText(/projecting/);
+ expect(projectingInput).toHaveValue(4);
+});
diff --git a/editor.planx.uk/src/@planx/components/Page/Public.tsx b/editor.planx.uk/src/@planx/components/Page/Public.tsx
index 81c18cc423..d96e3dfcf1 100644
--- a/editor.planx.uk/src/@planx/components/Page/Public.tsx
+++ b/editor.planx.uk/src/@planx/components/Page/Public.tsx
@@ -1,10 +1,12 @@
import { PublicProps } from "@planx/components/ui";
-import { useFormik } from "formik";
+import { FormikConfig, useFormik } from "formik";
import React from "react";
+import { flatten } from "../List/utils";
import Card from "../shared/Preview/Card";
import CardHeader from "../shared/Preview/CardHeader";
import { useSchema } from "../shared/Schema/hook";
+import { SchemaUserData } from "../shared/Schema/model";
import { SchemaFields } from "../shared/Schema/SchemaFields";
import { getPreviouslySubmittedData } from "../shared/utils";
import { Page } from "./model";
@@ -17,9 +19,28 @@ function PageComponent(props: Props) {
previousValues: getPreviouslySubmittedData(props),
});
+ const onSubmit: FormikConfig["onSubmit"] = (data) => {
+ if (!props.handleSubmit) return;
+
+ // Default data - used for "back", to maintain a copy of the data as generated by the component
+ const defaultPassportData = { [props.fn]: data.schemaData };
+
+ // Flattened data - used for access via automation, SetValue etc
+ const flattenedData = flatten({ [props.fn]: data.schemaData[0] });
+
+ const userData = {
+ data: {
+ ...defaultPassportData,
+ ...flattenedData,
+ },
+ };
+
+ props.handleSubmit(userData);
+ };
+
const formik = useFormik({
...formikConfig,
- onSubmit: (data) => console.log({ data }),
+ onSubmit,
});
return (