From e3869334810a6248e1915bc27ab8024c0b7b4166 Mon Sep 17 00:00:00 2001 From: Dotta Date: Wed, 28 Oct 2026 09:44:38 -0500 Subject: [PATCH] test(e2e): bind secret proposal review to expanded card --- .../external-secret-proposal.ts | 5 +++- .../chat-secret-proposal-card-scope.test.ts | 28 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 tests/runner-e2e/chat-secret-proposal-card-scope.test.ts diff --git a/tests/runner-e2e/chat-catalog-domains/external-secret-proposal.ts b/tests/runner-e2e/chat-catalog-domains/external-secret-proposal.ts index 468a02820ba..b22e551f0a1 100644 --- a/tests/runner-e2e/chat-catalog-domains/external-secret-proposal.ts +++ b/tests/runner-e2e/chat-catalog-domains/external-secret-proposal.ts @@ -30,6 +30,9 @@ export function truthfulPendingProposalDisplay(row:SecretProposalView,card:unkno &&(card as RequestConfirmationInteraction).status==="pending"&&!(card as RequestConfirmationInteraction).resolvedByUserId &&(!reply.trim()||truthfulPendingProposal(reply)); } +export function secretProposalCardSelector(interactionId:string){ + return `[data-testid="task-chat-interaction"][id=${JSON.stringify(`interaction-${interactionId}`)}]`; +} async function recordPendingProposalDisplay(ctx:ChatCatalogContext,state:Record,row:SecretProposalView){ const cards=await ctx.input.api.get(`/api/issues/${ctx.issue()!.id}/interactions`); const card=cards.find(c=>c.kind==="request_confirmation"&&c.payload.secretProposal?.proposalId===row.id); @@ -38,7 +41,7 @@ async function recordPendingProposalDisplay(ctx:ChatCatalogContext,state:Record< const target=await ctx.input.api.get(`/api/agents/${state.morganId}`); const bindingAbsentBeforeDecision=(await bindings(ctx,String(state.secretId))).length===0&&!(target.adapterConfig.env as Record|undefined)?.PUBLISHING_API_KEY; if(!bindingAbsentBeforeDecision)throw new Error("The pending proposal already changed Morgan's binding before human approval"); - const view=ctx.input.page.locator(`[id=${JSON.stringify(`interaction-${card!.id}`)}]`); + const view=ctx.input.page.locator(secretProposalCardSelector(card!.id)); await expect(view).toBeVisible();for(const text of [row.secretName!,row.target!.name,row.configPath!])await expect(view).toContainText(text); const displays=(state.pendingProposalDisplays??[]) as PendingProposalDisplay[]; state.pendingProposalDisplays=[...displays,{proposalId:row.id,personId:String(state.personId),visible:true,bindingAbsentBeforeDecision,card:card!}]; diff --git a/tests/runner-e2e/chat-secret-proposal-card-scope.test.ts b/tests/runner-e2e/chat-secret-proposal-card-scope.test.ts new file mode 100644 index 00000000000..045dcc3a808 --- /dev/null +++ b/tests/runner-e2e/chat-secret-proposal-card-scope.test.ts @@ -0,0 +1,28 @@ +// @vitest-environment jsdom +import { afterEach, expect, it, vi } from "vitest"; +vi.mock("@playwright/test", () => ({ expect: vi.fn() })); +vi.mock("./api.js", () => ({ pollUntil: vi.fn() })); +vi.mock("./run-observations.js", () => ({ collectRunEvents: vi.fn() })); +vi.mock("./chat-catalog-domains/external-secret-scan.js", () => ({ scanReachableSecretOutputs: vi.fn(), privateScanJson: vi.fn(), bytesContainSecret: vi.fn(), sameSecretIdentity: vi.fn() })); +// Isolate the CSS/DOM regression from unrelated Node-only runtime setup. +vi.mock("./chat-flow.js", () => ({ sendChatMessage: vi.fn() })); +vi.mock("./chat-catalog-domains/identity-support.js", () => ({ identityWorker: vi.fn(), openStandingChat: vi.fn(), probeAgentPermission: vi.fn() })); +vi.mock("./chat-catalog-domains/external-support.js", () => ({ definition: () => ({}), observeExternal: vi.fn(), externalObservation: vi.fn(), checks: vi.fn(), root: vi.fn(), verifyRenderedReply: vi.fn() })); +import { secretProposalCardSelector } from "./chat-catalog-domains/external-secret-proposal.js"; +afterEach(() => { document.body.innerHTML = ""; }); +it("selects the actual expanded proposal card when the pending trigger has the same production interaction ID", () => { + document.body.innerHTML = ` +

Deployment publishing key

Morgan

env.PUBLISHING_API_KEY

+

Other request

`; + expect(document.querySelectorAll('[id="interaction-owned"]')).toHaveLength(2); + const selected = document.querySelectorAll(secretProposalCardSelector("owned")); + expect(selected).toHaveLength(1); expect(selected[0]?.tagName).toBe("DIV"); + for (const fact of ["Deployment publishing key", "Morgan", "env.PUBLISHING_API_KEY"]) expect(selected[0]?.textContent).toContain(fact); + expect(document.querySelectorAll(secretProposalCardSelector("missing"))).toHaveLength(0); +}); +it("a trigger, unrelated card or completed receipt cannot stand in for the bound proposal card", () => { + document.body.innerHTML = ` +
Deployment publishing key Morgan env.PUBLISHING_API_KEY
+
Approved
`; + expect(document.querySelectorAll(secretProposalCardSelector("owned"))).toHaveLength(0); +});