Files
buzz/desktop/tests/e2e/huddle-transcription.spec.ts
T
cls 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
feat: import Chinese-localized Buzz source snapshot
Signed-off-by: cls_宁波本机 <908705107@qq.com>
2026-08-13 18:34:25 +08:00

1625 lines
50 KiB
TypeScript

import { expect, test } from "@playwright/test";
import {
KIND_HUDDLE_ENDED,
KIND_HUDDLE_STARTED,
} from "../../src/shared/constants/kinds";
import { waitForAnimations } from "../helpers/animations";
import { installMockBridge, TEST_IDENTITIES } from "../helpers/bridge";
const HUDDLE_CHANNEL_ID = "11111111-1111-4111-8111-111111111111";
const HUDDLE_PARENT_ID = "9a1657ac-f7aa-5db0-b632-d8bbeb6dfb50";
const HUDDLE_THREAD_ROOT_ID = "mock-general-welcome";
async function waitForMockLiveSubscription(
page: import("@playwright/test").Page,
channelName: string,
kind?: number,
) {
await expect
.poll(() =>
page.evaluate(
({ kind, name }) =>
window.__BUZZ_E2E_HAS_MOCK_LIVE_SUBSCRIPTION__?.({
channelName: name,
kind,
}) ?? false,
{ kind, name: channelName },
),
)
.toBe(true);
}
async function setHuddleSnapshot(
page: import("@playwright/test").Page,
members: Array<{
pubkey: string;
role: "member" | "bot";
}>,
transcriptionEnabled: boolean,
) {
await page.evaluate(
async ({ nextMembers, nextTranscriptionEnabled }) => {
const setSnapshot = (
window as Window & {
__BUZZ_E2E_SET_MOCK_HUDDLE_SNAPSHOT__?: (input: {
members: Array<{
pubkey: string;
role: "member" | "bot";
}>;
transcriptionEnabled: boolean;
}) => Promise<void>;
}
).__BUZZ_E2E_SET_MOCK_HUDDLE_SNAPSHOT__;
if (!setSnapshot) {
throw new Error("Mock huddle snapshot control is not installed.");
}
await setSnapshot({
members: nextMembers,
transcriptionEnabled: nextTranscriptionEnabled,
});
},
{ nextMembers: members, nextTranscriptionEnabled: transcriptionEnabled },
);
}
async function installFakeHuddleMicrophone(
page: import("@playwright/test").Page,
) {
await page.addInitScript(() => {
const mediaDevices = navigator.mediaDevices ?? ({} as MediaDevices);
if (!navigator.mediaDevices) {
Object.defineProperty(navigator, "mediaDevices", {
configurable: true,
value: mediaDevices,
});
}
Object.defineProperty(mediaDevices, "enumerateDevices", {
configurable: true,
value: async () => [
{
deviceId: "mock-huddle-microphone",
groupId: "mock-huddle-audio",
kind: "audioinput",
label: "Mock Huddle Microphone",
toJSON() {
return this;
},
} as MediaDeviceInfo,
],
});
Object.defineProperty(mediaDevices, "getUserMedia", {
configurable: true,
value: async () => {
const context = new AudioContext({ sampleRate: 48_000 });
const oscillator = context.createOscillator();
const gain = context.createGain();
const destination = context.createMediaStreamDestination();
gain.gain.value = 0;
oscillator.connect(gain);
gain.connect(destination);
oscillator.start();
return destination.stream;
},
});
});
}
test("keeps the drawer open until the huddle is expanded", async ({ page }) => {
await page.addInitScript(() => {
window.localStorage.setItem("buzz-theme", "buzz-dark");
});
await installMockBridge(page, {
huddle: {
parentChannelId: HUDDLE_PARENT_ID,
ephemeralChannelId: HUDDLE_CHANNEL_ID,
members: [
{ pubkey: TEST_IDENTITIES.tyler.pubkey, role: "member" },
{ pubkey: TEST_IDENTITIES.alice.pubkey, role: "bot" },
],
transcriptionEnabled: true,
},
});
await page.goto("/");
const gradientUnderlay = page.locator(".buzz-theme-gradient-underlay");
const openGradient = await gradientUnderlay.evaluate(
(element) => getComputedStyle(element).backgroundImage,
);
expect(openGradient).not.toBe("none");
const transcriptButton = page.getByRole("button", {
name: "Stop transcript",
});
await expect(transcriptButton).toBeVisible();
const huddleShell = page.locator(".buzz-huddle-shell");
await expect(huddleShell).toHaveAttribute("data-huddle-open", "true");
const huddleBackdrop = page.locator(".buzz-huddle-drawer-backdrop");
await expect(huddleBackdrop).toHaveClass(/buzz-huddle-drawer-backdrop-open/);
const [huddleBackdropColor, huddleDrawerColor] = await Promise.all([
huddleBackdrop.evaluate(
(element) => getComputedStyle(element).backgroundColor,
),
page
.locator(".buzz-huddle-drawer")
.first()
.evaluate((element) => getComputedStyle(element).backgroundColor),
]);
expect(huddleBackdropColor).toBe(huddleDrawerColor);
await expect
.poll(() =>
huddleBackdrop.evaluate((element) => {
const shell = element.parentElement;
const appSurface = shell?.querySelector(".buzz-huddle-app-surface");
if (!appSurface) return false;
const backdropStyle = getComputedStyle(element);
const appStyle = getComputedStyle(appSurface);
return Number(backdropStyle.zIndex) < Number(appStyle.zIndex);
}),
)
.toBe(true);
const drawerAgentMenu = page.getByRole("button", {
name: "Voice settings for alice",
});
await expect(
drawerAgentMenu.getByTestId("huddle-participant-avatar"),
).toBeVisible();
await drawerAgentMenu.click();
await expect(
page.getByText("Agent text-to-speech", { exact: true }),
).toBeVisible();
await expect(page.getByText("Agent voice", { exact: true })).toBeVisible();
await expect(
page.getByRole("button", { name: "Remove alice from huddle" }),
).toBeVisible();
await page.keyboard.press("Escape");
await expect(page.getByTestId("profile-huddle-control")).toHaveCount(0);
await page
.getByRole("button", { name: "Open huddle in a new window" })
.click();
await expect
.poll(() =>
page.evaluate(
() =>
(window.__BUZZ_E2E_COMMAND_LOG__ ?? []).filter(
(entry) => entry.command === "open_huddle_window",
).length,
),
)
.toBe(1);
const huddleControl = page.getByTestId("profile-huddle-control");
await expect(huddleControl).toBeVisible();
const mainContentSurface = page.locator(
"[data-buzz-content-surface]:not([data-buzz-content-unframed])",
);
await expect(mainContentSurface).toBeVisible();
const [mainContentColor, huddleCardColor] = await Promise.all([
mainContentSurface.evaluate(
(element) => getComputedStyle(element).backgroundColor,
),
huddleControl.evaluate(
(element) => getComputedStyle(element).backgroundColor,
),
]);
expect(huddleCardColor).toBe(mainContentColor);
await expect(huddleControl).toHaveCSS("border-top-width", "1px");
await expect(huddleControl).toContainText("In a huddle");
await expect(huddleControl).toContainText("#general");
const compactMicButton = huddleControl.getByRole("button", {
name: /microphone/i,
});
await expect(compactMicButton).toBeVisible();
await expect(compactMicButton).toHaveClass(/bg-destructive\/15/);
await expect(compactMicButton).toHaveClass(/text-destructive/);
await expect(
huddleControl.getByRole("button", { name: "Audio settings" }),
).not.toHaveClass(/bg-destructive\/15/);
const [micContainerRadius, micHoverRadius] = await Promise.all([
compactMicButton
.locator("..")
.evaluate((element) => getComputedStyle(element).borderTopLeftRadius),
compactMicButton.evaluate(
(element) => getComputedStyle(element).borderTopLeftRadius,
),
]);
expect(micHoverRadius).toBe(micContainerRadius);
await expect(huddleControl).toContainText("Leave");
await expect(
huddleControl.getByRole("button", { name: /huddle speaker/i }),
).toHaveCount(0);
await expect(transcriptButton).toHaveCount(0);
await huddleControl
.getByRole("button", { name: "Open huddle window" })
.click();
await expect
.poll(() =>
page.evaluate(
() =>
(window.__BUZZ_E2E_COMMAND_LOG__ ?? []).filter(
(entry) => entry.command === "open_huddle_window",
).length,
),
)
.toBe(2);
await huddleControl.getByRole("button", { name: "Leave huddle" }).click();
await expect
.poll(() =>
page.evaluate(
() =>
(window.__BUZZ_E2E_COMMAND_LOG__ ?? []).filter(
(entry) => entry.command === "leave_huddle",
).length,
),
)
.toBe(1);
await expect(page.locator(".buzz-huddle-shell")).toHaveAttribute(
"data-huddle-open",
"false",
);
const closedGradient = await gradientUnderlay.evaluate(
(element) => getComputedStyle(element).backgroundImage,
);
expect(closedGradient).toBe(openGradient);
});
test("shows speaker identity on every huddle chat message", async ({
page,
}) => {
await installMockBridge(page, {
windowLabel: `huddle-${HUDDLE_CHANNEL_ID}`,
huddle: {
parentChannelId: HUDDLE_PARENT_ID,
ephemeralChannelId: HUDDLE_CHANNEL_ID,
huddleThreadEventId: HUDDLE_THREAD_ROOT_ID,
members: [
{ pubkey: TEST_IDENTITIES.tyler.pubkey, role: "member" },
{ pubkey: TEST_IDENTITIES.alice.pubkey, role: "bot" },
],
transcriptionEnabled: true,
},
mock: { threadRepliesDelayMs: 1_500 },
});
await page.goto("/");
await expect
.poll(() =>
page.evaluate(
() => window.__TAURI_INTERNALS__?.metadata.currentWindow.label,
),
)
.toBe(`huddle-${HUDDLE_CHANNEL_ID}`);
await expect(page.getByTestId("huddle-transcript-intro")).toBeVisible();
await expect(page.getByTestId("message-thread-replies-loading")).toHaveCount(
0,
);
const transcriptTopGap = await page.evaluate(() => {
const participantStrip = document.querySelector(
'[data-testid="huddle-participant-strip"]',
);
const participantTray = participantStrip?.closest("header");
const transcriptIntro = document.querySelector(
'[data-testid="huddle-transcript-intro"]',
);
if (!participantTray || !transcriptIntro) return null;
return Math.round(
transcriptIntro.getBoundingClientRect().top -
participantTray.getBoundingClientRect().bottom,
);
});
expect(transcriptTopGap).toBe(16);
await waitForMockLiveSubscription(page, "huddle");
await page.evaluate(() => {
const threadRoot = window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "huddle",
content: "First huddle message",
});
window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "huddle",
content: "Second huddle message",
});
if (!threadRoot) throw new Error("Failed to create Huddle thread root.");
window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "huddle",
content: "Agent response flattened into the huddle chat",
parentEventId: threadRoot.id,
pubkey: "deadbeef".repeat(8),
});
});
for (const content of [
"First huddle message",
"Second huddle message",
"Agent response flattened into the huddle chat",
]) {
const row = page.getByTestId("message-row").filter({ hasText: content });
await expect(row).toBeVisible();
await expect(row.locator('[data-testid^="message-avatar-"]')).toBeVisible();
await expect(row.getByTestId("message-author")).toBeVisible();
await expect(row.getByTestId("message-timestamp")).toBeVisible();
}
await expect(page.getByTestId("message-thread-panel")).toHaveCount(0);
});
test("ignores persisted community onboarding in the huddle room", async ({
page,
}) => {
const persistedTransaction = {
id: "main-window-community-transaction",
source: "deep-link-join",
stage: "claiming",
relayUrl: "wss://other.example",
inviteCode: "main-window-invite",
communityName: "Other community",
createdAt: "2026-08-03T20:00:00.000Z",
updatedAt: "2026-08-03T20:00:00.000Z",
};
await page.addInitScript((transaction) => {
window.localStorage.setItem(
"buzz-community-onboarding-transaction.v1",
JSON.stringify(transaction),
);
}, persistedTransaction);
const claimRequests: string[] = [];
page.on("request", (request) => {
if (request.url().includes("/api/invites/claim")) {
claimRequests.push(request.url());
}
});
await installMockBridge(page, {
windowLabel: `huddle-${HUDDLE_CHANNEL_ID}`,
huddle: {
parentChannelId: HUDDLE_PARENT_ID,
ephemeralChannelId: HUDDLE_CHANNEL_ID,
members: [{ pubkey: TEST_IDENTITIES.tyler.pubkey, role: "member" }],
},
});
for (let load = 0; load < 2; load += 1) {
await page.goto("/");
await expect(page.getByTestId("huddle-transcript-intro")).toBeVisible();
await expect(
page.getByText("Setting up your community", { exact: true }),
).toHaveCount(0);
await expect
.poll(() =>
page.evaluate(() => {
const raw = window.localStorage.getItem(
"buzz-community-onboarding-transaction.v1",
);
return raw ? JSON.parse(raw) : null;
}),
)
.toEqual(persistedTransaction);
await expect
.poll(() =>
page.evaluate(() =>
JSON.parse(window.localStorage.getItem("buzz-communities") ?? "[]"),
),
)
.not.toContainEqual(
expect.objectContaining({ relayUrl: persistedTransaction.relayUrl }),
);
expect(claimRequests).toHaveLength(0);
}
});
test("keeps main-app shortcuts from navigating the huddle room", async ({
page,
}) => {
await installMockBridge(page, {
windowLabel: `huddle-${HUDDLE_CHANNEL_ID}`,
huddle: {
parentChannelId: HUDDLE_PARENT_ID,
ephemeralChannelId: HUDDLE_CHANNEL_ID,
members: [{ pubkey: TEST_IDENTITIES.tyler.pubkey, role: "member" }],
},
pendingCommunityDeepLinks: [
{
id: "companion-must-not-consume",
kind: "connect",
relayUrl: "wss://other.example",
},
],
});
await page.goto("/");
await expect(page).toHaveURL(
new RegExp(`/channels/${HUDDLE_CHANNEL_ID.replaceAll("-", "\\-")}`),
);
const huddleUrl = page.url();
const primaryModifier = process.platform === "darwin" ? "Meta" : "Control";
for (const shortcut of ["Shift+K", "Shift+A", "Comma"]) {
await page.keyboard.press(`${primaryModifier}+${shortcut}`);
await expect.poll(() => page.url()).toBe(huddleUrl);
await expect(page.getByTestId("settings-view")).toHaveCount(0);
}
await page.evaluate(async (channelId) => {
await window.__BUZZ_E2E_EMIT_TAURI_EVENT__?.("deep-link-message", {
channelId,
messageId: "mock-general-welcome",
threadRootId: null,
});
}, HUDDLE_PARENT_ID);
await expect.poll(() => page.url()).toBe(huddleUrl);
const pendingCommunityLink = {
code: null,
id: "companion-must-not-consume",
kind: "connect" as const,
name: null,
relayUrl: "wss://other.example",
};
await page.evaluate(async () => {
await window.__BUZZ_E2E_EMIT_TAURI_EVENT__?.("deep-link-connect", null);
});
await expect
.poll(() =>
page.evaluate(async () =>
window.__BUZZ_E2E_INVOKE_MOCK_COMMAND__?.(
"take_pending_community_deep_link",
),
),
)
.toEqual(pendingCommunityLink);
});
test("speaks the first eligible agent reply with its participant identity", async ({
page,
}) => {
await installMockBridge(page, {
huddle: {
parentChannelId: HUDDLE_PARENT_ID,
ephemeralChannelId: HUDDLE_CHANNEL_ID,
members: [
{ pubkey: TEST_IDENTITIES.tyler.pubkey, role: "member" },
{ pubkey: TEST_IDENTITIES.alice.pubkey, role: "bot" },
],
ttsEnabled: true,
},
});
await page.goto("/");
await waitForMockLiveSubscription(page, "huddle");
await page.evaluate((agentPubkey) => {
window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "huddle",
content: "This first reply should be spoken.",
pubkey: agentPubkey,
});
}, TEST_IDENTITIES.alice.pubkey);
await expect
.poll(() =>
page.evaluate(
() =>
(window.__BUZZ_E2E_COMMAND_LOG__ ?? []).find(
(entry) => entry.command === "speak_agent_message",
)?.payload,
),
)
.toMatchObject({
text: "This first reply should be spoken.",
speakerPubkey: TEST_IDENTITIES.alice.pubkey,
});
await expect(
page.getByRole("img", {
name: "Anyone can send instructions to this agent",
}),
).toHaveCount(0);
});
test("animates the responding agent with the shared speaker ring", async ({
page,
}) => {
await installMockBridge(page, {
windowLabel: `huddle-${HUDDLE_CHANNEL_ID}`,
huddle: {
parentChannelId: HUDDLE_PARENT_ID,
ephemeralChannelId: HUDDLE_CHANNEL_ID,
members: [
{ pubkey: TEST_IDENTITIES.tyler.pubkey, role: "member" },
{ pubkey: TEST_IDENTITIES.alice.pubkey, role: "bot" },
],
},
});
await page.goto("/");
const agentAvatar = page
.getByTestId("huddle-participant-strip")
.locator(".buzz-huddle-speaking-avatar")
.nth(1);
await expect(agentAvatar).toBeVisible();
await page.evaluate(async (pubkey) => {
await window.__BUZZ_E2E_EMIT_MOCK_HUDDLE_TTS_SPEAKER__?.({
pubkey,
level: 0.8,
});
}, TEST_IDENTITIES.alice.pubkey);
await expect
.poll(() =>
agentAvatar.evaluate((element) =>
element.style.getPropertyValue("--buzz-huddle-speaker-opacity"),
),
)
.toBe("0.890");
await page.evaluate(async () => {
await window.__BUZZ_E2E_EMIT_MOCK_HUDDLE_TTS_SPEAKER__?.({
pubkey: null,
level: 0,
});
});
await expect
.poll(() =>
agentAvatar.evaluate((element) =>
element.style.getPropertyValue("--buzz-huddle-speaker-opacity"),
),
)
.toBe("0");
});
test("stops the speaking agent from the huddle controls", async ({ page }) => {
await installMockBridge(page, {
windowLabel: `huddle-${HUDDLE_CHANNEL_ID}`,
huddle: {
parentChannelId: HUDDLE_PARENT_ID,
ephemeralChannelId: HUDDLE_CHANNEL_ID,
members: [
{ pubkey: TEST_IDENTITIES.tyler.pubkey, role: "member" },
{ pubkey: TEST_IDENTITIES.alice.pubkey, role: "bot" },
],
},
});
await page.goto("/");
const roomMicButton = page.getByRole("button", {
name: "Microphone unavailable",
});
await expect(roomMicButton).toHaveClass(/bg-destructive\/35/);
await expect(roomMicButton).toHaveClass(/text-destructive/);
await expect(
page.getByRole("button", { name: "Audio settings" }),
).not.toHaveClass(/bg-destructive\/35/);
const roomSpeakerButton = page.getByRole("button", {
name: "Unmute agent speech",
});
await expect(roomSpeakerButton).toHaveClass(/bg-destructive\/35/);
await expect(roomSpeakerButton).toHaveClass(/text-destructive/);
await expect(
page.getByRole("button", { name: "Speaker settings" }),
).not.toHaveClass(/bg-destructive\/35/);
await waitForAnimations(page);
const agentTile = page
.getByTestId("huddle-participant-strip")
.getByTestId("huddle-participant-tile")
.nth(1);
const agentAvatar = page
.getByTestId("huddle-participant-strip")
.locator(".buzz-huddle-speaking-avatar")
.nth(1);
const labelSlots = page.getByTestId("huddle-participant-label-slot");
await expect(agentAvatar).toBeVisible();
await waitForAnimations(page);
const idleTileHeight = await agentTile.evaluate(
(element) => element.offsetHeight,
);
const idleAgentLabelBox = await labelSlots.nth(1).boundingBox();
const humanLabelBox = await labelSlots.nth(0).boundingBox();
expect(humanLabelBox?.y).toBe(idleAgentLabelBox?.y);
expect(humanLabelBox?.height).toBe(idleAgentLabelBox?.height);
expect(humanLabelBox?.width).toBe(idleAgentLabelBox?.width);
await page.evaluate(async (pubkey) => {
await window.__BUZZ_E2E_EMIT_MOCK_HUDDLE_TTS_SPEAKER__?.({
pubkey,
level: 0.8,
});
}, TEST_IDENTITIES.alice.pubkey);
await expect
.poll(() =>
agentAvatar.evaluate((element) =>
element.style.getPropertyValue("--buzz-huddle-speaker-opacity"),
),
)
.toBe("0.890");
const stopButton = page.getByRole("button", { name: /^Stop .* speaking$/ });
await expect(stopButton).toBeVisible();
await expect(stopButton).toHaveClass(/bg-destructive\/15/);
expect(await labelSlots.nth(1).boundingBox()).toEqual(idleAgentLabelBox);
expect(await agentTile.evaluate((element) => element.offsetHeight)).toBe(
idleTileHeight,
);
await stopButton.click();
await expect
.poll(() =>
page.evaluate(
() =>
(window.__BUZZ_E2E_COMMAND_LOG__ ?? []).findLast(
(entry) => entry.command === "interrupt_huddle_speech",
)?.payload ?? null,
),
)
.toEqual({ agentPubkey: TEST_IDENTITIES.alice.pubkey });
});
test("assigns distinct agent voices and exposes compact per-agent controls", async ({
page,
}) => {
await installMockBridge(page, {
windowLabel: `huddle-${HUDDLE_CHANNEL_ID}`,
ttsSettings: {
version: 1,
agentTextToSpeech: true,
voicePreferences: ["pocket:vera"],
},
huddle: {
parentChannelId: HUDDLE_PARENT_ID,
ephemeralChannelId: HUDDLE_CHANNEL_ID,
members: [
{ pubkey: TEST_IDENTITIES.tyler.pubkey, role: "member" },
{ pubkey: TEST_IDENTITIES.alice.pubkey, role: "bot" },
{ pubkey: TEST_IDENTITIES.bob.pubkey, role: "bot" },
],
ttsEnabled: true,
},
});
await page.goto("/");
const voiceMenus = page.getByTestId("huddle-agent-voice-menu-trigger");
await expect(voiceMenus).toHaveCount(2);
await expect
.poll(async () => {
const state = (await page.evaluate(() =>
window.__BUZZ_E2E_INVOKE_MOCK_COMMAND__?.("get_huddle_state"),
)) as {
agent_voice_settings: Record<
string,
{ enabled: boolean; voice_key: string }
>;
};
return state.agent_voice_settings;
})
.toMatchObject({
[TEST_IDENTITIES.alice.pubkey]: {
enabled: true,
voice_key: "pocket:vera",
},
});
const assignedVoices = await page.evaluate(async () => {
const state = (await window.__BUZZ_E2E_INVOKE_MOCK_COMMAND__?.(
"get_huddle_state",
)) as {
agent_voice_settings: Record<string, { voice_key: string }>;
};
return Object.values(state.agent_voice_settings).map(
(settings) => settings.voice_key,
);
});
expect(new Set(assignedVoices).size).toBe(2);
await page.getByRole("button", { name: "Voice settings for alice" }).click();
await waitForAnimations(page);
const voiceMenu = page.locator(
'[data-testid="huddle-agent-voice-menu-content"][data-state="open"]',
);
await expect(voiceMenu).toBeVisible();
await expect(
voiceMenu.getByText("Agent text-to-speech", { exact: true }),
).toBeVisible();
const ttsToggle = voiceMenu.getByTestId("huddle-agent-tts-toggle");
await expect(ttsToggle).toBeChecked();
await expect(
voiceMenu.getByTestId("huddle-agent-voice-selector"),
).toContainText("Vera");
await ttsToggle.click();
await expect(
voiceMenu.getByTestId("huddle-agent-voice-selector"),
).toHaveCount(0);
await ttsToggle.click();
await expect(ttsToggle).toBeChecked();
const voiceSelector = voiceMenu.getByTestId("huddle-agent-voice-selector");
await expect(voiceSelector).toBeEnabled();
await voiceSelector.click();
await page.getByRole("menuitemradio", { name: "Jane" }).click();
await expect
.poll(() =>
page.evaluate(() => {
const updates = (window.__BUZZ_E2E_COMMAND_LOG__ ?? []).filter(
(entry) => entry.command === "set_huddle_agent_voice",
);
return updates.at(-1)?.payload ?? null;
}),
)
.toMatchObject({
agentPubkey: TEST_IDENTITIES.alice.pubkey,
voiceKey: "pocket:jane",
});
});
test("adds channel-mentioned agents to the live huddle roster", async ({
page,
}) => {
await installMockBridge(page, {
windowLabel: `huddle-${HUDDLE_CHANNEL_ID}`,
huddle: {
parentChannelId: HUDDLE_PARENT_ID,
ephemeralChannelId: HUDDLE_CHANNEL_ID,
members: [
{ pubkey: TEST_IDENTITIES.tyler.pubkey, role: "member" },
{ pubkey: TEST_IDENTITIES.alice.pubkey, role: "bot" },
],
},
});
await page.goto("/");
const participantTiles = page.getByTestId("huddle-participant-tile");
await expect(participantTiles).toHaveCount(2);
const result = await page.evaluate(
async ({ channelId, pubkey }) =>
window.__BUZZ_E2E_INVOKE_MOCK_COMMAND__?.(
"sync_agents_to_active_huddle",
{
channelId,
agentPubkeys: [pubkey],
},
),
{
channelId: HUDDLE_PARENT_ID,
pubkey: TEST_IDENTITIES.bob.pubkey,
},
);
expect(result).toEqual({
matched_active_huddle: true,
added: [TEST_IDENTITIES.bob.pubkey],
});
await expect(participantTiles).toHaveCount(3);
await expect(
page.getByRole("button", { name: "Voice settings for Bob" }),
).toBeVisible();
});
test("does not enroll available agents when sending an ordinary message", async ({
page,
}) => {
await installMockBridge(page, {
windowLabel: `huddle-${HUDDLE_CHANNEL_ID}`,
huddle: {
parentChannelId: HUDDLE_PARENT_ID,
ephemeralChannelId: HUDDLE_CHANNEL_ID,
members: [{ pubkey: TEST_IDENTITIES.tyler.pubkey, role: "member" }],
},
managedAgents: [
{
pubkey: TEST_IDENTITIES.alice.pubkey,
name: "alice",
status: "running",
},
{
pubkey: TEST_IDENTITIES.bob.pubkey,
name: "bob",
status: "running",
},
],
});
await page.goto("/");
const participantTiles = page.getByTestId("huddle-participant-tile");
await expect(participantTiles).toHaveCount(1);
await page.getByTestId("message-input").fill("A message for the room");
await page.getByTestId("send-message").click();
await expect(
page
.getByTestId("message-row")
.filter({ hasText: "A message for the room" }),
).toBeVisible();
await expect(participantTiles).toHaveCount(1);
expect(
await page.evaluate(
() =>
(window.__BUZZ_E2E_COMMAND_LOG__ ?? []).filter(
(entry) => entry.command === "sync_agents_to_active_huddle",
).length,
),
).toBe(0);
});
test("keeps the colored startup surface while huddle controls connect", async ({
page,
}) => {
await installMockBridge(page, {
windowLabel: `huddle-${HUDDLE_CHANNEL_ID}`,
huddle: {
parentChannelId: HUDDLE_PARENT_ID,
ephemeralChannelId: HUDDLE_CHANNEL_ID,
phase: "connected",
members: [{ pubkey: TEST_IDENTITIES.tyler.pubkey, role: "member" }],
},
});
await page.goto("/");
await expect(page.getByTestId("huddle-starting-view")).toBeVisible();
await expect(
page.getByRole("status", { name: "Starting huddle" }),
).toBeVisible();
await expect(
page.getByTestId("huddle-starting-view").locator(".bee-sprite"),
).toBeVisible();
await expect(page.getByTestId("setup-grainient-background")).toBeVisible();
await expect(
page.getByRole("button", { name: "Leave huddle" }),
).toBeVisible();
await expect(page.getByTestId("message-thread-loading")).toHaveCount(0);
await expect(page.getByTestId("huddle-participant-strip")).toHaveCount(0);
await expect(page.getByTestId("huddle-transcript-intro")).toHaveCount(0);
});
test("returns the companion transcript to the same channel in the main app", async ({
page,
}) => {
await installMockBridge(page, {
huddle: {
parentChannelId: HUDDLE_PARENT_ID,
ephemeralChannelId: HUDDLE_CHANNEL_ID,
huddleThreadEventId: HUDDLE_THREAD_ROOT_ID,
members: [{ pubkey: TEST_IDENTITIES.tyler.pubkey, role: "member" }],
transcriptionEnabled: true,
},
});
await page.goto("/");
await expect(page.locator(".buzz-huddle-shell")).toHaveAttribute(
"data-huddle-open",
"true",
);
await page.evaluate(() => {
const threadRoot = window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "huddle",
content: "Transcript written while the companion is open",
});
if (!threadRoot) throw new Error("Failed to create Huddle thread root.");
window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "huddle",
content: "Agent reply preserved across the Huddle handoff",
parentEventId: threadRoot.id,
pubkey: "deadbeef".repeat(8),
});
});
await page
.getByRole("button", { name: "Open huddle in a new window" })
.click();
await expect(page.locator(".buzz-huddle-shell")).toHaveAttribute(
"data-huddle-open",
"false",
);
await page.evaluate(async () => {
await window.__BUZZ_E2E_INVOKE_MOCK_COMMAND__?.("close_huddle_companion");
});
await expect(page).toHaveURL(
new RegExp(`/channels/${HUDDLE_CHANNEL_ID.replaceAll("-", "\\-")}`),
);
await expect(
page
.getByTestId("message-row")
.filter({ hasText: "Transcript written while the companion is open" }),
).toBeVisible();
await expect(
page
.getByTestId("message-row")
.filter({ hasText: "Agent reply preserved across the Huddle handoff" }),
).toBeVisible();
await expect(page.getByTestId("message-thread-panel")).toHaveCount(0);
await page
.getByRole("button", { name: "Open huddle in a new window" })
.click();
await expect(page).toHaveURL(
new RegExp(`/channels/${HUDDLE_PARENT_ID.replaceAll("-", "\\-")}`),
);
await expect(
page.locator(`[data-channel-id="${HUDDLE_CHANNEL_ID}"]`),
).toHaveCount(0);
});
test("returns to the parent channel when leaving a huddle channel in view", async ({
page,
}) => {
await installMockBridge(page, {
huddle: {
parentChannelId: HUDDLE_PARENT_ID,
ephemeralChannelId: HUDDLE_CHANNEL_ID,
members: [{ pubkey: TEST_IDENTITIES.tyler.pubkey, role: "member" }],
},
});
await page.goto("/");
await expect(page.locator(".buzz-huddle-shell")).toHaveAttribute(
"data-huddle-open",
"true",
);
await page.evaluate(async () => {
await window.__BUZZ_E2E_INVOKE_MOCK_COMMAND__?.("close_huddle_companion");
});
await expect(page).toHaveURL(
new RegExp(`/channels/${HUDDLE_CHANNEL_ID.replaceAll("-", "\\-")}`),
);
await page.getByRole("button", { name: "Leave huddle" }).click();
await expect(page).toHaveURL(
new RegExp(`/channels/${HUDDLE_PARENT_ID.replaceAll("-", "\\-")}`),
);
await expect(
page.locator(`[data-channel-id="${HUDDLE_CHANNEL_ID}"]`),
).toHaveCount(0);
});
test("keeps the huddle avatar strip compact and exposes the full roster", async ({
page,
}) => {
const members = Array.from({ length: 11 }, (_, index) => ({
pubkey: `${(index + 1).toString(16).padStart(2, "0")}${"a".repeat(62)}`,
role: index === 10 ? ("bot" as const) : ("member" as const),
}));
await installMockBridge(page, {
huddle: {
parentChannelId: HUDDLE_PARENT_ID,
ephemeralChannelId: HUDDLE_CHANNEL_ID,
members,
},
});
await page.goto("/");
const participantStrip = page.getByTestId("huddle-participant-strip");
const participantTrigger = page.getByRole("button", {
name: "Show all huddle participants (11)",
});
await expect(participantTrigger).toBeVisible();
await expect(
participantStrip.getByTestId("huddle-participant-avatar"),
).toHaveCount(9);
await expect(participantTrigger).toContainText("+2");
await expect(page.getByTestId("profile-huddle-control")).toHaveCount(0);
await participantTrigger.click();
await expect(
page.getByRole("heading", { name: "Participants" }),
).toBeVisible();
await expect(
page.getByRole("button", { name: /Remove Agent .* from huddle/ }),
).toHaveCount(1);
});
test("removes an agent from its menu without showing an extra participant control", async ({
page,
}) => {
await installMockBridge(page, {
windowLabel: `huddle-${HUDDLE_CHANNEL_ID}`,
huddle: {
parentChannelId: HUDDLE_PARENT_ID,
ephemeralChannelId: HUDDLE_CHANNEL_ID,
members: [
{ pubkey: TEST_IDENTITIES.tyler.pubkey, role: "member" },
{ pubkey: TEST_IDENTITIES.alice.pubkey, role: "bot" },
],
},
});
await page.goto("/");
await expect(
page.getByRole("button", { name: "Manage huddle participants" }),
).toHaveCount(0);
await page.getByTestId("huddle-agent-voice-menu-trigger").click();
const removeButton = page.getByRole("button", {
name: "Remove alice from huddle",
});
await expect(removeButton).toBeVisible();
page.once("dialog", (dialog) => dialog.accept());
await removeButton.click({ force: true });
await expect
.poll(() =>
page.evaluate(() =>
(window.__BUZZ_E2E_COMMAND_LOG__ ?? []).some(
(entry) => entry.command === "remove_agent_from_huddle",
),
),
)
.toBe(true);
await expect(page.getByTestId("huddle-agent-voice-menu-trigger")).toHaveCount(
0,
);
});
test("keeps a newer huddle event over a delayed hydration snapshot", async ({
page,
}) => {
await installMockBridge(page, {
huddle: {
parentChannelId: HUDDLE_PARENT_ID,
ephemeralChannelId: HUDDLE_CHANNEL_ID,
members: [
{ pubkey: TEST_IDENTITIES.tyler.pubkey, role: "member" },
{ pubkey: TEST_IDENTITIES.alice.pubkey, role: "bot" },
],
transcriptionEnabled: true,
},
huddleStateReadDelayMs: 250,
});
await page.goto("/");
await expect
.poll(() =>
page.evaluate(() =>
(window.__BUZZ_E2E_COMMAND_LOG__ ?? []).some(
(entry) => entry.command === "get_huddle_state",
),
),
)
.toBe(true);
await setHuddleSnapshot(
page,
[{ pubkey: TEST_IDENTITIES.tyler.pubkey, role: "member" }],
false,
);
await expect(
page
.getByTestId("huddle-participant-strip")
.getByTestId("huddle-participant-avatar"),
).toHaveCount(1);
await expect(
page.getByRole("button", { name: /Show all huddle participants/ }),
).toHaveCount(0);
await expect(
page.getByRole("button", { name: "Start transcript" }),
).toHaveAttribute("aria-pressed", "false");
await page.waitForTimeout(300);
await expect(
page
.getByTestId("huddle-participant-strip")
.getByTestId("huddle-participant-avatar"),
).toHaveCount(1);
});
test("keeps a starting huddle in the drawer after its companion closes", async ({
page,
}) => {
await installFakeHuddleMicrophone(page);
await installMockBridge(page, {
openHuddleWindowDelayMs: 500,
startHuddleReturnDelayMs: 1_500,
});
await page.goto("/");
await page.getByTestId("channel-alice-tyler").click();
await page.getByTestId("channel-start-huddle-trigger").click();
await expect
.poll(() =>
page.evaluate(
() =>
(window.__BUZZ_E2E_COMMAND_LOG__ ?? []).filter(
(entry) => entry.command === "open_huddle_window",
).length,
),
)
.toBe(1);
const ephemeralChannelId = await page.evaluate(async () => {
const state = (await window.__BUZZ_E2E_INVOKE_MOCK_COMMAND__?.(
"get_huddle_state",
)) as { ephemeral_channel_id: string };
return state.ephemeral_channel_id;
});
await page.evaluate(async () => {
await window.__BUZZ_E2E_INVOKE_MOCK_COMMAND__?.("close_huddle_companion");
});
await expect(page.locator(".buzz-huddle-shell")).toHaveAttribute(
"data-huddle-open",
"true",
);
await expect(page).toHaveURL(
new RegExp(`/channels/${ephemeralChannelId.replaceAll("-", "\\-")}`),
);
await expect
.poll(() =>
page.evaluate(async () => {
const state = (await window.__BUZZ_E2E_INVOKE_MOCK_COMMAND__?.(
"get_huddle_state",
)) as { phase: string };
return state.phase;
}),
)
.toBe("active");
await expect
.poll(() =>
page.evaluate(
() =>
(window.__BUZZ_E2E_COMMAND_LOG__ ?? []).filter(
(entry) => entry.command === "open_huddle_window",
).length,
),
)
.toBe(1);
await expect(page.locator(".buzz-huddle-shell")).toHaveAttribute(
"data-huddle-open",
"true",
);
await expect(page.getByTestId("profile-huddle-control")).toHaveCount(0);
await expect(
page.locator(`[data-channel-id="${ephemeralChannelId}"]`),
).toBeVisible();
});
test("starts unmuted with Push to Talk while preserving manual microphone control", async ({
page,
}) => {
await installFakeHuddleMicrophone(page);
await installMockBridge(page, {
openHuddleWindowDelayMs: 10_000,
startHuddleReturnDelayMs: 1_500,
});
await page.goto("/");
await page.getByTestId("channel-alice-tyler").click();
await page.getByTestId("channel-start-huddle-trigger").click();
const muteButton = page.getByRole("button", { name: "Mute microphone" });
await expect(muteButton).toBeVisible();
await expect(muteButton).not.toHaveClass(/bg-destructive\/15/);
await expect(
page.getByRole("button", { name: "Audio settings" }),
).not.toHaveClass(/bg-destructive\/15/);
await muteButton.click();
const unmuteButton = page.getByRole("button", {
name: "Unmute microphone",
});
await expect(unmuteButton).toBeVisible();
await expect(unmuteButton).toHaveClass(/bg-destructive\/15/);
await expect(unmuteButton).toHaveClass(/text-destructive/);
await expect
.poll(() =>
page.evaluate(
() =>
(window.__BUZZ_E2E_COMMAND_LOG__ ?? []).findLast(
(entry) => entry.command === "set_huddle_manual_mic_unmuted",
)?.payload,
),
)
.toEqual({ enabled: false });
await page.mouse.move(0, 0);
await unmuteButton.hover();
await expect(page.getByRole("tooltip")).toHaveAccessibleName(
/Click to unmute or hold .*Space/,
);
await page.evaluate(async () => {
await window.__BUZZ_E2E_EMIT_TAURI_EVENT__?.("ptt-state", true);
});
await expect(muteButton).toBeVisible();
await muteButton.click();
await expect
.poll(() =>
page.evaluate(
() =>
(window.__BUZZ_E2E_COMMAND_LOG__ ?? []).findLast(
(entry) => entry.command === "set_huddle_manual_mic_unmuted",
)?.payload,
),
)
.toEqual({ enabled: false });
await page.evaluate(async () => {
await window.__BUZZ_E2E_EMIT_TAURI_EVENT__?.("ptt-state", false);
});
await expect(unmuteButton).toBeVisible();
await page.getByRole("button", { name: "Audio settings" }).click();
await page.getByRole("button", { name: "Turn off Push to Talk" }).click();
await page.evaluate(async () => {
await window.__BUZZ_E2E_EMIT_TAURI_EVENT__?.("ptt-state", true);
});
await expect(unmuteButton).toBeVisible();
await page.getByRole("button", { name: "Turn on Push to Talk" }).click();
await expect(unmuteButton).toBeVisible();
await page.evaluate(async () => {
await window.__BUZZ_E2E_EMIT_TAURI_EVENT__?.("ptt-state", true);
});
await expect(muteButton).toBeVisible();
await page.evaluate(async () => {
await window.__BUZZ_E2E_EMIT_TAURI_EVENT__?.("ptt-state", false);
});
await expect(unmuteButton).toBeVisible();
await unmuteButton.click();
await expect(muteButton).toBeVisible();
await expect
.poll(() =>
page.evaluate(
() =>
(window.__BUZZ_E2E_COMMAND_LOG__ ?? []).findLast(
(entry) => entry.command === "set_huddle_manual_mic_unmuted",
)?.payload,
),
)
.toEqual({ enabled: true });
});
test("starts an agent DM huddle and hides its backing channel after it ends", async ({
page,
}) => {
await installFakeHuddleMicrophone(page);
await installMockBridge(page, {
openHuddleWindowDelayMs: 500,
startHuddleReturnDelayMs: 1_500,
});
await page.goto("/");
await page.getByTestId("channel-alice-tyler").click();
await expect(page.getByTestId("chat-title")).toHaveText("alice-tyler");
await expect
.poll(() =>
page.evaluate(
(pubkey) =>
window.__BUZZ_E2E_HAS_MOCK_OWNER_KIND_SUBSCRIPTION__?.({
ownerPubkey: pubkey,
kind: 44100,
}) ?? false,
"deadbeef".repeat(8),
),
)
.toBe(true);
const channelReadsBeforeStart = await page.evaluate(
() =>
(window.__BUZZ_E2E_COMMAND_LOG__ ?? []).filter(
(entry) => entry.command === "get_channels",
).length,
);
const startButton = page.getByTestId("channel-start-huddle-trigger");
await expect(startButton).toBeEnabled();
await startButton.click();
await expect
.poll(() =>
page.evaluate(
() =>
(window.__BUZZ_E2E_COMMAND_LOG__ ?? []).find(
(entry) => entry.command === "start_huddle",
)?.payload,
),
)
.toMatchObject({
memberPubkeys: [TEST_IDENTITIES.alice.pubkey],
parentChannelId: "f48efb06-0c93-5025-aac9-2e646bb6bfa8",
});
await expect
.poll(() =>
page.evaluate(
() =>
(window.__BUZZ_E2E_COMMAND_LOG__ ?? []).filter(
(entry) => entry.command === "open_huddle_window",
).length,
),
)
.toBe(1);
const startingState = await page.evaluate(async () =>
window.__BUZZ_E2E_INVOKE_MOCK_COMMAND__?.("get_huddle_state"),
);
expect(startingState).toMatchObject({ phase: "creating" });
await expect
.poll(() =>
page.evaluate(
() =>
(window.__BUZZ_E2E_COMMAND_LOG__ ?? []).filter(
(entry) => entry.command === "get_channels",
).length,
),
)
.toBeGreaterThan(channelReadsBeforeStart);
const pendingEphemeralChannelId = await page.evaluate(async () => {
const state = (await window.__BUZZ_E2E_INVOKE_MOCK_COMMAND__?.(
"get_huddle_state",
)) as { ephemeral_channel_id: string };
return state.ephemeral_channel_id;
});
await expect(
page.locator(`[data-channel-id="${pendingEphemeralChannelId}"]`),
).toHaveCount(0);
await expect(page.locator(".buzz-huddle-shell")).toHaveAttribute(
"data-huddle-open",
"false",
);
await expect
.poll(() =>
page.evaluate(
() =>
(window.__BUZZ_E2E_COMMAND_LOG__ ?? []).filter(
(entry) => entry.command === "open_huddle_window",
).length,
),
)
.toBe(1);
await expect(page.getByTestId("profile-huddle-control")).toBeVisible();
await expect(page.locator(".buzz-huddle-shell")).toHaveAttribute(
"data-huddle-open",
"false",
);
const ephemeralChannelId = await page.evaluate(async () => {
const state = (await window.__BUZZ_E2E_INVOKE_MOCK_COMMAND__?.(
"get_huddle_state",
)) as { ephemeral_channel_id: string };
return state.ephemeral_channel_id;
});
const huddleSidebarChannel = page.locator(
`[data-channel-id="${ephemeralChannelId}"]`,
);
await expect(huddleSidebarChannel).toHaveCount(0);
await page.evaluate(async () => {
await window.__BUZZ_E2E_INVOKE_MOCK_COMMAND__?.("close_huddle_companion");
});
await expect(page.locator(".buzz-huddle-shell")).toHaveAttribute(
"data-huddle-open",
"true",
);
await expect(page.getByTestId("profile-huddle-control")).toHaveCount(0);
await expect(page).toHaveURL(
new RegExp(`/channels/${ephemeralChannelId.replaceAll("-", "\\-")}`),
);
await expect(huddleSidebarChannel).toBeVisible();
await page
.getByRole("button", { name: "Open huddle in a new window" })
.click();
await expect(huddleSidebarChannel).toHaveCount(0);
await expect(page.locator(".buzz-huddle-shell")).toHaveAttribute(
"data-huddle-open",
"false",
);
await expect(page.getByTestId("profile-huddle-control")).toBeVisible();
await page.getByRole("button", { name: "Leave huddle" }).click();
await expect(huddleSidebarChannel).toHaveCount(0);
await expect(page.locator(".buzz-huddle-shell")).toHaveAttribute(
"data-huddle-open",
"false",
);
await waitForMockLiveSubscription(page, "alice-tyler");
const lifecycleCreatedAt = Math.floor(Date.now() / 1000);
await page.evaluate(
({ createdAt, ephemeralChannelId, kind }) => {
window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "alice-tyler",
content: JSON.stringify({ ephemeral_channel_id: ephemeralChannelId }),
createdAt,
id: "3".repeat(64),
kind,
});
},
{
createdAt: lifecycleCreatedAt,
ephemeralChannelId,
kind: KIND_HUDDLE_STARTED,
},
);
await expect(page.getByTestId("huddle-attachment")).toBeVisible();
await waitForMockLiveSubscription(page, "alice-tyler", KIND_HUDDLE_ENDED);
await page.evaluate(
({ createdAt, ephemeralChannelId, kind }) => {
window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "alice-tyler",
content: JSON.stringify({ ephemeral_channel_id: ephemeralChannelId }),
createdAt,
id: "4".repeat(64),
kind,
});
},
{
createdAt: lifecycleCreatedAt + 1,
ephemeralChannelId,
kind: KIND_HUDDLE_ENDED,
},
);
const endedHuddle = page
.getByTestId("huddle-attachment")
.filter({ hasText: "Huddle · Ended" });
await expect(endedHuddle).toBeVisible();
await endedHuddle.getByRole("button", { name: "View huddle" }).click();
await expect(page).toHaveURL(
new RegExp(`/channels/${ephemeralChannelId.replaceAll("-", "\\-")}`),
);
await expect(huddleSidebarChannel).toBeVisible();
await expect(page.getByTestId("message-thread-panel")).toHaveCount(0);
});
test("closes add-agent dialog when parent membership is already satisfied", async ({
page,
}) => {
await installMockBridge(page, {
addAgentToHuddleResult: {
ephemeral_added: true,
parent_added: true,
parent_error: null,
},
huddle: {
parentChannelId: HUDDLE_PARENT_ID,
ephemeralChannelId: HUDDLE_CHANNEL_ID,
members: [{ pubkey: TEST_IDENTITIES.tyler.pubkey, role: "member" }],
},
managedAgents: [
{
pubkey: TEST_IDENTITIES.bob.pubkey,
name: "bob",
status: "running",
},
],
});
await page.goto("/");
await page.getByRole("button", { name: "Add agent to huddle" }).click();
const dialog = page.getByRole("dialog", { name: "Add agents" });
await expect(dialog).toBeVisible();
await dialog.getByRole("button", { name: /bob/i }).click();
await expect(dialog).toHaveCount(0);
await expect(
page.getByText("Added to huddle, but parent channel failed:"),
).toHaveCount(0);
});
test("starts an available stopped agent before adding it to the huddle", async ({
page,
}) => {
await installMockBridge(page, {
addAgentToHuddleResult: {
ephemeral_added: true,
parent_added: true,
parent_error: null,
},
huddle: {
parentChannelId: HUDDLE_PARENT_ID,
ephemeralChannelId: HUDDLE_CHANNEL_ID,
members: [{ pubkey: TEST_IDENTITIES.tyler.pubkey, role: "member" }],
},
managedAgents: [
{
avatarUrl: "https://example.com/bob.png",
pubkey: TEST_IDENTITIES.bob.pubkey,
name: "bob",
status: "stopped",
},
],
});
await page.goto("/");
await page.getByRole("button", { name: "Add agent to huddle" }).click();
const dialog = page.getByRole("dialog", { name: "Add agents" });
await expect(dialog).toBeVisible();
await expect(dialog).toHaveClass(/data-\[state=open\]:animate-in/);
await expect(dialog).toHaveClass(/data-\[state=open\]:fade-in-0/);
await expect(dialog).toHaveClass(/data-\[state=open\]:zoom-in-95/);
await expect(dialog).toHaveClass(/duration-200/);
await expect(dialog).toHaveClass(/motion-reduce:animate-none/);
await expect(
dialog.getByText("Choose an agent to join this huddle.", { exact: true }),
).toBeVisible();
await expect(dialog.getByText("stopped", { exact: true })).toHaveCount(0);
await dialog.getByRole("button", { name: /bob/i }).click();
await expect
.poll(() =>
page.evaluate(() =>
(window.__BUZZ_E2E_COMMAND_LOG__ ?? [])
.filter(
(entry) =>
entry.command === "start_managed_agent" ||
entry.command === "add_agent_to_huddle",
)
.map((entry) => entry.command),
),
)
.toEqual(["start_managed_agent", "add_agent_to_huddle"]);
await expect(dialog).toHaveCount(0);
});
test("stops an agent started solely for a failed huddle add", async ({
page,
}) => {
await installMockBridge(page, {
addAgentToHuddleError: "membership publish rejected",
huddle: {
parentChannelId: HUDDLE_PARENT_ID,
ephemeralChannelId: HUDDLE_CHANNEL_ID,
members: [{ pubkey: TEST_IDENTITIES.tyler.pubkey, role: "member" }],
},
managedAgents: [
{
avatarUrl: "https://example.com/bob.png",
pubkey: TEST_IDENTITIES.bob.pubkey,
name: "bob",
status: "stopped",
},
],
});
await page.goto("/");
await page.getByRole("button", { name: "Add agent to huddle" }).click();
const dialog = page.getByRole("dialog", { name: "Add agents" });
await dialog.getByRole("button", { name: /bob/i }).click();
await expect(dialog.getByText(/Failed to add agent:/)).toBeVisible();
await expect
.poll(() =>
page.evaluate(() =>
(window.__BUZZ_E2E_COMMAND_LOG__ ?? [])
.filter((entry) =>
[
"start_managed_agent",
"add_agent_to_huddle",
"stop_managed_agent",
].includes(entry.command),
)
.map((entry) => entry.command),
),
)
.toEqual([
"start_managed_agent",
"add_agent_to_huddle",
"stop_managed_agent",
]);
});
test("does not deploy a provider agent when its huddle add fails", async ({
page,
}) => {
await installMockBridge(page, {
addAgentToHuddleError: "membership publish rejected",
huddle: {
parentChannelId: HUDDLE_PARENT_ID,
ephemeralChannelId: HUDDLE_CHANNEL_ID,
members: [{ pubkey: TEST_IDENTITIES.tyler.pubkey, role: "member" }],
},
managedAgents: [
{
avatarUrl: "https://example.com/bob.png",
backend: { type: "provider", id: "mock", config: {} },
pubkey: TEST_IDENTITIES.bob.pubkey,
name: "bob",
status: "not_deployed",
},
],
});
await page.goto("/");
await page.getByRole("button", { name: "Add agent to huddle" }).click();
const dialog = page.getByRole("dialog", { name: "Add agents" });
await dialog.getByRole("button", { name: /bob/i }).click();
await expect(dialog.getByText(/Failed to add agent:/)).toBeVisible();
await expect
.poll(() =>
page.evaluate(() =>
(window.__BUZZ_E2E_COMMAND_LOG__ ?? [])
.filter((entry) =>
[
"start_managed_agent",
"add_agent_to_huddle",
"stop_managed_agent",
].includes(entry.command),
)
.map((entry) => entry.command),
),
)
.toEqual(["add_agent_to_huddle"]);
});