Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: E2E Testing for Planning Constraints #4063

Merged
merged 12 commits into from
Dec 20, 2024
56 changes: 51 additions & 5 deletions e2e/tests/ui-driven/src/create-flow-with-geospatial.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ import {
} from "./helpers/context";
import { getTeamPage } from "./helpers/getPage";
import { createAuthenticatedSession } from "./helpers/globalHelpers";
import {
answerFindProperty,
answerQuestion,
clickContinue,
} from "./helpers/userActions";
import { answerQuestion, clickContinue } from "./helpers/userActions";
import { PlaywrightEditor } from "./pages/Editor";
import {
navigateToService,
Expand All @@ -37,6 +33,15 @@ import {
setupOSMapsStyles,
setupOSMapsVectorTiles,
} from "./mocks/osMapsResponse";
import {
planningConstraintHeadersMock,
setupGISMockResponse,
setupRoadsMockResponse,
} from "./mocks/gisResponse";
import {
answerFindProperty,
userChallengesPlanningConstraint,
} from "./helpers/geoSpatialUserActions";

test.describe("Flow creation, publish and preview", () => {
let context: TestContext = {
Expand Down Expand Up @@ -133,6 +138,9 @@ test.describe("Flow creation, publish and preview", () => {
setupOSMapsStyles(page);
setupOSMapsVectorTiles(page);

await setupGISMockResponse(page);
await setupRoadsMockResponse(page);

await expect(
page.locator("h1", { hasText: "Find the property" }),
).toBeVisible();
Expand Down Expand Up @@ -225,6 +233,44 @@ test.describe("Flow creation, publish and preview", () => {
"The correct value for area comes from the map properties ",
).toBeVisible();

await clickContinue({ page });

await expect(
page.locator("h1", { hasText: "Planning constraints" }),
).toBeVisible();

await expect(
page.getByText(
"These are the planning constraints we think apply to this property",
),
).toBeVisible();

const listedBuildingConstraintRowItem = page.getByRole("button", {
name: "Listed building outlines",
});

await expect(listedBuildingConstraintRowItem).toBeVisible();

await listedBuildingConstraintRowItem.click();

await userChallengesPlanningConstraint(page);

await expect(
listedBuildingConstraintRowItem.getByText("Marked as not applicable"),
).toBeVisible();

// click to hide constraint data
await listedBuildingConstraintRowItem.click();

// ensure constraints that don't apply show up
await page
.getByRole("button", { name: "Constraints that don't apply" })
.click();

const dontApplyHeadings = await page.getByRole("heading").allTextContents();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: should this rather sit in a unit test?


expect(dontApplyHeadings).toEqual(planningConstraintHeadersMock);

// TODO: answer uploadAndLabel
// TODO: answerPropertyInfo, answerPlanningConstraints
});
Expand Down
4 changes: 4 additions & 0 deletions e2e/tests/ui-driven/src/helpers/addComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ const createBaseComponent = async (
await page.getByLabel("Show users a 'change' link to").click();
break;
case ComponentType.PlanningConstraints:
await page
.getByRole("row", { name: "via Planning Data: conservation-area" })
.locator("span")
.click();
break;
case ComponentType.DrawBoundary:
break;
Expand Down
20 changes: 20 additions & 0 deletions e2e/tests/ui-driven/src/helpers/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,26 @@ export async function setUpTestContext(
submissionEmail: context.team.settings?.submissionEmail,
},
});

// has_planning_data needs to be altered manually for geospatial tests
await $admin.client.request(
gql`
mutation TogglePlanningData($teamId: Int) {
update_team_integrations(
where: { team_id: { _eq: $teamId } }
_set: { has_planning_data: true }
) {
returning {
has_planning_data
team_id
}
}
}
`,
{
teamId: context.team.id,
},
);
}
if (
context.flow &&
Expand Down
40 changes: 40 additions & 0 deletions e2e/tests/ui-driven/src/helpers/geoSpatialUserActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { expect, Page } from "@playwright/test";
import { setupOSMockResponse } from "../mocks/osPlacesResponse";

export async function answerFindProperty(page: Page) {
await setupOSMockResponse(page);
await page.getByLabel("Postcode").fill("SW1 1AA");
await page.getByLabel("Select an address").click();
await page.getByRole("option").first().click();
}

export const userChallengesPlanningConstraint = async (page: Page) => {
const thisDoesNotApplyConstraintButton = page.getByRole("button", {
name: "I don't think this constraint applies to this property",
});

await thisDoesNotApplyConstraintButton.click();

const constraintDoesNotApplyDialog = page.getByRole("heading", {
name: "I don't think this constraint applies to this property",
});
await constraintDoesNotApplyDialog.isVisible();

const noAddressSuppliedButton = page.getByTestId("entity-checkbox-42103309");
await noAddressSuppliedButton.click();

const tellUsWhyText = page.getByRole("textbox");
await tellUsWhyText.fill("This is the reason why");

const submitConstraintChallenge = page.getByTestId(
"override-modal-submit-button",
);
await submitConstraintChallenge.click();

await expect(
page.getByTestId("error-message-checklist-error-inaccurate-entities"),
).toBeHidden();
await expect(
page.getByTestId("error-message-input-error-inaccurate-entities"),
).toBeHidden();
};
8 changes: 0 additions & 8 deletions e2e/tests/ui-driven/src/helpers/userActions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { Locator, Page } from "@playwright/test";
import { expect } from "@playwright/test";
import { setupOSMockResponse } from "../mocks/osPlacesResponse";
import { findSessionId, getGraphQLClient } from "./context";
import { TEST_EMAIL, log, waitForDebugLog } from "./globalHelpers";
import { TestContext } from "./types";
Expand Down Expand Up @@ -194,13 +193,6 @@ export async function submitCardDetails(page: Page) {
await page.locator("#confirm").click();
}

export async function answerFindProperty(page: Page) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this to a separate geoSpatialUserActions doc to fit it better with the other ones

await setupOSMockResponse(page);
await page.getByLabel("Postcode").fill("SW1 1AA");
await page.getByLabel("Select an address").click();
await page.getByRole("option").first().click();
}

export async function answerContactInput(
page: Page,
{
Expand Down
2 changes: 1 addition & 1 deletion e2e/tests/ui-driven/src/invite-to-pay/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import { TEST_EMAIL, addSessionToContext, log } from "../helpers/globalHelpers";
import {
answerChecklist,
answerContactInput,
answerFindProperty,
fillInEmail,
} from "../helpers/userActions";
import { TestContext } from "../helpers/types";
import { answerFindProperty } from "../helpers/geoSpatialUserActions";

/**
* Navigates to pay component whilst completing the minimum requirements for an Invite to Pay flow
Expand Down
164 changes: 164 additions & 0 deletions e2e/tests/ui-driven/src/mocks/geospatialMocks.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { OptionWithDataValues } from "../helpers/types";
import { Feature, Polygon } from "geojson";
import propertyConstraintsMetadata from "./propertyConstraintMetadata.json";

type ChangeHandlerProperties = {
label: string;
Expand Down Expand Up @@ -64,3 +65,166 @@ export const mockChangedMapGeoJson: GeoJsonChangeHandler = {
"area.hectares": 0.001072,
},
};

export const mockPropertyConstraints = {
RODO94 marked this conversation as resolved.
Show resolved Hide resolved
sourceRequest:
RODO94 marked this conversation as resolved.
Show resolved Hide resolved
"https://www.planning.data.gov.uk/entity.json?entries=current&geometry=POINT%28-0.1151501+51.4745098%29&geometry_relation=intersects&exclude_field=geometry%2Cpoint&limit=100&dataset=article-4-direction-area&dataset=central-activities-zone&dataset=brownfield-land&dataset=brownfield-site&dataset=area-of-outstanding-natural-beauty&dataset=green-belt&dataset=national-park&dataset=world-heritage-site&dataset=world-heritage-site-buffer-zone&dataset=flood-risk-zone&dataset=listed-building&dataset=listed-building-outline&dataset=scheduled-monument&dataset=ancient-woodland&dataset=ramsar&dataset=special-area-of-conservation&dataset=special-protection-area&dataset=site-of-special-scientific-interest&dataset=park-and-garden&dataset=tree&dataset=tree-preservation-order&dataset=tree-preservation-zone",
constraints: {
listed: {
fn: "listed",
value: true,
text: "is, or is within, a Listed Building",
data: [
{
"entry-date": "2024-04-16",
"start-date": "1980-05-15",
"end-date": "",
entity: 42103309,
name: "No Address Supplied",
dataset: "listed-building-outline",
typology: "geography",
reference: "12/435 and 963/1",
prefix: "listed-building-outline",
"organisation-entity": "192",
},
],
category: "Heritage and conservation",
},
article4: {
fn: "article4",
value: false,
text: "is not in an Article 4 direction area",
category: "General policy",
},
"article4.caz": {
fn: "article4.caz",
value: false,
text: "is not in the Central Activities Zone",
category: "General policy",
},
brownfieldSite: {
fn: "brownfieldSite",
value: false,
text: "is not on Brownfield land",
category: "General policy",
},
"designated.AONB": {
fn: "designated.AONB",
value: false,
text: "is not in an Area of Outstanding Natural Beauty",
category: "Heritage and conservation",
},
greenBelt: {
fn: "greenBelt",
value: false,
text: "is not in a Green Belt",
category: "General policy",
},
"designated.nationalPark": {
fn: "designated.nationalPark",
value: false,
text: "is not in a National Park",
category: "Heritage and conservation",
},
"designated.nationalPark.broads": {
fn: "designated.nationalPark.broads",
value: false,
},
"designated.WHS": {
fn: "designated.WHS",
value: false,
text: "is not an UNESCO World Heritage Site",
category: "Heritage and conservation",
},
flood: {
fn: "flood",
value: false,
text: "is not in a Flood Risk Zone",
category: "Flooding",
},
monument: {
fn: "monument",
value: false,
text: "is not the site of a Scheduled Monument",
category: "Heritage and conservation",
},
"nature.ASNW": {
fn: "nature.ASNW",
value: false,
text: "is not in an Ancient Semi-Natural Woodland (ASNW)",
category: "Ecology",
},
"nature.ramsarSite": {
fn: "nature.ramsarSite",
value: false,
text: "is not in a Ramsar Site",
category: "Ecology",
},
"nature.SAC": {
fn: "nature.SAC",
value: false,
text: "is not in a Special Area of Conservation (SAC)",
category: "Ecology",
},
"nature.SPA": {
fn: "nature.SPA",
value: false,
text: "is not in a Special Protection Area (SPA)",
category: "Ecology",
},
"nature.SSSI": {
fn: "nature.SSSI",
value: false,
text: "is not a Site of Special Scientific Interest (SSSI)",
category: "Ecology",
},
registeredPark: {
fn: "registeredPark",
value: false,
text: "is not in a Historic Park or Garden",
category: "Heritage and conservation",
},
tpo: {
fn: "tpo",
value: false,
text: "is not in a Tree Preservation Order (TPO) Zone",
category: "Trees",
},
designated: {
value: true,
},
"listed.grade.I": {
fn: "listed.grade.I",
value: false,
},
"listed.grade.II": {
fn: "listed.grade.II",
value: false,
},
"listed.grade.II*": {
fn: "listed.grade.II*",
value: false,
},
},
metadata: propertyConstraintsMetadata,
};

export const mockRoadData = {
sourceRequest:
"https://api.os.uk/features/v1/wfs?service=WFS&request=GetFeature&version=2.0.0&typeNames=Highways_RoadLink&outputFormat=GEOJSON&srsName=urn%3Aogc%3Adef%3Acrs%3AEPSG%3A%3A4326&count=1&filter=%0A++++%3Cogc%3AFilter%3E%0A++++++%3Cogc%3APropertyIsLike+wildCard%3D%22%25%22+singleChar%3D%22%23%22+escapeChar%3D%22%21%22%3E%0A++++++++%3Cogc%3APropertyName%3EFormsPartOf%3C%2Fogc%3APropertyName%3E%0A++++++++%3Cogc%3ALiteral%3E%25Street%23usrn21900651%25%3C%2Fogc%3ALiteral%3E%0A++++++%3C%2Fogc%3APropertyIsLike%3E%0A++++%3C%2Fogc%3AFilter%3E%0A++&",
metadata: {
"road.classified": {
name: "Classified road",
plural: "Classified roads",
text: "This will effect your project if you are looking to add a dropped kerb. It may also impact some agricultural or forestry projects within 25 metres of a classified road.",
},
},
constraints: {
"road.classified": {
fn: "road.classified",
value: false,
text: "is not on a Classified Road",
category: "General policy",
},
},
};
Loading
Loading