mirror of
https://github.com/block/buzz.git
synced 2026-10-30 22:11:36 +00:00
## Summary Repair the mock-backed desktop smoke fixtures blocking release PR #7817. No application unread logic, styling, audio component, scheduler, or release-tool changes. - Require an exact channel-scoped kind-9 subscription before injecting unread messages, including after navigation. The old readiness check could accept a global-only, wrong-channel, or wrong-kind consumer. The extracted predicate is used by the real mock bridge and has regression coverage for those false positives and legacy behavior. - Seed the 24 audio messages offscreen with distinct timestamps, then open the channel with all cards in the load margin. Same-second random event IDs previously reordered the settling timeline, causing different visible cards to start loads. This was viewport churn, not a component restart defect. - Expose the existing real audio scheduler snapshot through the E2E bridge. Assert 3 active / 21 queued before navigation and 0 active / 0 queued afterward. Preserve the peak-3 cap, exact 3 fetches / cancellations / releases, zero object URLs, and existing unread/bold assertions. No sleeps, retries, skipped tests, or relaxed limits were added. ## Validation - Before commit, all 30 tests in `channel-activity-popover.spec.ts`, `channel-mute.spec.ts`, and `voice-note.spec.ts` passed five repetitions with retries disabled: **150/150**. This was the working repair on base `312cf674f`, before final formatting/cleanup, not the entire smoke suite. - At committed head `1b126afbe75c2a2afbdfe13744f0938fa584764e`, normal pre-push hooks passed: **6,591/6,591 desktop unit tests**, desktop checks, TypeScript typechecking, differential file-size gate, and branch-skew check. Pre-commit Biome formatting passed; working tree is clean. - Independent sidebar and audio reviews found no substantive blocker. Their formatting findings are resolved in this commit. - Full repository `just ci`, native release packaging, and the entire Playwright smoke suite were not run locally. GitHub CI is the remaining broader gate; this PR is not a release certification. ## Release follow-up After this repair is merged and required checks pass, regenerate #7817 through the desktop release tooling and validate the new candidate's exact head. This PR does not merge or publish a release. Originating discussion: buzz://message?channel=3428ec3f-a58b-429b-afbc-dc6a77918ce8&id=3303565b14334696e9bbf433ef3ad1aea4307acc69834f7f685a412e81354493 Signed-off-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz> Co-authored-by: Carl <32a2e2c9d428ee08902cab75d956da2c1d235a22d4766b0dd4138bf6e2e5db1d@buzz.block.builderlab.xyz>
202 lines
6.2 KiB
TypeScript
202 lines
6.2 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
|
|
import { TEST_IDENTITIES, installMockBridge } from "../helpers/bridge";
|
|
|
|
const MOCK_PUBKEY = "deadbeef".repeat(8);
|
|
const ENGINEERING_CHANNEL_ID = "1c7e1c02-87bb-5e88-b2da-5a7a9432d0c9";
|
|
const MUTE_STORAGE_KEY = `buzz-channel-mutes.v1:${MOCK_PUBKEY}`;
|
|
|
|
function seedMuteState(
|
|
page: import("@playwright/test").Page,
|
|
channelId: string,
|
|
) {
|
|
return page.addInitScript(
|
|
({ key, id }) => {
|
|
localStorage.setItem(
|
|
key,
|
|
JSON.stringify({
|
|
version: 1,
|
|
channels: {
|
|
[id]: { muted: true, updatedAt: 1700000000 },
|
|
},
|
|
}),
|
|
);
|
|
},
|
|
{ key: MUTE_STORAGE_KEY, id: channelId },
|
|
);
|
|
}
|
|
|
|
async function waitForMockLiveSubscription(
|
|
page: import("@playwright/test").Page,
|
|
channelName: string,
|
|
) {
|
|
await expect
|
|
.poll(async () => {
|
|
return page.evaluate(
|
|
({ ch }) =>
|
|
(
|
|
window as Window & {
|
|
__BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?: (input: {
|
|
channelName: string;
|
|
kind: number;
|
|
exactChannel: boolean;
|
|
}) => boolean;
|
|
}
|
|
).__BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?.({
|
|
channelName: ch,
|
|
kind: 9,
|
|
exactChannel: true,
|
|
}) ?? false,
|
|
{ ch: channelName },
|
|
);
|
|
})
|
|
.toBe(true);
|
|
}
|
|
|
|
test.describe("channel muting", () => {
|
|
test("01 — context menu shows Mute channel", async ({ page }) => {
|
|
await installMockBridge(page);
|
|
await page.goto("/");
|
|
await page.getByTestId("channel-general").click();
|
|
await expect(page.getByTestId("chat-title")).toHaveText("general");
|
|
|
|
await page.getByTestId("channel-random").click();
|
|
await expect(page.getByTestId("chat-title")).toHaveText("random");
|
|
|
|
await page.getByTestId("channel-general").click({ button: "right" });
|
|
const muteItem = page.getByRole("menuitem", { name: "Mute channel" });
|
|
await expect(muteItem).toBeVisible();
|
|
await muteItem.evaluate((el) =>
|
|
Promise.all(
|
|
el
|
|
.closest("[data-state]")
|
|
?.getAnimations()
|
|
.map((a) => a.finished) ?? [],
|
|
),
|
|
);
|
|
});
|
|
|
|
test("02 — muted channel is dimmed with BellOff icon", async ({ page }) => {
|
|
await seedMuteState(page, ENGINEERING_CHANNEL_ID);
|
|
await installMockBridge(page);
|
|
|
|
await page.goto("/");
|
|
await page.getByTestId("channel-random").click();
|
|
await expect(page.getByTestId("chat-title")).toHaveText("random");
|
|
|
|
const engRow = page.getByTestId("channel-engineering");
|
|
const engLabel = engRow.locator("[data-sidebar-row-label]");
|
|
await expect(engRow).toBeVisible();
|
|
await expect(engRow).toHaveCSS("opacity", "1");
|
|
await expect(engLabel).toHaveCSS("opacity", "0.5");
|
|
await expect(engRow.locator("svg.lucide-hash")).toHaveCSS("opacity", "0.5");
|
|
await expect(engRow.locator("svg.lucide-bell-off")).toHaveCount(1);
|
|
});
|
|
|
|
test("02b — muted channels recede further in dark mode", async ({ page }) => {
|
|
await page.addInitScript(() => {
|
|
window.localStorage.setItem("buzz-theme", "buzz-dark");
|
|
});
|
|
await seedMuteState(page, ENGINEERING_CHANNEL_ID);
|
|
await installMockBridge(page);
|
|
|
|
await page.goto("/");
|
|
await expect(page.locator("html")).toHaveClass(/dark/);
|
|
await page.getByTestId("channel-random").click();
|
|
|
|
const engRow = page.getByTestId("channel-engineering");
|
|
await expect(engRow).toHaveCSS("opacity", "1");
|
|
await expect(engRow.locator("[data-sidebar-row-label]")).toHaveCSS(
|
|
"opacity",
|
|
"0.45",
|
|
);
|
|
await expect(engRow.locator("svg.lucide-hash")).toHaveCSS(
|
|
"opacity",
|
|
"0.45",
|
|
);
|
|
});
|
|
|
|
test("03 — muted channel with a top-level @mention is emphasized", async ({
|
|
page,
|
|
}) => {
|
|
await seedMuteState(page, ENGINEERING_CHANNEL_ID);
|
|
await installMockBridge(page);
|
|
|
|
await page.goto("/");
|
|
await page.getByTestId("channel-engineering").click();
|
|
await expect(page.getByTestId("chat-title")).toHaveText("engineering");
|
|
await waitForMockLiveSubscription(page, "engineering");
|
|
|
|
await page.getByTestId("channel-random").click();
|
|
await expect(page.getByTestId("chat-title")).toHaveText("random");
|
|
await waitForMockLiveSubscription(page, "engineering");
|
|
|
|
await page.evaluate(
|
|
({ pubkey, mockPubkey }) => {
|
|
(
|
|
window as Window & {
|
|
__BUZZ_E2E_EMIT_MOCK_MESSAGE__?: (input: {
|
|
channelName: string;
|
|
content: string;
|
|
pubkey: string;
|
|
mentionPubkeys: string[];
|
|
}) => unknown;
|
|
}
|
|
).__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
|
|
channelName: "engineering",
|
|
content: "Hey check this out",
|
|
pubkey,
|
|
mentionPubkeys: [mockPubkey],
|
|
});
|
|
},
|
|
{
|
|
pubkey: TEST_IDENTITIES.alice.pubkey,
|
|
mockPubkey: MOCK_PUBKEY,
|
|
},
|
|
);
|
|
|
|
await expect(page.getByTestId("channel-engineering")).toHaveCSS(
|
|
"font-weight",
|
|
"700",
|
|
);
|
|
await expect(
|
|
page.getByTestId("channel-unread-dot-engineering"),
|
|
).toHaveCount(0);
|
|
});
|
|
|
|
test("04 — context menu shows Unmute channel when muted", async ({
|
|
page,
|
|
}) => {
|
|
await seedMuteState(page, ENGINEERING_CHANNEL_ID);
|
|
await installMockBridge(page);
|
|
|
|
await page.goto("/");
|
|
await page.getByTestId("channel-random").click();
|
|
await expect(page.getByTestId("chat-title")).toHaveText("random");
|
|
|
|
await page.getByTestId("channel-engineering").click({ button: "right" });
|
|
const unmuteItem = page.getByRole("menuitem", { name: "Unmute channel" });
|
|
await expect(unmuteItem).toBeVisible();
|
|
await unmuteItem.evaluate((el) =>
|
|
Promise.all(
|
|
el
|
|
.closest("[data-state]")
|
|
?.getAnimations()
|
|
.map((a) => a.finished) ?? [],
|
|
),
|
|
);
|
|
});
|
|
|
|
test("05 — muted icon visible on selected channel", async ({ page }) => {
|
|
await seedMuteState(page, ENGINEERING_CHANNEL_ID);
|
|
await installMockBridge(page);
|
|
|
|
await page.goto("/");
|
|
await page.getByTestId("channel-engineering").click();
|
|
await expect(page.getByTestId("chat-title")).toHaveText("engineering");
|
|
|
|
const engRow = page.getByTestId("channel-engineering");
|
|
await expect(engRow.locator("svg.lucide-bell-off")).toHaveCount(1);
|
|
});
|
|
});
|