Files
kandev/apps/web/e2e/tests/task/mobile-create-task-agent-compatibility.spec.ts
Jonathan Marbutt 97140168d8 fix(web): keep a usable agent selected when the executor changes (#3388)
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Carlos Florencio <carlosmflorencio@gmail.com>
2026-09-05 17:42:06 +00:00

154 lines
6.2 KiB
TypeScript

import { expect, test } from "../../fixtures/test-base";
import { useRegularMode } from "../../helpers/regular-mode";
import { MobileKanbanPage } from "../../pages/mobile-kanban-page";
import { seedIncompatibleAgentScenario, seedLockedWorkflow } from "./agent-compatibility-helpers";
useRegularMode();
const MOBILE_WIDTH = 390;
test.describe("Task creation agent compatibility on mobile", () => {
// @covers AC-TASKS-TASK-CREATE-AGENT-COMPATIBILITY-001.5
// @covers AC-TASKS-TASK-CREATE-AGENT-COMPATIBILITY-001.9
test("shows the workflow-locked note and keeps the credentials link reachable", async ({
testPage,
apiClient,
backend,
seedData,
}) => {
await backend.restart({ KANDEV_MOCK_PROVIDERS: "codex-acp" });
const scenario = await seedIncompatibleAgentScenario(
apiClient,
testPage,
seedData.agentProfileId,
{
executor: "E2E Mobile Docker Locked Agent",
dockerProfile: "Mobile Docker Locked Auth",
compatibleProfile: "Mobile Codex Unlocked",
},
);
const workflow = await seedLockedWorkflow(
apiClient,
seedData.workspaceId,
seedData.workflowId,
"Mobile Locked Agent",
seedData.agentProfileId,
);
try {
await testPage.setViewportSize({ width: MOBILE_WIDTH, height: 844 });
const mobile = new MobileKanbanPage(testPage);
await mobile.goto();
await mobile.mobileFab.tap();
const dialog = testPage.getByTestId("create-task-dialog");
await expect(dialog).toBeVisible();
await expect(dialog.getByTestId("workflow-selector-trigger")).toContainText(
"Mobile Locked Agent",
);
await dialog.getByTestId("task-title-input").fill("Mobile locked agent task");
await dialog.getByTestId("task-description-input").fill("workflow-locked on a phone");
const executorSelector = dialog.getByTestId("executor-profile-selector");
await expect(executorSelector).toBeVisible();
await expect(executorSelector).toBeEnabled();
await executorSelector.tap();
const executorOption = testPage.getByRole("option", {
name: /Mobile Docker Locked Auth/i,
});
await expect(executorOption).toBeVisible();
await executorOption.tap();
await expect(executorSelector).toContainText("Mobile Docker Locked Auth");
const note = dialog.getByTestId("agent-profile-incompatible-note");
await expect(note).toBeVisible();
await expect(note).toContainText("Mobile Locked Agent");
await expect(note).toContainText(scenario.seedProfileName);
await expect(note).toContainText("Mobile Docker Locked Auth");
const link = dialog.getByRole("link", { name: "Configure credentials" });
await expect(link).toBeVisible();
await expect(link).toHaveAttribute("href", `/settings/executors/${scenario.dockerProfileId}`);
await expect(dialog.getByTestId("agent-profile-empty-state")).toHaveCount(0);
await expect(dialog.getByTestId("submit-start-agent")).toBeDisabled();
expect(
await testPage.evaluate(() => document.documentElement.scrollWidth),
).toBeLessThanOrEqual(MOBILE_WIDTH);
await link.tap();
await expect(testPage).toHaveURL(
new RegExp(`/settings/executors/${scenario.dockerProfileId}(?:\\?.*)?$`),
);
} finally {
await workflow.cleanup();
await scenario.cleanup();
await backend.restart();
}
});
// @covers AC-TASKS-TASK-CREATE-AGENT-COMPATIBILITY-001.1
// @covers AC-TASKS-TASK-CREATE-AGENT-COMPATIBILITY-001.2
// @covers AC-TASKS-TASK-CREATE-AGENT-COMPATIBILITY-001.6
// @covers AC-TASKS-TASK-CREATE-AGENT-COMPATIBILITY-001.9
test("replaces an incompatible selection on a phone", async ({
testPage,
apiClient,
backend,
seedData,
}) => {
await backend.restart({ KANDEV_MOCK_PROVIDERS: "codex-acp" });
const scenario = await seedIncompatibleAgentScenario(
apiClient,
testPage,
seedData.agentProfileId,
{
executor: "E2E Mobile Docker Replace Agent",
dockerProfile: "Mobile Docker Codex Only",
compatibleProfile: "Mobile Codex Compatible",
},
);
try {
await testPage.setViewportSize({ width: MOBILE_WIDTH, height: 844 });
const mobile = new MobileKanbanPage(testPage);
await mobile.goto();
await mobile.mobileFab.tap();
const dialog = testPage.getByTestId("create-task-dialog");
await expect(dialog).toBeVisible();
await dialog.getByTestId("task-title-input").fill("Mobile replacement task");
await dialog.getByTestId("task-description-input").fill("executor switch on a phone");
const agentSelector = dialog.getByTestId("agent-profile-selector");
if (!(await agentSelector.textContent())?.includes(scenario.seedProfileName)) {
await agentSelector.tap();
const seedOption = testPage
.getByRole("option", { name: new RegExp(scenario.seedProfileName) })
.first();
await expect(seedOption).toBeVisible();
await seedOption.tap();
}
await expect(agentSelector).toContainText(scenario.seedProfileName);
const executorSelector = dialog.getByTestId("executor-profile-selector");
await expect(executorSelector).toBeVisible();
await expect(executorSelector).toBeEnabled();
await executorSelector.tap();
const executorOption = testPage.getByRole("option", {
name: /Mobile Docker Codex Only/i,
});
await expect(executorOption).toBeVisible();
await executorOption.tap();
await expect(executorSelector).toContainText("Mobile Docker Codex Only");
await expect(agentSelector).toContainText(scenario.secondAgentDisplayName);
await expect(agentSelector).not.toContainText(scenario.seedProfileName);
await expect(dialog.getByTestId("agent-profile-empty-state")).toHaveCount(0);
await expect(dialog.getByTestId("agent-profile-incompatible-note")).toHaveCount(0);
await expect(dialog.getByTestId("submit-start-agent")).toBeEnabled();
expect(
await testPage.evaluate(() => document.documentElement.scrollWidth),
).toBeLessThanOrEqual(MOBILE_WIDTH);
} finally {
await scenario.cleanup();
await backend.restart();
}
});
});