feat: publish shared task and reply activities through MCP

This commit is contained in:
2026-10-07 21:38:33 +09:00
parent 48ef396ec1
commit 794859e4a4
53 changed files with 4076 additions and 453 deletions
+142
View File
@@ -0,0 +1,142 @@
import { activityProposals, expect, test } from "../activity-fixtures";
import { ActivitiesPage } from "../models/ActivitiesPage";
test("shares published chores and reply activities with Home, Messages and MCP without losing user changes", async ({
page,
context,
homePage,
workspacePage,
messagesPage,
activitiesPage,
activityMcp,
}) => {
await homePage.goTo();
await expect(activitiesPage.card("buy-detergent")).toHaveCount(0);
expect((await activityMcp.context()).activities).toEqual([]);
await activityMcp.publish();
await expect(activitiesPage.card("buy-detergent")).toBeVisible();
await expect(activitiesPage.card("review-times")).toBeVisible();
await expect(activitiesPage.card("send-documents")).toBeVisible();
await activitiesPage.complete("Buy detergent").click();
await expect(activitiesPage.card("buy-detergent")).toHaveAttribute("data-status", "done");
await activitiesPage.openReply("review-times");
await expect(page).toHaveURL(/\/support\?.*activity=review-times/);
await expect(activitiesPage.details).toContainText(
"Read the review materials and choose two times",
);
await expect(activitiesPage.sources).toContainText(
"Please review the materials and suggest two times.",
);
await expect(activitiesPage.sources).toContainText("not the full conversation history");
await expect(activitiesPage.action("Send the completed documents")).toBeVisible();
const edited = "I checked the materials. Thursday at 14:00 works for me.";
await activitiesPage.saveReply(edited);
await expect
.poll(
async () =>
(await activityMcp.context()).activities.find((item) => item.id === "review-times")
?.userOverrides.draft,
)
.toBe(edited);
await activitiesPage.later.click();
await expect
.poll(
async () =>
(await activityMcp.context()).activities.find((item) => item.id === "review-times")
?.userState,
)
.toBe("deferred");
const before = await activityMcp.context();
expect(before.activities.find((item) => item.id === "send-documents")?.userState).toBe(
"available",
);
const refreshed = activityProposals.map((proposal) =>
proposal.kind === "reply"
? { ...proposal, reply: { ...proposal.reply, draft: "A newer agent suggestion" } }
: proposal,
);
await activityMcp.publish(refreshed);
const after = await activityMcp.context();
expect(after.activities).toHaveLength(3);
expect(after.activities.find((item) => item.id === "review-times")).toMatchObject({
userState: "deferred",
userOverrides: { draft: edited },
effective: { reply: { draft: edited } },
proposal: { reply: { draft: "A newer agent suggestion" } },
});
expect(after.activities.find((item) => item.id === "buy-detergent")?.userState).toBe("completed");
await page.reload();
await expect(activitiesPage.draft).toHaveValue(edited);
await expect(
activitiesPage.details.getByRole("button", {
name: /^(Send|Mark complete|Try sending)$/,
exact: true,
}),
).toHaveCount(0);
await activitiesPage.action("Send the completed documents").click();
await expect(activitiesPage.draft).toHaveValue("A newer agent suggestion");
await messagesPage.showConversationList();
await workspacePage.navigateTo("Home");
await expect(activitiesPage.card("review-times")).toContainText("Set aside");
const device = await context.newPage();
try {
const other = new ActivitiesPage(device);
await device.goto("/");
await expect(other.card("buy-detergent")).toHaveAttribute("data-status", "done");
await activityMcp.publish([
{
id: "later-chore",
kind: "task",
title: "Take the recycling out",
nextAction: "Bring the paper bag downstairs",
sources: [],
},
]);
await expect(activitiesPage.card("later-chore")).toBeVisible();
await expect(other.card("later-chore")).toBeVisible();
await device.reload();
await expect(other.card("later-chore")).toBeVisible();
} finally {
await device.close();
}
});
test("retries publication without duplicates and rejects invalid batches without partial writes", async ({
activityMcp,
}) => {
const input = {
requestId: "stable-publication",
expectedRevision: 0,
activities: activityProposals,
};
const receipt = await activityMcp.tool("publish_activities", input);
expect(receipt.ok).toBe(true);
expect(await activityMcp.tool("publish_activities", input)).toEqual(receipt);
expect(
await activityMcp.tool("publish_activities", { ...input, requestId: "stale" }),
).toMatchObject({ ok: false, error: { code: "revision-conflict" } });
const snapshot = await activityMcp.context();
expect(
await activityMcp.tool("publish_activities", {
requestId: "invalid",
expectedRevision: snapshot.revision,
activities: [
{
id: "valid-sibling",
kind: "task",
title: "Valid sibling",
nextAction: "Do the chore",
sources: [],
},
{
id: "invalid-sibling",
kind: "reply",
title: "Missing reply target",
nextAction: "Check",
sources: [],
},
],
}),
).toMatchObject({ ok: false, error: { code: "invalid-input" } });
expect(await activityMcp.context()).toEqual(snapshot);
});
+4 -4
View File
@@ -14,7 +14,7 @@ test("creates the owner once and enters onboarding with a real session", async (
db.$client.close();
await context.clearCookies();
await homePage.goTo();
await page.waitForLoadState("networkidle");
await expect(authPage.createAccountButton).toBeVisible();
await expect(page).toHaveURL(/\/setup$/);
expect((await a11y().analyze()).violations).toEqual([]);
await authPage.createAccount({
@@ -24,7 +24,7 @@ test("creates the owner once and enters onboarding with a real session", async (
setupCode: "isolated-e2e-setup-token-not-for-production",
});
await expect(page).toHaveURL(/\/onboarding$/);
await page.waitForLoadState("networkidle");
await expect(onboardingPage.continueButton).toBeEnabled();
await onboardingPage.complete();
await expect(homePage.greeting("Yuta")).toBeVisible();
});
@@ -70,7 +70,7 @@ test("signs in and revokes the session on sign out", async ({
await authPage.password.fill("E2E-only-passphrase-2026");
await authPage.signInButton.click();
await expect(page).toHaveURL("/");
await page.waitForLoadState("networkidle");
await expect(workspacePage.manageAccounts).toBeVisible();
const token = (await context.cookies()).find((cookie) => cookie.name === "workspace_session");
expect(token?.httpOnly).toBe(true);
expect(token?.sameSite).toBe("Lax");
@@ -99,7 +99,7 @@ test("requires onboarding and remembers its completion and name", async ({
try {
expect((await request.get("/api/research/events")).status()).toBe(403);
await homePage.goTo();
await page.waitForLoadState("networkidle");
await expect(onboardingPage.name).toBeVisible();
await expect(page).toHaveURL(/\/onboarding$/);
expect((await a11y().analyze()).violations).toEqual([]);
await onboardingPage.name.fill("Yuta Test");
+58 -69
View File
@@ -1,4 +1,8 @@
import { expect, test } from "../fixtures";
import { expect, test } from "../activity-fixtures";
test.beforeEach(async ({ activityMcp }) => {
await activityMcp.publish();
});
test("executes routine steps and records a measurement in the shared journal", async ({
page,
@@ -8,7 +12,7 @@ test("executes routine steps and records a measurement in the shared journal", a
workspacePage,
}, testInfo) => {
await homePage.goTo();
await page.waitForLoadState("networkidle");
await page.waitForLoadState("domcontentloaded");
await homePage.morningRoutine.click();
await expect(page).toHaveURL(/activity=task/);
await homePage.routineStep(/Drink water/).check();
@@ -30,15 +34,16 @@ test("shows the day flow and conversation context at desktop width", async ({
page,
homePage,
messagesPage,
activitiesPage,
}, testInfo) => {
await page.setViewportSize({ width: 1440, height: 1080 });
await homePage.goTo();
await page.waitForLoadState("networkidle");
await page.waitForLoadState("domcontentloaded");
await expect(homePage.todayPlan).toBeVisible();
await page.screenshot({ path: testInfo.outputPath("home-desktop.png") });
await messagesPage.goTo("?conversation=design-review");
await page.waitForLoadState("networkidle");
await expect(messagesPage.reply).toBeVisible();
await messagesPage.goTo("?activity=review-times&view=all");
await page.waitForLoadState("domcontentloaded");
await expect(activitiesPage.draft).toBeVisible();
await page.screenshot({ path: testInfo.outputPath("messages-desktop.png") });
});
@@ -49,7 +54,7 @@ test("previews a natural-language memo and shares the executed record with journ
workspacePage,
}) => {
await homePage.goTo();
await page.waitForLoadState("networkidle");
await page.waitForLoadState("domcontentloaded");
const memo = "明日のレビューは導線から確認する";
await homePage.previewCommand(`Note: ${memo}`);
const execute = homePage.applyAction;
@@ -63,7 +68,7 @@ test("previews a natural-language memo and shares the executed record with journ
test("keeps the home usable on narrow screens", async ({ page, a11y, homePage }, testInfo) => {
await homePage.goTo();
await page.waitForLoadState("networkidle");
await page.waitForLoadState("domcontentloaded");
for (const width of [320, 375, 414, 768]) {
await page.setViewportSize({ width, height: 850 });
await expect(homePage.input).toBeVisible();
@@ -73,80 +78,77 @@ test("keeps the home usable on narrow screens", async ({ page, a11y, homePage },
}
});
test("adds tasks only after confirmation and can defer and restore them", async ({
test("adds tasks only after confirmation and persists their deferred and completed state", async ({
page,
homePage,
activitiesPage,
activityMcp,
}) => {
await homePage.goTo();
await page.waitForLoadState("networkidle");
const complete = homePage.completeTask("grocery shopping");
const complete = activitiesPage.complete("grocery shopping");
await homePage.previewCommand("Add grocery shopping");
await expect(complete).toHaveCount(0);
await homePage.applyAction.click();
await expect(complete).toBeVisible();
await homePage.previewCommand("Defer grocery shopping");
await expect(complete).toBeVisible();
await homePage.applyAction.click();
await expect(complete).toHaveCount(0);
await homePage.restoreTask("grocery shopping").click();
await expect
.poll(
async () =>
(await activityMcp.context()).activities.find(
(item) => item.effective.title === "grocery shopping",
)?.userState,
)
.toBe("deferred");
await page.reload();
await complete.click();
await expect(complete).toHaveCount(0);
await expect(homePage.restoreTask("grocery shopping")).toBeVisible();
await expect(activitiesPage.restore("grocery shopping")).toBeVisible();
});
test("opens a conversation page from home and retains outcomes on return", async ({
test("opens a reply activity from home and retains its state through history and reload", async ({
page,
a11y,
homePage,
messagesPage,
workspacePage,
activitiesPage,
}) => {
await homePage.goTo();
await page.waitForLoadState("networkidle");
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(messagesPage.dialogs).toHaveCount(0);
await expect(messagesPage.reply).toBeVisible();
await activitiesPage.openReply("review-times");
await expect(page).toHaveURL(/activity=review-times/);
await expect(activitiesPage.draft).toBeVisible();
expect((await a11y().analyze()).violations).toEqual([]);
await page.goBack();
await expect(conversationLink).toBeVisible();
await expect(activitiesPage.card("review-times")).toBeVisible();
await page.goForward();
await expect(messagesPage.reply).toBeVisible();
await expect(activitiesPage.draft).toBeVisible();
await page.reload();
await page.waitForLoadState("networkidle");
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(messagesPage.moveToInbox).toBeVisible();
await messagesPage.moveToInbox.click();
await expect(activitiesPage.draft).toBeVisible();
await activitiesPage.later.click();
await messagesPage.showConversationList();
await workspacePage.navigateTo("Home");
await expect(conversationLink).toBeVisible();
await expect(activitiesPage.card("review-times")).toContainText("Set aside");
await activitiesPage.openReply("review-times");
await activitiesPage.bringBack.click();
await expect(activitiesPage.later).toBeVisible();
});
test("updates the prose brief as priorities change and opens the referenced conversation", async ({
page,
test("updates the prose brief as activities change and opens the referenced reply", async ({
homePage,
messagesPage,
workspacePage,
activitiesPage,
}) => {
await homePage.goTo();
await page.waitForLoadState("networkidle");
const brief = homePage.dailyBrief;
await expect(brief).toContainText("Review the documents");
await expect(brief).toContainText("3 conversations");
await homePage.completeTask("Review the documents").click();
await expect(brief).not.toContainText("Review the documents");
await homePage.openBriefConversation("Haruka Aoki");
await messagesPage.leaveForLater.click();
await expect(brief).toContainText("Buy detergent");
await activitiesPage.complete("Buy detergent").click();
await expect(brief).not.toContainText("Buy detergent");
await brief.getByRole("button", { name: "Propose review times", exact: true }).click();
await activitiesPage.later.click();
await messagesPage.showConversationList();
await workspacePage.navigateTo("Home");
await expect(brief).toContainText("2 conversations");
await expect(brief).not.toContainText("Haruka Aoki");
await expect(brief).not.toContainText("Propose review times");
await homePage.previewCommand("再開地点:資料の2ページ目から");
await homePage.applyAction.click();
await expect(brief).toContainText("資料の2ページ目から");
@@ -156,32 +158,19 @@ test("keeps completed actions in their original positions with visible outcomes"
page,
a11y,
homePage,
messagesPage,
workspacePage,
activitiesPage,
}, testInfo) => {
await homePage.goTo();
await page.waitForLoadState("networkidle");
const titles = homePage.flowTitles;
const before = await titles.allTextContents();
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 expect(activitiesPage.card("send-documents")).toBeVisible();
const before = await homePage.flowTitles.allTextContents();
await activitiesPage.complete("Buy detergent").click();
await expect(activitiesPage.restore("Buy detergent")).toHaveAttribute("aria-pressed", "true");
await expect(activitiesPage.card("buy-detergent")).toContainText("Completed");
await homePage.recordMeasurement("65.2");
await expect(homePage.recordedWeight("65.2")).toBeVisible();
expect(await titles.allTextContents()).toEqual(before);
expect(await homePage.flowTitles.allTextContents()).toEqual(before);
expect((await a11y().analyze()).violations).toEqual([]);
await page.screenshot({ path: testInfo.outputPath("completion-in-place.png") });
await homePage.restoreTask("Review the documents").click();
await expect(homePage.completeTask("Review the documents")).toHaveAttribute(
"aria-pressed",
"false",
);
await activitiesPage.restore("Buy detergent").click();
await expect(activitiesPage.complete("Buy detergent")).toHaveAttribute("aria-pressed", "false");
});
+49 -51
View File
@@ -1,71 +1,68 @@
import { expect, test } from "../fixtures";
import { expect, test } from "../activity-fixtures";
const reviewSubject = "Schedule next week’s design review";
const coffeeSubject = "Catch up over coffee";
test.beforeEach(async ({ activityMcp }) => {
await activityMcp.publish();
});
test("reviews an edited reply and keeps the simulated result in history", async ({
test("saves an edited reply without recording a simulated send", async ({
page,
a11y,
messagesPage,
activitiesPage,
activityMcp,
}) => {
await messagesPage.goTo();
await page.waitForLoadState("networkidle");
const rows = messagesPage.rows;
await expect(rows).toHaveCount(3);
await messagesPage.conversation(reviewSubject).click();
await messagesPage.chooseReplySuggestion(/^Polite/);
const reply = messagesPage.reply;
await expect(reply).toHaveValue(/Thank you for sharing/);
await messagesPage.goTo("?activity=review-times&view=all");
const edited = "I reviewed the materials. Let’s discuss the first-time experience.";
await reply.fill(edited);
const slot = "Mon, Oct 5, 14:00–14:30";
await messagesPage.addSuggestedTime(slot);
await expect(reply).toHaveValue(`${edited}\n\nWould ${slot} work for you?`);
await messagesPage.reviewReply.click();
const dialog = messagesPage.reviewDialog;
await expect(dialog).toContainText(edited);
await expect(dialog).toContainText(slot);
await expect(dialog).toContainText("No message will be sent");
await activitiesPage.saveReply(edited);
await expect(page.getByRole("status").filter({ hasText: "Draft saved" })).toBeVisible();
await expect(activitiesPage.details).toContainText("Sending messages is not connected yet.");
await expect(
activitiesPage.details.getByRole("button", { name: "Mark complete", exact: true }),
).toHaveCount(0);
await page.reload();
await expect(activitiesPage.draft).toHaveValue(edited);
const activity = (await activityMcp.context()).activities.find(
(item) => item.id === "review-times",
);
expect(activity).toMatchObject({ userState: "available", userOverrides: { draft: edited } });
expect((await a11y().analyze()).violations).toEqual([]);
await messagesPage.editReply.click();
await expect(reply).toHaveValue(new RegExp(edited));
await messagesPage.reviewReply.click();
await messagesPage.trySending.click();
await expect(dialog).toHaveCount(0);
await expect(messagesPage.conversation(reviewSubject)).toHaveCount(0);
await messagesPage.selectView("Archive");
await messagesPage.conversation(reviewSubject).click();
await expect(messagesPage.outcome).toContainText(edited);
await expect(messagesPage.outcome).toContainText(slot);
});
test("defers a conversation and restores it to the current queue", async ({
page,
test("defers one reply while keeping another action in the same conversation available", async ({
messagesPage,
activitiesPage,
activityMcp,
}) => {
await messagesPage.goTo();
await page.waitForLoadState("networkidle");
await messagesPage.conversation(coffeeSubject).click();
await expect(messagesPage.conversation(coffeeSubject)).toHaveAttribute("aria-current", "true");
await messagesPage.reply.fill("土曜の予定を確認してから返事するね。");
await messagesPage.leaveForLater.click();
await expect(messagesPage.conversation(coffeeSubject)).toHaveCount(0);
await messagesPage.selectView("Set aside");
await messagesPage.conversation(coffeeSubject).click();
await expect(messagesPage.reply).toHaveValue("土曜の予定を確認してから返事するね。");
await messagesPage.moveToInbox.click();
await messagesPage.showConversationList();
await expect(messagesPage.conversation(coffeeSubject)).toBeVisible();
await expect(messagesPage.inbox).toHaveAttribute("aria-pressed", "true");
await messagesPage.goTo("?activity=review-times&view=all");
await activitiesPage.saveReply("土曜の予定を確認してから返事するね。");
await expect(activitiesPage.useProposedDraft).toBeVisible();
await activitiesPage.later.click();
await expect(activitiesPage.bringBack).toBeVisible();
await activitiesPage.action("Send the completed documents").click();
await expect(activitiesPage.details).toContainText("Ready when you are");
const snapshot = await activityMcp.context();
expect(snapshot.activities.find((item) => item.id === "review-times")?.userState).toBe(
"deferred",
);
expect(snapshot.activities.find((item) => item.id === "send-documents")?.userState).toBe(
"available",
);
await activitiesPage.action("Propose review times").click();
await expect(activitiesPage.draft).toHaveValue("土曜の予定を確認してから返事するね。");
await activitiesPage.bringBack.click();
await expect(activitiesPage.later).toBeVisible();
});
test("keeps corrections as new records and summarizes only selected current facts", async ({
page,
a11y,
journalPage,
homePage,
workspacePage,
}) => {
await journalPage.goTo();
await page.waitForLoadState("networkidle");
await homePage.goTo();
await workspacePage.navigateTo("Journal");
await page.waitForLoadState("domcontentloaded");
await expect(journalPage.saveEntry).toBeDisabled();
await journalPage.entryText.fill("次はレビュー資料の導線を確認する");
await journalPage.saveEntry.click();
@@ -97,16 +94,17 @@ test("fits communication and journal interactions in narrow screens", async ({
page,
a11y,
messagesPage,
activitiesPage,
journalPage,
workspacePage,
}, testInfo) => {
for (const width of [320, 375, 414, 768]) {
await page.setViewportSize({ width, height: 850 });
await messagesPage.goTo();
await page.waitForLoadState("networkidle");
await page.waitForLoadState("domcontentloaded");
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBe(width);
await messagesPage.rows.first().click();
await expect(messagesPage.reply).toBeVisible();
await expect(activitiesPage.draft).toBeVisible();
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBe(width);
if (width === 320) expect((await a11y().analyze()).violations).toEqual([]);
await page.screenshot({ path: testInfo.outputPath(`messages-${width}.png`) });
+21 -11
View File
@@ -1,4 +1,14 @@
import { expect, test } from "../fixtures";
import type { Page } from "@playwright/test";
import { expect, test } from "../activity-fixtures";
import { waitForWorkspaceHydration } from "../models/ready";
async function reloadHydrated(page: Page) {
await Promise.all([waitForWorkspaceHydration(page), page.reload()]);
}
test.beforeEach(async ({ activityMcp }) => {
await activityMcp.publish();
});
test("restores article selection with browser history and reload", async ({ page, readerPage }) => {
await readerPage.goTo();
@@ -8,7 +18,7 @@ test("restores article selection with browser history and reload", async ({ page
await expect(readerPage.articleTitle).toHaveText(heading);
const selectedUrl = page.url();
expect(new URL(selectedUrl).searchParams.get("article")).toBeTruthy();
await page.reload({ waitUntil: "networkidle" });
await reloadHydrated(page);
await expect(readerPage.articleTitle).toHaveText(heading ?? "");
await page.goBack();
await expect(readerPage.workspace).toHaveAttribute("data-reading", "false");
@@ -24,14 +34,14 @@ test("restores search and replaces typing history", async ({
workspacePage,
}) => {
await homePage.goTo();
await page.waitForLoadState("networkidle");
await page.waitForLoadState("domcontentloaded");
await workspacePage.navigateTo("Reader");
const search = readerPage.searchInput;
await search.pressSequentially("browser");
await expect(search).toHaveValue("browser");
await expect.poll(() => new URL(page.url()).searchParams.get("q")).toBe("browser");
const count = await readerPage.rows.count();
await page.reload({ waitUntil: "networkidle" });
await reloadHydrated(page);
await expect(search).toHaveValue("browser");
await expect(readerPage.rows).toHaveCount(count);
await page.goBack();
@@ -46,7 +56,7 @@ test("restores account dialog without losing underlying article", async ({
await readerPage.goTo();
await connectedAccounts.open();
await expect.poll(() => new URL(page.url()).searchParams.get("accounts")).toBe("true");
await page.reload({ waitUntil: "networkidle" });
await reloadHydrated(page);
await expect(connectedAccounts.dialog).toBeVisible();
await page.goBack();
await expect(connectedAccounts.dialog).toHaveCount(0);
@@ -56,16 +66,16 @@ test("restores account dialog without losing underlying article", async ({
test("restores a message view and conversation from its URL", async ({ page, messagesPage }) => {
await messagesPage.goTo();
await page.waitForLoadState("networkidle");
await page.waitForLoadState("domcontentloaded");
await messagesPage.selectView("All");
const row = messagesPage.rows.nth(1);
const heading = await messagesPage.rowName(1).innerText();
const row = messagesPage.rows.first();
const heading = await messagesPage.rowName(0).innerText();
await row.click();
await expect(messagesPage.toolbarName).toHaveText(heading);
const url = page.url();
expect(new URL(url).searchParams.get("view")).toBe("all");
expect(new URL(url).searchParams.get("conversation")).toBeTruthy();
await page.reload({ waitUntil: "networkidle" });
expect(new URL(url).searchParams.get("activity")).toBeTruthy();
await reloadHydrated(page);
await expect(messagesPage.toolbarName).toHaveText(heading ?? "");
await expect(messagesPage.workspace).toHaveAttribute("data-reading", "true");
});
@@ -84,7 +94,7 @@ test("debounces search and cancels pending input on history navigation", async (
messagesPage,
}) => {
await messagesPage.goTo();
await page.waitForLoadState("networkidle");
await page.waitForLoadState("domcontentloaded");
await messagesPage.selectView("All");
await expect(page).toHaveURL(/view=all/);
await page.clock.install();
+6 -15
View File
@@ -7,8 +7,7 @@ test("filters body systems and opens lab history", async ({ page, vitalsPage, a1
await vitalsPage.selectSystem("Cardiovascular");
await expect(vitalsPage.systems).toHaveCount(1);
await expect(page).toHaveURL(/vitalTab=Cardiovascular/);
await page.reload();
await page.waitForLoadState("networkidle");
await vitalsPage.reload();
await expect(vitalsPage.systems).toHaveCount(1);
await vitalsPage.openFirstSystem();
const dialog = vitalsPage.systemDialog("Cardiovascular");
@@ -21,8 +20,7 @@ test("filters body systems and opens lab history", async ({ page, vitalsPage, a1
await vitalsPage.showLabHistory();
await expect(vitalsPage.history).toContainText("Jul 28");
await expect(vitalsPage.history).toContainText("93");
await page.reload();
await page.waitForLoadState("networkidle");
await vitalsPage.reload();
await expect(vitalsPage.history).toContainText("Jul 28");
await vitalsPage.showSystems();
await vitalsPage.selectSystem("Overview");
@@ -30,25 +28,19 @@ test("filters body systems and opens lab history", async ({ page, vitalsPage, a1
expect((await a11y().analyze()).violations).toEqual([]);
});
test("explores environment charts and simulated climate controls", async ({
page,
vitalsPage,
a11y,
}) => {
test("explores environment charts and simulated climate controls", async ({ vitalsPage, a11y }) => {
await vitalsPage.goTo();
await vitalsPage.navigateTo("Environment");
await expect(vitalsPage.environmentHeading).toBeVisible();
await vitalsPage.selectTrendPeriod("7D");
await vitalsPage.selectTrendMetric("CO₂");
await expect(vitalsPage.trendChart("7D", "CO₂")).toBeVisible();
await page.reload();
await page.waitForLoadState("networkidle");
await vitalsPage.reload();
await expect(vitalsPage.trendChart("7D", "CO₂")).toBeVisible();
await vitalsPage.openMetric("Room temperature");
const dialog = vitalsPage.metricDialog("Room temperature");
await expect(dialog).toContainText("64.0");
await page.reload();
await page.waitForLoadState("networkidle");
await vitalsPage.reload();
await expect(dialog).toContainText("64.0");
await vitalsPage.closeMetric("Room temperature");
await vitalsPage.syncReadings();
@@ -63,8 +55,7 @@ test("explores environment charts and simulated climate controls", async ({
await expect(temperature).toHaveValue("69");
await vitalsPage.turnOffPurifier();
await expect(vitalsPage.purifierOffButton).toHaveAttribute("aria-pressed", "false");
await page.reload();
await page.waitForLoadState("networkidle");
await vitalsPage.reload();
await expect(temperature).toHaveValue("68");
await expect(vitalsPage.autoButton).toHaveAttribute("aria-pressed", "true");
await expect(vitalsPage.purifierOnButton).toHaveAttribute("aria-pressed", "true");