Files
buzz/desktop/tests/e2e/invites-settings-screenshots.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

234 lines
9.1 KiB
TypeScript

import { expect, test } from "@playwright/test";
import { waitForAnimations } from "../helpers/animations";
import { TEST_IDENTITIES, installMockBridge } from "../helpers/bridge";
import { openSettings } from "../helpers/settings";
const OUTDIR = "test-results/invites-settings";
const DIRECT_ADD_HEX =
"ea9b4d7a7a78a3e3729e5568b14d764d4962be0e1f20f749bcf8d9dbbf9a9328";
const DIRECT_ADD_NPUB =
"npub1a2d567n60z37xu57245tzntkf4yk90swrus0wjdulrvah0u6jv5qusyp60";
const SECOND_DIRECT_ADD_HEX =
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const SECOND_DIRECT_ADD_NPUB =
"npub1424242424242424242424242424242424242424242424242424qamrcaj";
test.beforeEach(async ({ page }, testInfo) => {
await installMockBridge(page, {
relayRequiresMembership: true,
relayRole: testInfo.title.includes("admin can add members")
? "admin"
: "owner",
});
await page.route("**/api/invites", async (route) => {
await route.fulfill({
contentType: "application/json",
json: {
code: "community-email-test",
expires_at: Math.floor(Date.now() / 1000) + 3 * 86_400,
url: "https://alpha.example.com/invite/community-email-test",
},
status: 200,
});
});
await page.goto("/");
await openSettings(page, "community-members");
});
test("opens a profile from a community member avatar", async ({ page }) => {
await page.getByRole("button", { name: "Open profile for alice" }).click();
await expect(page).toHaveURL(
new RegExp(`/pulse\\?profile=${TEST_IDENTITIES.alice.pubkey}$`),
);
await expect(page.getByTestId("user-profile-panel")).toBeVisible();
});
test("capture: consolidated invites settings", async ({ page }) => {
const panel = page.getByTestId("settings-panel-community-members");
await expect(
page.getByTestId("settings-nav-community-members"),
).toContainText("Invites");
await expect(
page.getByRole("heading", { name: "Invites", exact: true }),
).toBeVisible();
await expect(page.getByTestId("community-icon-settings")).toHaveCount(0);
await expect(
page.getByTestId("community-invite-dialog-trigger"),
).toBeVisible();
await expect(page.getByTestId("community-invite-email-field")).toHaveCount(0);
await expect(page.getByTestId("copy-invite-link")).toHaveCount(0);
await expect(page.getByText("alice", { exact: true })).toBeVisible();
await expect(page.getByText("bob", { exact: true })).toBeVisible();
await expect(
page.getByText("Manage roles or remove access.", { exact: true }),
).toHaveCount(0);
await expect(
page.getByText("People who use the link join as members."),
).toHaveCount(0);
await expect(page.getByTestId("community-icon-save")).toHaveCount(0);
const aliceName = page.getByText("alice", { exact: true });
const aliceRow = page
.locator('[data-testid^="relay-member-row-"]')
.filter({ has: aliceName });
const aliceNpub = aliceRow.locator('[data-testid^="relay-member-npub-"]');
await expect(aliceName).toHaveCSS("opacity", "1");
await expect(aliceNpub).toHaveCSS("opacity", "0");
await aliceRow.hover();
await expect(aliceName).toHaveCSS("opacity", "0");
await expect(aliceNpub).toHaveCSS("opacity", "1");
await page.mouse.move(0, 0);
await waitForAnimations(page);
await panel.screenshot({ path: `${OUTDIR}/01-invites-settings.png` });
});
test("capture: share-style community invite dialog", async ({ page }) => {
await page.getByTestId("community-invite-dialog-trigger").click();
const dialog = page.getByTestId("community-invite-dialog");
await expect(dialog).toBeVisible();
await expect(
dialog.getByRole("heading", { name: "Invite to community" }),
).toBeVisible();
await expect(page.getByTestId("community-invite-email-field")).toHaveCount(0);
await expect(page.getByPlaceholder("Type an email address")).toHaveCount(0);
await expect(
dialog.getByText(
"Add someone directly or share a link they can use to join.",
),
).toBeVisible();
await expect(
dialog.getByRole("heading", { name: "Add someone", exact: true }),
).toHaveCount(0);
await expect(dialog.getByTestId("invite-options-divider")).toBeVisible();
await expect(
dialog.getByText("Or, copy a link", { exact: true }),
).toBeVisible();
await expect(dialog.getByText("Link settings", { exact: true })).toHaveCount(
0,
);
await expect(page.getByTestId("member-pubkey-input")).toBeVisible();
await expect(page.getByTestId("member-role")).toHaveCount(0);
await expect(page.getByTestId("confirm-add-member")).toHaveCount(0);
await expect(page.getByTestId("invite-link-url")).toHaveValue(
"https://alpha.example.com/invite/community-email-test",
);
await expect(page.getByTestId("copy-invite-link")).toHaveText("Copy link");
await expect(page.getByTestId("invite-link-ttl-trigger")).toHaveText(
"3 days",
);
await page.getByTestId("member-pubkey-input").fill(DIRECT_ADD_NPUB);
await expect(page.getByTestId("member-search-popover")).toBeVisible();
await page.getByTestId(`member-search-result-${DIRECT_ADD_HEX}`).click();
const memberRole = page.getByTestId("member-role");
const selectedChip = page.getByTestId(
`member-search-selection-remove-${DIRECT_ADD_HEX}`,
);
await expect(memberRole).toHaveText("Member");
const inviteButton = page.getByTestId("confirm-add-member");
await expect(inviteButton).toHaveText("Invite");
await waitForAnimations(page);
await expect(inviteButton).toHaveCSS("height", "44px");
await expect(inviteButton).toHaveJSProperty(
"offsetHeight",
await page
.getByTestId("member-recipient-field")
.evaluate((field) => Math.round(field.getBoundingClientRect().height)),
);
const selectedChipRemoveIcon = selectedChip.locator("span.absolute");
await expect(selectedChipRemoveIcon).toHaveCSS("opacity", "0");
await selectedChip.hover();
await expect(selectedChipRemoveIcon).toHaveCSS("opacity", "1");
const memberSearch = page.getByTestId("member-pubkey-input");
await expect(memberSearch).toBeFocused();
await memberSearch.fill(SECOND_DIRECT_ADD_NPUB);
await expect(page.getByTestId("member-search-popover")).toBeVisible();
await page
.getByTestId(`member-search-result-${SECOND_DIRECT_ADD_HEX}`)
.click();
await expect(
page.getByTestId(`member-search-selection-remove-${SECOND_DIRECT_ADD_HEX}`),
).toBeVisible();
await expect(memberSearch).toBeFocused();
await memberRole.click();
await expect(
page.getByRole("menuitemradio", { name: "Admin" }),
).toBeVisible();
await page.keyboard.press("Escape");
await expect(page.getByTestId("confirm-add-member")).toBeEnabled();
await waitForAnimations(page);
await page.mouse.move(0, 0);
await dialog.screenshot({ path: `${OUTDIR}/02-invite-dialog.png` });
});
test("admin can add members but cannot assign the admin role", async ({
page,
}) => {
await page.getByTestId("community-invite-dialog-trigger").click();
await page.getByTestId("member-pubkey-input").fill(DIRECT_ADD_NPUB);
await page.getByTestId(`member-search-result-${DIRECT_ADD_HEX}`).click();
const memberRole = page.getByTestId("member-role");
await expect(memberRole).toHaveText("Member");
await memberRole.click();
await expect(page.getByRole("menuitemradio", { name: "Admin" })).toHaveCount(
0,
);
await page.keyboard.press("Escape");
});
test("owner can add multiple admins directly by npub from live Invites UI", async ({
page,
}) => {
await page.getByTestId("community-invite-dialog-trigger").click();
await page.getByTestId("member-pubkey-input").fill(DIRECT_ADD_NPUB);
await page.getByTestId(`member-search-result-${DIRECT_ADD_HEX}`).click();
await page.getByTestId("member-pubkey-input").fill(SECOND_DIRECT_ADD_NPUB);
await page
.getByTestId(`member-search-result-${SECOND_DIRECT_ADD_HEX}`)
.click();
await page.getByTestId("member-role").click();
await page.getByRole("menuitemradio", { name: "Admin" }).click();
await page.getByTestId("confirm-add-member").click();
await expect
.poll(async () =>
page.evaluate(
({ targetPubkeys, role }) =>
targetPubkeys.every((targetPubkey) =>
(window.__BUZZ_E2E_COMMAND_PAYLOADS__ ?? []).some((entry) => {
if (entry.command !== "plugin:websocket|send") return false;
const wireMessage = (
entry.payload as {
message?: { data?: unknown };
}
)?.message?.data;
if (typeof wireMessage !== "string") return false;
const message = JSON.parse(wireMessage) as unknown[];
if (message[0] !== "EVENT") return false;
const event = message[1] as
| { kind?: number; tags?: string[][] }
| undefined;
return (
event?.kind === 9030 &&
event.tags?.some(
(tag) => tag[0] === "p" && tag[1] === targetPubkey,
) &&
event.tags.some((tag) => tag[0] === "role" && tag[1] === role)
);
}),
),
{
targetPubkeys: [DIRECT_ADD_HEX, SECOND_DIRECT_ADD_HEX],
role: "admin",
},
),
)
.toBe(true);
});