Files
kandev/apps/web/e2e/tests/integrations/linear-import.spec.ts
T
João Salavisa 5936bb6808 test: add e2e coverage and mock backends for jira and linear integrations (#771)
* test: add e2e coverage and mock backends for jira and linear integrations

Adds in-memory MockClient + MockController for both integrations gated by
KANDEV_MOCK_{JIRA,LINEAR}=true, plus apiClient mock helpers and Playwright
specs covering settings and import flows.

Also fixes ValidatedPopover's TriggerButton silently dropping radix Slot's
onClick handler — the popover wouldn't open under any synthetic-click path
(including Playwright). Spreads `...rest` onto the inner Button.

Reworks the integration cleanup hook in test-base as an auto fixture so it
runs for every test using the imported `test` object, not just tests in the
fixture file itself.

* fix: address PR review feedback on jira/linear mocks and e2e specs

- Fix SetAuthResult docstrings: nil simulates an unconfigured state, not the default success.
- Drop unused JSON tags from doneTransitionCall and setStateCall (Go-only test fixtures).
- Track Linear issue insertion order so SearchIssues returns deterministic results instead of map-iteration shuffle.
- Document filterByJQL precedence at the SearchTickets call site so the all-hits-on-no-match fallback is visible.
- Wait for the post-save auth-health probe before forcing a failure in the seeded-failure tests, eliminating a goroutine race.
- Reorder authMethod precedence in setJiraConfig/setLinearConfig to put the spread first so 'caller wins' reads naturally.

---------

Co-authored-by: Kandev Agent <agent@kandev.dev>
2026-05-02 14:41:36 +01:00

71 lines
2.5 KiB
TypeScript

import { test, expect } from "../../fixtures/test-base";
import { KanbanPage } from "../../pages/kanban-page";
test.describe("Linear import bar", () => {
test.beforeEach(async ({ apiClient, seedData }) => {
await apiClient.setLinearConfig({
workspaceId: seedData.workspaceId,
secret: "lin_api_xxx",
});
await apiClient.waitForIntegrationAuthHealthy("linear", seedData.workspaceId);
});
test("pasting a known identifier fills the title and description", async ({
testPage,
apiClient,
}) => {
await apiClient.mockLinearAddIssues([
{
id: "issue-1",
identifier: "ENG-12",
title: "Add billing endpoint",
description: "Spec lives at notion://...",
url: "https://linear.app/mock-org/issue/ENG-12",
},
]);
const kanban = new KanbanPage(testPage);
await kanban.goto();
await kanban.createTaskButton.first().click();
await expect(testPage.getByTestId("create-task-dialog")).toBeVisible();
await testPage.getByTestId("linear-import-trigger").click();
await testPage.getByTestId("linear-import-input").fill("ENG-12");
await testPage.getByTestId("linear-import-submit").click();
await expect(testPage.getByTestId("task-title-input")).toHaveValue(
"[ENG-12] Add billing endpoint",
);
await expect(testPage.getByTestId("task-description-input")).toContainText(
"Spec lives at notion://",
);
});
test("invalid input shows the validation hint", async ({ testPage }) => {
const kanban = new KanbanPage(testPage);
await kanban.goto();
await kanban.createTaskButton.first().click();
await testPage.getByTestId("linear-import-trigger").click();
const submit = testPage.getByTestId("linear-import-submit");
await expect(submit).toBeDisabled();
await testPage.getByTestId("linear-import-input").fill("garbage");
await submit.click();
await expect(testPage.getByTestId("linear-import-error")).toContainText(
/Paste a Linear issue URL or identifier/i,
);
});
test("unknown identifier surfaces the backend error inline", async ({ testPage }) => {
const kanban = new KanbanPage(testPage);
await kanban.goto();
await kanban.createTaskButton.first().click();
await testPage.getByTestId("linear-import-trigger").click();
await testPage.getByTestId("linear-import-input").fill("NOPE-99");
await testPage.getByTestId("linear-import-submit").click();
await expect(testPage.getByTestId("linear-import-error")).toContainText(/NOPE-99/);
});
});