Files
buzz/desktop/tests/e2e/channel-mute.spec.ts
klopez4212 540b58920c Polish sidebar unread hierarchy (#4573)
## Summary

- Keep selected sidebar rows regular by default; manually unread rows
become bold immediately.
- Apply a clearer dark-mode hierarchy: standard inactive rows at 75%,
muted rows at 45%, and unread rows at full emphasis.
- Keep hover text color stable while retaining the selected-row and
unread cues.

## Validation

- `pnpm typecheck`
- `pnpm build:e2e`
- Playwright: sidebar badge and channel-mute coverage

## Screenshots

Posted in the PR comments.

---------

Signed-off-by: kenny lopez <klopez4212@gmail.com>
2026-08-04 15:39:45 +00:00

191 lines
5.8 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;
}) => boolean;
}
).__BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?.({ channelName: ch }) ??
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");
await expect(engRow).toBeVisible();
await expect(engRow).toHaveCSS("opacity", "1");
await expect(engRow.locator("[data-sidebar-row-label]")).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 page.getByTestId("channel-random").click();
const mutedLabel = page
.getByTestId("channel-engineering")
.locator("[data-sidebar-row-label]");
await expect(mutedLabel).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 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);
});
});