Files
kandev/apps/web/e2e/tests/task/mobile-task-status-summary.spec.ts
T

133 lines
4.7 KiB
TypeScript

import { expect } from "@playwright/test";
import { test } from "../../fixtures/test-base";
import { SessionPage } from "../../pages/session-page";
const TARGET_TITLE = "Mobile inactive summary target";
test.describe("Mobile task status summary", () => {
test("keeps pending CI yellow in native task switcher status updates", async ({
testPage,
apiClient,
seedData,
prCapture,
}) => {
test.setTimeout(90_000);
const stepOptions = {
workflow_id: seedData.workflowId,
workflow_step_id: seedData.startStepId,
};
const navTask = await apiClient.seedTask(
seedData.workspaceId,
"Mobile summary navigation",
stepOptions,
);
const targetTask = await apiClient.seedTask(seedData.workspaceId, TARGET_TITLE, {
...stepOptions,
state: "IN_PROGRESS",
});
await apiClient.seedTaskSession(navTask.task_id, {
state: "WAITING_FOR_INPUT",
agentProfileId: seedData.agentProfileId,
});
const targetSession = await apiClient.seedTaskSession(targetTask.task_id, {
state: "WAITING_FOR_INPUT",
agentProfileId: seedData.agentProfileId,
});
await apiClient.mockGitHubAssociateTaskPR({
workspace_id: seedData.workspaceId,
task_id: targetTask.task_id,
owner: "kandev-e2e",
repo: "mobile-summary-fixtures",
pr_number: 43,
pr_url: "https://github.test/kandev-e2e/mobile-summary-fixtures/pull/43",
pr_title: "Mobile bounded summary fixture",
head_branch: "feature/mobile-summary",
base_branch: "main",
author_login: "e2e",
state: "open",
review_state: "approved",
checks_state: "pending",
mergeable_state: "blocked",
required_reviews: 1,
checks_total: 2,
checks_passing: 1,
});
await testPage.goto(`/t/${navTask.task_id}`);
const session = new SessionPage(testPage);
await session.waitForLoad();
await testPage.getByTestId("mobile-task-picker-trigger").click();
const sheet = testPage.getByRole("dialog");
const targetRow = sheet.getByTestId("sidebar-task-item").filter({
hasText: TARGET_TITLE,
});
await expect(targetRow).toBeVisible({ timeout: 15_000 });
await apiClient.seedTaskSession(targetTask.task_id, {
sessionId: targetSession.session_id,
state: "RUNNING",
});
const runningStatus = targetRow.getByTestId("task-state-running");
await expect(runningStatus).toBeVisible({ timeout: 15_000 });
await expect
.poll(async () =>
runningStatus.evaluate((element) => ({
tagName: element.tagName,
svgAnimated: element.querySelector("svg")?.classList.contains("animate-spin") ?? false,
})),
)
.toEqual({ tagName: "SPAN", svgAnimated: false });
await apiClient.seedSessionMessage(targetSession.session_id, {
type: "clarification_request",
content: "Choose a mobile-safe approach",
});
await expect(targetRow.getByTestId("task-state-waiting-for-input")).toBeVisible({
timeout: 15_000,
});
await apiClient.seedTaskSession(targetTask.task_id, {
sessionId: targetSession.session_id,
state: "WAITING_FOR_INPUT",
metadata: {
last_agent_error: {
message: "Mobile inactive agent failed",
occurred_at: new Date().toISOString(),
},
},
});
await expect(targetRow.getByTestId("task-agent-error-icon")).toBeVisible({ timeout: 15_000 });
const prIcon = targetRow.getByTestId(`pr-task-icon-${targetTask.task_id}`);
await expect(prIcon).toHaveAttribute("data-pr-state", "Open", { timeout: 15_000 });
await expect(prIcon).toHaveClass(/text-yellow-500/);
await prCapture.screenshot("mobile-task-switcher-pending-ci", {
caption: "Mobile task switcher keeps pending CI yellow after reload",
});
const viewport = testPage.viewportSize();
expect(viewport).not.toBeNull();
expect(
await testPage.evaluate(
() => document.documentElement.scrollWidth <= document.documentElement.clientWidth,
),
).toBe(true);
expect(viewport!.width).toBeGreaterThan(0);
// The passive PR icon must not steal the row's native touch target.
await targetRow.tap();
await expect(testPage).toHaveURL(new RegExp(`/t/${targetTask.task_id}$`));
await session.waitForLoad();
await expect(session.prStatusChip()).toBeVisible({ timeout: 15_000 });
await session.tapPRStatusChip();
const author = session.prStatusChipDrawer().getByTestId("pr-popover-author");
await expect(author).toBeInViewport({ ratio: 1 });
await expect(author).toHaveText("by e2e");
await prCapture.screenshot("mobile-task-status-summary-author", {
caption: "Mobile PR status drawer with the linked author identity",
});
});
});