Files
buzz/desktop/tests/e2e/cloud-provenance.spec.ts
Logan Johnson 4afef8649a fix(desktop): restore mention chip identity icons (#7338)
## Summary

Restore the missing **@ glyph for people and robot icon for agents**
after #7133, and incorporate the requested compact public-key display.

- Wrapping mention chips render their existing bounded icon-bearing
leading fragment.
- Readonly chips show bound keys using the same `8 leading…4 trailing`
formatter as the channel member list: `Scout (150b20bd…15dc)`.
- Full literal labels and exact keys remain authoritative in metadata,
profile targets, title/accessible-name attributes, editor text, saved
bodies and recipient tags. Display abbreviations are never used for
recipient lookup.
- Copy/paste restores the full literal label for a complete compact
chip; partial selections remain plain text. Two keys sharing the same
abbreviation still round-trip to their separate exact recipients.
- No recipient-resolution, authorization, wire-format, composer, or CSS
changes. Existing labels, icons, cloud markers and ordinary mentions
remain intact.

## Verification

Published candidate `9365ab9bc9d9c5d10802580cd576f8e378ff492f`, based on
main `e09f715c9d0ee2cb7bf8a39061e601f3a502f588`:

- **6,444 desktop unit tests passed** on this candidate's final source
tree.
- **44 mock-Chromium tests passed, zero retries in the final run**
across mention recipients, clipboard and cloud provenance: exact
recipient selection, ambiguity rejection, send/edit/reopen, forwarding,
full/partial copy, mismatched-key rejection, matching-abbreviation
collisions and 100%/150% narrow-window geometry.
- TypeScript, desktop Biome/check guards, protected-feature production
build and E2E build passed.
- The compact-renderer regression fails with the formatting call
removed. Original missing-icon and hidden-text accessibility regressions
have red/green evidence.
- Fresh self-review traced rendering, full-key metadata, copy
classifier, paste normalization and identity trust. The same display
formatter owns the accepted compact form on both clipboard sides.

Iteration exposed an existing team-insertion separator flake (passed
final full run) and two new fixture assumptions: non-member sends
require invitation, and Chromium rich paste may retain an NBSP
separator. Tests now exercise invitation and normalize only that
separator when comparing the captured full body and exact tags; no
product change was needed for either.

Earlier local repository-wide `just ci` completed in two invocations
because its initial call hit the ten-minute tool limit during Tauri
compilation. Unchanged native/mobile/backend evidence is reused; the
desktop delta received the full checks above and new remote CI. Native
VoiceOver, real Tauri selection, dark theme and non-Chromium observation
were not performed. Browser artifacts exercise real frontend with mocked
Tauri/relay boundaries, not an installed release.

## Review and visual evidence

Current-head CI and automated review must complete after this update;
the old `2997bfb5` green results do not establish this new head.
Required human review remains separate from agent approvals. No
merge/install/restart authorization.

Before/after icon evidence:
https://github.com/block/buzz/pull/7338#issuecomment-5544575866

Updated compact-key screenshots are posted below. The editor
intentionally retains the full literal address; only readonly chip
display is abbreviated.

Origin:
buzz://message?channel=3355d33a-b72a-423a-b064-a58275f9a8af&id=38b3a27e689f5a9604e273d45f4e3122fceba76081e7bcd3bbdbf439524a5a18

---------

Signed-off-by: Logan Johnson <loganj@squareup.com>
Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
2026-09-04 13:36:17 -07:00

208 lines
7.7 KiB
TypeScript

import { expect, test } from "@playwright/test";
import { waitForAnimations } from "../helpers/animations";
import { installMockBridge, openNewMessagePage } from "../helpers/bridge";
const OWNER = "deadbeef".repeat(8);
const REMOTE = "ed".repeat(32);
const GENERAL = "9a1657ac-f7aa-5db0-b632-d8bbeb6dfb50";
const LABEL = "Not managed on this device";
// The delayed fixture exceeds the marker assertion's 5s deadline, proving that
// source readiness is awaited independently of whether a cloud ever renders.
for (const agentListDelayMs of [0, 6_000]) {
test(`existing owned member uses one cloud across picker, members, author, chip, hover, profile and DM (directory delay ${agentListDelayMs}ms)`, async ({
page,
}, testInfo) => {
await installMockBridge(page, {
agentListDelayMs,
managedAgents: [],
searchProfiles: [
{
pubkey: REMOTE,
displayName: "Remote Scout",
ownerPubkey: OWNER,
isAgent: true,
},
],
relayAgents: [
{
pubkey: REMOTE,
name: "Remote Scout",
ownerPubkey: OWNER,
respondTo: "owner-only",
channelNames: ["general"],
status: "offline",
},
],
});
await page.goto("/");
await page.getByTestId("channel-general").click();
await expect(page.getByTestId("chat-title")).toHaveText("general");
// The channel shell can mount before the provider's directory queries settle.
// Wait for successful source reads, not a delay or a larger marker timeout:
// the assertions below must still fail if ready data renders no cloud.
await expect
.poll(
() =>
page.evaluate(() => {
const client = window.__BUZZ_E2E_QUERY_CLIENT__;
return Object.fromEntries(
["identity", "managed-agents", "relay-agents"].map((key) => {
const state = client?.getQueryState([key]);
return [
key,
{ status: state?.status, fetchStatus: state?.fetchStatus },
];
}),
);
}),
{
message:
"Cloud provenance requires successful identity and agent directory reads",
timeout: 10_000,
},
)
.toMatchObject({
identity: { status: "success" },
"managed-agents": { status: "success" },
"relay-agents": { status: "success" },
});
// Fixture setup only: the UI workflow starts with membership and a DM already present.
const dm = await page.evaluate(
async ({ pubkey, channelId }) => {
await window.__BUZZ_E2E_INVOKE_MOCK_COMMAND__?.("add_channel_members", {
channelId,
pubkeys: [pubkey],
role: "bot",
});
const dm = (await window.__BUZZ_E2E_INVOKE_MOCK_COMMAND__?.("open_dm", {
pubkeys: [pubkey],
})) as { id: string };
await window.__BUZZ_E2E_QUERY_CLIENT__?.invalidateQueries({
queryKey: ["channels"],
});
return dm;
},
{ pubkey: REMOTE, channelId: GENERAL },
);
await page.getByTestId("channel-general").click();
const input = page.getByTestId("message-input");
await input.fill("@Remote");
const suggestion = page.getByTestId(`mention-suggestion-${REMOTE}`);
await expect(
suggestion.getByRole("img", { name: LABEL }).locator("svg.lucide-cloud"),
).toBeVisible();
await waitForAnimations(page);
await page
.getByTestId("mention-autocomplete")
.screenshot({ path: testInfo.outputPath("cloud-picker.png") });
await input.press("Escape");
await input.fill("");
await page.getByTestId("channel-members-trigger").click();
const members = page.getByTestId("members-sidebar");
const memberMarker = page.getByTestId(
`sidebar-member-agent-provenance-${REMOTE}`,
);
await expect(memberMarker).toHaveAttribute("aria-label", LABEL);
await expect(memberMarker.locator("svg.lucide-cloud")).toBeVisible();
await waitForAnimations(page);
await members.screenshot({
path: testInfo.outputPath("cloud-members.png"),
});
await members.getByRole("button", { name: "Close", exact: true }).click();
await expect
.poll(() =>
page.evaluate(() =>
window.__BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?.({
channelName: "general",
}),
),
)
.toBe(true);
await page.evaluate((pubkey) => {
window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "general",
content: "Cloud provenance example: @Remote Scout",
pubkey,
// A self-reference is non-notifying, but still resolves a mention chip.
extraTags: [["mention", pubkey]],
kind: 40002,
});
}, REMOTE);
const article = page
.getByTestId("message-row")
.filter({ hasText: "Cloud provenance example:" });
await expect(
article.getByTestId("message-header").getByRole("img", { name: LABEL }),
).toBeVisible();
const chip = article.locator("[data-mention]");
await expect(chip.locator("svg.lucide-cloud")).toBeVisible();
const leading = chip.locator(".inline-chip-leading-fragment");
await expect(leading).toHaveText("Remot");
expect(
await leading.evaluate(
(element) => getComputedStyle(element, "::before").display,
),
).toBe("block");
await waitForAnimations(page);
await article.screenshot({
path: testInfo.outputPath("cloud-author-chip.png"),
});
await chip.hover();
const hover = page.getByTestId("user-profile-popover");
await expect(
hover.getByTestId("user-profile-popover-agent-provenance"),
).toHaveAttribute("title", LABEL);
await waitForAnimations(page);
await hover.screenshot({ path: testInfo.outputPath("cloud-hover.png") });
await chip.click();
const panel = page.getByTestId("user-profile-panel");
await expect(
panel.getByRole("img", { name: LABEL }).locator("svg.lucide-cloud"),
).toBeVisible();
await waitForAnimations(page);
await panel.screenshot({ path: testInfo.outputPath("cloud-profile.png") });
await page.getByTestId("auxiliary-panel-close").click();
await expect(
page
.getByTestId(`channel-agent-provenance-${dm.id}`)
.locator("svg.lucide-cloud"),
).toBeVisible();
await page.locator(`[data-channel-id="${dm.id}"]`).click();
await expect(
page
.getByTestId("chat-header-agent-provenance")
.locator("svg.lucide-cloud"),
).toBeVisible();
await waitForAnimations(page);
await page.screenshot({ path: testInfo.outputPath("cloud-dm.png") });
await openNewMessagePage(page);
await page.getByTestId("new-dm-search").fill("Remote Scout");
const recipient = page.getByTestId(`new-dm-result-${REMOTE}`);
await expect(
recipient.getByRole("img", { name: LABEL }).locator("svg.lucide-cloud"),
).toBeVisible();
await waitForAnimations(page);
await recipient.screenshot({
path: testInfo.outputPath("cloud-recipient.png"),
});
await page.getByTestId("channel-random").click();
await page.getByTestId("channel-members-trigger").click();
await page.getByPlaceholder("Add people and agents").fill("Remote Scout");
const addResult = page.getByTestId(`channel-user-search-result-${REMOTE}`);
await expect(
addResult.getByRole("img", { name: LABEL }).locator("svg.lucide-cloud"),
).toBeVisible();
await waitForAnimations(page);
await addResult.screenshot({
path: testInfo.outputPath("cloud-add-member-picker.png"),
});
// No invitation or local lifecycle action is exercised by this presentation test.
await expect(
page.getByRole("button", { name: "Invite", exact: true }),
).toHaveCount(0);
});
}