7326796df2
Co-authored-by: Kandev Agent <agent@kandev.dev> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
161 lines
6.5 KiB
TypeScript
161 lines
6.5 KiB
TypeScript
import { test, expect } from "../../fixtures/test-base";
|
|
import { GITLAB_PROJECT, seedGitLabReview } from "../../helpers/gitlab";
|
|
import {
|
|
assertLocatorWithinViewportX,
|
|
assertNoDocumentHorizontalOverflow,
|
|
} from "../../helpers/layout-assertions";
|
|
import { GitLabSettingsPage } from "../../pages/gitlab-settings-page";
|
|
import { KanbanPage } from "../../pages/kanban-page";
|
|
|
|
test.describe("GitLab watch controls", () => {
|
|
test("review watch dispatches exactly once and supports pause plus reset", async ({
|
|
testPage,
|
|
apiClient,
|
|
seedData,
|
|
}) => {
|
|
test.setTimeout(120_000);
|
|
await apiClient.configureGitLab(seedData.workspaceId);
|
|
const watch = await apiClient.createGitLabReviewWatch({
|
|
workspace_id: seedData.workspaceId,
|
|
workflow_id: seedData.workflowId,
|
|
workflow_step_id: seedData.startStepId,
|
|
agent_profile_id: seedData.agentProfileId,
|
|
executor_profile_id: seedData.worktreeExecutorProfileId,
|
|
projects: [{ path: GITLAB_PROJECT }],
|
|
});
|
|
await expect
|
|
.poll(async () => {
|
|
const response = await apiClient.rawRequest(
|
|
"GET",
|
|
`/api/v1/gitlab/watches/review?workspace_id=${encodeURIComponent(seedData.workspaceId)}`,
|
|
);
|
|
const body = (await response.json()) as {
|
|
watches: Array<{ id: string; last_polled_at?: string }>;
|
|
};
|
|
return body.watches.find((item) => item.id === watch.id)?.last_polled_at ?? null;
|
|
})
|
|
.not.toBeNull();
|
|
await seedGitLabReview(apiClient, seedData.workspaceId, 91, "Watch exact-once MR");
|
|
|
|
const settings = new GitLabSettingsPage(testPage);
|
|
await settings.goto(seedData.workspaceId);
|
|
const card = settings.reviewWatches;
|
|
const table = card.getByTestId("gitlab-watch-desktop-table");
|
|
await expect(table.getByText(GITLAB_PROJECT, { exact: true })).toBeVisible();
|
|
await assertLocatorWithinViewportX(card, "desktop review watches");
|
|
await assertNoDocumentHorizontalOverflow(testPage, "desktop review watch settings");
|
|
|
|
await table.getByRole("button", { name: "Check now" }).click();
|
|
await expect(testPage.getByText(/Found 1 matching merge request/)).toBeVisible();
|
|
const taskTitle = `[${GITLAB_PROJECT}!91] Watch exact-once MR`;
|
|
const kanban = new KanbanPage(testPage);
|
|
await kanban.goto();
|
|
await expect(kanban.taskCardByTitle(taskTitle)).toHaveCount(1, {
|
|
timeout: 20_000,
|
|
});
|
|
|
|
await settings.goto(seedData.workspaceId);
|
|
await table.getByRole("button", { name: "Check now" }).click();
|
|
await expect(
|
|
testPage.getByText("No new merge requests matched", { exact: true }),
|
|
).toBeVisible();
|
|
await kanban.goto();
|
|
await expect(kanban.taskCardByTitle(taskTitle)).toHaveCount(1);
|
|
|
|
await settings.goto(seedData.workspaceId);
|
|
await table.getByRole("button", { name: "Pause watch" }).click();
|
|
const save = testPage
|
|
.getByTestId("settings-floating-save")
|
|
.getByRole("button", { name: /save changes/i });
|
|
await expect(save).toBeEnabled();
|
|
await save.click();
|
|
await expect(table.getByText("Paused", { exact: true })).toBeVisible();
|
|
await expect(table.getByRole("button", { name: "Check now" })).toBeDisabled();
|
|
|
|
await table.getByRole("button", { name: "Enable watch" }).click();
|
|
await save.click();
|
|
await table.getByRole("button", { name: "Reset watch" }).click();
|
|
const reset = testPage.getByTestId("reset-watch-dialog");
|
|
await expect(reset).toBeVisible();
|
|
await expect(testPage.getByTestId("reset-watch-dialog-description")).toContainText(
|
|
/delete 1 task/i,
|
|
);
|
|
await testPage.getByTestId("reset-watch-dialog-confirm").click();
|
|
// Singular form: the toast is an i18next `_one`/`_other` plural, not "task(s)".
|
|
await expect(testPage.getByText(/Review watch reset; 1 task deleted/)).toBeVisible();
|
|
await kanban.goto();
|
|
await expect(kanban.taskCardByTitle(taskTitle)).toHaveCount(1, {
|
|
timeout: 20_000,
|
|
});
|
|
});
|
|
|
|
test("issue watch creates one visible task for a repeated match", async ({
|
|
testPage,
|
|
apiClient,
|
|
seedData,
|
|
}) => {
|
|
await apiClient.configureGitLab(seedData.workspaceId);
|
|
const now = new Date().toISOString();
|
|
const watch = await apiClient.createGitLabIssueWatch({
|
|
workspace_id: seedData.workspaceId,
|
|
workflow_id: seedData.workflowId,
|
|
workflow_step_id: seedData.startStepId,
|
|
agent_profile_id: seedData.agentProfileId,
|
|
executor_profile_id: seedData.worktreeExecutorProfileId,
|
|
projects: [{ path: GITLAB_PROJECT }],
|
|
});
|
|
await expect
|
|
.poll(async () => {
|
|
const response = await apiClient.rawRequest(
|
|
"GET",
|
|
`/api/v1/gitlab/watches/issue?workspace_id=${encodeURIComponent(seedData.workspaceId)}`,
|
|
);
|
|
const body = (await response.json()) as {
|
|
watches: Array<{ id: string; last_polled_at?: string }>;
|
|
};
|
|
return body.watches.find((item) => item.id === watch.id)?.last_polled_at ?? null;
|
|
})
|
|
.not.toBeNull();
|
|
await apiClient.mockGitLabAddIssues(seedData.workspaceId, GITLAB_PROJECT, [
|
|
{
|
|
id: 10_092,
|
|
iid: 92,
|
|
project_id: 101,
|
|
title: "Watch exact-once issue",
|
|
body: "Issue body",
|
|
url: `https://gitlab.com/${GITLAB_PROJECT}/-/issues/92`,
|
|
web_url: `https://gitlab.com/${GITLAB_PROJECT}/-/issues/92`,
|
|
state: "opened",
|
|
author_username: "reporter",
|
|
project_namespace: "platform",
|
|
project_path: GITLAB_PROJECT,
|
|
labels: ["bug"],
|
|
assignees: [],
|
|
created_at: now,
|
|
updated_at: now,
|
|
},
|
|
]);
|
|
|
|
const settings = new GitLabSettingsPage(testPage);
|
|
await settings.goto(seedData.workspaceId);
|
|
const card = settings.issueWatches;
|
|
const table = card.getByTestId("gitlab-watch-desktop-table");
|
|
await assertLocatorWithinViewportX(card, "desktop issue watches");
|
|
await table.getByRole("button", { name: "Check now" }).click();
|
|
await expect(testPage.getByText(/Found 1 matching issue/)).toBeVisible();
|
|
const taskTitle = `[${GITLAB_PROJECT}#92] Watch exact-once issue`;
|
|
const kanban = new KanbanPage(testPage);
|
|
await kanban.goto();
|
|
await expect(kanban.taskCardByTitle(taskTitle)).toHaveCount(1, {
|
|
timeout: 20_000,
|
|
});
|
|
|
|
await settings.goto(seedData.workspaceId);
|
|
await table.getByRole("button", { name: "Check now" }).click();
|
|
await expect(testPage.getByText("No new issues matched", { exact: true })).toBeVisible();
|
|
await kanban.goto();
|
|
await expect(kanban.taskCardByTitle(taskTitle)).toHaveCount(1);
|
|
await assertNoDocumentHorizontalOverflow(testPage, "desktop issue watch settings");
|
|
});
|
|
});
|