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

test[e2e]: refactor, and add to public-facing editor flow test #3683

Merged
merged 45 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
b11f728
Add more guidance to readme
jamdelion Sep 3, 2024
1700ad9
Extract out createQuestion and createNotice helpers
jamdelion Sep 3, 2024
f3b6848
Add checklist component to flow
jamdelion Sep 3, 2024
4aea059
Prettier
jamdelion Sep 3, 2024
9c89e5d
Create text input
jamdelion Sep 3, 2024
8fac0eb
Add number input
jamdelion Sep 3, 2024
f3a796a
Create date input
jamdelion Sep 3, 2024
1a1b618
Prettier
jamdelion Sep 3, 2024
414dff4
Use uuid for random id
jamdelion Sep 2, 2024
71e1a37
Address input component
jamdelion Sep 4, 2024
42a5338
Add contact input
jamdelion Sep 4, 2024
a4458b5
Restructure helper files
jamdelion Sep 4, 2024
5b523a5
Prettier
jamdelion Sep 4, 2024
f18162a
Merge branch 'main' into jh/playwright-initial
jamdelion Sep 4, 2024
107e7ae
Refactor to use createBaseInput helper
jamdelion Sep 4, 2024
5efb97a
Prettier again
jamdelion Sep 4, 2024
7cf8e6b
Merge branch 'main' into jh/playwright-more-components
jamdelion Sep 5, 2024
fbafa6e
Add tasklist component
jamdelion Sep 5, 2024
f120cef
Add review component
jamdelion Sep 5, 2024
d753c08
Add find property node
jamdelion Sep 5, 2024
4ac804d
Add planning contraints component
jamdelion Sep 5, 2024
888f26b
Add draw boundary component
jamdelion Sep 5, 2024
a3af6fd
Use an enum instead of magic strings
jamdelion Sep 5, 2024
fe9d645
Lint fix
jamdelion Sep 5, 2024
d48a205
Create next steps component
jamdelion Sep 5, 2024
614626e
Lint fix again
jamdelion Sep 5, 2024
fa6ce2e
Add file upload component
jamdelion Sep 5, 2024
ceba074
I really need to learn to run lint fix before committing
jamdelion Sep 5, 2024
780964a
getNextNode as function
jamdelion Sep 16, 2024
e3eaf8d
Simplify button selector and use existing enum from planx-core
jamdelion Sep 16, 2024
658b48e
Add linting to husky for e2e dir
jamdelion Sep 16, 2024
24d2bd6
Test lint
jamdelion Sep 16, 2024
a58a216
Fix linting
jamdelion Sep 16, 2024
3ff2997
Merge branch 'main' into jh/playwright-public-pov
jamdelion Sep 16, 2024
7debbb6
Start to use page object model for editor
jamdelion Sep 16, 2024
1eca97b
Fully use Editor class - moves complexity around
jamdelion Sep 16, 2024
f92d16e
Split create-flow test into two
jamdelion Sep 17, 2024
11ab75a
Lint fix
jamdelion Sep 17, 2024
0b4d8bf
Add to user facing test
jamdelion Sep 17, 2024
0aadb8b
Merge branch 'main' into jh/playwright-public-pov
jamdelion Sep 17, 2024
6a992f9
Refactor continue and expectedQuestion into helpers
jamdelion Sep 17, 2024
7da5771
Move mocks around
jamdelion Sep 17, 2024
0bd1e43
Merge branch 'main' into jh/playwright-public-pov
jamdelion Sep 17, 2024
2218b0c
Undo move create-flow for cleaner PR
jamdelion Sep 17, 2024
1200b9e
Merge branch 'main' into jh/playwright-public-pov
jamdelion Sep 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api.planx.uk/.husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
cd api.planx.uk
pnpm dlx lint-staged
pnpm dlx lint-staged
275 changes: 108 additions & 167 deletions e2e/tests/ui-driven/src/create-flow/create-flow.spec.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,26 @@
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,
setUpTestContext,
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,
};
Expand All @@ -52,166 +43,55 @@ 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();
});

Comment on lines -55 to -108
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Split out into a 'page-refresh' test file to reduce the length of this one

test("Create a flow", async ({ browser }) => {
const page = await getTeamPage({
browser,
userId: context.user!.id!,
teamName: context.team.name,
});

const editor = new PlaywrightEditor(page);
Copy link
Member

Choose a reason for hiding this comment

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

Cool to see page object models in action here - seems like very worthwhile refactor / much easier to maintain and extend now !


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();
Copy link
Member

Choose a reason for hiding this comment

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

Per bigger picture approach questions in your PR description:

  • I'm definitely in favor of splitting out geo components into separate tests/flows as own Trello ticket suggests - makes perfect sense that draw boundary & other map-based ones are going to be a bit of a stumper here / need special handling
    • This matches current separate tests for Pay & Send - which I wouldn't expect to necessarily be in this list either !
  • Otherwise though I like the idea of as many component types in a single flow as we can for realistic testing - if you're finding it's very long running maybe we simply mark as @regression so it's picked up on the nightly run, but not per commit?

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 ({
Expand Down Expand Up @@ -321,5 +201,66 @@ test.describe("Navigation", () => {
await expect(
page.locator("h1", { hasText: "Sorry, this is a test" }),
).toBeVisible();
await clickContinue({ 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.

Adding to the 'user-facing' part of the test


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: "[email protected]",
});
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 });
});
});
Loading
Loading