diff --git a/tests/runner-e2e/playwright-support.config.ts b/tests/runner-e2e/playwright-support.config.ts index 72cc2bfac65..0960467d8ce 100644 --- a/tests/runner-e2e/playwright-support.config.ts +++ b/tests/runner-e2e/playwright-support.config.ts @@ -3,7 +3,7 @@ import { defineConfig } from "@playwright/test"; /** Browser-only harness regressions: no Paperclip instance or provider credentials. */ export default defineConfig({ testDir: ".", - testMatch: ["question-resume-ui.spec.ts", "clarification-readback.spec.ts", "project-context-readback.spec.ts", "skill-studio-flow.spec.ts", "native-task-reply.spec.ts", "screenshot-readiness.spec.ts", "service-worker-reload.spec.ts", "lost-send.spec.ts", "chat-restart.spec.ts", "settings-toggle.spec.ts", "browser-bootstrap-diagnostics.spec.ts", "service-worker-module-loading.spec.ts", "browser-bootstrap-recovery.spec.ts", "blocker-input.spec.ts", "native-blocker-visible.spec.ts", "copilot-permission-card.spec.ts", "kimi-permission-card.spec.ts", "github-review-check.spec.ts", "antigravity-journey-browser.spec.ts", "task-search-filter.spec.ts"], + testMatch: ["question-resume-ui.spec.ts", "clarification-readback.spec.ts", "project-context-readback.spec.ts", "skill-studio-flow.spec.ts", "native-task-reply.spec.ts", "screenshot-readiness.spec.ts", "service-worker-reload.spec.ts", "lost-send.spec.ts", "chat-restart.spec.ts", "settings-toggle.spec.ts", "browser-bootstrap-diagnostics.spec.ts", "service-worker-module-loading.spec.ts", "browser-bootstrap-recovery.spec.ts", "blocker-input.spec.ts", "native-blocker-visible.spec.ts", "copilot-permission-card.spec.ts", "kimi-permission-card.spec.ts", "github-review-check.spec.ts", "antigravity-journey-browser.spec.ts", "task-search-filter.spec.ts", "task-document-navigation.spec.ts"], workers: 1, retries: 0, timeout: 10_000, diff --git a/tests/runner-e2e/product-journeys/task-document-flow.test.ts b/tests/runner-e2e/product-journeys/task-document-flow.test.ts index 0d28da0be36..21b546778ee 100644 --- a/tests/runner-e2e/product-journeys/task-document-flow.test.ts +++ b/tests/runner-e2e/product-journeys/task-document-flow.test.ts @@ -25,7 +25,7 @@ describe("task document reopen navigation", () => { expect(hasText).toBe(issue.title); return { first: () => ({ click }) }; } } - : { isVisible: async () => true }, + : { isVisible: async () => true, first: () => ({ isVisible: async () => true }) }, }, } as unknown as JourneyContext; await reopenTaskDocument(context, issue); diff --git a/tests/runner-e2e/product-journeys/task-document-flow.ts b/tests/runner-e2e/product-journeys/task-document-flow.ts index 29ea5491a7d..8e6327f68c2 100644 --- a/tests/runner-e2e/product-journeys/task-document-flow.ts +++ b/tests/runner-e2e/product-journeys/task-document-flow.ts @@ -4,13 +4,20 @@ import { JourneyError, type JourneyContext, type JourneyEvidence, type TargetSes async function openDocumentAuthoring({ page }: JourneyContext) { const create = page.getByRole("button", { name: "New document", exact: true }); - if (await create.isVisible()) return; const properties = page.getByRole("button", { name: /^(Show properties|Properties)$/ }).first(); - if (await properties.isVisible()) await properties.click(); const artifacts = page.getByRole("tab", { name: /^Artifacts/ }).first(); + const addTab = page.getByRole("button", { name: "Open a new tab", exact: true }); + const panelReady = async () => await create.isVisible() || await artifacts.isVisible() || await addTab.isVisible(); + await expect.poll(async () => await properties.isVisible() || await panelReady()).toBe(true); + if (await create.isVisible()) return; + if (await properties.isVisible()) { + await properties.click(); + await expect.poll(panelReady).toBe(true); + if (await create.isVisible()) return; + } if (await artifacts.isVisible()) await artifacts.click(); else { - await page.getByRole("button", { name: "Open a new tab", exact: true }).click(); + await addTab.click(); await page.getByRole("option", { name: /^Artifacts/ }).click(); } await expect(create).toBeVisible(); diff --git a/tests/runner-e2e/task-document-navigation.spec.ts b/tests/runner-e2e/task-document-navigation.spec.ts new file mode 100644 index 00000000000..8571290d779 --- /dev/null +++ b/tests/runner-e2e/task-document-navigation.spec.ts @@ -0,0 +1,42 @@ +import { expect, test } from "@playwright/test"; +import { reopenTaskDocument } from "./product-journeys/task-document-flow.js"; +import type { JourneyContext } from "./product-journeys/types.js"; + +for (const layout of ["collapsed", "artifacts", "launcher", "classic"] as const) { + test(`document reopen waits for the ${layout} task controls after reload`, async ({ page }) => { + const issue = { title: "Journey QA document navigation" }; + let taskLoads = 0; + await page.route("https://document-navigation.test/**", async route => { + if (new URL(route.request().url()).pathname.endsWith("/issues")) { + await route.fulfill({ contentType: "text/html", body: `${issue.title}` }); + return; + } + taskLoads++; + await route.fulfill({ contentType: "text/html", body: `
` }); + }); + const context = { page, api: { origin: "https://document-navigation.test" }, company: { issuePrefix: "QA" } } as JourneyContext; + await reopenTaskDocument(context, issue); + await expect(page.locator("#document-qa-note")).toHaveText("Saved revision two"); + expect(taskLoads).toBe(2); + }); +} + +test("document reopen fails when the task has no authoring controls", async ({ page }) => { + await page.route("https://document-navigation.test/**", async route => { + const list = new URL(route.request().url()).pathname.endsWith("/issues"); + await route.fulfill({ contentType: "text/html", body: list ? 'Journey QA document navigation' : '
Task without document permissions
' }); + }); + const context = { page, api: { origin: "https://document-navigation.test" }, company: { issuePrefix: "QA" } } as JourneyContext; + await expect(reopenTaskDocument(context, { title: "Journey QA document navigation" })).rejects.toThrow(); + await expect(page.getByRole("button", { name: "New document", exact: true })).toHaveCount(0); +});