Files
buzz/desktop/tests/e2e/project-pr-review.spec.ts
cls 9dfa06ffee
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
feat: import Chinese-localized Buzz source snapshot
Signed-off-by: cls_宁波本机 <908705107@qq.com>
2026-08-13 18:34:25 +08:00

1384 lines
48 KiB
TypeScript

import { expect, test } from "@playwright/test";
import { waitForAnimations } from "../helpers/animations";
import { installMockBridge, TEST_IDENTITIES } from "../helpers/bridge";
const SHOTS = "test-results/project-pr-review";
const RECOVERY_SHOTS = "test-results/project-pr-conflict-recovery";
const REVIEWER_AGENT_PUBKEY = "a".repeat(64);
const DEFAULT_MOCK_PUBKEY = "deadbeef".repeat(8);
// The projects surface is a preview feature — opt in before the app mounts.
// Must run before installMockBridge so React reads the override on mount.
async function enableProjectsFeature(page: import("@playwright/test").Page) {
await page.addInitScript(() => {
window.localStorage.setItem(
"buzz-feature-overrides-v1",
JSON.stringify({ projects: true }),
);
});
}
async function openBuzzProject(page: import("@playwright/test").Page) {
await page.goto("/", { waitUntil: "domcontentloaded" });
await page.getByTestId("open-projects-view").click();
await page.getByTestId("projects-section-projects").click();
const projectEntry = page
.locator(
'[data-testid="project-card-buzz"], [data-testid="project-row-buzz"]',
)
.first();
await expect(projectEntry).toBeVisible({ timeout: 10_000 });
await projectEntry.click();
}
test("same-second request changes supersedes approval", async ({ page }) => {
await enableProjectsFeature(page);
await page.addInitScript(() => {
Date.now = () => 1_900_000_000_000;
});
await installMockBridge(page);
await openBuzzProject(page);
await page.getByRole("tab", { name: "Pull Request" }).click();
const aliceRow = page
.getByTestId("project-pull-request-row")
.filter({ hasText: "alice" })
.first();
await expect(aliceRow).toBeVisible({ timeout: 10_000 });
await aliceRow.getByRole("button", { name: /^#/ }).click();
await page.getByRole("button", { name: "Approve", exact: true }).click();
const approveDialog = page.getByRole("dialog", {
name: "Approve pull request",
});
await approveDialog
.getByRole("textbox", { name: "Approval summary" })
.fill("Approved at the fixed second.");
await approveDialog
.getByRole("button", { name: "Approve", exact: true })
.click();
await expect(page.getByText("Pull request approved.")).toBeVisible();
await expect(
page.getByRole("button", { name: "Approve", exact: true }),
).toHaveCount(0);
const commentComposer = page.getByTestId(
"project-pull-request-comment-composer",
);
await commentComposer
.getByRole("button", { name: "Comment", exact: true })
.click();
await page.getByRole("menuitemradio", { name: "Request changes" }).click();
await commentComposer
.locator('[contenteditable="true"]')
.fill("Changes requested at the same fixed second.");
await commentComposer.getByRole("button", { name: "Send message" }).click();
await expect(page.getByText("Changes requested.")).toBeVisible();
const [approvalEvent, changeRequestEvent] = await page.evaluate(() => {
const decisions =
window.__BUZZ_E2E_SIGNED_EVENTS__?.filter(
(event) =>
event.kind === 1 &&
event.tags.some(
(tag) =>
tag[0] === "t" &&
(tag[1] === "approval" || tag[1] === "changes-requested"),
),
) ?? [];
return [decisions.at(-2), decisions.at(-1)];
});
expect(approvalEvent?.tags).toContainEqual(["t", "approval"]);
expect(changeRequestEvent?.tags).toContainEqual(["t", "changes-requested"]);
expect(changeRequestEvent?.createdAt).toBeGreaterThan(
approvalEvent?.createdAt ?? 0,
);
});
test("PR creator/owner can toggle draft, request reviews, and approve", async ({
page,
}) => {
await enableProjectsFeature(page);
await page.addInitScript(() => {
window.__BUZZ_E2E_REJECT_PROJECT_EVENT_KINDS__ = [1631];
});
await installMockBridge(page);
await openBuzzProject(page);
await page.getByRole("tab", { name: "Pull Request" }).click();
const prRows = page.getByTestId("project-pull-request-row");
await expect(prRows.first()).toBeVisible({ timeout: 10_000 });
// Pick a PR authored by alice: the viewer is not the author, so the
// Approve button must be available alongside the owner status controls.
const aliceRow = prRows.filter({ hasText: "alice" }).first();
await expect(aliceRow).toBeVisible();
await aliceRow.getByRole("button", { name: /^#/ }).click();
const header = page.getByRole("heading", { level: 3 });
await expect(header.first()).toBeVisible();
const sourceChannelLink = page.getByRole("button", {
name: "Open author-claimed origin channel #general",
exact: true,
});
await expect(sourceChannelLink).toBeVisible();
// Owner viewing an open PR: draft toggle and both review decisions are offered.
const morePullRequestActions = page.getByRole("button", {
name: "More pull request actions",
});
const approve = page.getByRole("button", { name: "Approve", exact: true });
const commentComposer = page.getByTestId(
"project-pull-request-comment-composer",
);
const reviewMode = commentComposer.getByRole("button", {
name: "Comment",
exact: true,
});
await expect(morePullRequestActions).toBeVisible();
await expect(approve).toBeVisible();
await expect(reviewMode).toBeVisible();
// Request a review from bob via the centered reviewer dialog.
await page.getByRole("button", { name: "Add Reviewer", exact: true }).click();
await expect(
page.getByRole("dialog").getByRole("heading", { name: "Add reviewer" }),
).toBeVisible();
await waitForAnimations(page);
await page.screenshot({
fullPage: false,
path: `${SHOTS}/00-add-reviewer-dialog.png`,
});
await page.getByTestId("project-reviewer-search").fill("bob");
await page
.getByTestId(`project-reviewer-result-${TEST_IDENTITIES.bob.pubkey}`)
.evaluate((button) => {
button.click();
button.click();
});
await expect(page.getByText("Review requested.")).toBeVisible();
await expect
.poll(() =>
page.evaluate(
() =>
window.__BUZZ_E2E_SIGNED_EVENTS__?.filter(
(event) =>
event.kind === 1 &&
event.tags.some(
(tag) => tag[0] === "t" && tag[1] === "review-request",
),
).length ?? 0,
),
)
.toBe(1);
const reviewHistoryToggle = page.getByTestId(
"project-pull-request-review-history-toggle",
);
await expect(reviewHistoryToggle).toHaveAttribute("aria-expanded", "true");
await expect(
page.getByTestId("project-pull-request-timeline-row"),
).toHaveCount(1);
// The requested reviewer appears in the reviewers row and default timeline.
await expect(page.getByText("Requested a review from bob")).toBeVisible({
timeout: 10_000,
});
await waitForAnimations(page);
await page.screenshot({
fullPage: false,
path: `${SHOTS}/01-review-requested.png`,
});
await reviewMode.click();
await page.getByRole("menuitemradio", { name: "Request changes" }).click();
await commentComposer
.locator('[contenteditable="true"]')
.fill("Please handle the empty state before merging.");
await commentComposer.getByRole("button", { name: "Send message" }).click();
await expect(page.getByText("Changes requested.")).toBeVisible();
await expect(reviewMode).toHaveText("Comment");
await expect(
page.getByText("Please handle the empty state before merging."),
).toBeVisible();
await expect(
page
.getByTestId("project-pull-request-timeline-row")
.filter({ hasText: "requested changes" }),
).toBeVisible({ timeout: 10_000 });
await expect(
page.getByText("Changes requested", { exact: true }),
).toHaveCount(0);
const changeRequestEvent = await page.evaluate(() =>
window.__BUZZ_E2E_SIGNED_EVENTS__
?.filter(
(event) =>
event.kind === 1 &&
event.tags.some(
(tag) => tag[0] === "t" && tag[1] === "changes-requested",
),
)
.at(-1),
);
expect(changeRequestEvent?.content).toBe(
"Please handle the empty state before merging.",
);
expect(changeRequestEvent?.tags).toContainEqual(["c", expect.any(String)]);
const reviewDecisionEvents = await page.evaluate(
() =>
window.__BUZZ_E2E_SIGNED_EVENTS__?.filter(
(event) =>
event.kind === 1 &&
event.tags.some(
(tag) =>
tag[0] === "t" &&
(tag[1] === "approval" || tag[1] === "changes-requested"),
),
) ?? [],
);
expect(reviewDecisionEvents).toHaveLength(1);
await waitForAnimations(page);
await page.screenshot({
fullPage: false,
path: `${SHOTS}/05-changes-requested.png`,
});
const changeRequestRow = page
.getByTestId("project-pull-request-timeline-row")
.filter({ hasText: "requested changes" })
.first();
await changeRequestRow.getByRole("button").first().hover();
await expect(page.getByTestId("user-profile-popover")).toBeVisible();
await page.mouse.move(0, 0);
await expect(page.getByTestId("user-profile-popover")).toBeHidden();
await expect(reviewHistoryToggle).toContainText("Collapse review history");
const expandedReviewRows = page.getByTestId(
"project-pull-request-timeline-row",
);
await expect(expandedReviewRows).toHaveCount(2);
await expect(expandedReviewRows.nth(0)).toContainText(
"Requested a review from bob",
);
await expect(expandedReviewRows.nth(1)).toContainText("requested changes");
await expect(approve).toBeVisible();
await reviewHistoryToggle.click();
await expect(reviewHistoryToggle).toContainText("Show 2 earlier activities");
await expect(
page.getByTestId("project-pull-request-timeline-row"),
).toHaveCount(0);
await expect(changeRequestRow).toBeHidden();
// Replace the completed change request with an approval. Both decisions
// remain tied to the current commit and their timestamps preserve order.
await approve.click();
const approveDialog = page.getByRole("dialog", {
name: "Approve pull request",
});
await approveDialog
.getByRole("textbox", { name: "Approval summary" })
.fill("Ready to merge.");
await approveDialog
.getByRole("button", { name: "Approve", exact: true })
.click();
await expect(page.getByText("Pull request approved.")).toBeVisible();
await expect(
page.getByRole("button", { name: "Approve", exact: true }),
).toHaveCount(0);
await expect(page.getByText("Approved", { exact: true })).toHaveCount(0);
const approvalEvent = await page.evaluate(() =>
window.__BUZZ_E2E_SIGNED_EVENTS__
?.filter(
(event) =>
event.kind === 1 &&
event.tags.some((tag) => tag[0] === "t" && tag[1] === "approval"),
)
.at(-1),
);
expect(approvalEvent?.content).toBe("Ready to merge.");
expect(approvalEvent?.tags).toContainEqual(["c", expect.any(String)]);
expect(approvalEvent?.createdAt).toBeGreaterThan(
changeRequestEvent?.createdAt ?? 0,
);
await reviewHistoryToggle.click();
await expect(page.getByText("Ready to merge.")).toBeVisible({
timeout: 10_000,
});
await expect(
page.getByTestId("project-pull-request-timeline-row"),
).toHaveCount(3);
await waitForAnimations(page);
await page.screenshot({
fullPage: false,
path: `${SHOTS}/02-approved.png`,
});
// Histories over three entries show only the latest three until explicitly
// expanded. Collapsing the whole timeline preserves that inner choice.
await commentComposer
.locator('[contenteditable="true"]')
.fill("Remember the expanded history state.");
await commentComposer.getByRole("button", { name: "Send message" }).click();
await expect(page.getByText("Comment posted.")).toBeVisible();
const timelineRows = page.getByTestId("project-pull-request-timeline-row");
const earlierActivities = page.getByTestId(
"project-pull-request-earlier-activities",
);
await expect(timelineRows).toHaveCount(3);
await expect(earlierActivities).toContainText("Show 1 earlier activity");
await reviewHistoryToggle.click();
await expect(timelineRows).toHaveCount(0);
await reviewHistoryToggle.click();
await expect(timelineRows).toHaveCount(3);
await expect(earlierActivities).toBeVisible();
await earlierActivities.click();
await expect(timelineRows).toHaveCount(4);
await reviewHistoryToggle.click();
await expect(timelineRows).toHaveCount(0);
await reviewHistoryToggle.click();
await expect(timelineRows).toHaveCount(4);
await expect(earlierActivities).toHaveCount(0);
// Convert to draft: badge flips to Draft and the ready button appears.
await morePullRequestActions.click();
await page.getByRole("menuitem", { name: "Convert to draft" }).click();
await expect(page.getByText("Converted to draft.")).toBeVisible();
const readyForReview = page.getByRole("button", {
name: "Ready for review",
});
await expect(readyForReview).toBeVisible({ timeout: 10_000 });
await expect(morePullRequestActions).toBeVisible();
await waitForAnimations(page);
await page.screenshot({
fullPage: false,
path: `${SHOTS}/03-draft.png`,
});
// And back: Ready for review restores the Open state.
await readyForReview.click();
await expect(page.getByText("Marked as ready for review.")).toBeVisible();
await expect(morePullRequestActions).toBeVisible({ timeout: 10_000 });
// Closing is reversible, unlike merging: a closed PR can be reopened.
await morePullRequestActions.click();
const closePullRequest = page.getByRole("menuitem", {
name: "Close pull request",
});
await closePullRequest.click();
await expect(page.getByText("Pull request closed.")).toBeVisible();
const reopenPullRequest = page.getByRole("button", {
name: "Reopen pull request",
});
await expect(reopenPullRequest).toBeVisible({ timeout: 10_000 });
await expect(closePullRequest).toHaveCount(0);
await reopenPullRequest.click();
await expect(page.getByText("Pull request reopened.")).toBeVisible();
await expect(morePullRequestActions).toBeVisible({ timeout: 10_000 });
await page.getByRole("button", { name: "Merge", exact: true }).click();
await expect(page.getByTestId("merge-pull-request-confirm")).toBeVisible();
await page.getByTestId("merge-pull-request-confirm-button").click();
await expect(page.getByText("Merged feature into main.")).toBeVisible();
await expect
.poll(() =>
page.evaluate(
() =>
window.__BUZZ_E2E_SIGNED_EVENTS__?.filter(
(event) => event.kind === 1631,
).length ?? 0,
),
)
.toBe(1);
await expect(
page.getByRole("button", {
name: "Publish merged status",
exact: true,
}),
).toBeVisible();
await page
.getByRole("button", {
name: "Publish merged status",
exact: true,
})
.click();
await expect(
page.getByText("Published merged pull request status."),
).toBeVisible();
await expect
.poll(() =>
page.evaluate(
() =>
window.__BUZZ_E2E_SIGNED_EVENTS__?.filter(
(event) => event.kind === 1631,
).length ?? 0,
),
)
.toBe(1);
const mergedEvent = await page.evaluate(() =>
window.__BUZZ_E2E_SIGNED_EVENTS__
?.filter((event) => event.kind === 1631)
.at(-1),
);
expect(mergedEvent?.tags).toContainEqual([
"merge-commit",
"abcdef0123456789abcdef0123456789abcdef01",
]);
expect(mergedEvent?.tags.some((tag) => tag[0] === "e")).toBe(true);
const mergeCommandCount = await page.evaluate(
() =>
window.__BUZZ_E2E_COMMANDS__?.filter(
(command) => command === "merge_project_pull_request",
).length ?? 0,
);
expect(mergeCommandCount).toBe(1);
const mergePayload = await page.evaluate(() =>
window.__BUZZ_E2E_COMMAND_PAYLOADS__?.find(
(entry) => entry.command === "merge_project_pull_request",
),
);
expect(mergePayload?.payload).toMatchObject({
input: {
expectedCommit: expect.any(String),
sourceBranch: expect.any(String),
targetBranch: "main",
targetOwner: DEFAULT_MOCK_PUBKEY,
},
});
await sourceChannelLink.click();
await expect(page.getByTestId("chat-title")).toHaveText("general");
});
test("merge conflicts offer persistent terminal recovery", async ({ page }) => {
await enableProjectsFeature(page);
await installMockBridge(page);
await openBuzzProject(page);
await page.evaluate(() => {
window.__BUZZ_E2E_PROJECT_MERGE_ERROR__ = {
code: "merge_conflict",
message: "Pull request has merge conflicts.",
recovery: {
action: "open_terminal",
sourceBranch: "feature",
targetBranch: "main",
},
};
});
await page.getByRole("tab", { name: "Pull Request" }).click();
const aliceRow = page
.getByTestId("project-pull-request-row")
.filter({ hasText: "alice" })
.first();
await aliceRow.getByRole("button", { name: /^#/ }).click();
await page.getByRole("button", { name: "Merge", exact: true }).click();
await page.getByTestId("merge-pull-request-confirm-button").click();
const recovery = page.getByTestId("merge-conflict-recovery");
await expect(recovery).toBeVisible();
await expect(
recovery.getByRole("button", { name: "Copy commands" }),
).toBeDisabled();
await waitForAnimations(page);
await recovery.screenshot({
path: `${RECOVERY_SHOTS}/01-merge-conflict.png`,
});
await recovery.getByRole("button", { name: "Resolve in Terminal" }).click();
await expect(
page.getByText("Recovery commit fetched and terminal opened."),
).toBeVisible();
await expect(
page.getByText("Recovery commit fetched and terminal opened."),
).toBeHidden({ timeout: 10_000 });
await expect(recovery).toContainText("git switch 'main'");
await expect(recovery).toContainText("git merge 'refs/buzz/merge-recovery/");
await expect(
recovery.getByRole("button", { name: "Copy commands" }),
).toBeEnabled();
await waitForAnimations(page);
await recovery.screenshot({
path: `${RECOVERY_SHOTS}/02-merge-conflict-prepared.png`,
});
await expect
.poll(() =>
page.evaluate(
() =>
window.__BUZZ_E2E_COMMAND_PAYLOADS__?.find(
(entry) => entry.command === "open_project_merge_recovery_terminal",
) ?? null,
),
)
.toMatchObject({
command: "open_project_merge_recovery_terminal",
payload: {
input: {
expectedCommit: expect.any(String),
sourceBranch: "feature",
targetBranch: "main",
},
},
});
});
test("reviewer can leave a commit-scoped inline diff comment", async ({
page,
}) => {
await enableProjectsFeature(page);
await installMockBridge(page);
await openBuzzProject(page);
await page.getByRole("tab", { name: "Pull Request" }).click();
const aliceRow = page
.getByTestId("project-pull-request-row")
.filter({ hasText: "alice" })
.first();
await aliceRow.getByRole("button", { name: /^#/ }).click();
await page.getByRole("tab", { name: /Files changed/ }).click();
const diffLine = page
.getByTestId("project-diff-line")
.filter({ hasText: "function CommunityTabs({ selectedCommitHash })" });
await expect(diffLine).toBeVisible({ timeout: 10_000 });
await diffLine.hover();
await diffLine.getByTestId("project-diff-add-comment").click();
const composer = page.getByTestId("project-inline-comment-thread");
await composer
.locator("[contenteditable='true']")
.fill("Please add a type for this parameter.");
await composer.getByRole("button", { name: "Comment", exact: true }).click();
await page.getByRole("menuitemradio", { name: "Request changes" }).click();
await composer.getByRole("button", { name: "Send message" }).click();
await expect(page.getByText("Changes requested.")).toBeVisible();
await expect
.poll(() =>
page.evaluate(() =>
window.__BUZZ_E2E_SIGNED_EVENTS__?.find(
(event) => event.content === "Please add a type for this parameter.",
),
),
)
.not.toBeUndefined();
const inlineCommentEvent = await page.evaluate(() =>
window.__BUZZ_E2E_SIGNED_EVENTS__?.find(
(event) => event.content === "Please add a type for this parameter.",
),
);
expect(inlineCommentEvent?.tags).toContainEqual(["t", "inline-comment"]);
expect(inlineCommentEvent?.tags).toContainEqual(["t", "changes-requested"]);
expect(inlineCommentEvent?.tags).toContainEqual(["c", expect.any(String)]);
expect(inlineCommentEvent?.tags).toContainEqual([
"file",
"desktop/src/features/projects/ui/ProjectDetailScreen.tsx",
]);
expect(inlineCommentEvent?.tags).toContainEqual(["side", "new"]);
expect(inlineCommentEvent?.tags).toContainEqual(["line", "3"]);
await expect(page.getByTestId("project-inline-comment")).toContainText(
"Please add a type for this parameter.",
);
await page.getByRole("tab", { name: "Conversation" }).click();
await expect(
page.getByTestId("project-pull-request-review-history-toggle"),
).toHaveAttribute("aria-expanded", "true");
await expect(
page.getByText("Please add a type for this parameter."),
).toBeVisible();
await expect(
page.getByText("desktop/src/features/projects/ui/ProjectDetailScreen.tsx"),
).toBeVisible();
await waitForAnimations(page);
await page.screenshot({
fullPage: false,
path: `${SHOTS}/04-inline-comment.png`,
});
await page
.getByRole("button", {
name: "Open desktop/src/features/projects/ui/ProjectDetailScreen.tsx new line 3 in Files changed",
})
.click();
await expect(
page.getByRole("tab", { name: /Files changed/ }),
).toHaveAttribute("data-state", "active");
const focusedLine = page.getByTestId("project-diff-focused-line");
await expect(focusedLine).toBeVisible();
await expect(focusedLine).toHaveAttribute(
"data-path",
"desktop/src/features/projects/ui/ProjectDetailScreen.tsx",
);
await expect(focusedLine).toHaveAttribute("data-side", "new");
await expect(focusedLine).toHaveAttribute("data-line", "3");
await focusedLine.click();
await expect(page.getByTestId("project-diff-focused-line")).toHaveCount(0);
});
test("managed agent repository owner can merge", async ({ page }) => {
await enableProjectsFeature(page);
await page.addInitScript((owner) => {
window.__BUZZ_E2E_PROJECT_OWNER_OVERRIDE__ = owner;
}, TEST_IDENTITIES.alice.pubkey);
await installMockBridge(page, {
managedAgents: [
{
pubkey: TEST_IDENTITIES.alice.pubkey,
name: "Brain",
},
{
pubkey: REVIEWER_AGENT_PUBKEY,
name: "Reviewer Bot",
},
],
});
await openBuzzProject(page);
await page.getByRole("tab", { name: "Pull Request" }).click();
const agentRow = page
.getByTestId("project-pull-request-row")
.filter({ hasText: "Brain" })
.first();
await expect(agentRow).toBeVisible({ timeout: 10_000 });
await agentRow.getByRole("button", { name: /^#/ }).click();
await page.getByRole("button", { name: "Add Reviewer", exact: true }).click();
await page.getByTestId("project-reviewer-search").fill("Reviewer Bot");
await page
.getByTestId(`project-reviewer-result-${REVIEWER_AGENT_PUBKEY}`)
.click();
await expect(page.getByText("Review requested.")).toBeVisible();
const reviewRequestPayload = await page.evaluate(() =>
window.__BUZZ_E2E_COMMAND_PAYLOADS__?.find(
(entry) => entry.command === "sign_project_pull_request_review_request",
),
);
expect(reviewRequestPayload?.payload).toMatchObject({
input: {
reviewers: [REVIEWER_AGENT_PUBKEY],
targetOwner: TEST_IDENTITIES.alice.pubkey,
},
});
await page.getByRole("button", { name: "More pull request actions" }).click();
const closePullRequest = page.getByRole("menuitem", {
name: "Close pull request",
});
await expect(closePullRequest).toBeVisible();
await closePullRequest.click();
await expect(page.getByText("Pull request closed.")).toBeVisible();
await page.getByRole("button", { name: "Reopen pull request" }).click();
await expect(page.getByText("Pull request reopened.")).toBeVisible();
const statusPayloads = await page.evaluate(() =>
window.__BUZZ_E2E_COMMAND_PAYLOADS__?.filter(
(entry) => entry.command === "sign_project_pull_request_status",
),
);
expect(statusPayloads).toHaveLength(2);
expect(statusPayloads?.map((entry) => entry.payload)).toEqual([
expect.objectContaining({
input: expect.objectContaining({
status: "closed",
targetOwner: TEST_IDENTITIES.alice.pubkey,
}),
}),
expect.objectContaining({
input: expect.objectContaining({
status: "open",
targetOwner: TEST_IDENTITIES.alice.pubkey,
}),
}),
]);
await page.getByRole("button", { name: "Merge", exact: true }).click();
await page.getByTestId("merge-pull-request-confirm-button").click();
await expect(page.getByText("Merged feature into main.")).toBeVisible();
const mergePayload = await page.evaluate(() =>
window.__BUZZ_E2E_COMMAND_PAYLOADS__?.find(
(entry) => entry.command === "merge_project_pull_request",
),
);
expect(mergePayload?.payload).toMatchObject({
input: {
expectedCommit: expect.any(String),
sourceBranch: expect.any(String),
targetBranch: "main",
targetOwner: TEST_IDENTITIES.alice.pubkey,
},
});
});
test("viewer without repository ownership cannot merge", async ({ page }) => {
await enableProjectsFeature(page);
await page.addInitScript((owner) => {
window.__BUZZ_E2E_PROJECT_OWNER_OVERRIDE__ = owner;
}, TEST_IDENTITIES.alice.pubkey);
await installMockBridge(page, {
managedAgents: [
{
pubkey: REVIEWER_AGENT_PUBKEY,
name: "Reviewer Bot",
},
],
});
await openBuzzProject(page);
await page.getByRole("tab", { name: "Pull Request" }).click();
const prRow = page.getByTestId("project-pull-request-row").first();
await expect(prRow).toBeVisible({ timeout: 10_000 });
await prRow.getByRole("button", { name: /^#/ }).click();
await expect(
page.getByRole("button", { name: "Merge", exact: true }),
).toHaveCount(0);
const mergeCommandCount = await page.evaluate(
() =>
window.__BUZZ_E2E_COMMANDS__?.filter(
(command) => command === "merge_project_pull_request",
).length ?? 0,
);
expect(mergeCommandCount).toBe(0);
const authorizationError = await page.evaluate(async (targetOwner) => {
try {
await window.__BUZZ_E2E_INVOKE_MOCK_COMMAND__?.(
"merge_project_pull_request",
{
input: {
expectedCommit: "1".repeat(40),
pullRequestAuthor: "2".repeat(64),
pullRequestId: "3".repeat(64),
repoAddress: `30617:${targetOwner}:buzz`,
sourceBranch: "feature/untrusted",
statusCreatedAt: 1,
targetBranch: "main",
targetOwner,
},
},
);
return null;
} catch (error) {
return error instanceof Error ? error.message : String(error);
}
}, TEST_IDENTITIES.alice.pubkey);
expect(authorizationError).toContain(
"Only the repository owner or the owner of its managed agent",
);
});
test("project pull requests preserve partial results from batched queries", async ({
page,
}) => {
await enableProjectsFeature(page);
await page.addInitScript(() => {
window.__BUZZ_E2E_REJECT_PROJECT_QUERY_KINDS__ = [1619];
});
await installMockBridge(page);
await page.goto("/", { waitUntil: "domcontentloaded" });
await page.getByTestId("open-projects-view").click();
await page
.getByRole("button", { name: "Pull Requests", exact: true })
.click();
await expect(
page.getByRole("button", { name: /^View / }).first(),
).toBeVisible();
await expect(
page.getByText(/Some pull request details could not be loaded/),
).toBeVisible();
await expect(page.getByRole("button", { name: "Retry" })).toBeVisible();
const workItemFilters = await page.evaluate(
() =>
window.__BUZZ_E2E_PROJECT_QUERY_FILTERS__?.filter(
(filter) => filter.limit === 2_000,
) ?? [],
);
expect(
workItemFilters
.map((filter) => JSON.stringify([...(filter.kinds ?? [])].sort()))
.sort(),
).toEqual(
[[1], [1618, 1621], [1619], [1630, 1631, 1632, 1633]]
.map((kinds) => JSON.stringify(kinds))
.sort(),
);
expect(
workItemFilters.every((filter) => (filter["#a"]?.length ?? 0) > 1),
).toBe(true);
const expectedRepoAddresses = [
`30617:${DEFAULT_MOCK_PUBKEY}:buzz`,
`30617:${TEST_IDENTITIES.alice.pubkey}:relay-tools`,
`30617:${TEST_IDENTITIES.bob.pubkey}:design-system`,
].sort();
for (const filter of workItemFilters) {
expect([...(filter["#a"] ?? [])].sort()).toEqual(expectedRepoAddresses);
}
await page.evaluate(() => {
window.__BUZZ_E2E_REJECT_PROJECT_QUERY_KINDS__ = [];
});
await page.getByRole("button", { name: "Retry" }).click();
await expect(
page.getByText(/Some pull request details could not be loaded/),
).toHaveCount(0);
});
test("project pull request author rollover stays identity-only", async ({
page,
}) => {
await enableProjectsFeature(page);
await installMockBridge(page);
await page.goto("/", { waitUntil: "domcontentloaded" });
await page.getByTestId("open-projects-view").click();
await page
.getByRole("button", { name: "Pull Requests", exact: true })
.click();
await page.getByRole("button", { name: "List layout" }).click();
const row = page.locator('[data-testid^="projects-pr-row-"]').first();
const author = row.getByTestId("projects-pr-author");
await expect(author).toBeVisible();
await expect(
author.locator(
'[data-testid="projects-pr-author-avatar-image"], [data-testid="projects-pr-author-avatar-fallback"]',
),
).toBeVisible();
const authorLabel = (
await author.getByTestId("projects-pr-author-label").innerText()
).trim();
await author.hover();
const rollover = page.getByTestId("projects-pr-author-rollover");
await expect(rollover).toBeVisible();
await expect(rollover).toContainText(authorLabel);
await expect(rollover).toContainText(/Agent|Person/);
await expect(rollover).not.toContainText("Created");
await expect(page.getByTestId("user-profile-popover")).toHaveCount(0);
});
test("project issue author rollover matches pull requests", async ({
page,
}) => {
await enableProjectsFeature(page);
await installMockBridge(page);
await page.goto("/", { waitUntil: "domcontentloaded" });
await page.getByTestId("open-projects-view").click();
await page.getByRole("button", { name: "Issues", exact: true }).click();
await page.getByRole("button", { name: "List layout" }).click();
const row = page.locator('[data-testid^="projects-issue-row-"]').first();
const author = row.getByTestId("projects-issue-author");
await expect(author).toBeVisible();
await expect(
author.locator(
'[data-testid="projects-issue-author-avatar-image"], [data-testid="projects-issue-author-avatar-fallback"]',
),
).toBeVisible();
const authorLabel = (
await author.getByTestId("projects-issue-author-label").innerText()
).trim();
await author.hover();
const rollover = page.getByTestId("projects-issue-author-rollover");
await expect(rollover).toBeVisible();
await expect(rollover).toContainText(authorLabel);
await expect(rollover).toContainText(/Agent|Person/);
await expect(rollover).not.toContainText("Created");
await expect(page.getByTestId("user-profile-popover")).toHaveCount(0);
});
test("project pull requests report aggregate root query failures", async ({
page,
}) => {
await enableProjectsFeature(page);
await page.addInitScript(() => {
window.__BUZZ_E2E_REJECT_PROJECT_QUERY_KINDS__ = [1618];
});
await installMockBridge(page);
await page.goto("/", { waitUntil: "domcontentloaded" });
await page.getByTestId("open-projects-view").click();
await page
.getByRole("button", { name: "Pull Requests", exact: true })
.click();
await expect(page.getByText("Could not load pull requests.")).toBeVisible();
await expect(page.getByRole("button", { name: "Retry" })).toBeVisible();
await expect(page.getByText("No pull requests yet.")).toHaveCount(0);
await page.evaluate(() => {
window.__BUZZ_E2E_REJECT_PROJECT_QUERY_KINDS__ = [];
});
await page.getByRole("button", { name: "Retry" }).click();
await expect(page.getByText("Could not load pull requests.")).toHaveCount(0);
await expect(
page.getByRole("button", { name: /^View / }).first(),
).toBeVisible();
});
test("project issues preserve partial results from aggregate queries", async ({
page,
}) => {
await enableProjectsFeature(page);
await page.addInitScript(() => {
window.__BUZZ_E2E_REJECT_PROJECT_QUERY_KINDS__ = [1];
});
await installMockBridge(page);
await page.goto("/", { waitUntil: "domcontentloaded" });
await page.getByTestId("open-projects-view").click();
await page.getByRole("button", { name: "Issues", exact: true }).click();
await expect(
page.getByRole("button", { name: /^View / }).first(),
).toBeVisible();
await expect(
page.getByText("Some issue details could not be loaded."),
).toBeVisible();
await expect(page.getByText(/Missing comments\./)).toBeVisible();
await expect(page.getByRole("button", { name: "Retry" })).toBeVisible();
await page.evaluate(() => {
window.__BUZZ_E2E_REJECT_PROJECT_QUERY_KINDS__ = [];
});
await page.getByRole("button", { name: "Retry" }).click();
await expect(
page.getByText("Some issue details could not be loaded."),
).toHaveCount(0);
});
test("project overview reports aggregate work-item failures", async ({
page,
}) => {
await enableProjectsFeature(page);
await page.addInitScript(() => {
window.__BUZZ_E2E_REJECT_PROJECT_QUERY_KINDS__ = [1618];
});
await installMockBridge(page);
await page.goto("/", { waitUntil: "domcontentloaded" });
await page.getByTestId("open-projects-view").click();
await expect(
page.getByText("Could not load project activity."),
).toBeVisible();
await expect(page.getByRole("button", { name: "Retry" })).toBeVisible();
await page.evaluate(() => {
window.__BUZZ_E2E_REJECT_PROJECT_QUERY_KINDS__ = [];
});
await page.getByRole("button", { name: "Retry" }).click();
await expect(page.getByText("Could not load project activity.")).toHaveCount(
0,
);
});
test("project overview does not paint a background behind its cards", async ({
page,
}) => {
await enableProjectsFeature(page);
await installMockBridge(page);
await page.goto("/", { waitUntil: "domcontentloaded" });
await page.getByTestId("open-projects-view").click();
await expect(page.getByTestId("projects-overview-panel")).toHaveCSS(
"background-color",
"rgba(0, 0, 0, 0)",
);
const stats = page.getByTestId("projects-overview-stat");
await expect(stats).toHaveCount(4);
for (let index = 0; index < 4; index += 1) {
await expect(stats.nth(index)).toHaveCSS(
"background-color",
"rgba(0, 0, 0, 0)",
);
await expect(stats.nth(index)).toHaveCSS("border-style", "solid");
}
const activityCards = page.getByTestId("projects-activity-card");
await expect(activityCards.first()).toBeVisible();
const activityCardCount = await activityCards.count();
for (let index = 0; index < activityCardCount; index += 1) {
await expect(activityCards.nth(index)).toHaveCSS(
"background-color",
"rgba(0, 0, 0, 0)",
);
await expect(activityCards.nth(index)).toHaveCSS("border-style", "solid");
}
});
test("repository rows identify their git host", async ({ page }) => {
await enableProjectsFeature(page);
await installMockBridge(page);
await page.goto("/", { waitUntil: "domcontentloaded" });
await page.getByTestId("open-projects-view").click();
await page.getByRole("button", { name: "Repositories", exact: true }).click();
await page.getByRole("button", { name: "List layout" }).click();
const buzzHostIcon = page
.getByTestId("repository-row-buzz")
.getByTestId("repository-host-icon");
await expect(buzzHostIcon).toHaveAttribute(
"aria-label",
"Buzz-hosted repository",
);
await expect(
page
.getByTestId("repository-row-relay-tools")
.getByTestId("repository-host-icon"),
).toHaveAttribute("aria-label", "Git data hosted on github.com");
await buzzHostIcon.hover();
await expect(
page.getByRole("tooltip", { name: "Buzz-hosted repository" }),
).toBeVisible();
});
test("project subsections do not paint backgrounds behind list or grid items", async ({
page,
}) => {
await enableProjectsFeature(page);
await installMockBridge(page);
await page.goto("/", { waitUntil: "domcontentloaded" });
await page.getByTestId("open-projects-view").click();
for (const section of ["Repositories", "Pull Requests", "Issues"] as const) {
await page.getByRole("button", { name: section, exact: true }).click();
await page.getByRole("button", { name: "List layout" }).click();
const listItems = page.locator(
section === "Repositories"
? '[data-testid^="repository-row-"]'
: section === "Pull Requests"
? '[data-testid^="projects-pr-row-"]'
: '[data-testid^="projects-issue-row-"]',
);
await expect(listItems.first()).toBeVisible();
const listItemCount = await listItems.count();
for (let index = 0; index < listItemCount; index += 1) {
await expect(listItems.nth(index)).toHaveCSS(
"background-color",
"rgba(0, 0, 0, 0)",
);
await expect(listItems.nth(index)).toHaveCSS("border-style", "solid");
}
await page.getByRole("button", { name: "Grid layout" }).click();
const gridCards = page.locator(
section === "Repositories"
? '[data-testid^="repository-card-"]'
: "[data-projects-grid-card]",
);
await expect(gridCards.first()).toBeVisible();
const gridCardCount = await gridCards.count();
for (let index = 0; index < gridCardCount; index += 1) {
await expect(gridCards.nth(index)).toHaveCSS(
"background-color",
"rgba(0, 0, 0, 0)",
);
await expect(gridCards.nth(index)).toHaveCSS("border-style", "solid");
}
}
});
test("project detail content areas do not paint background fills", async ({
page,
}) => {
await enableProjectsFeature(page);
await installMockBridge(page);
await openBuzzProject(page);
const expectVisiblePanelsToBeTransparent = async () => {
const panels = page.locator("[data-project-detail-panel]:visible");
await expect(panels.first()).toBeVisible();
const panelCount = await panels.count();
for (let index = 0; index < panelCount; index += 1) {
await expect(panels.nth(index)).toHaveCSS(
"background-color",
"rgba(0, 0, 0, 0)",
);
await expect(panels.nth(index)).toHaveCSS("border-style", "solid");
}
};
for (const tab of [
"Overview",
"Files",
"Commits",
"Issues",
"Pull Request",
"Contributors",
]) {
await page.getByRole("tab", { name: tab, exact: true }).click();
await expectVisiblePanelsToBeTransparent();
}
await page.getByRole("tab", { name: "Pull Request", exact: true }).click();
const pullRequest = page.getByTestId("project-pull-request-row").first();
await expect(pullRequest).toBeVisible();
await pullRequest.getByRole("button", { name: /^#/ }).click();
await expectVisiblePanelsToBeTransparent();
});
test("project without a checkout offers fetch feedback and dropdown cloning", async ({
page,
}) => {
await enableProjectsFeature(page);
await installMockBridge(page);
await openBuzzProject(page);
await expect(
page.getByRole("button", { name: "Buzz", exact: true }),
).toBeVisible();
await expect(
page.getByRole("button", { name: "Buzz", exact: true }),
).toHaveClass(/\bborder-input\/40\b/);
await expect(page.getByRole("button", { name: /main/ })).toHaveClass(
/\bborder-input\/40\b/,
);
await expect(
page.getByRole("button", { name: "Clone", exact: true }),
).toHaveCount(0);
await page.getByRole("button", { name: "Fetch", exact: true }).click();
await expect(page.getByText("Remote state refreshed.")).toBeVisible();
await page.getByRole("button", { name: "Buzz", exact: true }).click();
const cloneItem = page.getByRole("menuitem", {
name: "Local missing Clone",
});
await expect(cloneItem.getByText("Local missing")).toHaveClass(
/text-muted-foreground/,
);
await expect(cloneItem.getByText("Clone", { exact: true })).toHaveClass(
/\bborder-input\/60\b/,
);
await cloneItem.click();
await expect(page.getByText("Cloned repository.")).toBeVisible();
const commands = await page.evaluate(
() => window.__BUZZ_E2E_COMMANDS__ ?? [],
);
expect(commands).toContain("clone_project_repository");
});
test("project branches can be created from the selected remote branch", async ({
page,
}) => {
await enableProjectsFeature(page);
await installMockBridge(page, {
projectHeadBranch: "master",
relaySelf: TEST_IDENTITIES.bob.pubkey,
});
await openBuzzProject(page);
await page.getByRole("button", { name: /main/ }).click();
await page.getByTestId("project-create-branch").click();
await page
.getByTestId("project-create-branch-name")
.fill("feature/branch-management");
await page.getByTestId("project-create-branch-submit").click();
await expect(
page.getByText("Created branch feature/branch-management from main.", {
exact: true,
}),
).toBeVisible();
await expect(
page.getByRole("button", { name: /feature\/branch-management/ }),
).toBeVisible();
await page
.getByRole("button", { name: /feature\/branch-management/ })
.click();
await expect(
page.getByRole("menuitemradio", { name: "feature/branch-management" }),
).toBeVisible();
await page.getByRole("menuitemradio", { name: "main" }).click();
await page.getByRole("button", { name: /main/ }).click();
await expect(
page.getByRole("menuitemradio", { name: "feature/branch-management" }),
).toBeVisible();
const commands = await page.evaluate(
() => window.__BUZZ_E2E_COMMANDS__ ?? [],
);
expect(commands).toContain("create_project_remote_branch");
await openBuzzProject(page);
await page.getByRole("button", { name: /main/ }).click();
await expect(
page.getByRole("menuitemradio", { name: "feature/branch-management" }),
).toBeVisible();
});
test("repository tags can be browsed as immutable remote snapshots", async ({
page,
}) => {
await enableProjectsFeature(page);
await installMockBridge(page);
await openBuzzProject(page);
await page.getByRole("button", { name: /main/ }).click();
await expect(page.getByText("Tags", { exact: true })).toBeVisible();
await expect(
page.getByRole("menuitemradio", { name: /v1\.0\.0.*0123456/ }),
).toBeVisible();
await page.getByRole("menuitemradio", { name: /v1\.0\.0.*0123456/ }).click();
await expect(page.getByRole("button", { name: /v1\.0\.0/ })).toBeVisible();
await expect(
page.getByRole("button", { name: "Buzz", exact: true }),
).toBeVisible();
await expect
.poll(() =>
page.evaluate(() => {
const call = [...(window.__BUZZ_E2E_COMMAND_PAYLOADS__ ?? [])]
.reverse()
.find((entry) => entry.command === "get_project_repo_snapshot");
return (call?.payload as { targetRef?: string } | undefined)?.targetRef;
}),
)
.toBe("refs/tags/v1.0.0");
await page.getByRole("button", { name: /v1\.0\.0/ }).click();
await expect(page.getByTestId("project-create-branch")).toHaveCount(0);
await expect(page.getByTestId("project-delete-branch")).toHaveCount(0);
await page.getByRole("menuitemradio", { name: "main" }).click();
await page.getByRole("button", { name: /main/ }).click();
await expect(page.getByTestId("project-create-branch")).toBeVisible();
});
test("project branches can be deleted but the default branch cannot", async ({
page,
}) => {
await enableProjectsFeature(page);
await installMockBridge(page);
await openBuzzProject(page);
await page.getByRole("button", { name: /main/ }).click();
await expect(page.getByTestId("project-delete-branch")).toBeDisabled();
await page.getByTestId("project-create-branch").click();
await page
.getByTestId("project-create-branch-name")
.fill("feature/delete-me");
await page.getByTestId("project-create-branch-submit").click();
await expect(
page.getByRole("button", { name: /feature\/delete-me/ }),
).toBeVisible();
await page.getByRole("button", { name: /feature\/delete-me/ }).click();
await page.getByTestId("project-delete-branch").click();
await expect(page.getByTestId("project-delete-branch-dialog")).toBeVisible();
await page.getByTestId("project-delete-branch-submit").click();
await expect(
page.getByText("Deleted branch feature/delete-me.", { exact: true }),
).toBeVisible();
await expect(page.getByRole("button", { name: /main/ })).toBeVisible();
const commands = await page.evaluate(
() => window.__BUZZ_E2E_COMMANDS__ ?? [],
);
expect(commands).toContain("delete_project_remote_branch");
});
test("pushed local branch can open a pull request", async ({ page }) => {
await enableProjectsFeature(page);
await page.addInitScript(() => {
const commit = "1234567890abcdef1234567890abcdef12345678";
window.__BUZZ_E2E_PROJECT_REPO_SYNC_STATUS__ = {
local_path: "/tmp/buzz/REPOS/buzz",
local_branch: "feature/projects-workflow",
local_branches: ["feature/projects-workflow", "space"],
local_head: commit,
local_short_head: commit.slice(0, 7),
remote_branch: "feature/projects-workflow",
remote_head: commit,
remote_short_head: commit.slice(0, 7),
merge_base: "0123456789abcdef0123456789abcdef01234567",
ahead_count: 0,
behind_count: 0,
has_uncommitted_changes: false,
has_untracked_files: false,
can_push: false,
push_block_reason: "Local branch is already pushed.",
can_pull: false,
pull_block_reason: "Local branch is up to date.",
};
});
await installMockBridge(page);
await openBuzzProject(page);
await page.getByRole("button", { name: /main/ }).click();
await expect(
page.getByRole("menuitemradio", { name: "space" }),
).toBeVisible();
await page
.getByRole("menuitemradio", { name: "feature/projects-workflow" })
.click();
await page.getByRole("tab", { name: "Pull Request", exact: true }).click();
await page.getByRole("button", { name: "Pull Request", exact: true }).click();
await expect(page.getByTestId("create-pull-request-repository")).toHaveValue(
/:buzz$/,
);
await expect(page.getByTestId("create-pull-request-base-branch")).toHaveValue(
"main",
);
await expect(
page.getByTestId("create-pull-request-compare-branch"),
).toHaveValue("feature/projects-workflow");
await page
.getByTestId("create-pull-request-title")
.fill("Complete the Projects git workflow");
await page
.getByTestId("create-pull-request-body")
.fill("Adds the missing desktop write path.");
await page.getByTestId("create-pull-request-submit").evaluate((button) => {
button.click();
button.click();
});
await expect(page.getByText("Pull request created.")).toBeVisible();
const createdEvents = await page.evaluate(
() =>
window.__BUZZ_E2E_SIGNED_EVENTS__?.filter(
(event) => event.kind === 1618,
) ?? [],
);
expect(createdEvents).toHaveLength(1);
const [createdEvent] = createdEvents;
expect(createdEvent?.tags).toContainEqual([
"branch-name",
"feature/projects-workflow",
]);
expect(createdEvent?.tags).toContainEqual(["target-branch", "main"]);
expect(createdEvent?.tags).toContainEqual([
"subject",
"Complete the Projects git workflow",
]);
});
test("project issue can be created from the issues header", async ({
page,
}) => {
await enableProjectsFeature(page);
await installMockBridge(page);
await openBuzzProject(page);
await page.getByRole("tab", { name: "Issues", exact: true }).click();
await page.getByRole("button", { name: "Issues", exact: true }).click();
await page
.getByTestId("create-issue-title")
.fill("Document the broken workflow");
await page
.getByTestId("create-issue-body")
.fill("The project workflow needs a clear repair path.");
await page.getByTestId("create-issue-submit").click();
await expect(page.getByText("Issue created.")).toBeVisible();
const createdEvent = await page.evaluate(() =>
window.__BUZZ_E2E_SIGNED_EVENTS__?.find((event) => event.kind === 1621),
);
expect(createdEvent?.tags).toContainEqual([
"subject",
"Document the broken workflow",
]);
});