Skip to content

Commit

Permalink
Merge branch 'main' into jh/refactor-checklist-more
Browse files Browse the repository at this point in the history
  • Loading branch information
jamdelion authored Dec 18, 2024
2 parents 79b9f86 + af37fb1 commit 3987fe4
Show file tree
Hide file tree
Showing 15 changed files with 403 additions and 58 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ hasura.planx.uk/.env.test
/playwright-report/
/playwright/.cache/
api.planx.uk/tmp/
.python-version
__pycache__

# Ignore certificate files
**/*.chain
Expand Down
70 changes: 63 additions & 7 deletions e2e/tests/ui-driven/src/create-flow-with-geospatial.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,24 @@ import {
} from "./helpers/navigateAndPublish";
import { TestContext } from "./helpers/types";
import { serviceProps } from "./helpers/serviceData";
import { checkGeoJsonContent } from "./helpers/geospatialChecks";
import {
mockMapGeoJson,
alterDrawGeoJson,
checkGeoJsonContent,
checkUploadFileAltRoute,
getMapProperties,
resetMapBoundary,
waitForMapComponent,
} from "./helpers/geospatialChecks";
import {
GeoJsonChangeHandler,
mockChangedMapGeoJson,
mockPropertyTypeOptions,
mockTitleBoundaryGeoJson,
} from "./mocks/geospatialMocks";
import {
setupOSMapsStyles,
setupOSMapsVectorTiles,
} from "./mocks/osMapsResponse";

test.describe("Flow creation, publish and preview", () => {
let context: TestContext = {
Expand Down Expand Up @@ -72,16 +85,14 @@ test.describe("Flow creation, publish and preview", () => {
await editor.createInternalPortal();
await editor.populateInternalPortal();
await page.getByRole("link", { name: "start" }).click(); // return to main flow
await editor.createUploadAndLabel();
// TODO: editor.createPropertyInfo()
// await editor.createUploadAndLabel();
await editor.createDrawBoundary();
await editor.createPlanningConstraints();
// await editor.createFileUpload();

await expect(editor.nodeList).toContainText([
"Find property",
"an internal portalEdit Portal",
"Upload and label",
"Confirm your location plan",
"Planning constraints",
// "File upload",
Expand Down Expand Up @@ -119,6 +130,9 @@ test.describe("Flow creation, publish and preview", () => {
`/${context.team.slug}/${serviceProps.slug}/published?analytics=false`,
);

setupOSMapsStyles(page);
setupOSMapsVectorTiles(page);

await expect(
page.locator("h1", { hasText: "Find the property" }),
).toBeVisible();
Expand All @@ -130,7 +144,7 @@ test.describe("Flow creation, publish and preview", () => {
).toBeVisible();

// Check map component has geoJson content
await checkGeoJsonContent(page, mockMapGeoJson);
await checkGeoJsonContent(page, "geojsondata", mockTitleBoundaryGeoJson);

// Check property info is being shown
await expect(page.getByText("Test Street, Testville")).toBeVisible();
Expand Down Expand Up @@ -169,7 +183,49 @@ test.describe("Flow creation, publish and preview", () => {
).toBeVisible();
await clickContinue({ page });

const drawBoundaryTitle = page.getByRole("heading", {
name: "Confirm your location plan",
});
await expect(drawBoundaryTitle).toBeVisible();

await checkGeoJsonContent(
page,
"drawgeojsondata",
mockTitleBoundaryGeoJson,
);

const area = "The property boundary you have drawn is 490.37";

await expect(page.getByText(area)).toBeVisible();

// navigate to upload file page and back
await checkUploadFileAltRoute(page);

await expect(
drawBoundaryTitle,
"We have navigated back to the map component",
).toBeVisible();

// ensure map has loaded correctly
await waitForMapComponent(page);

await resetMapBoundary(page);

await alterDrawGeoJson(page);

// extract new GeoJSON data
const newGeoJson = await getMapProperties(page, "drawgeojsondata");
const parsedJson: GeoJsonChangeHandler = JSON.parse(newGeoJson!);

// check it matches our static mock
await checkGeoJsonContent(page, "drawgeojsondata", mockChangedMapGeoJson);

await expect(
page.getByText(`${parsedJson.properties!["area.squareMetres"]}`),
"The correct value for area comes from the map properties ",
).toBeVisible();

// TODO: answer uploadAndLabel
// TODO: answerPropertyInfo, answerDrawBoundary, answerPlanningConstraints
// TODO: answerPropertyInfo, answerPlanningConstraints
});
});
81 changes: 78 additions & 3 deletions e2e/tests/ui-driven/src/helpers/geospatialChecks.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,87 @@
import { expect, Page } from "@playwright/test";
import { Feature } from "geojson";

export const checkGeoJsonContent = async (page: Page, geoJson: Feature) => {
export const waitForMapComponent = async (page: Page) => {
await page.waitForFunction(() => {
const map = document.getElementById("draw-boundary-map");
return map;
});
};

export const getMapProperties = async (
page: Page,
attribute: "geojsondata" | "drawgeojsondata",
) => {
const mapComponent = await page.waitForSelector("my-map");
return await mapComponent.getAttribute(attribute);
};

export const alterDrawGeoJson = async (page: Page) => {
const map = page.getByTestId("map-test-id");

await map.click({ button: "left", position: { x: 100, y: 200 } });
await map.click({ button: "left", position: { x: 150, y: 250 } });
await map.click({ button: "left", position: { x: 200, y: 250 } });
await map.click({ button: "left", position: { x: 100, y: 200 } });
};

export const resetMapBoundary = async (page: Page) => {
const resetButton = page.getByLabel("Reset map view");
await resetButton.click();

const resetGeoJson = await getMapProperties(page, "drawgeojsondata");

expect(resetGeoJson, "drawGeoJsonData should be reset").toEqual(null);
};

export const checkGeoJsonContent = async (
page: Page,
attribute: "geojsondata" | "drawgeojsondata",
geoJson: Feature,
) => {
// Wait for the map component to be present
const mapComponent = await page.waitForSelector("my-map");

await page.waitForFunction(() => customElements.get("my-map"));
await expect(
page.getByTestId("map-test-id"),
"Check we can see the map",
).toBeVisible();

// Get the geojsonData attribute
const geojsonData = await mapComponent.getAttribute("geojsondata");
const geojsonData = await mapComponent.getAttribute(attribute);

expect(
JSON.parse(geojsonData!),
"map attribute matches expected mock attribute",
).toEqual(geoJson);
};

export const checkUploadFileAltRoute = async (page: Page) => {
const uploadButton = page.getByTestId("upload-file-button");

await expect(
uploadButton,
"We can see a button to upload a file instead",
).toBeVisible();

await uploadButton.click();

await expect(
page.getByRole("heading", { name: "Upload a location plan" }),
"Should be in a page for uploading a file",
).toBeVisible();

await expect(
page.getByRole("button", { name: "Drop file here or choose" }),
"A button for uploading files is visible",
).toBeVisible();

await page.getByTestId("continue-button").click();

await page.getByTestId("error-message-upload-location-plan").isVisible();

const useMapButton = page.getByTestId("use-map-button");

expect(JSON.parse(geojsonData!)).toEqual(geoJson);
await useMapButton.click();
};
35 changes: 31 additions & 4 deletions e2e/tests/ui-driven/src/mocks/geospatialMocks.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import { OptionWithDataValues } from "../helpers/types";
import { Feature, Polygon } from "geojson";

type ChangeHandlerProperties = {
label: string;
"area.squareMetres": number;
"area.hectares": number;
};

export type GeoJsonChangeHandler = Feature<Polygon, ChangeHandlerProperties>;

export const mockPropertyTypeOptions: OptionWithDataValues[] = [
{ optionText: "Residential", dataValue: "residential" },
{ optionText: "Commercial", dataValue: "commercial" },
];

import { Feature } from "geojson";

export const mockMapGeoJson: Feature = {
export const mockTitleBoundaryGeoJson: Feature = {
type: "Feature",
geometry: {
type: "MultiPolygon",
coordinates: [
Expand All @@ -23,7 +31,6 @@ export const mockMapGeoJson: Feature = {
],
],
},
type: "Feature",
properties: {
"entry-date": "2024-05-06",
"start-date": "2010-05-12",
Expand All @@ -37,3 +44,23 @@ export const mockMapGeoJson: Feature = {
"organisation-entity": "13",
},
};

export const mockChangedMapGeoJson: GeoJsonChangeHandler = {
type: "Feature",
geometry: {
type: "Polygon",
coordinates: [
[
[-0.6341888375038146, 51.60562241658701],
[-0.6341217822784424, 51.605580770520504],
[-0.63405472705307, 51.605580770520504],
[-0.6341888375038146, 51.60562241658701],
],
],
},
properties: {
label: "1",
"area.squareMetres": 10.72,
"area.hectares": 0.001072,
},
};
22 changes: 22 additions & 0 deletions e2e/tests/ui-driven/src/mocks/osMapsMockData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export const osMapsStylesResponse = {
version: 8,
sprite:
"https://api.os.uk/maps/vector/v1/vts/resources/sprites/sprite?key=YOUR_KEY&srs=3857",
glyphs:
"https://api.os.uk/maps/vector/v1/vts/resources/fonts/{fontstack}/{range}.pbf?key=YOUR_KEY&srs=3857",
sources: {
esri: {
type: "vector",
url: "https://api.os.uk/maps/vector/v1/vts?key=YOUR_KEY&srs=3857",
},
},
layers: [
{
id: "background",
type: "background",
paint: {
"background-color": "#0437F2",
},
},
],
};
27 changes: 27 additions & 0 deletions e2e/tests/ui-driven/src/mocks/osMapsResponse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Page } from "@playwright/test";
import { osMapsStylesResponse } from "./osMapsMockData";

export async function setupOSMapsStyles(page: Page) {
const ordnanceSurveyMapsStyles = new RegExp(
/\/proxy\/ordnance-survey\/maps\/vector\/v1\/vts\/resources\/styles.*/,
);
await page.route(ordnanceSurveyMapsStyles, async (route) => {
await route.fulfill({
status: 200,
body: JSON.stringify(osMapsStylesResponse),
});
});
}

export async function setupOSMapsVectorTiles(page: Page) {
const ordnanceSurveyVectorTiles = new RegExp(
/\/proxy\/ordnance-survey\/maps\/vector\/v1\/vts\/tile/,
);

await page.route(ordnanceSurveyVectorTiles, async (route) => {
await route.fulfill({
status: 200,
body: Buffer.from([]),
});
});
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useStore } from "pages/FlowEditor/lib/store";
import React from "react";

import { Option } from "../../shared";
import { Props } from "../types";
import { AutoAnsweredChecklist } from "./components/AutoAnsweredChecklist";
import { VisibleChecklist } from "./components/VisibleChecklist";
Expand All @@ -25,4 +26,4 @@ const ChecklistComponent: React.FC<Props> = (props) => {
return <VisibleChecklist {...props} />;
};

export default ChecklistComponent;
export default ChecklistComponent;
6 changes: 6 additions & 0 deletions editor.planx.uk/src/@planx/components/List/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ import { ICONS } from "../shared/icons";
import { EditorProps } from "../shared/types";
import { List, parseContent, validationSchema } from "./model";
import { ProposedAdvertisements } from "./schemas/Adverts";
import { ExistingBuildingsCIL } from "./schemas/CIL/ExistingCIL";
import { MezzanineCIL } from "./schemas/CIL/MezzanineCIL";
import { UnoccupiedBuildingsCIL } from "./schemas/CIL/UnoccupiedCIL";
import { NonResidentialFloorspace } from "./schemas/Floorspace";
import { BuildingDetailsGLA } from "./schemas/GLA/BuildingDetails";
import { CommunalSpaceGLA } from "./schemas/GLA/CommunalSpace";
Expand Down Expand Up @@ -69,6 +72,9 @@ export const SCHEMAS = [
{ name: "Proposed advertisements", schema: ProposedAdvertisements },
{ name: "Parking details", schema: Parking },
{ name: "Parking details (GLA)", schema: ParkingGLA },
{ name: "Existing buildings (CIL)", schema: ExistingBuildingsCIL },
{ name: "Unoccupied buildings (CIL)", schema: UnoccupiedBuildingsCIL },
{ name: "Mezzanine floors (CIL)", schema: MezzanineCIL },
{ name: "Trees", schema: Trees },
{ name: "Trees (Map first)", schema: TreesMapFirst },
];
Expand Down
Loading

0 comments on commit 3987fe4

Please sign in to comment.