133 lines
5.1 KiB
TypeScript
133 lines
5.1 KiB
TypeScript
import { test, expect } from "../../fixtures/test-base";
|
|
import { ChangeWorkflowPage } from "../../pages/change-workflow-page";
|
|
import {
|
|
allTaskActionOutcomes,
|
|
seedActionThreads,
|
|
seedLinkedIssue,
|
|
ThreadActionsPage,
|
|
withTaskActionSettings,
|
|
} from "./threads-task-actions-helpers";
|
|
import {
|
|
failedActionOutcomes,
|
|
filteredArchiveOutcome,
|
|
lateArchiveOutcome,
|
|
} from "./threads-task-actions-edge-helpers";
|
|
import { pendingArchiveRecovery, pendingLastArchive } from "./threads-pending-archive-helpers";
|
|
|
|
for (const [name, outcome] of [
|
|
["pending archive recovers without taking focus", pendingArchiveRecovery],
|
|
["pending last archive stays empty through settlement", pendingLastArchive],
|
|
] as const) {
|
|
test(name, async ({ testPage, apiClient, seedData }, testInfo) => {
|
|
test.setTimeout(120_000);
|
|
await withTaskActionSettings(apiClient, () =>
|
|
outcome(testPage, apiClient, seedData, false, testInfo),
|
|
);
|
|
});
|
|
}
|
|
|
|
for (const [name, outcome] of [
|
|
["failures and retry", failedActionOutcomes],
|
|
["late archive retains a newer menu", lateArchiveOutcome],
|
|
["filtered opener retains archive identity", filteredArchiveOutcome],
|
|
] as const) {
|
|
test(name, async ({ testPage, apiClient, seedData }) => {
|
|
test.setTimeout(120_000);
|
|
await withTaskActionSettings(apiClient, () => outcome(testPage, apiClient, seedData, false));
|
|
});
|
|
}
|
|
|
|
test("searches long desktop workflow steps in the change form", async ({
|
|
testPage,
|
|
apiClient,
|
|
seedData,
|
|
}, testInfo) => {
|
|
test.setTimeout(120_000);
|
|
const { a, destination } = await seedActionThreads(apiClient, seedData);
|
|
let finalStepId = "";
|
|
for (let index = 0; index < 30; index++) {
|
|
const step = await apiClient.createWorkflowStep(
|
|
destination.id,
|
|
`${index} ${"LongStep".repeat(20)}`,
|
|
index + 1,
|
|
);
|
|
if (index === 29) finalStepId = step.id;
|
|
}
|
|
await testPage.setViewportSize({ width: 900, height: 500 });
|
|
await testPage.goto(`/threads?workspace=${seedData.workspaceId}`);
|
|
const ui = new ThreadActionsPage(testPage);
|
|
await ui.open(a.id);
|
|
await ui.pick("Change workflow...");
|
|
const form = new ChangeWorkflowPage(testPage);
|
|
await expect(form.desktopDialog).toBeVisible();
|
|
await form.chooseWorkflow(destination.id);
|
|
await form.form.getByTestId("change-workflow-step").click();
|
|
const finalStep = testPage.locator(`[role="option"][data-value="${finalStepId}"]`);
|
|
await finalStep.scrollIntoViewIfNeeded();
|
|
await expect(finalStep).toBeVisible();
|
|
await expect(finalStep.locator("xpath=ancestor::*[@data-slot='popover-content']")).toHaveCSS(
|
|
"opacity",
|
|
"1",
|
|
);
|
|
expect(
|
|
await finalStep.evaluate((element) => {
|
|
const rect = element.getBoundingClientRect();
|
|
const topmost = document.elementFromPoint(rect.x + rect.width / 2, rect.y + rect.height / 2);
|
|
return topmost === element || element.contains(topmost);
|
|
}),
|
|
).toBe(true);
|
|
await testPage.screenshot({ path: testInfo.outputPath("desktop-change-workflow-long-step.png") });
|
|
await testPage.keyboard.press("Escape");
|
|
await form.form.getByTestId("change-workflow-cancel").click();
|
|
await expect(ui.trigger(a.id)).toBeFocused();
|
|
});
|
|
|
|
test("completes all six task actions from desktop Threads and cancels destructive choices", async ({
|
|
testPage,
|
|
apiClient,
|
|
seedData,
|
|
}) => {
|
|
test.setTimeout(240_000);
|
|
await seedLinkedIssue(apiClient);
|
|
try {
|
|
await allTaskActionOutcomes(testPage, apiClient, seedData, false);
|
|
} finally {
|
|
await apiClient.saveUserSettings({ confirm_task_archive: true });
|
|
}
|
|
});
|
|
|
|
// @covers AC-TASKS-THREADS-ACTIONS-003.6, AC-TASKS-THREADS-ACTIONS-004.1, AC-TASKS-THREADS-ACTIONS-004.6
|
|
test("keeps native chat context, supports header right-click and keyboard dismissal", async ({
|
|
testPage,
|
|
apiClient,
|
|
seedData,
|
|
}) => {
|
|
test.setTimeout(180_000);
|
|
const { a } = await seedActionThreads(apiClient, seedData);
|
|
const ui = new ThreadActionsPage(testPage);
|
|
await testPage.goto(`/threads?workspace=${seedData.workspaceId}&taskId=${a.id}`);
|
|
await ui.expectHeaderActionAlignment(a.id);
|
|
await ui.column(a.id).locator("header p").click({ button: "right" });
|
|
await expect(testPage.getByTestId("task-management-menu")).toBeVisible();
|
|
await testPage.keyboard.press("Escape");
|
|
await expect(ui.trigger(a.id)).toBeFocused();
|
|
await ui.trigger(a.id).press("Enter");
|
|
await testPage.getByTestId("task-context-priority").focus();
|
|
await testPage.keyboard.press("ArrowRight");
|
|
await expect(testPage.getByTestId("task-context-priority-low")).toBeVisible();
|
|
await testPage.keyboard.press("ArrowLeft");
|
|
await testPage.keyboard.press("Escape");
|
|
await expect(ui.trigger(a.id)).toBeFocused();
|
|
const editor = ui.column(a.id).locator(".tiptap.ProseMirror");
|
|
await editor.click({ button: "right" });
|
|
await expect(testPage.getByTestId("task-management-menu")).toHaveCount(0);
|
|
await editor.fill("Draft kept after task actions");
|
|
await ui.open(a.id);
|
|
await testPage.keyboard.press("Escape");
|
|
await expect(editor).toHaveText("Draft kept after task actions");
|
|
await ui.open(a.id);
|
|
await testPage.mouse.click(4, 4);
|
|
await expect(testPage.getByTestId("task-management-menu")).toHaveCount(0);
|
|
await expect(ui.trigger(a.id)).toBeFocused();
|
|
});
|