refactor: organize E2E tests with page objects

This commit is contained in:
2026-10-07 21:13:40 +09:00
parent 1e03e8f4ff
commit 48ef396ec1
28 changed files with 1494 additions and 834 deletions
+99 -101
View File
@@ -3,187 +3,185 @@ import { expect, test } from "../fixtures";
test("executes routine steps and records a measurement in the shared journal", async ({
page,
a11y,
homePage,
journalPage,
workspacePage,
}, testInfo) => {
await page.goto("/");
await homePage.goTo();
await page.waitForLoadState("networkidle");
await page.getByRole("button", { name: /Morning routine 0 of 3/ }).click();
await homePage.morningRoutine.click();
await expect(page).toHaveURL(/activity=task/);
await page.getByRole("checkbox", { name: /Drink water/ }).check();
await expect(page.getByRole("button", { name: "Finish routine" })).toBeDisabled();
await page.getByRole("checkbox", { name: /Get ready/ }).check();
await page.getByRole("checkbox", { name: /Have breakfast/ }).check();
await homePage.routineStep(/Drink water/).check();
await expect(homePage.finishRoutine).toBeDisabled();
await homePage.routineStep(/Get ready/).check();
await homePage.routineStep(/Have breakfast/).check();
expect((await a11y().analyze()).violations).toEqual([]);
await page.screenshot({ path: testInfo.outputPath("home-routine.png"), fullPage: true });
await page.getByRole("button", { name: "Finish routine" }).click();
await page.getByRole("button", { name: /Record weight A quick check-in/ }).click();
await page.getByRole("spinbutton", { name: "Weight", exact: true }).fill("65.2");
await page.getByRole("button", { name: "Save measurement" }).click();
await expect(
page.getByRole("button", { name: /Record weight Recorded · 65.2 kg/ }),
).toBeVisible();
await page.getByRole("link", { name: "Journal", exact: true }).first().click();
await expect(page.getByRole("article", { name: "Weight entry" })).toContainText("65.2 kg");
await page.getByRole("link", { name: "Home", exact: true }).first().click();
await expect(page.getByRole("button", { name: "Restore Morning routine" })).toBeVisible();
await homePage.finishRoutine.click();
await homePage.recordMeasurement("65.2");
await expect(homePage.recordedWeight("65.2")).toBeVisible();
await workspacePage.navigateTo("Journal");
await expect(journalPage.weightEntries).toContainText("65.2 kg");
await workspacePage.navigateTo("Home");
await expect(homePage.restoreTask("Morning routine")).toBeVisible();
});
test("shows the day flow and conversation context at desktop width", async ({ page }, testInfo) => {
test("shows the day flow and conversation context at desktop width", async ({
page,
homePage,
messagesPage,
}, testInfo) => {
await page.setViewportSize({ width: 1440, height: 1080 });
await page.goto("/");
await homePage.goTo();
await page.waitForLoadState("networkidle");
await expect(page.getByRole("region", { name: "Today’s plan" })).toBeVisible();
await expect(homePage.todayPlan).toBeVisible();
await page.screenshot({ path: testInfo.outputPath("home-desktop.png") });
await page.goto("/support?conversation=design-review");
await messagesPage.goTo("?conversation=design-review");
await page.waitForLoadState("networkidle");
await expect(page.getByRole("textbox", { name: "Reply", exact: true })).toBeVisible();
await expect(messagesPage.reply).toBeVisible();
await page.screenshot({ path: testInfo.outputPath("messages-desktop.png") });
});
test("previews a natural-language memo and shares the executed record with journal", async ({
page,
homePage,
journalPage,
workspacePage,
}) => {
await page.goto("/");
await homePage.goTo();
await page.waitForLoadState("networkidle");
const memo = "明日のレビューは導線から確認する";
await page.getByRole("textbox", { name: "Home input" }).fill(`Note: ${memo}`);
await page.getByRole("button", { name: "Preview action" }).click();
const execute = page.getByRole("button", { name: "Apply", exact: true });
await homePage.previewCommand(`Note: ${memo}`);
const execute = homePage.applyAction;
await expect(execute).toBeVisible();
await execute.click();
await page.getByRole("link", { name: "Journal", exact: true }).first().click();
await expect(page.getByRole("article", { name: "Note entry" })).toContainText(memo);
await page.getByRole("link", { name: "Home", exact: true }).first().click();
await expect(page.getByRole("textbox", { name: "Home input" })).toBeVisible();
await workspacePage.navigateTo("Journal");
await expect(journalPage.noteEntries).toContainText(memo);
await workspacePage.navigateTo("Home");
await expect(homePage.input).toBeVisible();
});
test("keeps the home usable on narrow screens", async ({ page, a11y }, testInfo) => {
await page.goto("/");
test("keeps the home usable on narrow screens", async ({ page, a11y, homePage }, testInfo) => {
await homePage.goTo();
await page.waitForLoadState("networkidle");
for (const width of [320, 375, 414, 768]) {
await page.setViewportSize({ width, height: 850 });
await expect(page.getByRole("textbox", { name: "Home input" })).toBeVisible();
await expect(homePage.input).toBeVisible();
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBe(width);
await page.screenshot({ path: testInfo.outputPath(`home-${width}.png`) });
if (width === 320) expect((await a11y().analyze()).violations).toEqual([]);
}
});
test("adds tasks only after confirmation and can defer and restore them", async ({ page }) => {
await page.goto("/");
test("adds tasks only after confirmation and can defer and restore them", async ({
page,
homePage,
}) => {
await homePage.goTo();
await page.waitForLoadState("networkidle");
const input = page.getByRole("textbox", { name: "Home input" });
const complete = page.getByRole("button", {
name: "Complete grocery shopping",
exact: true,
});
await input.fill("Add grocery shopping");
await page.getByRole("button", { name: "Preview action" }).click();
const complete = homePage.completeTask("grocery shopping");
await homePage.previewCommand("Add grocery shopping");
await expect(complete).toHaveCount(0);
await page.getByRole("button", { name: "Apply", exact: true }).click();
await homePage.applyAction.click();
await expect(complete).toBeVisible();
await input.fill("Defer grocery shopping");
await page.getByRole("button", { name: "Preview action" }).click();
await homePage.previewCommand("Defer grocery shopping");
await expect(complete).toBeVisible();
await page.getByRole("button", { name: "Apply", exact: true }).click();
await homePage.applyAction.click();
await expect(complete).toHaveCount(0);
await page.getByRole("button", { name: "Restore grocery shopping", exact: true }).click();
await homePage.restoreTask("grocery shopping").click();
await complete.click();
await expect(complete).toHaveCount(0);
await expect(
page.getByRole("button", { name: "Restore grocery shopping", exact: true }),
).toBeVisible();
await expect(homePage.restoreTask("grocery shopping")).toBeVisible();
});
test("opens a conversation page from home and retains outcomes on return", async ({
page,
a11y,
homePage,
messagesPage,
workspacePage,
}) => {
await page.goto("/");
await homePage.goTo();
await page.waitForLoadState("networkidle");
const conversationLink = page.getByRole("link", { name: "Open conversation with Haruka Aoki" });
const conversationLink = homePage.conversation("Haruka Aoki");
await expect(conversationLink).toHaveAttribute("href", /conversation=design-review/);
await conversationLink.click();
await expect(page).toHaveURL(/\/support\?.*conversation=design-review/);
await expect(page.getByRole("dialog")).toHaveCount(0);
await expect(page.getByRole("textbox", { name: "Reply", exact: true })).toBeVisible();
await expect(messagesPage.dialogs).toHaveCount(0);
await expect(messagesPage.reply).toBeVisible();
expect((await a11y().analyze()).violations).toEqual([]);
await page.goBack();
await expect(conversationLink).toBeVisible();
await page.goForward();
await expect(page.getByRole("textbox", { name: "Reply", exact: true })).toBeVisible();
await expect(messagesPage.reply).toBeVisible();
await page.reload();
await page.waitForLoadState("networkidle");
await expect(page.getByRole("textbox", { name: "Reply", exact: true })).toBeVisible();
await page.getByRole("button", { name: "Leave for later" }).click();
await page.getByRole("link", { name: "Home", exact: true }).first().click();
await expect(messagesPage.reply).toBeVisible();
await messagesPage.leaveForLater.click();
await workspacePage.navigateTo("Home");
await expect(conversationLink).toContainText("Set aside");
await conversationLink.click();
await expect(page).toHaveURL(/conversation=design-review/);
await expect(page.getByRole("button", { name: "Move to Inbox" })).toBeVisible();
await page.getByRole("button", { name: "Move to Inbox" }).click();
const back = page.getByRole("button", { name: "Back to messages" });
if (await back.isVisible()) await back.click();
await page.getByRole("link", { name: "Home", exact: true }).first().click();
await expect(messagesPage.moveToInbox).toBeVisible();
await messagesPage.moveToInbox.click();
await messagesPage.showConversationList();
await workspacePage.navigateTo("Home");
await expect(conversationLink).toBeVisible();
});
test("updates the prose brief as priorities change and opens the referenced conversation", async ({
page,
homePage,
messagesPage,
workspacePage,
}) => {
await page.goto("/");
await homePage.goTo();
await page.waitForLoadState("networkidle");
const brief = page.getByRole("region", { name: "Daily brief" });
const brief = homePage.dailyBrief;
await expect(brief).toContainText("Review the documents");
await expect(brief).toContainText("3 conversations");
await page.getByRole("button", { name: "Complete Review the documents", exact: true }).click();
await homePage.completeTask("Review the documents").click();
await expect(brief).not.toContainText("Review the documents");
await brief.getByRole("button", { name: "Reply to Haruka Aoki" }).click();
await page.getByRole("button", { name: "Leave for later" }).click();
await page.getByRole("link", { name: "Home", exact: true }).first().click();
await homePage.openBriefConversation("Haruka Aoki");
await messagesPage.leaveForLater.click();
await workspacePage.navigateTo("Home");
await expect(brief).toContainText("2 conversations");
await expect(brief).not.toContainText("Haruka Aoki");
await page.getByRole("textbox", { name: "Home input" }).fill("再開地点:資料の2ページ目から");
await page.getByRole("button", { name: "Preview action" }).click();
await page.getByRole("button", { name: "Apply", exact: true }).click();
await homePage.previewCommand("再開地点:資料の2ページ目から");
await homePage.applyAction.click();
await expect(brief).toContainText("資料の2ページ目から");
});
test("keeps completed actions in their original positions with visible outcomes", async ({
page,
a11y,
homePage,
messagesPage,
workspacePage,
}, testInfo) => {
await page.goto("/");
await homePage.goTo();
await page.waitForLoadState("networkidle");
const titles = page.locator("[data-testid='execution-flow-title']");
const titles = homePage.flowTitles;
const before = await titles.allTextContents();
await page.getByRole("button", { name: "Complete Review the documents", exact: true }).click();
await expect(
page.getByRole("button", { name: "Restore Review the documents", exact: true }),
).toHaveAttribute("aria-pressed", "true");
await expect(
page.getByRole("button", { name: "Review the documents Completed", exact: true }),
).toBeVisible();
await page.getByRole("link", { name: "Open conversation with Haruka Aoki" }).click();
await page.getByRole("button", { name: "Review reply", exact: true }).click();
await page
.getByRole("dialog", { name: "Review reply", exact: true })
.getByRole("button", { name: "Try sending" })
.click();
await page.getByRole("link", { name: "Home", exact: true }).first().click();
await expect(
page.getByRole("link", { name: "Open conversation with Haruka Aoki" }),
).toContainText("Reply recorded");
await page.getByRole("button", { name: /Record weight A quick check-in/ }).click();
await page.getByRole("spinbutton", { name: "Weight", exact: true }).fill("65.2");
await page.getByRole("button", { name: "Save measurement" }).click();
await expect(
page.getByRole("button", { name: /Record weight Recorded · 65.2 kg/ }),
).toBeVisible();
await homePage.completeTask("Review the documents").click();
await expect(homePage.restoreTask("Review the documents")).toHaveAttribute(
"aria-pressed",
"true",
);
await expect(homePage.completedTask("Review the documents")).toBeVisible();
await homePage.conversation("Haruka Aoki").click();
await messagesPage.reviewReply.click();
await messagesPage.trySending.click();
await workspacePage.navigateTo("Home");
await expect(homePage.conversation("Haruka Aoki")).toContainText("Reply recorded");
await homePage.recordMeasurement("65.2");
await expect(homePage.recordedWeight("65.2")).toBeVisible();
expect(await titles.allTextContents()).toEqual(before);
expect((await a11y().analyze()).violations).toEqual([]);
await page.screenshot({ path: testInfo.outputPath("completion-in-place.png") });
await page.getByRole("button", { name: "Restore Review the documents", exact: true }).click();
await expect(
page.getByRole("button", { name: "Complete Review the documents", exact: true }),
).toHaveAttribute("aria-pressed", "false");
await homePage.restoreTask("Review the documents").click();
await expect(homePage.completeTask("Review the documents")).toHaveAttribute(
"aria-pressed",
"false",
);
});