mirror of
https://github.com/willchen96/mike.git
synced 2026-07-26 23:51:08 +02:00
fix(e2e): realign selectors with the olp UI and upstream route shape
upstream-main (olp's tip) ships the #215/#216 liquid-surfaces UI, so the same
selector drifts fixed on the fork's suite (commit 3d46814 on main) also apply
here. Ports those realigned hunks, plus one upstream-specific route fix.
* Chat input placeholder is "How can I help?", not
"Ask a question about your documents..." (ChatInput/TRChatInput). Updated in
chat-management (rename/delete/project-assistant) and critical-path.
* The project-assistant empty state replaced the "+ Create New" text link with
a PillButton reading "Create" (ProjectAssistantTable) — critical-path and
chat-management now use getByRole("button", { name: "Create" }).
* The sidebar chat row's active marker is APP_SURFACE_ACTIVE_CLASS
("bg-app-surface-active"), not "bg-gray-200/60"; the row wrapper is now h-8,
not h-9 (SidebarChatItem). The rename/delete tests locate the row accordingly.
* The documents-toolbar folder button is "Folder" (TabPillButton wired to the
root createFolderAction in ProjectDocumentsView), not "Add Subfolder"; it
still opens the autofocused "Folder name" root input.
* NewTRModal's footer submit and the tabular page CTA both read "Create", so
the create-review helper scopes to the modal submit
(button[name="modalAction"][value="create-review"]).
* The built-in workflow detail test navigated to the flat /workflows/[id],
which upstream does not route — only the typed /workflows/assistant/[id] and
/workflows/tabular-review/[id] exist. builtin-cp-checklist is assistant-type,
so it now navigates to /workflows/assistant/builtin-cp-checklist (the path
the app itself links to via workflowDetailPath; works on the fork too).
Verified: full 27-test suite green against upstream-main + test-harness +
demo-mode(+provider-registry), backend + local Supabase (upstream schema.sql +
backend/migrations) + MinIO, demo model, e2e@mike.local.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CEguyEgXa9JjCciXCcVemC
This commit is contained in:
parent
94987e6bd7
commit
ffad860ed6
5 changed files with 35 additions and 21 deletions
|
|
@ -124,7 +124,7 @@ test("rename chat: sidebar rename interaction updates the title", async ({ page
|
|||
|
||||
// ── Step 1: create a new chat ─────────────────────────────────────────────────
|
||||
await page.goto("/assistant");
|
||||
const textarea = page.getByPlaceholder("Ask a question about your documents...");
|
||||
const textarea = page.getByPlaceholder("How can I help?");
|
||||
await expect(textarea).toBeVisible({ timeout: 10_000 });
|
||||
// Pick the keyless demo model so the submit isn't blocked by the
|
||||
// ApiKeyMissingModal (no provider key is configured in this run).
|
||||
|
|
@ -155,13 +155,13 @@ test("rename chat: sidebar rename interaction updates the title", async ({ page
|
|||
|
||||
// ── Step 4: locate the active chat item ──────────────────────────────────────
|
||||
// SidebarChatItem.tsx renders a `div.group.relative` wrapper for each chat.
|
||||
// When isActive=true the wrapper class includes "bg-gray-200/60" as a
|
||||
// standalone Tailwind class. Inactive items have "hover:bg-gray-100" (a
|
||||
// different token), so matching the "bg-gray-200/60" class distinguishes the
|
||||
// active item. Use an attribute-substring match ([class*=]) to avoid having
|
||||
// to CSS-escape the "/" in the Tailwind class name.
|
||||
// When isActive=true the wrapper carries APP_SURFACE_ACTIVE_CLASS
|
||||
// ("bg-app-surface-active"); inactive items carry APP_SURFACE_HOVER_CLASS
|
||||
// ("hover:bg-app-surface-hover", a different token), so matching
|
||||
// "bg-app-surface-active" distinguishes the active item. (The olp liquid-
|
||||
// surface refresh renamed the old "bg-gray-200/60" active token.)
|
||||
const activeItem = page
|
||||
.locator('div.group.relative[class*="bg-gray-200/60"]')
|
||||
.locator('div.group.relative[class*="bg-app-surface-active"]')
|
||||
.first();
|
||||
|
||||
// The active item's trigger is already opacity-100, but hover is harmless and
|
||||
|
|
@ -214,7 +214,7 @@ test("delete chat: sidebar delete action removes the chat from history", async (
|
|||
|
||||
// ── Step 1: create a new chat ─────────────────────────────────────────────────
|
||||
await page.goto("/assistant");
|
||||
const textarea = page.getByPlaceholder("Ask a question about your documents...");
|
||||
const textarea = page.getByPlaceholder("How can I help?");
|
||||
await expect(textarea).toBeVisible({ timeout: 10_000 });
|
||||
// ── Step 2: create the chat, riding out transient gateway 502s ───────────────
|
||||
// ChatInput.handleSubmit creates the chat (saveChat → POST /chat/create) then
|
||||
|
|
@ -276,7 +276,7 @@ test("delete chat: sidebar delete action removes the chat from history", async (
|
|||
// just-created chat is active and prepended, so it is the first row; rename it
|
||||
// via the same three-dot menu the rename test exercises.
|
||||
const uniqueTitle = `Delete Target ${Date.now()}`;
|
||||
const firstRow = page.locator("div.group.relative.h-9.rounded-md").first();
|
||||
const firstRow = page.locator("div.group.relative.h-8.rounded-md").first();
|
||||
await firstRow.hover();
|
||||
await firstRow.locator("button").last().click();
|
||||
await page.getByRole("menuitem", { name: "Rename" }).click();
|
||||
|
|
@ -290,7 +290,7 @@ test("delete chat: sidebar delete action removes the chat from history", async (
|
|||
await expect(targetTitle).toBeVisible({ timeout: 10_000 });
|
||||
// The row wrapper that contains that title button (for reaching its menu).
|
||||
const targetRow = page
|
||||
.locator("div.group.relative.h-9.rounded-md")
|
||||
.locator("div.group.relative.h-8.rounded-md")
|
||||
.filter({ has: targetTitle });
|
||||
|
||||
// ── Step 5-7: delete that specific chat, riding out flaky Supabase 500s ──────
|
||||
|
|
@ -397,7 +397,9 @@ test("project assistant: create a new chat and submit a question", async ({ page
|
|||
// found". A genuinely broken assistant tab never shows the button on any
|
||||
// attempt, so the final assertion still fails.
|
||||
const assistantUrl = page.url() + "/assistant";
|
||||
const createNewBtn = page.getByText("+ Create New");
|
||||
// The olp UI replaced the old "+ Create New" text link with a PillButton
|
||||
// reading "Create" in the ProjectAssistantTable empty state.
|
||||
const createNewBtn = page.getByRole("button", { name: "Create", exact: true });
|
||||
const projectNotFound = page.getByText("Project not found");
|
||||
const TAB_ATTEMPTS = 4;
|
||||
for (let attempt = 0; attempt < TAB_ATTEMPTS; attempt++) {
|
||||
|
|
@ -452,7 +454,7 @@ test("project assistant: create a new chat and submit a question", async ({ page
|
|||
// ── Step 9: assert the ChatInput textarea is visible ─────────────────────────
|
||||
// ProjectAssistantChatPage renders <ChatInput> in the right "Project Assistant"
|
||||
// panel (line 1221-1229 of the chat page component).
|
||||
const chatInput = page.getByPlaceholder("Ask a question about your documents...");
|
||||
const chatInput = page.getByPlaceholder("How can I help?");
|
||||
await expect(chatInput).toBeVisible({ timeout: 10_000 });
|
||||
|
||||
// ── Step 10-11: pick an available model, submit a question, assert it clears ──
|
||||
|
|
|
|||
|
|
@ -143,9 +143,11 @@ test("create project, upload PDF, ask a question and receive a response", async
|
|||
the "Assistant" item in the sidebar nav. The workspace fetches
|
||||
getProject() on mount and does NOT retry, so under the local-Supabase load
|
||||
the page can land on a permanent "Project not found" or a slow skeleton;
|
||||
re-navigate until the assistant tab's "+ Create New" affordance renders. */
|
||||
re-navigate until the assistant tab's empty-state "Create" affordance
|
||||
renders. (The olp UI replaced the old "+ Create New" text link with a
|
||||
PillButton reading "Create" — ProjectAssistantTable empty state.) */
|
||||
const projectUrl = page.url().split("?")[0];
|
||||
const createNew = page.getByText("+ Create New");
|
||||
const createNew = page.getByRole("button", { name: "Create", exact: true });
|
||||
for (let attempt = 1; attempt <= 6; attempt++) {
|
||||
await page.goto(`${projectUrl}/assistant`);
|
||||
await page
|
||||
|
|
@ -163,9 +165,7 @@ test("create project, upload PDF, ask a question and receive a response", async
|
|||
await page.waitForLoadState("networkidle", { timeout: 20_000 }).catch(() => {});
|
||||
|
||||
/* ── Step 7: select the keyless demo model, type a question, submit ───── */
|
||||
const chatInput = page.getByPlaceholder(
|
||||
"Ask a question about your documents...",
|
||||
);
|
||||
const chatInput = page.getByPlaceholder("How can I help?");
|
||||
await expect(chatInput).toBeVisible({ timeout: 10_000 });
|
||||
|
||||
/* The default Gemini model has no key configured, so submitting it would be
|
||||
|
|
|
|||
|
|
@ -291,7 +291,11 @@ test("create a folder inside a project", async ({ page }) => {
|
|||
* "Add Subfolder") only appears once the project has loaded, so reload until
|
||||
* it does.
|
||||
*/
|
||||
const addSubfolderBtn = page.getByRole("button", { name: "Add Subfolder" });
|
||||
/* The olp UI renamed the documents-toolbar folder-create button from
|
||||
"Add Subfolder" to "Folder" (a TabPillButton wired to the root
|
||||
createFolderAction — ProjectDocumentsView). Clicking it still renders the
|
||||
autofocused "Folder name" input at root level (creatingIn === null). */
|
||||
const addSubfolderBtn = page.getByRole("button", { name: "Folder" });
|
||||
await waitForProjectLoaded(page, addSubfolderBtn);
|
||||
|
||||
/* Confirm the uploaded document rendered, i.e. the project is non-empty and
|
||||
|
|
|
|||
|
|
@ -133,7 +133,12 @@ async function createReview(
|
|||
const respP = page
|
||||
.waitForResponse(isCreateReviewPost, { timeout: 30_000 })
|
||||
.catch(() => null);
|
||||
await page.getByRole("button", { name: "Create", exact: true }).click();
|
||||
// The modal footer's submit button and the page's own "Create" CTA both
|
||||
// read "Create"; scope to the modal's submit (button[name="modalAction"]
|
||||
// value="create-review") to avoid a strict-mode ambiguity.
|
||||
await page
|
||||
.locator('button[name="modalAction"][value="create-review"]')
|
||||
.click();
|
||||
const resp = await respP;
|
||||
if (resp && resp.ok()) {
|
||||
review = (await resp.json()) as { id: string };
|
||||
|
|
|
|||
|
|
@ -134,8 +134,11 @@ test.describe("Workflows", () => {
|
|||
page,
|
||||
}) => {
|
||||
// Navigate directly to the known built-in ID; this avoids having to click
|
||||
// through the DisplayWorkflowModal "View Page" button.
|
||||
await page.goto("/workflows/builtin-cp-checklist");
|
||||
// through the DisplayWorkflowModal "View Page" button. builtin-cp-checklist
|
||||
// is an assistant-type workflow, so use the typed detail route
|
||||
// (/workflows/assistant/[id]) that the app itself links to via
|
||||
// workflowDetailPath — the flat /workflows/[id] path does not exist here.
|
||||
await page.goto("/workflows/assistant/builtin-cp-checklist");
|
||||
|
||||
// The page loads and shows the built-in workflow title
|
||||
await expect(page.getByText("Draft CP Checklist")).toBeVisible({
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue