feat: import Chinese-localized Buzz source snapshot
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
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>
This commit is contained in:
@@ -0,0 +1,380 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import { expect, test } from "@playwright/test";
|
||||
|
||||
test("home page loads with Buzz branding", async ({ page }) => {
|
||||
await page.goto("./");
|
||||
await expect(
|
||||
page.getByRole("main").getByRole("img", { name: "Buzz" }),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test("home page shows repositories section", async ({ page }) => {
|
||||
await page.goto("./");
|
||||
await expect(page.getByText("代码仓库")).toBeVisible();
|
||||
});
|
||||
|
||||
test("defaults to Simplified Chinese and persists the selected locale", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("./");
|
||||
await expect(page.locator("html")).toHaveAttribute("lang", "zh-Hans");
|
||||
await expect(page.getByText("代码仓库")).toBeVisible();
|
||||
|
||||
await page.getByRole("button", { name: "切换为 English" }).click();
|
||||
await expect(page.locator("html")).toHaveAttribute("lang", "en");
|
||||
await expect(page.getByText("Repositories")).toBeVisible();
|
||||
|
||||
await page.reload();
|
||||
await expect(page.locator("html")).toHaveAttribute("lang", "en");
|
||||
await expect(page.getByText("Repositories")).toBeVisible();
|
||||
});
|
||||
|
||||
test("uses the /buzz base path for relay URLs and invite APIs", async ({
|
||||
page,
|
||||
}) => {
|
||||
let policyUrl = "";
|
||||
await page.route("**/buzz/api/join-policy", async (route) => {
|
||||
policyUrl = route.request().url();
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ policy: null }),
|
||||
});
|
||||
});
|
||||
|
||||
await page.goto("./invite/base-path-code");
|
||||
await expect(
|
||||
page.getByRole("link", { name: "在 Buzz 中接受邀请" }),
|
||||
).toHaveAttribute("href", /relay=ws%3A%2F%2F127\.0\.0\.1%3A4173%2Fbuzz/);
|
||||
expect(policyUrl).toContain("/buzz/api/join-policy");
|
||||
});
|
||||
|
||||
test("invite requires age and legal consent before opening Buzz", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.route("**/buzz/api/join-policy", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({
|
||||
policy: {
|
||||
terms_markdown: "# Terms",
|
||||
privacy_markdown: "# Privacy",
|
||||
age_attestation_required: true,
|
||||
version: "policy-v1",
|
||||
},
|
||||
}),
|
||||
});
|
||||
});
|
||||
await page.route("https://api.github.com/**", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
headers: { "Access-Control-Allow-Origin": "*" },
|
||||
body: JSON.stringify([
|
||||
{ draft: false, prerelease: false, assets: [] },
|
||||
{
|
||||
draft: false,
|
||||
prerelease: false,
|
||||
assets: [
|
||||
{
|
||||
name: "Buzz_0.4.9_aarch64.dmg",
|
||||
browser_download_url:
|
||||
"https://github.com/block/buzz/releases/download/v0.4.9/Buzz_0.4.9_aarch64.dmg",
|
||||
},
|
||||
{
|
||||
name: "Buzz_0.4.9_x64.dmg",
|
||||
browser_download_url:
|
||||
"https://github.com/block/buzz/releases/download/v0.4.9/Buzz_0.4.9_x64.dmg",
|
||||
},
|
||||
{
|
||||
name: "Buzz_0.4.9_amd64.AppImage",
|
||||
browser_download_url:
|
||||
"https://github.com/block/buzz/releases/download/v0.4.9/Buzz_0.4.9_amd64.AppImage",
|
||||
},
|
||||
{
|
||||
name: "Buzz_0.4.9_x64-setup_alpha-unsigned.exe",
|
||||
browser_download_url:
|
||||
"https://github.com/block/buzz/releases/download/v0.4.9/Buzz_0.4.9_x64-setup_alpha-unsigned.exe",
|
||||
},
|
||||
],
|
||||
},
|
||||
]),
|
||||
});
|
||||
});
|
||||
await page.goto("./invite/demo-code");
|
||||
|
||||
await expect(page.getByRole("link", { name: "立即下载" })).toHaveAttribute(
|
||||
"href",
|
||||
"https://github.com/block/buzz/releases/download/v0.4.9/Buzz_0.4.9_x64-setup_alpha-unsigned.exe",
|
||||
);
|
||||
|
||||
const ageConfirmation = page.getByLabel("我已年满 18 周岁。");
|
||||
const agreementConfirmation = page.getByLabel(
|
||||
"我同意 Buzz 的服务条款和隐私政策。",
|
||||
);
|
||||
const acceptInvite = page.getByRole("button", {
|
||||
name: "在 Buzz 中接受邀请",
|
||||
});
|
||||
|
||||
await expect(ageConfirmation).toBeVisible();
|
||||
await expect(agreementConfirmation).toBeVisible();
|
||||
await expect(acceptInvite).toBeDisabled();
|
||||
|
||||
const termsLink = page.getByRole("button", { name: "服务条款" });
|
||||
const privacyLink = page.getByRole("button", { name: "隐私政策" });
|
||||
await expect(termsLink).toHaveCSS("text-decoration-line", "none");
|
||||
await expect(privacyLink).toHaveCSS("text-decoration-line", "none");
|
||||
await termsLink.hover();
|
||||
await expect(termsLink).toHaveCSS("text-decoration-line", "underline");
|
||||
await page.mouse.move(0, 0);
|
||||
await privacyLink.hover();
|
||||
await expect(privacyLink).toHaveCSS("text-decoration-line", "underline");
|
||||
|
||||
await page.locator("label").filter({ hasText: "我已年满 18 周岁。" }).click();
|
||||
await expect(ageConfirmation).toBeChecked();
|
||||
await expect(acceptInvite).toBeDisabled();
|
||||
await page
|
||||
.locator("label")
|
||||
.filter({
|
||||
hasText: "我同意 Buzz 的服务条款和隐私政策。",
|
||||
})
|
||||
.click({ position: { x: 8, y: 8 } });
|
||||
await expect(agreementConfirmation).toBeChecked();
|
||||
await expect(acceptInvite).toBeEnabled();
|
||||
|
||||
const consentBox = await page
|
||||
.getByTestId("invite-join-policy-notice")
|
||||
.boundingBox();
|
||||
const acceptButtonBox = await acceptInvite.boundingBox();
|
||||
expect(consentBox?.y).toBeLessThan(acceptButtonBox?.y ?? 0);
|
||||
expect(consentBox?.width).toBe(acceptButtonBox?.width);
|
||||
});
|
||||
|
||||
test("invite can enroll a NIP-07 identity for browser access", async ({
|
||||
page,
|
||||
}) => {
|
||||
const pubkey = "ab".repeat(32);
|
||||
await page.addInitScript((extensionPubkey) => {
|
||||
(
|
||||
window as Window & {
|
||||
nostr?: {
|
||||
getPublicKey(): Promise<string>;
|
||||
signEvent(
|
||||
event: Record<string, unknown>,
|
||||
): Promise<Record<string, unknown>>;
|
||||
};
|
||||
}
|
||||
).nostr = {
|
||||
async getPublicKey() {
|
||||
return extensionPubkey;
|
||||
},
|
||||
async signEvent(event) {
|
||||
return {
|
||||
...event,
|
||||
id: "cd".repeat(32),
|
||||
pubkey: extensionPubkey,
|
||||
sig: "ef".repeat(64),
|
||||
};
|
||||
},
|
||||
};
|
||||
}, pubkey);
|
||||
await page.route("**/buzz/api/join-policy", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ policy: null }),
|
||||
});
|
||||
});
|
||||
|
||||
let claimObserved = false;
|
||||
await page.route("**/buzz/api/invites/claim", async (route) => {
|
||||
claimObserved = true;
|
||||
const request = route.request();
|
||||
const body = request.postData() ?? "";
|
||||
expect(JSON.parse(body)).toEqual({
|
||||
code: "browser-code",
|
||||
});
|
||||
|
||||
const authorization = request.headers().authorization;
|
||||
expect(authorization).toMatch(/^Nostr /);
|
||||
const event = JSON.parse(
|
||||
Buffer.from(authorization.slice("Nostr ".length), "base64").toString(
|
||||
"utf8",
|
||||
),
|
||||
) as {
|
||||
pubkey: string;
|
||||
tags: string[][];
|
||||
};
|
||||
expect(event.pubkey).toBe(pubkey);
|
||||
expect(event.tags).toContainEqual(["u", request.url()]);
|
||||
expect(event.tags).toContainEqual(["method", "POST"]);
|
||||
expect(event.tags).toContainEqual([
|
||||
"payload",
|
||||
createHash("sha256").update(body).digest("hex"),
|
||||
]);
|
||||
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({
|
||||
status: "joined",
|
||||
community_id: "community-id",
|
||||
host: "127.0.0.1",
|
||||
role: "member",
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
await page.goto("./invite/browser-code");
|
||||
await page.getByRole("button", { name: "在浏览器中加入" }).click();
|
||||
await expect(page).toHaveURL(/\/buzz\/$/);
|
||||
expect(claimObserved).toBe(true);
|
||||
});
|
||||
|
||||
test("invite asks Safari users to choose their Mac download", async ({
|
||||
browser,
|
||||
}) => {
|
||||
const context = await browser.newContext({
|
||||
userAgent:
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Version/26.5 Safari/605.1.15",
|
||||
});
|
||||
await context.addInitScript(() => {
|
||||
Object.defineProperties(navigator, {
|
||||
platform: { configurable: true, value: "MacIntel" },
|
||||
maxTouchPoints: { configurable: true, value: 0 },
|
||||
userAgentData: { configurable: true, value: undefined },
|
||||
});
|
||||
});
|
||||
const page = await context.newPage();
|
||||
await page.route("**/buzz/api/join-policy", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ policy: null }),
|
||||
});
|
||||
});
|
||||
await page.route("https://api.github.com/**", async (route) => {
|
||||
await route.fulfill({ status: 500 });
|
||||
});
|
||||
|
||||
await page.goto("./invite/demo-code");
|
||||
const download = page.getByRole("link", { name: "立即下载" });
|
||||
await expect(download).toHaveAttribute("aria-haspopup", "dialog");
|
||||
await download.click();
|
||||
|
||||
const chooser = page.getByRole("dialog", {
|
||||
name: "你的 Mac 是哪一款?",
|
||||
});
|
||||
await expect(chooser).toBeVisible();
|
||||
await expect(chooser.getByRole("link", { name: /较新的 Mac/ })).toContainText(
|
||||
"2021 年或之后发布",
|
||||
);
|
||||
await expect(chooser.getByRole("link", { name: /较早的 Mac/ })).toContainText(
|
||||
"2019 年或之前发布",
|
||||
);
|
||||
await expect(chooser.getByText("关于本机")).toBeVisible();
|
||||
|
||||
const openedPagePromise = context.waitForEvent("page");
|
||||
await chooser.getByRole("link", { name: /较新的 Mac/ }).click();
|
||||
const openedPage = await openedPagePromise;
|
||||
await expect(chooser).toBeHidden();
|
||||
await expect(openedPage).toHaveURL("https://github.com/block/buzz/releases");
|
||||
await expect(page).toHaveURL(/\/buzz\/invite\/demo-code$/);
|
||||
await openedPage.close();
|
||||
|
||||
await download.click();
|
||||
await expect(chooser).toBeVisible();
|
||||
await page.keyboard.press("Escape");
|
||||
await expect(chooser).toBeHidden();
|
||||
await expect(download).toBeFocused();
|
||||
await context.close();
|
||||
});
|
||||
|
||||
test("invite download falls back for mobile and non-desktop devices", async ({
|
||||
browser,
|
||||
}) => {
|
||||
const unsupportedDevices = [
|
||||
{
|
||||
name: "iPhone Safari",
|
||||
platform: "iPhone",
|
||||
userAgent:
|
||||
"Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15",
|
||||
maxTouchPoints: 5,
|
||||
},
|
||||
{
|
||||
name: "iPadOS desktop mode",
|
||||
platform: "MacIntel",
|
||||
userAgent:
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15",
|
||||
maxTouchPoints: 5,
|
||||
},
|
||||
{
|
||||
name: "Android phone",
|
||||
platform: "Linux armv8l",
|
||||
userAgent:
|
||||
"Mozilla/5.0 (Linux; Android 15; Pixel 9 Pro) AppleWebKit/537.36 Mobile",
|
||||
maxTouchPoints: 5,
|
||||
},
|
||||
{
|
||||
name: "ChromeOS",
|
||||
platform: "Linux x86_64",
|
||||
userAgent: "Mozilla/5.0 (X11; CrOS x86_64 16093.68.0) AppleWebKit/537.36",
|
||||
maxTouchPoints: 0,
|
||||
},
|
||||
];
|
||||
|
||||
for (const device of unsupportedDevices) {
|
||||
const context = await browser.newContext({ userAgent: device.userAgent });
|
||||
await context.addInitScript(({ platform, maxTouchPoints }) => {
|
||||
Object.defineProperties(navigator, {
|
||||
platform: { configurable: true, value: platform },
|
||||
maxTouchPoints: { configurable: true, value: maxTouchPoints },
|
||||
userAgentData: {
|
||||
configurable: true,
|
||||
value: { platform, mobile: maxTouchPoints > 0 },
|
||||
},
|
||||
});
|
||||
}, device);
|
||||
const page = await context.newPage();
|
||||
await page.route("**/buzz/api/join-policy", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ policy: null }),
|
||||
});
|
||||
});
|
||||
await page.route("https://api.github.com/**", async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: "application/json",
|
||||
headers: { "Access-Control-Allow-Origin": "*" },
|
||||
body: JSON.stringify([
|
||||
{
|
||||
draft: false,
|
||||
prerelease: false,
|
||||
assets: [
|
||||
{
|
||||
name: "Buzz_0.4.9_x64.dmg",
|
||||
browser_download_url:
|
||||
"https://github.com/block/buzz/releases/download/v0.4.9/Buzz_0.4.9_x64.dmg",
|
||||
},
|
||||
{
|
||||
name: "Buzz_0.4.9_amd64.AppImage",
|
||||
browser_download_url:
|
||||
"https://github.com/block/buzz/releases/download/v0.4.9/Buzz_0.4.9_amd64.AppImage",
|
||||
},
|
||||
],
|
||||
},
|
||||
]),
|
||||
});
|
||||
});
|
||||
|
||||
await page.goto("./invite/demo-code");
|
||||
await expect(
|
||||
page.getByRole("link", { name: "立即下载" }),
|
||||
device.name,
|
||||
).toHaveAttribute("href", "https://github.com/block/buzz/releases");
|
||||
await context.close();
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user