From e8b55eccabd4f777388a3d4f88e3396414d71d19 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Wed, 11 Mar 2026 01:30:04 +0700 Subject: [PATCH] fix(tests): iteration 16 --- packages/app/e2e/daemon-connectivity.spec.ts | 4 +-- packages/app/e2e/global-setup.ts | 14 ++++++++ .../app/e2e/helpers/agent-bottom-anchor.ts | 14 ++++---- packages/app/e2e/helpers/app.ts | 28 ++++++++++++++-- packages/relay/package.json | 21 ++++++------ .../terminal-mcp/terminal-manager.test.ts | 32 +++---------------- .../server/voice-mcp-bridge-command.test.ts | 5 +-- .../src/server/voice-mcp-bridge.test.ts | 7 ++-- 8 files changed, 70 insertions(+), 55 deletions(-) diff --git a/packages/app/e2e/daemon-connectivity.spec.ts b/packages/app/e2e/daemon-connectivity.spec.ts index e1ccdebf1..d779099d2 100644 --- a/packages/app/e2e/daemon-connectivity.spec.ts +++ b/packages/app/e2e/daemon-connectivity.spec.ts @@ -1,5 +1,5 @@ import { test, expect } from './fixtures'; -import { gotoHome, openSettings } from './helpers/app'; +import { gotoAppShell, openSettings } from './helpers/app'; test('daemon is connected in settings', async ({ page }) => { const daemonPort = process.env.E2E_DAEMON_PORT; @@ -11,7 +11,7 @@ test('daemon is connected in settings', async ({ page }) => { throw new Error('E2E_SERVER_ID is not set (expected from globalSetup).'); } - await gotoHome(page); + await gotoAppShell(page); await openSettings(page); await expect(page.getByText(`127.0.0.1:${daemonPort}`)).toBeVisible(); diff --git a/packages/app/e2e/global-setup.ts b/packages/app/e2e/global-setup.ts index b64d24e66..2884a7f21 100644 --- a/packages/app/e2e/global-setup.ts +++ b/packages/app/e2e/global-setup.ts @@ -199,6 +199,19 @@ function stripAnsi(input: string): string { return input.replace(/\u001b\[[0-9;]*m/g, ''); } +function ensureRelayBuildArtifact(repoRoot: string): void { + const relayDistEntry = path.join(repoRoot, 'packages/relay/dist/e2ee.js'); + if (existsSync(relayDistEntry)) { + return; + } + + console.log('[e2e] Building @getpaseo/relay for daemon startup'); + execSync('npm run build --workspace=@getpaseo/relay', { + cwd: repoRoot, + stdio: 'inherit', + }); +} + function decodeOfferFromFragmentUrl(url: string): OfferPayload { const marker = '#offer='; const idx = url.indexOf(marker); @@ -217,6 +230,7 @@ function decodeOfferFromFragmentUrl(url: string): OfferPayload { export default async function globalSetup() { const repoRoot = path.resolve(__dirname, '../../..'); + ensureRelayBuildArtifact(repoRoot); const envTestPath = path.join(repoRoot, '.env.test'); if (existsSync(envTestPath)) { dotenv.config({ path: envTestPath }); diff --git a/packages/app/e2e/helpers/agent-bottom-anchor.ts b/packages/app/e2e/helpers/agent-bottom-anchor.ts index 839fb9f13..9f7a0e037 100644 --- a/packages/app/e2e/helpers/agent-bottom-anchor.ts +++ b/packages/app/e2e/helpers/agent-bottom-anchor.ts @@ -165,8 +165,12 @@ export async function seedBottomAnchorAgent(input: { }; } +function getVisibleChatScroll(page: Page) { + return page.locator('[data-testid="agent-chat-scroll"]:visible').first(); +} + export async function readScrollMetrics(page: Page): Promise { - return page.getByTestId("agent-chat-scroll").evaluate((root: Element) => { + return getVisibleChatScroll(page).evaluate((root: Element) => { const rootElement = root as HTMLElement; const candidates = [rootElement, ...Array.from(rootElement.querySelectorAll("*"))]; const scrollElement = @@ -194,7 +198,7 @@ export async function readScrollMetrics(page: Page): Promise { } export async function scrollUpFromBottom(page: Page, pixels: number): Promise { - const scrollViewport = page.getByTestId("agent-chat-scroll"); + const scrollViewport = getVisibleChatScroll(page); await expect(scrollViewport).toHaveCount(1, { timeout: 30000 }); await scrollViewport.evaluate( (root: Element, amount: number) => { @@ -240,7 +244,7 @@ export async function scrollUpFromBottom(page: Page, pixels: number): Promise { - await expect(page.getByTestId("agent-chat-scroll")).toBeVisible({ timeout: 60000 }); + await expect(getVisibleChatScroll(page)).toBeVisible({ timeout: 60000 }); await expect(page.getByRole("textbox", { name: "Message agent..." }).first()).toBeVisible({ timeout: 60000, }); @@ -287,9 +291,7 @@ export async function waitForContentGrowth( } export async function getChatContainerKey(page: Page): Promise { - return page - .getByTestId("agent-chat-scroll") - .evaluate((element) => { + return getVisibleChatScroll(page).evaluate((element) => { const nativeId = (element as HTMLElement).id; const prefix = "agent-chat-scroll-"; return nativeId.startsWith(prefix) ? nativeId.slice(prefix.length) : null; diff --git a/packages/app/e2e/helpers/app.ts b/packages/app/e2e/helpers/app.ts index 014e1efd6..1b212300e 100644 --- a/packages/app/e2e/helpers/app.ts +++ b/packages/app/e2e/helpers/app.ts @@ -136,14 +136,36 @@ async function assertE2EUsesSeededTestDaemon(page: Page): Promise { } } -export const gotoHome = async (page: Page) => { +export const gotoAppShell = async (page: Page) => { await page.goto('/'); await ensureE2EStorageSeeded(page); - await expect(page.getByText('New agent', { exact: true }).first()).toBeVisible(); +}; + +export const gotoHome = async (page: Page) => { + await gotoAppShell(page); const composer = page.getByRole('textbox', { name: 'Message agent...' }); if (!(await composer.first().isVisible().catch(() => false))) { + const addProjectCta = page.getByText('Add a project', { exact: true }).first(); + const addProjectSidebar = page.getByText('Add project', { exact: true }).first(); const newAgentButton = page.getByText('New agent', { exact: true }).first(); - await newAgentButton.click(); + + await expect + .poll( + async () => + (await addProjectCta.isVisible().catch(() => false)) || + (await addProjectSidebar.isVisible().catch(() => false)) || + (await newAgentButton.isVisible().catch(() => false)), + { timeout: 10000 } + ) + .toBe(true); + + if (await addProjectCta.isVisible().catch(() => false)) { + await addProjectCta.click(); + } else if (await addProjectSidebar.isVisible().catch(() => false)) { + await addProjectSidebar.click(); + } else { + await newAgentButton.click(); + } } await expect(composer.first()).toBeVisible({ timeout: 30000 }); }; diff --git a/packages/relay/package.json b/packages/relay/package.json index f15b0a594..ae46541e4 100644 --- a/packages/relay/package.json +++ b/packages/relay/package.json @@ -13,24 +13,21 @@ "exports": { ".": { "types": "./dist/index.d.ts", - "default": [ - "./dist/index.js", - "./src/index.ts" - ] + "node": "./dist/index.js", + "import": "./src/index.ts", + "default": "./src/index.ts" }, "./e2ee": { "types": "./dist/e2ee.d.ts", - "default": [ - "./dist/e2ee.js", - "./src/e2ee.ts" - ] + "node": "./dist/e2ee.js", + "import": "./src/e2ee.ts", + "default": "./src/e2ee.ts" }, "./cloudflare": { "types": "./dist/cloudflare-adapter.d.ts", - "default": [ - "./dist/cloudflare-adapter.js", - "./src/cloudflare-adapter.ts" - ] + "node": "./dist/cloudflare-adapter.js", + "import": "./src/cloudflare-adapter.ts", + "default": "./src/cloudflare-adapter.ts" } }, "scripts": { diff --git a/packages/server/src/server/terminal-mcp/terminal-manager.test.ts b/packages/server/src/server/terminal-mcp/terminal-manager.test.ts index 740023bc6..182c67730 100644 --- a/packages/server/src/server/terminal-mcp/terminal-manager.test.ts +++ b/packages/server/src/server/terminal-mcp/terminal-manager.test.ts @@ -284,23 +284,9 @@ describe("TerminalManager - Command Execution", () => { 5000 ); - // First command - await manager.sendTextToCommand( - execResult.commandId, - "x = 5", - true, - { lines: 50, maxWait: 2000 } - ); + await manager.sendTextToCommand(execResult.commandId, "x = 5", true); + await manager.sendTextToCommand(execResult.commandId, "y = 3", true); - // Second command - await manager.sendTextToCommand( - execResult.commandId, - "y = 3", - true, - { lines: 50, maxWait: 2000 } - ); - - // Third command - use variables const output = await manager.sendTextToCommand( execResult.commandId, "print(x + y)", @@ -449,24 +435,16 @@ describe("TerminalManager - Command Execution", () => { expect(execResult.output).toContain(">"); // Node prompt expect(execResult.isDead).toBe(false); - // Execute JavaScript - await manager.sendTextToCommand( - execResult.commandId, - "const x = [1, 2, 3]", - true, - { lines: 50, maxWait: 2000 } - ); + await manager.sendTextToCommand(execResult.commandId, "const x = [1, 2, 3]", true); const output2 = await manager.sendTextToCommand( execResult.commandId, - "x.map(n => n * 2)", + "console.log(x.map(n => n * 2).join(','))", true, { lines: 50, maxWait: 2000 } ); - expect(output2).toContain("2"); - expect(output2).toContain("4"); - expect(output2).toContain("6"); + expect(output2).toContain("2,4,6"); // Exit await manager.sendTextToCommand(execResult.commandId, ".exit", true); diff --git a/packages/server/src/server/voice-mcp-bridge-command.test.ts b/packages/server/src/server/voice-mcp-bridge-command.test.ts index ba5893ac1..be8d70428 100644 --- a/packages/server/src/server/voice-mcp-bridge-command.test.ts +++ b/packages/server/src/server/voice-mcp-bridge-command.test.ts @@ -1,4 +1,3 @@ -import path from "node:path"; import { fileURLToPath } from "node:url"; import { describe, expect, test } from "vitest"; @@ -26,7 +25,9 @@ describe("resolveVoiceMcpBridgeFromRuntime", () => { }); test("uses explicit script override when provided", () => { - const explicitScriptPath = path.resolve(process.cwd(), "scripts/mcp-stdio-socket-bridge-cli.mjs"); + const explicitScriptPath = fileURLToPath( + new URL("../../scripts/mcp-stdio-socket-bridge-cli.mjs", bootstrapModuleUrl) + ); const result = resolveVoiceMcpBridgeFromRuntime({ bootstrapModuleUrl, diff --git a/packages/server/src/server/voice-mcp-bridge.test.ts b/packages/server/src/server/voice-mcp-bridge.test.ts index 50a1285e7..4cada8437 100644 --- a/packages/server/src/server/voice-mcp-bridge.test.ts +++ b/packages/server/src/server/voice-mcp-bridge.test.ts @@ -9,6 +9,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import pino from "pino"; import { createVoiceMcpSocketBridgeManager } from "./voice-mcp-bridge.js"; +import { resolveVoiceMcpBridgeScriptPath } from "./voice-mcp-bridge-command.js"; describe("voice MCP bridge", () => { test("proxies stdio MCP bytes through per-agent unix socket bridge", async () => { @@ -54,12 +55,12 @@ describe("voice MCP bridge", () => { const socketPath = await bridgeManager.ensureBridgeForCaller(callerAgentId); - const bridgeScript = path.resolve(process.cwd(), "scripts/mcp-stdio-socket-bridge-cli.mjs"); - const transport = new StdioClientTransport({ command: process.execPath, args: [ - bridgeScript, + resolveVoiceMcpBridgeScriptPath({ + bootstrapModuleUrl: import.meta.url, + }), "--socket", socketPath, ],