fix(tests): iteration 16

This commit is contained in:
Mohamed Boudra
2026-03-11 01:30:04 +07:00
parent 40ebd1b730
commit e8b55eccab
8 changed files with 70 additions and 55 deletions

View File

@@ -1,5 +1,5 @@
import { test, expect } from './fixtures'; 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 }) => { test('daemon is connected in settings', async ({ page }) => {
const daemonPort = process.env.E2E_DAEMON_PORT; 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).'); throw new Error('E2E_SERVER_ID is not set (expected from globalSetup).');
} }
await gotoHome(page); await gotoAppShell(page);
await openSettings(page); await openSettings(page);
await expect(page.getByText(`127.0.0.1:${daemonPort}`)).toBeVisible(); await expect(page.getByText(`127.0.0.1:${daemonPort}`)).toBeVisible();

View File

@@ -199,6 +199,19 @@ function stripAnsi(input: string): string {
return input.replace(/\u001b\[[0-9;]*m/g, ''); 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 { function decodeOfferFromFragmentUrl(url: string): OfferPayload {
const marker = '#offer='; const marker = '#offer=';
const idx = url.indexOf(marker); const idx = url.indexOf(marker);
@@ -217,6 +230,7 @@ function decodeOfferFromFragmentUrl(url: string): OfferPayload {
export default async function globalSetup() { export default async function globalSetup() {
const repoRoot = path.resolve(__dirname, '../../..'); const repoRoot = path.resolve(__dirname, '../../..');
ensureRelayBuildArtifact(repoRoot);
const envTestPath = path.join(repoRoot, '.env.test'); const envTestPath = path.join(repoRoot, '.env.test');
if (existsSync(envTestPath)) { if (existsSync(envTestPath)) {
dotenv.config({ path: envTestPath }); dotenv.config({ path: envTestPath });

View File

@@ -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<ScrollMetrics> { export async function readScrollMetrics(page: Page): Promise<ScrollMetrics> {
return page.getByTestId("agent-chat-scroll").evaluate((root: Element) => { return getVisibleChatScroll(page).evaluate((root: Element) => {
const rootElement = root as HTMLElement; const rootElement = root as HTMLElement;
const candidates = [rootElement, ...Array.from(rootElement.querySelectorAll("*"))]; const candidates = [rootElement, ...Array.from(rootElement.querySelectorAll("*"))];
const scrollElement = const scrollElement =
@@ -194,7 +198,7 @@ export async function readScrollMetrics(page: Page): Promise<ScrollMetrics> {
} }
export async function scrollUpFromBottom(page: Page, pixels: number): Promise<void> { export async function scrollUpFromBottom(page: Page, pixels: number): Promise<void> {
const scrollViewport = page.getByTestId("agent-chat-scroll"); const scrollViewport = getVisibleChatScroll(page);
await expect(scrollViewport).toHaveCount(1, { timeout: 30000 }); await expect(scrollViewport).toHaveCount(1, { timeout: 30000 });
await scrollViewport.evaluate( await scrollViewport.evaluate(
(root: Element, amount: number) => { (root: Element, amount: number) => {
@@ -240,7 +244,7 @@ export async function scrollUpFromBottom(page: Page, pixels: number): Promise<vo
} }
export async function waitForAgentReady(page: Page, expectedTailText?: string): Promise<void> { export async function waitForAgentReady(page: Page, expectedTailText?: string): Promise<void> {
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({ await expect(page.getByRole("textbox", { name: "Message agent..." }).first()).toBeVisible({
timeout: 60000, timeout: 60000,
}); });
@@ -287,9 +291,7 @@ export async function waitForContentGrowth(
} }
export async function getChatContainerKey(page: Page): Promise<string | null> { export async function getChatContainerKey(page: Page): Promise<string | null> {
return page return getVisibleChatScroll(page).evaluate((element) => {
.getByTestId("agent-chat-scroll")
.evaluate((element) => {
const nativeId = (element as HTMLElement).id; const nativeId = (element as HTMLElement).id;
const prefix = "agent-chat-scroll-"; const prefix = "agent-chat-scroll-";
return nativeId.startsWith(prefix) ? nativeId.slice(prefix.length) : null; return nativeId.startsWith(prefix) ? nativeId.slice(prefix.length) : null;

View File

@@ -136,14 +136,36 @@ async function assertE2EUsesSeededTestDaemon(page: Page): Promise<void> {
} }
} }
export const gotoHome = async (page: Page) => { export const gotoAppShell = async (page: Page) => {
await page.goto('/'); await page.goto('/');
await ensureE2EStorageSeeded(page); 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...' }); const composer = page.getByRole('textbox', { name: 'Message agent...' });
if (!(await composer.first().isVisible().catch(() => false))) { 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(); 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 }); await expect(composer.first()).toBeVisible({ timeout: 30000 });
}; };

View File

@@ -13,24 +13,21 @@
"exports": { "exports": {
".": { ".": {
"types": "./dist/index.d.ts", "types": "./dist/index.d.ts",
"default": [ "node": "./dist/index.js",
"./dist/index.js", "import": "./src/index.ts",
"./src/index.ts" "default": "./src/index.ts"
]
}, },
"./e2ee": { "./e2ee": {
"types": "./dist/e2ee.d.ts", "types": "./dist/e2ee.d.ts",
"default": [ "node": "./dist/e2ee.js",
"./dist/e2ee.js", "import": "./src/e2ee.ts",
"./src/e2ee.ts" "default": "./src/e2ee.ts"
]
}, },
"./cloudflare": { "./cloudflare": {
"types": "./dist/cloudflare-adapter.d.ts", "types": "./dist/cloudflare-adapter.d.ts",
"default": [ "node": "./dist/cloudflare-adapter.js",
"./dist/cloudflare-adapter.js", "import": "./src/cloudflare-adapter.ts",
"./src/cloudflare-adapter.ts" "default": "./src/cloudflare-adapter.ts"
]
} }
}, },
"scripts": { "scripts": {

View File

@@ -284,23 +284,9 @@ describe("TerminalManager - Command Execution", () => {
5000 5000
); );
// First command await manager.sendTextToCommand(execResult.commandId, "x = 5", true);
await manager.sendTextToCommand( await manager.sendTextToCommand(execResult.commandId, "y = 3", true);
execResult.commandId,
"x = 5",
true,
{ lines: 50, maxWait: 2000 }
);
// Second command
await manager.sendTextToCommand(
execResult.commandId,
"y = 3",
true,
{ lines: 50, maxWait: 2000 }
);
// Third command - use variables
const output = await manager.sendTextToCommand( const output = await manager.sendTextToCommand(
execResult.commandId, execResult.commandId,
"print(x + y)", "print(x + y)",
@@ -449,24 +435,16 @@ describe("TerminalManager - Command Execution", () => {
expect(execResult.output).toContain(">"); // Node prompt expect(execResult.output).toContain(">"); // Node prompt
expect(execResult.isDead).toBe(false); expect(execResult.isDead).toBe(false);
// Execute JavaScript await manager.sendTextToCommand(execResult.commandId, "const x = [1, 2, 3]", true);
await manager.sendTextToCommand(
execResult.commandId,
"const x = [1, 2, 3]",
true,
{ lines: 50, maxWait: 2000 }
);
const output2 = await manager.sendTextToCommand( const output2 = await manager.sendTextToCommand(
execResult.commandId, execResult.commandId,
"x.map(n => n * 2)", "console.log(x.map(n => n * 2).join(','))",
true, true,
{ lines: 50, maxWait: 2000 } { lines: 50, maxWait: 2000 }
); );
expect(output2).toContain("2"); expect(output2).toContain("2,4,6");
expect(output2).toContain("4");
expect(output2).toContain("6");
// Exit // Exit
await manager.sendTextToCommand(execResult.commandId, ".exit", true); await manager.sendTextToCommand(execResult.commandId, ".exit", true);

View File

@@ -1,4 +1,3 @@
import path from "node:path";
import { fileURLToPath } from "node:url"; import { fileURLToPath } from "node:url";
import { describe, expect, test } from "vitest"; import { describe, expect, test } from "vitest";
@@ -26,7 +25,9 @@ describe("resolveVoiceMcpBridgeFromRuntime", () => {
}); });
test("uses explicit script override when provided", () => { 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({ const result = resolveVoiceMcpBridgeFromRuntime({
bootstrapModuleUrl, bootstrapModuleUrl,

View File

@@ -9,6 +9,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import pino from "pino"; import pino from "pino";
import { createVoiceMcpSocketBridgeManager } from "./voice-mcp-bridge.js"; import { createVoiceMcpSocketBridgeManager } from "./voice-mcp-bridge.js";
import { resolveVoiceMcpBridgeScriptPath } from "./voice-mcp-bridge-command.js";
describe("voice MCP bridge", () => { describe("voice MCP bridge", () => {
test("proxies stdio MCP bytes through per-agent unix socket bridge", async () => { 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 socketPath = await bridgeManager.ensureBridgeForCaller(callerAgentId);
const bridgeScript = path.resolve(process.cwd(), "scripts/mcp-stdio-socket-bridge-cli.mjs");
const transport = new StdioClientTransport({ const transport = new StdioClientTransport({
command: process.execPath, command: process.execPath,
args: [ args: [
bridgeScript, resolveVoiceMcpBridgeScriptPath({
bootstrapModuleUrl: import.meta.url,
}),
"--socket", "--socket",
socketPath, socketPath,
], ],