mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
## Summary - Separate direct invites from link sharing with a labeled divider. - Show the generated invite URL inline with truncation and a copy control. - Use shared loading feedback and a restrained copy-status resize. ## Validation - `pnpm -C desktop exec playwright test tests/e2e/invite-link-copy.spec.ts tests/e2e/invites-settings-screenshots.spec.ts` (7 passed) --------- Signed-off-by: kenny lopez <klopez4212@gmail.com>
164 lines
5.4 KiB
TypeScript
164 lines
5.4 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
||
|
||
import { installMockBridge } from "../helpers/bridge";
|
||
import { openSettings } from "../helpers/settings";
|
||
|
||
let invitePayloads: Record<string, unknown>[];
|
||
|
||
test.beforeEach(async ({ page }) => {
|
||
invitePayloads = [];
|
||
await page.context().grantPermissions(["clipboard-read", "clipboard-write"], {
|
||
origin: "http://127.0.0.1:4173",
|
||
});
|
||
await installMockBridge(page, {
|
||
relayRequiresMembership: true,
|
||
});
|
||
await page.route("**/api/invites", async (route) => {
|
||
invitePayloads.push(route.request().postDataJSON());
|
||
await route.fulfill({
|
||
contentType: "application/json",
|
||
json: {
|
||
code: "qr-download-test",
|
||
expires_at: Math.floor(Date.now() / 1000) + 86_400,
|
||
url: "buzz://join?relay=wss%3A%2F%2Frelay.example.com&code=qr-download-test",
|
||
},
|
||
status: 200,
|
||
});
|
||
});
|
||
});
|
||
|
||
test("copies a freshly minted invite link from the link field", async ({
|
||
page,
|
||
}) => {
|
||
await page.goto("/");
|
||
await openSettings(page, "community-members");
|
||
await expect(page.getByTestId("settings-community-members")).toBeVisible();
|
||
|
||
await page.getByTestId("community-invite-dialog-trigger").click();
|
||
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(
|
||
"buzz://join?relay=wss%3A%2F%2Frelay.example.com&code=qr-download-test",
|
||
);
|
||
await expect(page.getByTestId("invite-link-qr-code")).toHaveCount(0);
|
||
await expect(page.getByTestId("invite-link-max-uses-trigger")).toHaveText(
|
||
"No limit",
|
||
);
|
||
await page.getByTestId("copy-invite-link").click();
|
||
await expect(page.getByTestId("copy-invite-link")).toContainText("Copied");
|
||
expect(invitePayloads).toEqual([{ ttl_secs: 3 * 24 * 60 * 60 }]);
|
||
|
||
const payload = await page.evaluate(() => {
|
||
const log = (
|
||
window as Window & {
|
||
__BUZZ_E2E_COMMAND_LOG__?: Array<{
|
||
command: string;
|
||
payload: Record<string, unknown> | null;
|
||
}>;
|
||
}
|
||
).__BUZZ_E2E_COMMAND_LOG__;
|
||
return log?.findLast(({ command }) => command === "copy_text_to_clipboard")
|
||
?.payload;
|
||
});
|
||
|
||
expect(payload).toEqual({
|
||
text: "buzz://join?relay=wss%3A%2F%2Frelay.example.com&code=qr-download-test",
|
||
});
|
||
});
|
||
|
||
test("sets a selected invite-use limit", async ({ page }) => {
|
||
await page.goto("/");
|
||
await openSettings(page, "community-members");
|
||
await page.getByTestId("community-invite-dialog-trigger").click();
|
||
|
||
const maxUsesTrigger = page.getByTestId("invite-link-max-uses-trigger");
|
||
await maxUsesTrigger.click();
|
||
await expect(
|
||
page.getByRole("menuitemradio", { name: "No limit" }),
|
||
).toBeVisible();
|
||
await expect(
|
||
page.getByRole("menuitemradio", { name: "25 uses" }),
|
||
).toBeVisible();
|
||
await page.getByTestId("invite-link-max-uses-10").click();
|
||
await expect(maxUsesTrigger).toHaveText("10 uses");
|
||
await expect
|
||
.poll(() => invitePayloads.at(-1))
|
||
.toEqual({
|
||
max_uses: 10,
|
||
ttl_secs: 3 * 24 * 60 * 60,
|
||
});
|
||
await page.getByTestId("copy-invite-link").click();
|
||
await expect(page.getByTestId("copy-invite-link")).toContainText("Copied");
|
||
});
|
||
|
||
test("retries a failed invite-link generation", async ({ page }) => {
|
||
let attempts = 0;
|
||
await page.route("**/api/invites", async (route) => {
|
||
attempts += 1;
|
||
if (attempts === 1) {
|
||
await route.fulfill({ status: 500 });
|
||
return;
|
||
}
|
||
|
||
await route.fulfill({
|
||
contentType: "application/json",
|
||
json: {
|
||
code: "retry-test",
|
||
expires_at: Math.floor(Date.now() / 1000) + 86_400,
|
||
url: "buzz://join?relay=wss%3A%2F%2Frelay.example.com&code=retry-test",
|
||
},
|
||
status: 200,
|
||
});
|
||
});
|
||
|
||
await page.goto("/");
|
||
await openSettings(page, "community-members");
|
||
await page.getByTestId("community-invite-dialog-trigger").click();
|
||
|
||
const linkField = page.getByTestId("invite-link-url");
|
||
const copyButton = page.getByTestId("copy-invite-link");
|
||
await expect(linkField).toHaveAttribute(
|
||
"placeholder",
|
||
"Couldn’t create invite link",
|
||
);
|
||
await expect(copyButton).toHaveText("Retry");
|
||
await expect(copyButton).toBeEnabled();
|
||
|
||
await copyButton.click();
|
||
await expect(linkField).toHaveValue(
|
||
"buzz://join?relay=wss%3A%2F%2Frelay.example.com&code=retry-test",
|
||
);
|
||
await expect(copyButton).toHaveText("Copy link");
|
||
expect(attempts).toBe(2);
|
||
});
|
||
|
||
test("reopens with the default expiry before generating a new link", async ({
|
||
page,
|
||
}) => {
|
||
await page.goto("/");
|
||
await openSettings(page, "community-members");
|
||
await page.getByTestId("community-invite-dialog-trigger").click();
|
||
|
||
await expect
|
||
.poll(() => invitePayloads)
|
||
.toEqual([{ ttl_secs: 3 * 24 * 60 * 60 }]);
|
||
await page.getByTestId("invite-link-ttl-trigger").click();
|
||
await page.getByTestId("invite-link-ttl-604800").click();
|
||
await expect
|
||
.poll(() => invitePayloads)
|
||
.toEqual([{ ttl_secs: 3 * 24 * 60 * 60 }, { ttl_secs: 7 * 24 * 60 * 60 }]);
|
||
|
||
const dialog = page.getByTestId("community-invite-dialog");
|
||
await dialog.getByRole("button", { name: "Close" }).click();
|
||
await expect(dialog).toHaveCount(0);
|
||
await page.getByTestId("community-invite-dialog-trigger").click();
|
||
await expect
|
||
.poll(() => invitePayloads)
|
||
.toEqual([
|
||
{ ttl_secs: 3 * 24 * 60 * 60 },
|
||
{ ttl_secs: 7 * 24 * 60 * 60 },
|
||
{ ttl_secs: 3 * 24 * 60 * 60 },
|
||
]);
|
||
});
|