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
Signed-off-by: cls_宁波本机 <908705107@qq.com>
234 lines
9.1 KiB
TypeScript
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);
|
|
});
|