mirror of
https://github.com/getpaseo/paseo.git
synced 2026-08-14 12:23:16 +00:00
fix(tests): iteration 16
This commit is contained in:
@@ -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();
|
||||||
|
|||||||
@@ -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 });
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 });
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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": {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user