diff --git a/api.planx.uk/.husky/pre-commit b/api.planx.uk/.husky/pre-commit index 58eb265738..2dca158161 100755 --- a/api.planx.uk/.husky/pre-commit +++ b/api.planx.uk/.husky/pre-commit @@ -1,4 +1,4 @@ #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" cd api.planx.uk -pnpm dlx lint-staged \ No newline at end of file +pnpm dlx lint-staged diff --git a/e2e/tests/ui-driven/src/create-flow/create-flow.spec.ts b/e2e/tests/ui-driven/src/create-flow/create-flow.spec.ts index 0db5895bcc..d3eda04740 100644 --- a/e2e/tests/ui-driven/src/create-flow/create-flow.spec.ts +++ b/e2e/tests/ui-driven/src/create-flow/create-flow.spec.ts @@ -1,21 +1,4 @@ import { Browser, expect, test } from "@playwright/test"; -import { - createAddressInput, - createChecklist, - createContactInput, - createDateInput, - createDrawBoundary, - createFileUpload, - createFindProperty, - createNextSteps, - createNotice, - createNumberInput, - createPlanningConstraints, - createQuestionWithOptions, - createReview, - createTaskList, - createTextInput, -} from "../helpers/addComponent"; import type { Context } from "../helpers/context"; import { contextDefaults, @@ -23,13 +6,21 @@ import { tearDownTestContext, } from "../helpers/context"; import { getTeamPage } from "../helpers/getPage"; +import { createAuthenticatedSession } from "../helpers/globalHelpers"; import { - createAuthenticatedSession, - isGetUserRequest, -} from "../helpers/globalHelpers"; -import { answerQuestion, clickContinue } from "../helpers/userActions"; - -test.describe("Navigation", () => { + answerAddressInput, + answerChecklist, + answerContactInput, + answerDateInput, + answerFindProperty, + answerNumberInput, + answerQuestion, + answerTextInput, + clickContinue, +} from "../helpers/userActions"; +import { PlaywrightEditor } from "../pages/Editor"; + +test.describe("Flow creation, publish and preview", () => { let context: Context = { ...contextDefaults, }; @@ -52,60 +43,6 @@ test.describe("Navigation", () => { await tearDownTestContext(context); }); - test("user data persists on page refresh @regression", async ({ - browser, - }) => { - const page = await createAuthenticatedSession({ - browser, - userId: context.user!.id!, - }); - - const initialRequest = page.waitForRequest(isGetUserRequest); - - Promise.all([await page.goto("/"), await initialRequest]); - - const team = page.locator("h3", { hasText: context.team.name }); - - let isRepeatedRequestMade = false; - page.on( - "request", - (req) => (isRepeatedRequestMade = isGetUserRequest(req)), - ); - - Promise.all([ - await team.click(), - expect(isRepeatedRequestMade).toBe(false), - ]); - - const reloadRequest = page.waitForRequest(isGetUserRequest); - - Promise.all([await page.reload(), await reloadRequest]); - }); - - test("team data persists on page refresh @regression", async ({ - browser, - }) => { - const page = await createAuthenticatedSession({ - browser, - userId: context.user!.id!, - }); - - await page.goto("/"); - const team = page.locator("h3", { hasText: context.team.name }); - await team.click(); - - const teamSlugInHeader = page.getByRole("link", { - name: context.team.slug, - }); - await expect(teamSlugInHeader).toBeVisible(); - - await page.reload(); - await expect(teamSlugInHeader).toBeVisible(); - - await page.goBack(); - await expect(teamSlugInHeader).toBeHidden(); - }); - test("Create a flow", async ({ browser }) => { const page = await getTeamPage({ browser, @@ -113,105 +50,48 @@ test.describe("Navigation", () => { teamName: context.team.name, }); + const editor = new PlaywrightEditor(page); + page.on("dialog", (dialog) => dialog.accept(serviceProps.name)); - await page.locator("button", { hasText: "Add a new service" }).click(); + await editor.addNewService(); // update context to allow flow to be torn down context.flow = { ...serviceProps }; - const firstNode = page.locator("li.hanger > a").first(); - - const questionText = "Is this a test?"; - await createQuestionWithOptions(page, firstNode, questionText, [ - "Yes", - "No", - ]); - await expect( - page.locator("a").filter({ hasText: questionText }), - ).toBeVisible(); - - // Add a notice to the "Yes" path - const yesBranch = page.locator("#flow .card .options .option").nth(0); - - const yesBranchNoticeText = "Yes! this is a test"; - await createNotice( - page, - yesBranch.locator(".hanger > a"), - yesBranchNoticeText, - ); - - // Add a notice to the "No" path - const noBranch = page.locator("#flow .card .options .option").nth(1); - const noBranchNoticeText = "Sorry, this is a test"; - await createNotice( - page, - noBranch.locator(".hanger > a"), - noBranchNoticeText, - ); - - const getNextNode = () => page.locator(".hanger > a").last(); - - await createChecklist(page, getNextNode(), "A checklist title", [ + await editor.createQuestion(); + await editor.createNoticeOnEachBranch(); + await editor.createChecklist(); + await editor.createTextInput(); + await editor.createNumberInput(); + await editor.createDateInput(); + await editor.createAddressInput(); + await editor.createContactInput(); + await editor.createTaskList(); + await editor.createFindProperty(); + await editor.createDrawBoundary(); + await editor.createPlanningConstraints(); + await editor.createFileUpload(); + await editor.createNextSteps(); + await editor.createReview(); + + await expect(editor.nodeList).toContainText([ + "Is this a test?", + "Yes! this is a test", + "Sorry, this is a test", "Checklist item 1", - "Second checklist item", - "The third checklist item", - ]); - - await createTextInput(page, getNextNode(), "Tell us about your trees."); - await createNumberInput(page, getNextNode(), "How old are you?", "years"); - await createDateInput(page, getNextNode(), "When is your birthday?"); - - await createAddressInput( - page, - getNextNode(), + "Tell us about your trees.", + "How old are you?", + "When is your birthday?", "What is your address?", - "some data field", - ); - - await createContactInput( - page, - getNextNode(), "What is your contact info?", - "some data field", - ); - - await createTaskList(page, getNextNode(), "What you should do next", [ - "Have a cup of tea", - "Continue through this flow", - ]); - - await createFindProperty(page, getNextNode()); - await createDrawBoundary(page, getNextNode()); - await createPlanningConstraints(page, getNextNode()); - await createFileUpload(page, getNextNode(), "some data field"); - - await createNextSteps(page, getNextNode(), [ - "A possible next step", - "Another option", + "What you should do next", + "Find property", + "Confirm your location plan", + "Planning constraints", + "File upload", + "Next steps", + "Check your answers before sending your application", ]); - - await createReview(page, getNextNode()); - - const nodes = page.locator(".card"); - await expect(nodes.getByText(questionText)).toBeVisible(); - await expect(nodes.getByText(yesBranchNoticeText)).toBeVisible(); - await expect(nodes.getByText(noBranchNoticeText)).toBeVisible(); - await expect(nodes.getByText("Checklist item 1")).toBeVisible(); - await expect(nodes.getByText("Tell us about your trees.")).toBeVisible(); - await expect(nodes.getByText("How old are you?")).toBeVisible(); - await expect(nodes.getByText("When is your birthday?")).toBeVisible(); - await expect(nodes.getByText("What is your address?")).toBeVisible(); - await expect(nodes.getByText("What is your contact info?")).toBeVisible(); - await expect(nodes.getByText("What you should do next")).toBeVisible(); - await expect(nodes.getByText("Find property")).toBeVisible(); - await expect(nodes.getByText("Confirm your location plan")).toBeVisible(); - await expect(nodes.getByText("Planning constraints")).toBeVisible(); - await expect(nodes.getByText("File upload")).toBeVisible(); - - await expect(nodes.getByText("Next steps")).toBeVisible(); - await expect( - nodes.getByText("Check your answers before sending your application"), - ).toBeVisible(); }); test("Cannot preview an unpublished flow", async ({ @@ -321,5 +201,66 @@ test.describe("Navigation", () => { await expect( page.locator("h1", { hasText: "Sorry, this is a test" }), ).toBeVisible(); + await clickContinue({ page }); + + await answerChecklist({ + page, + title: "A checklist title", + answers: ["Checklist item 1", "Second checklist item"], + }); + await clickContinue({ page }); + + await answerTextInput(page, { + expectedQuestion: "Tell us about your trees.", + answer: "My trees are lovely", + continueToNext: true, + }); + + await answerNumberInput(page, { + expectedQuestion: "How old are you?", + answer: 30, + continueToNext: true, + }); + + await answerDateInput(page, { + expectedQuestion: "When is your birthday?", + day: 30, + month: 12, + year: 1980, + continueToNext: true, + }); + + await answerAddressInput(page, { + expectedQuestion: "What is your address?", + addressLineOne: "1 Silver Street", + town: "Bamburgh", + postcode: "BG1 2SS", + continueToNext: true, + }); + + await expect( + page.locator("h1", { hasText: "What is your contact info?" }), + ).toBeVisible(); + await answerContactInput(page, { + firstName: "Freddie", + lastName: "Mercury", + phoneNumber: "01234 555555", + email: "freddie@queen.com", + }); + await clickContinue({ page }); + + await expect( + page.locator("h1", { hasText: "What you should do next" }), + ).toBeVisible(); + await expect( + page.locator("h2", { hasText: "Have a cup of tea" }), + ).toBeVisible(); + await expect( + page.locator("h2", { hasText: "Continue through this flow" }), + ).toBeVisible(); + await clickContinue({ page }); + + await answerFindProperty(page); + await clickContinue({ page }); }); }); diff --git a/e2e/tests/ui-driven/src/helpers/userActions.ts b/e2e/tests/ui-driven/src/helpers/userActions.ts index bb2a048125..51c7cbe7ca 100644 --- a/e2e/tests/ui-driven/src/helpers/userActions.ts +++ b/e2e/tests/ui-driven/src/helpers/userActions.ts @@ -1,6 +1,6 @@ import type { Locator, Page } from "@playwright/test"; import { expect } from "@playwright/test"; -import { mockOSPlacesResponse } from "../mocks/osPlacesResponse"; +import { setupOSMockResponse } from "../mocks/osPlacesResponse"; import type { Context } from "./context"; import { findSessionId, getGraphQLClient } from "./context"; import { TEST_EMAIL, log, waitForDebugLog } from "./globalHelpers"; @@ -121,7 +121,7 @@ export async function answerChecklist({ title: string; answers: string[]; }) { - const checklist = await page.getByRole("heading").filter({ + const checklist = page.getByRole("heading").filter({ hasText: title, }); await expect(checklist).toBeVisible(); @@ -196,23 +196,14 @@ export async function submitCardDetails(page: Page) { export async function answerFindProperty(page: Page) { await setupOSMockResponse(page); + await expect( + page.locator("h1", { hasText: "Find the property" }), + ).toBeVisible(); await page.getByLabel("Postcode").fill("SW1 1AA"); await page.getByLabel("Select an address").click(); await page.getByRole("option").first().click(); } -async function setupOSMockResponse(page: Page) { - const ordnanceSurveryPlacesEndpoint = new RegExp( - /proxy\/ordnance-survey\/search\/places\/v1\/postcode\/*/, - ); - await page.route(ordnanceSurveryPlacesEndpoint, async (route) => { - await route.fulfill({ - status: 200, - body: JSON.stringify(mockOSPlacesResponse), - }); - }); -} - export async function answerContactInput( page: Page, { @@ -232,3 +223,96 @@ export async function answerContactInput( await page.getByLabel("Phone number").fill(phoneNumber); await page.getByLabel("Email address").fill(email); } + +export async function answerTextInput( + page: Page, + { + expectedQuestion, + answer, + continueToNext, + }: { + expectedQuestion: string; + answer: string; + continueToNext: boolean; + }, +) { + await expect(page.locator("p", { hasText: expectedQuestion })).toBeVisible(); + await page.locator("label div input[type='text']").fill(answer); + if (continueToNext) { + await clickContinue({ page }); + } +} + +export async function answerNumberInput( + page: Page, + { + expectedQuestion, + answer, + continueToNext, + }: { + expectedQuestion: string; + answer: number; + continueToNext: boolean; + }, +) { + await expect(page.locator("p", { hasText: expectedQuestion })).toBeVisible(); + await page.locator("label div input[type='number']").fill(answer.toString()); + if (continueToNext) { + await clickContinue({ page }); + } +} + +export async function answerDateInput( + page: Page, + { + expectedQuestion, + + day, + month, + year, + continueToNext, + }: { + expectedQuestion: string; + + day: number; + month: number; + year: number; + continueToNext: boolean; + }, +) { + await expect(page.locator("h1", { hasText: expectedQuestion })).toBeVisible(); + await page.getByLabel("Day").fill(day.toString()); + await page.getByLabel("Month").fill(month.toString()); + await page.getByLabel("Year").fill(year.toString()); + + if (continueToNext) { + await clickContinue({ page }); + } +} + +export async function answerAddressInput( + page: Page, + { + expectedQuestion, + + addressLineOne, + town, + postcode, + continueToNext, + }: { + expectedQuestion: string; + + addressLineOne: string; + town: string; + postcode: string; + continueToNext: boolean; + }, +) { + await expect(page.locator("h1", { hasText: expectedQuestion })).toBeVisible(); + await page.getByLabel("Address line 1").fill(addressLineOne); + await page.getByLabel("Town").fill(town); + await page.getByLabel("Postcode").fill(postcode); + if (continueToNext) { + await clickContinue({ page }); + } +} diff --git a/e2e/tests/ui-driven/src/mocks/osPlacesResponse.ts b/e2e/tests/ui-driven/src/mocks/osPlacesResponse.ts index 6b6baf7d4b..5f4547be28 100644 --- a/e2e/tests/ui-driven/src/mocks/osPlacesResponse.ts +++ b/e2e/tests/ui-driven/src/mocks/osPlacesResponse.ts @@ -1,3 +1,5 @@ +import { Page } from "@playwright/test"; + export const mockOSPlacesResponse = { header: { uri: "https://api.os.uk/search/places/v1/postcode?postcode=SW1%201AA&dataset=LPI&maxResults=100&output_srs=EPSG%3A4326&lr=EN&offset=0", @@ -58,3 +60,14 @@ export const mockOSPlacesResponse = { }, ], }; +export async function setupOSMockResponse(page: Page) { + const ordnanceSurveryPlacesEndpoint = new RegExp( + /proxy\/ordnance-survey\/search\/places\/v1\/postcode\/*/, + ); + await page.route(ordnanceSurveryPlacesEndpoint, async (route) => { + await route.fulfill({ + status: 200, + body: JSON.stringify(mockOSPlacesResponse), + }); + }); +} diff --git a/e2e/tests/ui-driven/src/pages/Editor.ts b/e2e/tests/ui-driven/src/pages/Editor.ts new file mode 100644 index 0000000000..accbd03265 --- /dev/null +++ b/e2e/tests/ui-driven/src/pages/Editor.ts @@ -0,0 +1,174 @@ +import { expect, type Locator, type Page } from "@playwright/test"; +import { + createAddressInput, + createChecklist, + createContactInput, + createDateInput, + createDrawBoundary, + createFileUpload, + createFindProperty, + createNextSteps, + createNotice, + createNumberInput, + createPlanningConstraints, + createQuestionWithOptions, + createReview, + createTaskList, + createTextInput, +} from "../helpers/addComponent"; + +export class PlaywrightEditor { + readonly page: Page; + readonly addNewServiceButton: Locator; + readonly firstNode: Locator; + readonly yesBranch: Locator; + readonly noBranch: Locator; + readonly nodeList: Locator; + readonly answers: { + questionText: string; + yesBranchNoticeText: string; + noBranchNoticeText: string; + }; + + constructor(page: Page) { + this.page = page; + this.addNewServiceButton = page.locator("button", { + hasText: "Add a new service", + }); + this.firstNode = page.locator("li.hanger > a").first(); + this.yesBranch = page.locator("#flow .card .options .option").nth(0); + this.noBranch = page.locator("#flow .card .options .option").nth(1); + this.nodeList = page.locator(".card"); + this.answers = { + questionText: "Is this a test?", + yesBranchNoticeText: "Yes! this is a test", + noBranchNoticeText: "Sorry, this is a test", + }; + } + + async addNewService() { + await this.addNewServiceButton.click(); + } + + async createQuestion() { + await createQuestionWithOptions( + this.page, + this.firstNode, + this.answers.questionText, + ["Yes", "No"], + ); + await expect( + this.page.locator("a").filter({ hasText: this.answers.questionText }), + ).toBeVisible(); + } + + async createNoticeOnEachBranch() { + // Add a notice to the "Yes" path + await createNotice( + this.page, + this.yesBranch.locator(".hanger > a"), + this.answers.yesBranchNoticeText, + ); + // Add a notice to the "No" path + await createNotice( + this.page, + this.noBranch.locator(".hanger > a"), + this.answers.noBranchNoticeText, + ); + + await expect( + this.page.locator("a").filter({ hasText: this.answers.questionText }), + ).toBeVisible(); + } + + getNextNode() { + return this.page.locator(".hanger > a").last(); + } + + async createChecklist() { + await createChecklist(this.page, this.getNextNode(), "A checklist title", [ + "Checklist item 1", + "Second checklist item", + "The third checklist item", + ]); + } + + async createTextInput() { + await createTextInput( + this.page, + this.getNextNode(), + "Tell us about your trees.", + ); + } + + async createNumberInput() { + await createNumberInput( + this.page, + this.getNextNode(), + "How old are you?", + "years", + ); + } + + async createDateInput() { + await createDateInput( + this.page, + this.getNextNode(), + "When is your birthday?", + ); + } + + async createAddressInput() { + await createAddressInput( + this.page, + this.getNextNode(), + "What is your address?", + "some data field", + ); + } + + async createContactInput() { + await createContactInput( + this.page, + this.getNextNode(), + "What is your contact info?", + "some data field", + ); + } + + async createTaskList() { + await createTaskList( + this.page, + this.getNextNode(), + "What you should do next", + ["Have a cup of tea", "Continue through this flow"], + ); + } + + async createFindProperty() { + await createFindProperty(this.page, this.getNextNode()); + } + + async createDrawBoundary() { + await createDrawBoundary(this.page, this.getNextNode()); + } + + async createPlanningConstraints() { + await createPlanningConstraints(this.page, this.getNextNode()); + } + + async createFileUpload() { + await createFileUpload(this.page, this.getNextNode(), "some data field"); + } + + async createNextSteps() { + await createNextSteps(this.page, this.getNextNode(), [ + "A possible next step", + "Another option", + ]); + } + + async createReview() { + await createReview(this.page, this.getNextNode()); + } +} diff --git a/e2e/tests/ui-driven/src/refresh-page.spec.ts b/e2e/tests/ui-driven/src/refresh-page.spec.ts new file mode 100644 index 0000000000..309d09c0f4 --- /dev/null +++ b/e2e/tests/ui-driven/src/refresh-page.spec.ts @@ -0,0 +1,85 @@ +import { expect, test } from "@playwright/test"; +import type { Context } from "./helpers/context"; +import { + contextDefaults, + setUpTestContext, + tearDownTestContext, +} from "./helpers/context"; +import { + createAuthenticatedSession, + isGetUserRequest, +} from "./helpers/globalHelpers"; + +test.describe("Refresh page", () => { + let context: Context = { + ...contextDefaults, + }; + + test.beforeAll(async () => { + try { + context = await setUpTestContext(context); + } catch (error) { + // ensure proper teardown if setup fails + await tearDownTestContext(context); + throw error; + } + }); + + test.afterAll(async () => { + await tearDownTestContext(context); + }); + + test("user data persists on page refresh @regression", async ({ + browser, + }) => { + const page = await createAuthenticatedSession({ + browser, + userId: context.user!.id!, + }); + + const initialRequest = page.waitForRequest(isGetUserRequest); + + Promise.all([await page.goto("/"), await initialRequest]); + + const team = page.locator("h3", { hasText: context.team.name }); + + let isRepeatedRequestMade = false; + page.on( + "request", + (req) => (isRepeatedRequestMade = isGetUserRequest(req)), + ); + + Promise.all([ + await team.click(), + expect(isRepeatedRequestMade).toBe(false), + ]); + + const reloadRequest = page.waitForRequest(isGetUserRequest); + + Promise.all([await page.reload(), await reloadRequest]); + }); + + test("team data persists on page refresh @regression", async ({ + browser, + }) => { + const page = await createAuthenticatedSession({ + browser, + userId: context.user!.id!, + }); + + await page.goto("/"); + const team = page.locator("h3", { hasText: context.team.name }); + await team.click(); + + const teamSlugInHeader = page.getByRole("link", { + name: context.team.slug, + }); + await expect(teamSlugInHeader).toBeVisible(); + + await page.reload(); + await expect(teamSlugInHeader).toBeVisible(); + + await page.goBack(); + await expect(teamSlugInHeader).toBeHidden(); + }); +}); diff --git a/editor.planx.uk/src/@planx/components/MapAndLabel/Public/index.test.tsx b/editor.planx.uk/src/@planx/components/MapAndLabel/Public/index.test.tsx index 5d0cdcd880..5addd9b4c3 100644 --- a/editor.planx.uk/src/@planx/components/MapAndLabel/Public/index.test.tsx +++ b/editor.planx.uk/src/@planx/components/MapAndLabel/Public/index.test.tsx @@ -60,14 +60,14 @@ describe("Basic UI", () => { await waitFor(() => expect( - queryByText("Plot a feature on the map to begin") - ).not.toBeInTheDocument() + queryByText("Plot a feature on the map to begin"), + ).not.toBeInTheDocument(), ); }); it("renders the schema name as the tab title", async () => { const { queryByText, getByRole, getByTestId } = setup( - + , ); expect(queryByText(/Tree 1/)).not.toBeInTheDocument(); @@ -81,7 +81,7 @@ describe("Basic UI", () => { it("should not have any accessibility violations", async () => { const { queryByText, getByTestId, container } = setup( - + , ); expect(queryByText(/Tree 1/)).not.toBeInTheDocument(); @@ -98,7 +98,7 @@ describe("Basic UI", () => { describe("validation and error handling", () => { it("shows all fields are required", async () => { const { getByTestId, user, queryByRole, getAllByTestId } = setup( - + , ); const map = getByTestId("map-and-label-map"); @@ -172,7 +172,7 @@ describe("validation and error handling", () => { // ?? it("an error state is applied to a tabpanel button, when it's associated feature is invalid", async () => { const { getByTestId, user, queryByRole } = setup( - + , ); const map = getByTestId("map-and-label-map"); @@ -194,7 +194,7 @@ describe("validation and error handling", () => { it("does not trigger handleSubmit when errors exist", async () => { const handleSubmit = vi.fn(); const { getByTestId, user } = setup( - + , ); const map = getByTestId("map-and-label-map"); @@ -497,11 +497,11 @@ describe("payload generation", () => { test.todo("a submitted payload contains a GeoJSON feature collection"); // check payload contains GeoJSON feature collection test.todo( - "the feature collection contains all geospatial data inputted by the user" + "the feature collection contains all geospatial data inputted by the user", ); // feature collection matches the mocked data test.todo( - "each feature's properties correspond with the details entered for that feature" + "each feature's properties correspond with the details entered for that feature", ); // feature properties contain the answers to inputs }); diff --git a/editor.planx.uk/src/@planx/components/MapAndLabel/test/utils.ts b/editor.planx.uk/src/@planx/components/MapAndLabel/test/utils.ts index 1873246808..0b2424e603 100644 --- a/editor.planx.uk/src/@planx/components/MapAndLabel/test/utils.ts +++ b/editor.planx.uk/src/@planx/components/MapAndLabel/test/utils.ts @@ -11,7 +11,7 @@ import { mockTreeData } from "./mocks/GenericValues"; */ export const addFeaturesToMap = async ( map: HTMLElement, - features: Feature[] + features: Feature[], ) => { const mockEvent = new CustomEvent("geojsonChange", { detail: { @@ -22,7 +22,7 @@ export const addFeaturesToMap = async ( }; export const addMultipleFeatures = ( - featureArray: Feature[] + featureArray: Feature[], ) => { const map = screen.getByTestId("map-and-label-map"); const pointsAddedArray: Feature[] = []; diff --git a/editor.planx.uk/src/components/RouteLoadingIndicator.tsx b/editor.planx.uk/src/components/RouteLoadingIndicator.tsx index 72c6852ce2..4417471a18 100644 --- a/editor.planx.uk/src/components/RouteLoadingIndicator.tsx +++ b/editor.planx.uk/src/components/RouteLoadingIndicator.tsx @@ -33,4 +33,4 @@ const RouteLoadingIndicator: React.FC<{ ); }; -export default RouteLoadingIndicator; \ No newline at end of file +export default RouteLoadingIndicator; diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Team/TeamMembers.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Team/TeamMembers.tsx index 1ae158e124..e6b0535e30 100644 --- a/editor.planx.uk/src/pages/FlowEditor/components/Team/TeamMembers.tsx +++ b/editor.planx.uk/src/pages/FlowEditor/components/Team/TeamMembers.tsx @@ -16,7 +16,7 @@ import { TeamMember } from "./types"; export const TeamMembers = () => { const [teamMembers, teamSlug] = useStore((state) => [ - state.teamMembers, + state.teamMembers, state.teamSlug, ]); @@ -48,7 +48,11 @@ export const TeamMembers = () => { Editors have access to edit your services. - + @@ -57,7 +61,10 @@ export const TeamMembers = () => { Admins have editor access across all teams. - + {archivedMembers.length > 0 && ( diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.addNewEditor.test.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.addNewEditor.test.tsx index 1c9a54c6a6..c82b41cf71 100644 --- a/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.addNewEditor.test.tsx +++ b/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.addNewEditor.test.tsx @@ -94,14 +94,18 @@ describe("when the addNewEditor modal is rendered", () => { }); describe("'add a new editor' button is hidden from Templates team", () => { - beforeEach(async() => { - useStore.setState({ teamMembers: mockTeamMembersData, teamSlug: "templates" }); + beforeEach(async () => { + useStore.setState({ + teamMembers: mockTeamMembersData, + teamSlug: "templates", + }); }); it("hides the button on the Templates team", async () => { const { user: _user } = await setupTeamMembersScreen(); const teamEditorsTable = screen.getByTestId("team-editors"); - const addEditorButton = within(teamEditorsTable).queryByText("Add a new editor"); + const addEditorButton = + within(teamEditorsTable).queryByText("Add a new editor"); expect(addEditorButton).not.toBeInTheDocument(); }); }); diff --git a/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.updateEditor.test.tsx b/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.updateEditor.test.tsx index 7cba480610..7527470705 100644 --- a/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.updateEditor.test.tsx +++ b/editor.planx.uk/src/pages/FlowEditor/components/Team/tests/TeamMembers.updateEditor.test.tsx @@ -24,7 +24,7 @@ describe("when a user presses 'edit button'", () => { const teamEditorsTable = screen.getByTestId("team-editors"); const addEditorButton = await within(teamEditorsTable).findByTestId( - "edit-button-0" + "edit-button-0", ); user.click(addEditorButton); @@ -64,7 +64,7 @@ describe("when a user deletes an input value", () => { const teamEditorsTable = screen.getByTestId("team-editors"); const addEditorButton = await within(teamEditorsTable).findByTestId( - "edit-button-0" + "edit-button-0", ); await user.click(addEditorButton); @@ -98,7 +98,7 @@ describe("when a user updates a field correctly", () => { const teamEditorsTable = screen.getByTestId("team-editors"); const addEditorButton = await within(teamEditorsTable).findByTestId( - "edit-button-0" + "edit-button-0", ); await user.click(addEditorButton); @@ -112,7 +112,7 @@ describe("when a user updates a field correctly", () => { it("updates the field", async () => { const firstNameInput = await screen.findByLabelText("First name"); expect(firstNameInput).toHaveDisplayValue( - mockTeamMembersData[1].firstName + "bo" + mockTeamMembersData[1].firstName + "bo", ); }); it("enables the update user button", async () => { @@ -130,7 +130,7 @@ describe("when a user correctly updates an Editor", () => { const teamEditorsTable = screen.getByTestId("team-editors"); const addEditorButton = await within(teamEditorsTable).findByTestId( - "edit-button-0" + "edit-button-0", ); await user.click(addEditorButton); @@ -150,7 +150,7 @@ describe("when a user correctly updates an Editor", () => { expect(within(membersTable).getByText(/Billbo/)).toBeInTheDocument(); }); expect( - await screen.findByText(/Successfully updated a user/) + await screen.findByText(/Successfully updated a user/), ).toBeInTheDocument(); }); it("closes the modal", async () => { @@ -160,14 +160,18 @@ describe("when a user correctly updates an Editor", () => { }); it("shows a success message", async () => { expect( - await screen.findByText(/Successfully updated a user/) + await screen.findByText(/Successfully updated a user/), ).toBeInTheDocument(); }); }); describe("'edit' button is hidden from Templates team", () => { - beforeEach(async() => { - useStore.setState({ teamMembers: mockTeamMembersData, user: mockPlatformAdminUser, teamSlug: "templates" }); + beforeEach(async () => { + useStore.setState({ + teamMembers: mockTeamMembersData, + user: mockPlatformAdminUser, + teamSlug: "templates", + }); }); it("hides the button on the Templates team", async () => { diff --git a/editor.planx.uk/src/pages/FlowEditor/index.tsx b/editor.planx.uk/src/pages/FlowEditor/index.tsx index 4dd0e5a36c..9e580d5800 100644 --- a/editor.planx.uk/src/pages/FlowEditor/index.tsx +++ b/editor.planx.uk/src/pages/FlowEditor/index.tsx @@ -20,7 +20,8 @@ const EditorContainer = styled(Box)(() => ({ })); const FlowEditor = () => { - const [ flow, ...breadcrumbs ] = useCurrentRoute().url.pathname.split("/").at(-1)?.split(",") || []; + const [flow, ...breadcrumbs] = + useCurrentRoute().url.pathname.split("/").at(-1)?.split(",") || []; const scrollContainerRef = useRef(null); useScrollControlsAndRememberPosition(scrollContainerRef); diff --git a/editor.planx.uk/src/routes/team.tsx b/editor.planx.uk/src/routes/team.tsx index 02e14e96b4..864d158a59 100644 --- a/editor.planx.uk/src/routes/team.tsx +++ b/editor.planx.uk/src/routes/team.tsx @@ -85,7 +85,9 @@ const routes = compose( "/:flow/service": setFlowAndLazyLoad(() => import("./serviceSettings")), - "/:flow/submissions-log": setFlowAndLazyLoad(() => import("./submissionsLog")), + "/:flow/submissions-log": setFlowAndLazyLoad( + () => import("./submissionsLog"), + ), "/members": lazy(() => import("./teamMembers")), "/design": compose(