Files
buzz/desktop/tests/e2e/identity-archive.spec.ts
klopez4212 63f961c7e4 Refine channel settings and profile panels (#5574)
## Summary

- simplify channel settings into concise detail, member, canvas, and
action sections
- align human and agent profiles around shared rows, segmented tabs, and
top-level actions
- add agent runtime presentation, sticky glass behavior, and
scroll-linked action transitions

## Snapshots

### Channel settings

![Channel
settings](https://raw.githubusercontent.com/block/buzz/72d3958374a6f31c0f15912a8307101415eed084/pr-5574--01-channel-settings.png)

### Agent info

![Agent
info](https://raw.githubusercontent.com/block/buzz/72d3958374a6f31c0f15912a8307101415eed084/pr-5574--02-agent-info.png)

### Agent runtime

![Agent
runtime](https://raw.githubusercontent.com/block/buzz/72d3958374a6f31c0f15912a8307101415eed084/pr-5574--03-agent-runtime.png)

## Validation

- `pnpm -C desktop check`
- `pnpm -C desktop test` (4,604 passed)
- `pnpm -C desktop build:e2e`
- focused channel settings and agent profile Playwright tests

---------

Signed-off-by: kenny lopez <klopez4212@gmail.com>
Co-authored-by: Mongo <9cfd347903944d5b85aa6c93d2ab67381b978a92a31914bca69998968752a1d7@buzz.block.builderlab.xyz>
2026-08-12 08:25:04 -07:00

141 lines
5.0 KiB
TypeScript

import { expect, test } from "@playwright/test";
import { installMockBridge } from "../helpers/bridge";
// NIP-IA archive button + "Archived" flair gate matrix.
//
// Guards the composition `canArchive = isSelf || isRelayAdminOrOwner ||
// isOaOwnerOfViewee` in UserProfilePanel.tsx. Unit tests cover each input in
// isolation; this spec covers the OR composition where silent regressions
// (refactor turns OR into AND, role expansion bypasses a branch, etc.) would
// otherwise slip past code review.
const ALICE_PUBKEY =
"953d3363262e86b770419834c53d2446409db6d918a57f8f339d495d54ab001f";
async function openSelfProfile(page: import("@playwright/test").Page) {
await page.goto("/");
await page.getByTestId("channel-general").click();
await expect(page.getByTestId("chat-title")).toHaveText("general");
// First seed message in #general is from the active identity.
const firstMessage = page.getByTestId("message-row").first();
await firstMessage.locator("button", { hasText: "npub1mock..." }).click();
await expect(page.getByTestId("user-profile-panel")).toBeVisible();
}
async function openAliceProfile(page: import("@playwright/test").Page) {
await page.goto("/");
await page.getByTestId("channel-general").click();
await expect(page.getByTestId("chat-title")).toHaveText("general");
// Second seed message in #general is from Alice. Her display name "alice"
// is registered in mockDisplayNames, so the author button text is "alice".
const aliceMessage = page.getByTestId("message-row").nth(1);
await aliceMessage.locator("button", { hasText: "alice" }).first().click();
const panel = page.getByTestId("user-profile-panel");
await expect(panel).toBeVisible();
await expect(panel).toContainText(ALICE_PUBKEY.slice(0, 8));
}
async function openProfileSettingsMenu(page: import("@playwright/test").Page) {
const trigger = page.getByTestId("user-profile-settings-menu-trigger");
await expect(trigger).toBeVisible();
await trigger.click();
}
test.describe("NIP-IA archive button gate", () => {
test("case 1 — self viewer + self target: Archive visible, no flair", async ({
page,
}) => {
await installMockBridge(page, { relayRole: null, oaOwnerIsMe: false });
await openSelfProfile(page);
await openProfileSettingsMenu(page);
const archiveButton = page.getByTestId("user-profile-archive-identity");
await expect(archiveButton).toBeVisible();
await expect(page.getByTestId("user-profile-archived-flair")).toHaveCount(
0,
);
// Archive is now gated behind a confirmation modal — clicking the button
// opens the dialog rather than firing immediately. Drive the full flow so
// the gate stays meaningful: the modal must surface, then confirm fires.
await expect(page.getByTestId("archive-confirm-dialog")).toHaveCount(0);
await archiveButton.click();
await expect(page.getByTestId("archive-confirm-dialog")).toBeVisible();
const confirm = page.getByTestId("archive-confirm-action");
await expect(confirm).toBeVisible();
await confirm.click();
await expect(page.getByTestId("archive-confirm-dialog")).toHaveCount(0);
});
test("case 2 — relay admin viewing Alice: Archive visible", async ({
page,
}) => {
await installMockBridge(page, {
relayRole: "admin",
relayRequiresMembership: true,
oaOwnerIsMe: false,
archivedIdentities: [],
});
await openAliceProfile(page);
await expect(
page.getByTestId("user-profile-archive-agent-row"),
).toBeVisible();
});
test("case 3 — verified OA owner viewing Alice: Archive visible", async ({
page,
}) => {
await installMockBridge(page, {
relayRole: null,
oaOwnerIsMe: true,
archivedIdentities: [],
});
await openAliceProfile(page);
await expect(
page.getByTestId("user-profile-archive-agent-row"),
).toBeVisible();
});
test("case 4 — no authority viewing Alice: Archive hidden", async ({
page,
}) => {
await installMockBridge(page, {
relayRole: null,
oaOwnerIsMe: false,
archivedIdentities: [],
});
await openAliceProfile(page);
await expect(
page.getByTestId("user-profile-settings-menu-trigger"),
).toHaveCount(0);
await expect(page.getByTestId("user-profile-archive-identity")).toHaveCount(
0,
);
await expect(
page.getByTestId("user-profile-unarchive-identity"),
).toHaveCount(0);
await expect(
page.getByTestId("user-profile-archive-agent-row"),
).toHaveCount(0);
});
test("case 5 — Alice archived: flair + Unarchive button (under admin gate)", async ({
page,
}) => {
await installMockBridge(page, {
relayRole: "admin",
relayRequiresMembership: true,
oaOwnerIsMe: false,
archivedIdentities: [ALICE_PUBKEY],
});
await openAliceProfile(page);
await expect(page.getByTestId("user-profile-archived-flair")).toBeVisible();
await expect(
page.getByTestId("user-profile-unarchive-agent-row"),
).toBeVisible();
await expect(
page.getByTestId("user-profile-archive-agent-row"),
).toHaveCount(0);
});
});