diff --git a/e2e/tests/ui-driven/src/create-flow-with-geospatial.spec.ts b/e2e/tests/ui-driven/src/create-flow-with-geospatial.spec.ts index 8bc6fe181b..02ecfbc29e 100644 --- a/e2e/tests/ui-driven/src/create-flow-with-geospatial.spec.ts +++ b/e2e/tests/ui-driven/src/create-flow-with-geospatial.spec.ts @@ -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 = { @@ -72,8 +85,7 @@ 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(); @@ -81,7 +93,6 @@ test.describe("Flow creation, publish and preview", () => { await expect(editor.nodeList).toContainText([ "Find property", "an internal portalEdit Portal", - "Upload and label", "Confirm your location plan", "Planning constraints", // "File upload", @@ -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(); @@ -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(); @@ -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 }); }); diff --git a/e2e/tests/ui-driven/src/helpers/geospatialChecks.ts b/e2e/tests/ui-driven/src/helpers/geospatialChecks.ts index 7b55e01997..ea13894975 100644 --- a/e2e/tests/ui-driven/src/helpers/geospatialChecks.ts +++ b/e2e/tests/ui-driven/src/helpers/geospatialChecks.ts @@ -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(); }; diff --git a/e2e/tests/ui-driven/src/mocks/geospatialMocks.ts b/e2e/tests/ui-driven/src/mocks/geospatialMocks.ts index fb26308b1d..e923545f46 100644 --- a/e2e/tests/ui-driven/src/mocks/geospatialMocks.ts +++ b/e2e/tests/ui-driven/src/mocks/geospatialMocks.ts @@ -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; 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: [ @@ -23,7 +31,6 @@ export const mockMapGeoJson: Feature = { ], ], }, - type: "Feature", properties: { "entry-date": "2024-05-06", "start-date": "2010-05-12", @@ -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, + }, +}; diff --git a/e2e/tests/ui-driven/src/mocks/osMapsMockData.ts b/e2e/tests/ui-driven/src/mocks/osMapsMockData.ts new file mode 100644 index 0000000000..b99f14f4d3 --- /dev/null +++ b/e2e/tests/ui-driven/src/mocks/osMapsMockData.ts @@ -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", + }, + }, + ], +}; diff --git a/e2e/tests/ui-driven/src/mocks/osMapsResponse.ts b/e2e/tests/ui-driven/src/mocks/osMapsResponse.ts new file mode 100644 index 0000000000..ccd6f6de6f --- /dev/null +++ b/e2e/tests/ui-driven/src/mocks/osMapsResponse.ts @@ -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([]), + }); + }); +}