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>
553 lines
19 KiB
TypeScript
553 lines
19 KiB
TypeScript
import { expect, test, type Page } from "@playwright/test";
|
|
|
|
import { installMockBridge, openChannelBrowser } from "../helpers/bridge";
|
|
|
|
const MOCK_PUBKEY = "deadbeef".repeat(8);
|
|
const CUSTOM_SECTION = { id: "sec-projects", name: "Projects", order: 0 };
|
|
|
|
async function seedCustomSection(page: Page) {
|
|
await page.addInitScript(
|
|
({ pubkey, section }) => {
|
|
window.localStorage.setItem(
|
|
`buzz-channel-sections.v1:${pubkey}`,
|
|
JSON.stringify({ version: 1, sections: [section], assignments: {} }),
|
|
);
|
|
},
|
|
{ pubkey: MOCK_PUBKEY, section: CUSTOM_SECTION },
|
|
);
|
|
}
|
|
|
|
test.beforeEach(async ({ page }, testInfo) => {
|
|
await installMockBridge(
|
|
page,
|
|
testInfo.title.includes("failed section create")
|
|
? { createChannelErrors: ["Create failed"] }
|
|
: undefined,
|
|
);
|
|
});
|
|
|
|
test("keyboard shortcut opens the channel browser dialog", async ({ page }) => {
|
|
await page.goto("/");
|
|
await expect(page.getByTestId("app-sidebar")).toBeVisible();
|
|
|
|
const isMacBrowser = await page.evaluate(() =>
|
|
/mac|iphone|ipad|ipod/i.test(navigator.platform),
|
|
);
|
|
|
|
if (isMacBrowser) {
|
|
await page.evaluate(() => {
|
|
window.dispatchEvent(
|
|
new KeyboardEvent("keydown", {
|
|
bubbles: true,
|
|
cancelable: true,
|
|
key: "O",
|
|
metaKey: true,
|
|
shiftKey: true,
|
|
}),
|
|
);
|
|
});
|
|
} else {
|
|
await page.keyboard.press("Control+Shift+O");
|
|
}
|
|
await expect(page.getByTestId("channel-browser-dialog")).toBeVisible();
|
|
});
|
|
|
|
test("channel browser shows channels not yet joined", async ({ page }) => {
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
await expect(page.getByTestId("channel-browser-dialog")).toBeVisible();
|
|
await expect(
|
|
page.getByRole("heading", { name: "Browse channels" }),
|
|
).toBeVisible();
|
|
|
|
// "design" and "sales" are open channels the mock user is NOT a member of
|
|
await expect(page.getByTestId("browse-channel-design")).toBeVisible();
|
|
await expect(page.getByTestId("browse-channel-sales")).toBeVisible();
|
|
|
|
// "general" is a channel the mock user IS a member of — shown in "Joined" section
|
|
await expect(page.getByTestId("browse-channel-general")).toBeVisible();
|
|
});
|
|
|
|
test("channel browser sorts alphabetically or by member count", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
const rows = page.locator('[data-testid^="browse-channel-"]');
|
|
|
|
await expect(rows).toHaveText([
|
|
/#agents/,
|
|
/#all-replies/,
|
|
/#deep-history/,
|
|
/#design/,
|
|
/#engineering/,
|
|
/#general/,
|
|
/#random/,
|
|
/#sales/,
|
|
/#secret-projects/,
|
|
/#welcome-everyone/,
|
|
]);
|
|
|
|
await page.getByTestId("channel-browser-sort").click();
|
|
await page.getByTestId("channel-browser-sort-members").click();
|
|
|
|
await expect(rows).toHaveText([
|
|
/#general/,
|
|
/#agents/,
|
|
/#engineering/,
|
|
/#random/,
|
|
/#all-replies/,
|
|
/#deep-history/,
|
|
/#design/,
|
|
/#sales/,
|
|
/#secret-projects/,
|
|
/#welcome-everyone/,
|
|
]);
|
|
await expect(page.getByTestId("channel-browser-sort")).toHaveAttribute(
|
|
"aria-label",
|
|
"Sort channels: Most members",
|
|
);
|
|
});
|
|
|
|
test("channel browser sorts by recent activity", async ({ page }) => {
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
const rows = page.locator('[data-testid^="browse-channel-"]');
|
|
|
|
await page.getByTestId("channel-browser-sort").click();
|
|
await page.getByTestId("channel-browser-sort-recent").click();
|
|
|
|
await expect(rows).toHaveText([
|
|
/#all-replies/,
|
|
/#deep-history/,
|
|
/#general/,
|
|
/#agents/,
|
|
/#sales/,
|
|
/#engineering/,
|
|
/#design/,
|
|
/#random/,
|
|
/#secret-projects/,
|
|
/#welcome-everyone/,
|
|
]);
|
|
await expect(page.getByTestId("channel-browser-sort")).toHaveAttribute(
|
|
"aria-label",
|
|
"Sort channels: Recent",
|
|
);
|
|
});
|
|
|
|
test("channel browser search filters by name", async ({ page }) => {
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
await expect(page.getByTestId("channel-browser-dialog")).toBeVisible();
|
|
|
|
await page.getByTestId("channel-browser-search").fill("design");
|
|
|
|
await expect(page.getByTestId("browse-channel-design")).toBeVisible();
|
|
await expect(page.getByTestId("browse-channel-sales")).toHaveCount(0);
|
|
await expect(page.getByTestId("browse-channel-general")).toHaveCount(0);
|
|
});
|
|
|
|
test("channel browser search filters by description", async ({ page }) => {
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
await page.getByTestId("channel-browser-search").fill("pipeline");
|
|
|
|
// "sales" has "pipeline" in its description
|
|
await expect(page.getByTestId("browse-channel-sales")).toBeVisible();
|
|
await expect(page.getByTestId("browse-channel-design")).toHaveCount(0);
|
|
});
|
|
|
|
test("channel browser shows no results for unmatched search", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
await page.getByTestId("channel-browser-search").fill("zzz-nonexistent");
|
|
|
|
await expect(page.getByText("No channels match your search")).toBeVisible();
|
|
});
|
|
|
|
test("channel browser fuzzy-matches a subsequence", async ({ page }) => {
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
// "engr" is not a substring of "engineering", but it is an in-order
|
|
// subsequence — plain includes() would miss it, fuzzy matching finds it.
|
|
await page.getByTestId("channel-browser-search").fill("engr");
|
|
|
|
await expect(page.getByTestId("browse-channel-engineering")).toBeVisible();
|
|
await expect(page.getByTestId("browse-channel-general")).toHaveCount(0);
|
|
});
|
|
|
|
test("channel browser matches a scattered subsequence", async ({ page }) => {
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
// "sls" is neither a substring nor a prefix of "sales" — it only matches as
|
|
// an in-order subsequence (s·a·l·e·s). Proves fuzzy matching end-to-end.
|
|
await page.getByTestId("channel-browser-search").fill("sls");
|
|
|
|
await expect(page.getByTestId("browse-channel-sales")).toBeVisible();
|
|
await expect(page.getByTestId("browse-channel-general")).toHaveCount(0);
|
|
});
|
|
|
|
test("channel browser ranks the best match first", async ({ page }) => {
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
// "gen" is a prefix of "general" (strong match) but only a substring of
|
|
// "agents" and a subsequence of "engineering" (weaker). The prefix match
|
|
// should float to the top regardless of the alphabetical default sort.
|
|
await page.getByTestId("channel-browser-search").fill("gen");
|
|
|
|
const firstRow = page.getByTestId(/^browse-channel-/).first();
|
|
await expect(firstRow).toHaveAttribute(
|
|
"data-testid",
|
|
"browse-channel-general",
|
|
);
|
|
});
|
|
|
|
test("sidebar add-channel button creates without treating the click as a callback", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto("/");
|
|
await expect(page.getByTestId("app-sidebar")).toBeVisible();
|
|
|
|
await page.getByTestId("section-actions-channels-quick-create").click();
|
|
|
|
await expect(page.getByTestId("channel-browser-dialog")).toBeVisible();
|
|
const channelName = `sidebar-created-${Date.now()}`;
|
|
await page.getByTestId("channel-browser-search").fill(channelName);
|
|
await page.getByTestId("channel-browser-create-row").click();
|
|
await page.getByTestId("create-channel-submit").click();
|
|
|
|
await expect(page.getByTestId("channel-browser-dialog")).not.toBeVisible();
|
|
await expect(page.getByTestId("stream-list")).toContainText(channelName);
|
|
});
|
|
|
|
test("custom section add button creates directly into that section", async ({
|
|
page,
|
|
}) => {
|
|
await seedCustomSection(page);
|
|
await page.goto("/");
|
|
|
|
const addButton = page.getByTestId(
|
|
`section-actions-${CUSTOM_SECTION.id}-quick-create`,
|
|
);
|
|
await expect(addButton).toHaveAccessibleName("Add channel to Projects");
|
|
await addButton.click();
|
|
await expect(page.getByTestId("channel-browser-dialog")).toBeVisible();
|
|
|
|
const channelName = `section-created-${Date.now()}`;
|
|
await page.getByTestId("channel-browser-search").fill(channelName);
|
|
await page.getByTestId("channel-browser-create-row").click();
|
|
await page.getByTestId("create-channel-submit").click();
|
|
|
|
await expect(page.getByTestId("channel-browser-dialog")).not.toBeVisible();
|
|
await expect(
|
|
page.getByTestId(`section-title-${CUSTOM_SECTION.id}`),
|
|
).toBeVisible();
|
|
await expect(page.getByTestId(`channel-${channelName}`)).toBeVisible();
|
|
await expect(page.getByTestId("stream-list")).not.toContainText(channelName);
|
|
});
|
|
|
|
test("canceling section create does not affect the next global create", async ({
|
|
page,
|
|
}) => {
|
|
await seedCustomSection(page);
|
|
await page.goto("/");
|
|
|
|
await page
|
|
.getByTestId(`section-actions-${CUSTOM_SECTION.id}-quick-create`)
|
|
.click();
|
|
// Gate on the dialog mounting before dismissing it. Escape sent before mount
|
|
// is dropped (no handler yet), and not.toBeVisible() then passes vacuously
|
|
// against a dialog that hasn't rendered — so the dialog opens *after* the
|
|
// assertion and its overlay swallows every later click.
|
|
await expect(page.getByTestId("channel-browser-dialog")).toBeVisible();
|
|
await page.keyboard.press("Escape");
|
|
await expect(page.getByTestId("channel-browser-dialog")).not.toBeVisible();
|
|
// The overlay outlives the content by one exit animation; wait for it to
|
|
// detach so it can't intercept the next click.
|
|
await expect(page.getByTestId("dialog-overlay")).toHaveCount(0);
|
|
|
|
await page.getByTestId("section-actions-channels-quick-create").click();
|
|
const channelName = `global-after-cancel-${Date.now()}`;
|
|
await page.getByTestId("channel-browser-search").fill(channelName);
|
|
await page.getByTestId("channel-browser-create-row").click();
|
|
await page.getByTestId("create-channel-submit").click();
|
|
|
|
await expect(page.getByTestId("stream-list")).toContainText(channelName);
|
|
});
|
|
|
|
test("failed section create retry still assigns to the section", async ({
|
|
page,
|
|
}) => {
|
|
await seedCustomSection(page);
|
|
await page.goto("/");
|
|
|
|
await page
|
|
.getByTestId(`section-actions-${CUSTOM_SECTION.id}-quick-create`)
|
|
.click();
|
|
const channelName = `section-retry-${Date.now()}`;
|
|
await page.getByTestId("channel-browser-search").fill(channelName);
|
|
await page.getByTestId("channel-browser-create-row").click();
|
|
await page.getByTestId("create-channel-submit").click();
|
|
await expect(page.getByText("Create failed")).toBeVisible();
|
|
|
|
await page.getByTestId("create-channel-submit").click();
|
|
|
|
await expect(page.getByTestId("channel-browser-dialog")).not.toBeVisible();
|
|
await expect(page.getByTestId(`channel-${channelName}`)).toBeVisible();
|
|
await expect(page.getByTestId("stream-list")).not.toContainText(channelName);
|
|
});
|
|
|
|
test("create affordance is visible on open before typing", async ({ page }) => {
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
|
|
// The create row is present from the get-go so it's clear you can browse OR
|
|
// create — not just after you start typing.
|
|
const createRow = page.getByTestId("channel-browser-create-row");
|
|
await expect(createRow).toBeVisible();
|
|
await expect(createRow).toContainText("Create a new channel");
|
|
});
|
|
|
|
test("typing a partial match surfaces a persistent create row", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
// "desig" matches "design" by substring but is not an exact channel name,
|
|
// so both the matching channel AND the create row are shown.
|
|
await page.getByTestId("channel-browser-search").fill("desig");
|
|
|
|
const createRow = page.getByTestId("channel-browser-create-row");
|
|
await expect(createRow).toBeVisible();
|
|
await expect(createRow).toContainText("desig");
|
|
await expect(page.getByTestId("browse-channel-design")).toBeVisible();
|
|
});
|
|
|
|
test("exact name match hides the create row", async ({ page }) => {
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
await page.getByTestId("channel-browser-search").fill("general");
|
|
|
|
await expect(page.getByTestId("browse-channel-general")).toBeVisible();
|
|
await expect(page.getByTestId("channel-browser-create-row")).toHaveCount(0);
|
|
});
|
|
|
|
test("no-match search pins a create row above the empty state", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
await page.getByTestId("channel-browser-search").fill("zzz-nonexistent");
|
|
|
|
await expect(page.getByText("No channels match your search")).toBeVisible();
|
|
const createRow = page.getByTestId("channel-browser-create-row");
|
|
await expect(createRow).toBeVisible();
|
|
await expect(createRow).toContainText("zzz-nonexistent");
|
|
});
|
|
|
|
test("create row leads to the prefilled create form", async ({ page }) => {
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
await page.getByTestId("channel-browser-search").fill("desig");
|
|
await page.getByTestId("channel-browser-create-row").click();
|
|
|
|
// Create mode reuses the shared form; the name is prefilled from the query.
|
|
await expect(page.getByTestId("create-channel-name")).toHaveValue("desig");
|
|
|
|
// Back returns to the search list without closing the dialog.
|
|
await page.getByTestId("channel-browser-create-back").click();
|
|
await expect(page.getByTestId("channel-browser-search")).toBeVisible();
|
|
});
|
|
|
|
test("creating from the browser adds the channel to the sidebar", async ({
|
|
page,
|
|
}) => {
|
|
const channelName = `browse-created-${Date.now()}`;
|
|
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
await page.getByTestId("channel-browser-search").fill(channelName);
|
|
await page.getByTestId("channel-browser-create-row").click();
|
|
|
|
await expect(page.getByTestId("create-channel-name")).toHaveValue(
|
|
channelName,
|
|
);
|
|
await page.getByTestId("create-channel-submit").click();
|
|
|
|
await expect(page.getByTestId("channel-browser-dialog")).not.toBeVisible();
|
|
await expect(page.getByTestId("stream-list")).toContainText(channelName);
|
|
await expect(page.getByTestId("chat-title")).toContainText(channelName);
|
|
});
|
|
|
|
test("Enter with no matches jumps to create", async ({ page }) => {
|
|
const channelName = `enter-created-${Date.now()}`;
|
|
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
await page.getByTestId("channel-browser-search").fill(channelName);
|
|
await page.keyboard.press("Enter");
|
|
|
|
await expect(page.getByTestId("create-channel-name")).toHaveValue(
|
|
channelName,
|
|
);
|
|
});
|
|
|
|
test("arrow keys reach the pinned create row and Enter activates it", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
// "desig" keeps a channel match (#design) AND the create row visible, so the
|
|
// create row is not the only actionable item — it must be reachable by
|
|
// keyboard, not just Tab.
|
|
await page.getByTestId("channel-browser-search").fill("desig");
|
|
|
|
const createRow = page.getByTestId("channel-browser-create-row");
|
|
await expect(createRow).toBeVisible();
|
|
|
|
// The create row is pinned at the top → first ArrowDown highlights it.
|
|
await page.keyboard.press("ArrowDown");
|
|
await expect(createRow).toHaveAttribute("data-selected", "true");
|
|
|
|
// Enter on the highlighted create row enters the prefilled create form.
|
|
await page.keyboard.press("Enter");
|
|
await expect(page.getByTestId("create-channel-name")).toHaveValue("desig");
|
|
});
|
|
|
|
test("Enter selects a channel when create row is not highlighted", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
// With the create row present but NOT highlighted, Enter should still select
|
|
// the first channel match rather than jumping to create.
|
|
await page.getByTestId("channel-browser-search").fill("desig");
|
|
await expect(page.getByTestId("browse-channel-design")).toBeVisible();
|
|
|
|
await page.keyboard.press("Enter");
|
|
|
|
await expect(page.getByTestId("channel-browser-dialog")).not.toBeVisible();
|
|
await expect(page.getByTestId("chat-title")).toHaveText("design");
|
|
});
|
|
|
|
test("joining a channel from browser adds it to the sidebar", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto("/");
|
|
|
|
// Verify "design" is not in the sidebar
|
|
const streamList = page.getByTestId("stream-list");
|
|
await expect(streamList).not.toContainText("design");
|
|
|
|
// Open browser and join
|
|
await openChannelBrowser(page);
|
|
await expect(page.getByTestId("channel-browser-dialog")).toBeVisible();
|
|
await page
|
|
.getByTestId("browse-channel-design")
|
|
.getByRole("button", { name: "Join" })
|
|
.click();
|
|
|
|
// Dialog should close and navigate to the joined channel
|
|
await expect(page.getByTestId("channel-browser-dialog")).not.toBeVisible();
|
|
await expect(page).toHaveURL(/#\/channels\//);
|
|
await expect(page.getByTestId("chat-title")).toHaveText("design");
|
|
|
|
// Channel should now appear in the sidebar
|
|
await expect(streamList).toContainText("design");
|
|
});
|
|
|
|
test("clicking a joined channel in browser navigates to it", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
await expect(page.getByTestId("channel-browser-dialog")).toBeVisible();
|
|
|
|
// "general" is already joined — clicking should navigate without join
|
|
await page.getByTestId("browse-channel-general").click();
|
|
|
|
await expect(page.getByTestId("channel-browser-dialog")).not.toBeVisible();
|
|
await expect(page).toHaveURL(/#\/channels\//);
|
|
await expect(page.getByTestId("chat-title")).toHaveText("general");
|
|
});
|
|
|
|
test("channel browser does not show DM or private channels", async ({
|
|
page,
|
|
}) => {
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
await expect(page.getByTestId("channel-browser-dialog")).toBeVisible();
|
|
|
|
// DM channels should not appear
|
|
await expect(page.getByTestId("browse-channel-alice-tyler")).toHaveCount(0);
|
|
await expect(page.getByTestId("browse-channel-bob-tyler")).toHaveCount(0);
|
|
|
|
// Private forum should not appear
|
|
await expect(page.getByTestId("browse-channel-announcements")).toHaveCount(0);
|
|
});
|
|
|
|
test("channel browser closes on escape", async ({ page }) => {
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
await expect(page.getByTestId("channel-browser-dialog")).toBeVisible();
|
|
|
|
await page.keyboard.press("Escape");
|
|
await expect(page.getByTestId("channel-browser-dialog")).not.toBeVisible();
|
|
});
|
|
|
|
test("keyboard navigation works in channel browser", async ({ page }) => {
|
|
await page.goto("/");
|
|
|
|
await openChannelBrowser(page);
|
|
await expect(page.getByTestId("channel-browser-dialog")).toBeVisible();
|
|
|
|
// Filter to unjoined channels only to get a predictable list
|
|
await page.getByTestId("channel-browser-search").fill("design");
|
|
await expect(page.getByTestId("browse-channel-design")).toBeVisible();
|
|
|
|
// Press Enter to join the selected (first) channel
|
|
await page.keyboard.press("Enter");
|
|
|
|
await expect(page.getByTestId("channel-browser-dialog")).not.toBeVisible();
|
|
await expect(page.getByTestId("chat-title")).toHaveText("design");
|
|
});
|
|
|
|
test("sidebar only shows channels the user has joined", async ({ page }) => {
|
|
await page.goto("/");
|
|
|
|
const streamList = page.getByTestId("stream-list");
|
|
|
|
// Channels the mock user IS a member of
|
|
await expect(streamList).toContainText("general");
|
|
await expect(streamList).toContainText("random");
|
|
await expect(streamList).toContainText("engineering");
|
|
await expect(streamList).toContainText("agents");
|
|
|
|
// Channels the mock user is NOT a member of
|
|
await expect(streamList).not.toContainText("design");
|
|
await expect(streamList).not.toContainText("sales");
|
|
});
|