Switch to double quotes and reformat codebase with Biome
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import { $, ProcessPromise } from 'zx'
|
||||
import { join } from 'node:path'
|
||||
import { $, ProcessPromise } from "zx";
|
||||
import { join } from "node:path";
|
||||
|
||||
const CLI_ENTRY = join(import.meta.dirname, '..', '..', 'dist', 'index.js')
|
||||
const CLI_ENTRY = join(import.meta.dirname, "..", "..", "dist", "index.js");
|
||||
|
||||
export function runLocalPaseo(args: string[], env: NodeJS.ProcessEnv = {}): ProcessPromise {
|
||||
$.verbose = false
|
||||
return $({ env: { ...process.env, ...env } })`${process.execPath} ${CLI_ENTRY} ${args}`.nothrow()
|
||||
$.verbose = false;
|
||||
return $({ env: { ...process.env, ...env } })`${process.execPath} ${CLI_ENTRY} ${args}`.nothrow();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createServer } from 'node:net'
|
||||
import { createServer } from "node:net";
|
||||
|
||||
/**
|
||||
* Reserve and release an ephemeral TCP port, returning the port number.
|
||||
@@ -6,27 +6,27 @@ import { createServer } from 'node:net'
|
||||
*/
|
||||
export async function getAvailablePort(): Promise<number> {
|
||||
return new Promise<number>((resolve, reject) => {
|
||||
const server = createServer()
|
||||
server.unref()
|
||||
const server = createServer();
|
||||
server.unref();
|
||||
|
||||
server.once('error', reject)
|
||||
server.listen(0, '127.0.0.1', () => {
|
||||
const address = server.address()
|
||||
if (!address || typeof address === 'string') {
|
||||
server.once("error", reject);
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const address = server.address();
|
||||
if (!address || typeof address === "string") {
|
||||
server.close(() => {
|
||||
reject(new Error('Failed to resolve an available TCP port'))
|
||||
})
|
||||
return
|
||||
reject(new Error("Failed to resolve an available TCP port"));
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const { port } = address
|
||||
const { port } = address;
|
||||
server.close((error) => {
|
||||
if (error) {
|
||||
reject(error)
|
||||
return
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
resolve(port)
|
||||
})
|
||||
})
|
||||
})
|
||||
resolve(port);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -12,139 +12,139 @@
|
||||
* 5. Cleanup: Kill daemon and remove temp dirs after each test
|
||||
*/
|
||||
|
||||
import { mkdtemp, rm, mkdir } from 'fs/promises'
|
||||
import { existsSync } from 'fs'
|
||||
import { tmpdir } from 'os'
|
||||
import { join } from 'path'
|
||||
import { ChildProcess, spawn } from 'child_process'
|
||||
import { getAvailablePort } from './network.ts'
|
||||
import { mkdtemp, rm, mkdir } from "fs/promises";
|
||||
import { existsSync } from "fs";
|
||||
import { tmpdir } from "os";
|
||||
import { join } from "path";
|
||||
import { ChildProcess, spawn } from "child_process";
|
||||
import { getAvailablePort } from "./network.ts";
|
||||
|
||||
export interface TestDaemonContext {
|
||||
/** Available local port for test daemon (never 6767) */
|
||||
port: number
|
||||
port: number;
|
||||
/** WebSocket URL for connecting to daemon */
|
||||
wsUrl: string
|
||||
wsUrl: string;
|
||||
/** Temp directory for PASEO_HOME */
|
||||
paseoHome: string
|
||||
paseoHome: string;
|
||||
/** Temp directory for agent working directory */
|
||||
workDir: string
|
||||
workDir: string;
|
||||
/** Running daemon process */
|
||||
process: ChildProcess | null
|
||||
process: ChildProcess | null;
|
||||
/** Whether the daemon is ready to accept connections */
|
||||
isReady: boolean
|
||||
isReady: boolean;
|
||||
/** Stop the daemon and clean up resources */
|
||||
stop: () => Promise<void>
|
||||
stop: () => Promise<void>;
|
||||
}
|
||||
|
||||
const TEST_DAEMON_ENV_DEFAULTS: Record<string, string> = {
|
||||
PASEO_RELAY_ENABLED: 'false',
|
||||
PASEO_LOCAL_SPEECH_AUTO_DOWNLOAD: process.env.PASEO_LOCAL_SPEECH_AUTO_DOWNLOAD ?? '0',
|
||||
PASEO_DICTATION_ENABLED: process.env.PASEO_DICTATION_ENABLED ?? '0',
|
||||
PASEO_VOICE_MODE_ENABLED: process.env.PASEO_VOICE_MODE_ENABLED ?? '0',
|
||||
}
|
||||
const TEST_DAEMON_HOST = '127.0.0.1'
|
||||
PASEO_RELAY_ENABLED: "false",
|
||||
PASEO_LOCAL_SPEECH_AUTO_DOWNLOAD: process.env.PASEO_LOCAL_SPEECH_AUTO_DOWNLOAD ?? "0",
|
||||
PASEO_DICTATION_ENABLED: process.env.PASEO_DICTATION_ENABLED ?? "0",
|
||||
PASEO_VOICE_MODE_ENABLED: process.env.PASEO_VOICE_MODE_ENABLED ?? "0",
|
||||
};
|
||||
const TEST_DAEMON_HOST = "127.0.0.1";
|
||||
|
||||
const DEFAULT_OUTPUT_CAPTURE_LIMIT = 256 * 1024
|
||||
const DEFAULT_OUTPUT_CAPTURE_LIMIT = 256 * 1024;
|
||||
const TEST_OUTPUT_CAPTURE_LIMIT = Number.parseInt(
|
||||
process.env.PASEO_TEST_OUTPUT_CAPTURE_BYTES ?? `${DEFAULT_OUTPUT_CAPTURE_LIMIT}`,
|
||||
10
|
||||
)
|
||||
10,
|
||||
);
|
||||
|
||||
type OutputCapture = {
|
||||
value: string
|
||||
truncated: boolean
|
||||
}
|
||||
value: string;
|
||||
truncated: boolean;
|
||||
};
|
||||
|
||||
function createOutputCapture(): OutputCapture {
|
||||
return { value: '', truncated: false }
|
||||
return { value: "", truncated: false };
|
||||
}
|
||||
|
||||
function appendOutputCapture(target: OutputCapture, chunk: Buffer): void {
|
||||
const next = target.value + chunk.toString()
|
||||
const next = target.value + chunk.toString();
|
||||
if (next.length <= TEST_OUTPUT_CAPTURE_LIMIT) {
|
||||
target.value = next
|
||||
return
|
||||
target.value = next;
|
||||
return;
|
||||
}
|
||||
target.truncated = true
|
||||
target.value = next.slice(next.length - TEST_OUTPUT_CAPTURE_LIMIT)
|
||||
target.truncated = true;
|
||||
target.value = next.slice(next.length - TEST_OUTPUT_CAPTURE_LIMIT);
|
||||
}
|
||||
|
||||
function formatOutputCapture(target: OutputCapture): string {
|
||||
if (!target.truncated) {
|
||||
return target.value
|
||||
return target.value;
|
||||
}
|
||||
return `[truncated; showing last ${TEST_OUTPUT_CAPTURE_LIMIT} chars]\n${target.value}`
|
||||
return `[truncated; showing last ${TEST_OUTPUT_CAPTURE_LIMIT} chars]\n${target.value}`;
|
||||
}
|
||||
|
||||
function readNodeErrnoCode(error: unknown): string | undefined {
|
||||
if (typeof error !== 'object' || error === null || !('code' in error)) {
|
||||
return undefined
|
||||
if (typeof error !== "object" || error === null || !("code" in error)) {
|
||||
return undefined;
|
||||
}
|
||||
return typeof (error as { code?: unknown }).code === 'string'
|
||||
? ((error as { code: string }).code)
|
||||
: undefined
|
||||
return typeof (error as { code?: unknown }).code === "string"
|
||||
? (error as { code: string }).code
|
||||
: undefined;
|
||||
}
|
||||
|
||||
function signalProcessTree(pid: number, signal: NodeJS.Signals): boolean {
|
||||
if (!Number.isInteger(pid) || pid <= 0) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
if (process.platform !== 'win32') {
|
||||
if (process.platform !== "win32") {
|
||||
try {
|
||||
process.kill(-pid, signal)
|
||||
return true
|
||||
process.kill(-pid, signal);
|
||||
return true;
|
||||
} catch (error) {
|
||||
const code = readNodeErrnoCode(error)
|
||||
if (code === 'ESRCH') {
|
||||
return false
|
||||
const code = readNodeErrnoCode(error);
|
||||
if (code === "ESRCH") {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
process.kill(pid, signal)
|
||||
return true
|
||||
process.kill(pid, signal);
|
||||
return true;
|
||||
} catch (error) {
|
||||
const code = readNodeErrnoCode(error)
|
||||
if (code === 'ESRCH') {
|
||||
return false
|
||||
const code = readNodeErrnoCode(error);
|
||||
if (code === "ESRCH") {
|
||||
return false;
|
||||
}
|
||||
throw error
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async function terminateProcessTree(processRef: ChildProcess, timeoutMs: number): Promise<void> {
|
||||
const pid = processRef.pid
|
||||
const pid = processRef.pid;
|
||||
if (!Number.isInteger(pid) || pid <= 0) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
if (processRef.exitCode !== null || processRef.signalCode !== null) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
signalProcessTree(pid, 'SIGTERM')
|
||||
signalProcessTree(pid, "SIGTERM");
|
||||
|
||||
await new Promise<void>((resolve) => {
|
||||
let settled = false
|
||||
let settled = false;
|
||||
const finish = () => {
|
||||
if (settled) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
settled = true
|
||||
clearTimeout(timeoutId)
|
||||
resolve()
|
||||
}
|
||||
settled = true;
|
||||
clearTimeout(timeoutId);
|
||||
resolve();
|
||||
};
|
||||
|
||||
const timeoutId = setTimeout(() => {
|
||||
signalProcessTree(pid, 'SIGKILL')
|
||||
finish()
|
||||
}, timeoutMs)
|
||||
signalProcessTree(pid, "SIGKILL");
|
||||
finish();
|
||||
}, timeoutMs);
|
||||
|
||||
processRef.once('exit', () => {
|
||||
finish()
|
||||
})
|
||||
})
|
||||
processRef.once("exit", () => {
|
||||
finish();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,32 +153,29 @@ async function terminateProcessTree(processRef: ChildProcess, timeoutMs: number)
|
||||
* NEVER uses 6767 (user's running daemon)
|
||||
*/
|
||||
export function getRandomPort(): number {
|
||||
return 20000 + Math.floor(Math.random() * 10000)
|
||||
return 20000 + Math.floor(Math.random() * 10000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create isolated temp directories for testing
|
||||
*/
|
||||
export async function createTempDirs(): Promise<{ paseoHome: string; workDir: string }> {
|
||||
const paseoHome = await mkdtemp(join(tmpdir(), 'paseo-e2e-home-'))
|
||||
const workDir = await mkdtemp(join(tmpdir(), 'paseo-e2e-work-'))
|
||||
const paseoHome = await mkdtemp(join(tmpdir(), "paseo-e2e-home-"));
|
||||
const workDir = await mkdtemp(join(tmpdir(), "paseo-e2e-work-"));
|
||||
|
||||
// Create the agents directory that the daemon expects
|
||||
const agentsDir = join(paseoHome, 'agents')
|
||||
await mkdir(agentsDir, { recursive: true })
|
||||
const agentsDir = join(paseoHome, "agents");
|
||||
await mkdir(agentsDir, { recursive: true });
|
||||
|
||||
return { paseoHome, workDir }
|
||||
return { paseoHome, workDir };
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for daemon to be ready by running `paseo agent ls`
|
||||
* This connects via WebSocket and ensures the daemon is responsive
|
||||
*/
|
||||
async function waitForDaemonReady(
|
||||
port: number,
|
||||
timeout = 30000
|
||||
): Promise<void> {
|
||||
const start = Date.now()
|
||||
async function waitForDaemonReady(port: number, timeout = 30000): Promise<void> {
|
||||
const start = Date.now();
|
||||
|
||||
while (Date.now() - start < timeout) {
|
||||
try {
|
||||
@@ -186,28 +183,28 @@ async function waitForDaemonReady(
|
||||
{
|
||||
port,
|
||||
wsUrl: `ws://${TEST_DAEMON_HOST}:${port}`,
|
||||
paseoHome: '',
|
||||
workDir: '',
|
||||
paseoHome: "",
|
||||
workDir: "",
|
||||
process: null,
|
||||
isReady: false,
|
||||
stop: async () => {}
|
||||
stop: async () => {},
|
||||
},
|
||||
['agent', 'ls']
|
||||
)
|
||||
["agent", "ls"],
|
||||
);
|
||||
|
||||
if (exitCode === 0) {
|
||||
return // Daemon is ready
|
||||
return; // Daemon is ready
|
||||
}
|
||||
} catch {
|
||||
// Connection failed, keep trying
|
||||
}
|
||||
await sleep(100)
|
||||
await sleep(100);
|
||||
}
|
||||
throw new Error(`Daemon failed to become ready on port ${port} within ${timeout}ms`)
|
||||
throw new Error(`Daemon failed to become ready on port ${port} within ${timeout}ms`);
|
||||
}
|
||||
|
||||
function sleep(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms))
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -217,57 +214,58 @@ function sleep(ms: number): Promise<void> {
|
||||
* with isolated PASEO_HOME and PASEO_LISTEN environment variables.
|
||||
*/
|
||||
export async function startTestDaemon(options?: {
|
||||
port?: number
|
||||
paseoHome?: string
|
||||
workDir?: string
|
||||
timeout?: number
|
||||
port?: number;
|
||||
paseoHome?: string;
|
||||
workDir?: string;
|
||||
timeout?: number;
|
||||
}): Promise<TestDaemonContext> {
|
||||
const port = options?.port ?? await getAvailablePort()
|
||||
const { paseoHome, workDir } = options?.paseoHome && options?.workDir
|
||||
? { paseoHome: options.paseoHome, workDir: options.workDir }
|
||||
: await createTempDirs()
|
||||
const timeout = options?.timeout ?? 30000
|
||||
const port = options?.port ?? (await getAvailablePort());
|
||||
const { paseoHome, workDir } =
|
||||
options?.paseoHome && options?.workDir
|
||||
? { paseoHome: options.paseoHome, workDir: options.workDir }
|
||||
: await createTempDirs();
|
||||
const timeout = options?.timeout ?? 30000;
|
||||
|
||||
const wsUrl = `ws://${TEST_DAEMON_HOST}:${port}`
|
||||
const wsUrl = `ws://${TEST_DAEMON_HOST}:${port}`;
|
||||
|
||||
// Find the CLI entry point - use the source file directly with tsx
|
||||
const cliDir = join(import.meta.dirname, '..', '..')
|
||||
const cliSrcPath = join(cliDir, 'src', 'index.ts')
|
||||
const cliDir = join(import.meta.dirname, "..", "..");
|
||||
const cliSrcPath = join(cliDir, "src", "index.ts");
|
||||
|
||||
// Start daemon process using tsx to run TypeScript directly
|
||||
const daemonProcess = spawn('npx', ['tsx', cliSrcPath, 'daemon', 'start', '--foreground'], {
|
||||
const daemonProcess = spawn("npx", ["tsx", cliSrcPath, "daemon", "start", "--foreground"], {
|
||||
env: {
|
||||
...process.env,
|
||||
...TEST_DAEMON_ENV_DEFAULTS,
|
||||
PASEO_HOME: paseoHome,
|
||||
PASEO_LISTEN: `${TEST_DAEMON_HOST}:${port}`,
|
||||
// Force no TTY to prevent QR code output
|
||||
CI: 'true',
|
||||
CI: "true",
|
||||
},
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
detached: process.platform !== 'win32',
|
||||
})
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
detached: process.platform !== "win32",
|
||||
});
|
||||
|
||||
const stdout = createOutputCapture()
|
||||
const stderr = createOutputCapture()
|
||||
const stdout = createOutputCapture();
|
||||
const stderr = createOutputCapture();
|
||||
|
||||
daemonProcess.stdout?.on('data', (data) => {
|
||||
appendOutputCapture(stdout, data)
|
||||
})
|
||||
daemonProcess.stdout?.on("data", (data) => {
|
||||
appendOutputCapture(stdout, data);
|
||||
});
|
||||
|
||||
daemonProcess.stderr?.on('data', (data) => {
|
||||
appendOutputCapture(stderr, data)
|
||||
})
|
||||
daemonProcess.stderr?.on("data", (data) => {
|
||||
appendOutputCapture(stderr, data);
|
||||
});
|
||||
|
||||
const cleanup = async () => {
|
||||
if (daemonProcess) {
|
||||
await terminateProcessTree(daemonProcess, 5000)
|
||||
await terminateProcessTree(daemonProcess, 5000);
|
||||
}
|
||||
|
||||
// Clean up temp directories
|
||||
try {
|
||||
if (existsSync(paseoHome)) {
|
||||
await rm(paseoHome, { recursive: true, force: true })
|
||||
await rm(paseoHome, { recursive: true, force: true });
|
||||
}
|
||||
} catch {
|
||||
// Ignore cleanup errors
|
||||
@@ -275,27 +273,27 @@ export async function startTestDaemon(options?: {
|
||||
|
||||
try {
|
||||
if (existsSync(workDir)) {
|
||||
await rm(workDir, { recursive: true, force: true })
|
||||
await rm(workDir, { recursive: true, force: true });
|
||||
}
|
||||
} catch {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Handle process errors
|
||||
daemonProcess.on('error', (err) => {
|
||||
console.error('Daemon process error:', err)
|
||||
})
|
||||
daemonProcess.on("error", (err) => {
|
||||
console.error("Daemon process error:", err);
|
||||
});
|
||||
|
||||
daemonProcess.on('exit', (code) => {
|
||||
daemonProcess.on("exit", (code) => {
|
||||
if (code !== 0 && code !== null) {
|
||||
console.error(`Daemon process exited with code ${code}`)
|
||||
const stderrText = formatOutputCapture(stderr)
|
||||
console.error(`Daemon process exited with code ${code}`);
|
||||
const stderrText = formatOutputCapture(stderr);
|
||||
if (stderrText) {
|
||||
console.error('Daemon stderr:', stderrText)
|
||||
console.error("Daemon stderr:", stderrText);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
const ctx: TestDaemonContext = {
|
||||
port,
|
||||
@@ -305,22 +303,22 @@ export async function startTestDaemon(options?: {
|
||||
process: daemonProcess,
|
||||
isReady: false,
|
||||
stop: cleanup,
|
||||
}
|
||||
};
|
||||
|
||||
// Wait for daemon to be ready
|
||||
try {
|
||||
await waitForDaemonReady(port, timeout)
|
||||
ctx.isReady = true
|
||||
await waitForDaemonReady(port, timeout);
|
||||
ctx.isReady = true;
|
||||
} catch (err) {
|
||||
// Daemon failed to start - clean up and rethrow
|
||||
await cleanup()
|
||||
const message = err instanceof Error ? err.message : String(err)
|
||||
await cleanup();
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
throw new Error(
|
||||
`Failed to start test daemon: ${message}\nStdout: ${formatOutputCapture(stdout)}\nStderr: ${formatOutputCapture(stderr)}`
|
||||
)
|
||||
`Failed to start test daemon: ${message}\nStdout: ${formatOutputCapture(stdout)}\nStderr: ${formatOutputCapture(stderr)}`,
|
||||
);
|
||||
}
|
||||
|
||||
return ctx
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -333,18 +331,18 @@ export async function runPaseoCli(
|
||||
ctx: TestDaemonContext,
|
||||
args: string[],
|
||||
options?: {
|
||||
timeout?: number
|
||||
cwd?: string
|
||||
}
|
||||
timeout?: number;
|
||||
cwd?: string;
|
||||
},
|
||||
): Promise<{ exitCode: number; stdout: string; stderr: string }> {
|
||||
const timeout = options?.timeout ?? 60000
|
||||
const cwd = options?.cwd ?? ctx.workDir
|
||||
const timeout = options?.timeout ?? 60000;
|
||||
const cwd = options?.cwd ?? ctx.workDir;
|
||||
|
||||
const cliDir = join(import.meta.dirname, '..', '..')
|
||||
const cliSrcPath = join(cliDir, 'src', 'index.ts')
|
||||
const cliDir = join(import.meta.dirname, "..", "..");
|
||||
const cliSrcPath = join(cliDir, "src", "index.ts");
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const proc = spawn('npx', ['tsx', cliSrcPath, ...args], {
|
||||
const proc = spawn("npx", ["tsx", cliSrcPath, ...args], {
|
||||
env: {
|
||||
...process.env,
|
||||
...TEST_DAEMON_ENV_DEFAULTS,
|
||||
@@ -352,42 +350,42 @@ export async function runPaseoCli(
|
||||
PASEO_HOME: ctx.paseoHome,
|
||||
},
|
||||
cwd,
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
detached: process.platform !== 'win32',
|
||||
})
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
detached: process.platform !== "win32",
|
||||
});
|
||||
|
||||
const stdout = createOutputCapture()
|
||||
const stderr = createOutputCapture()
|
||||
const stdout = createOutputCapture();
|
||||
const stderr = createOutputCapture();
|
||||
|
||||
proc.stdout?.on('data', (data) => {
|
||||
appendOutputCapture(stdout, data)
|
||||
})
|
||||
proc.stdout?.on("data", (data) => {
|
||||
appendOutputCapture(stdout, data);
|
||||
});
|
||||
|
||||
proc.stderr?.on('data', (data) => {
|
||||
appendOutputCapture(stderr, data)
|
||||
})
|
||||
proc.stderr?.on("data", (data) => {
|
||||
appendOutputCapture(stderr, data);
|
||||
});
|
||||
|
||||
const timeoutId = setTimeout(() => {
|
||||
if (proc.pid) {
|
||||
signalProcessTree(proc.pid, 'SIGKILL')
|
||||
signalProcessTree(proc.pid, "SIGKILL");
|
||||
}
|
||||
reject(new Error(`CLI command timed out after ${timeout}ms: paseo ${args.join(' ')}`))
|
||||
}, timeout)
|
||||
reject(new Error(`CLI command timed out after ${timeout}ms: paseo ${args.join(" ")}`));
|
||||
}, timeout);
|
||||
|
||||
proc.on('exit', (code) => {
|
||||
clearTimeout(timeoutId)
|
||||
proc.on("exit", (code) => {
|
||||
clearTimeout(timeoutId);
|
||||
resolve({
|
||||
exitCode: code ?? 1,
|
||||
stdout: formatOutputCapture(stdout),
|
||||
stderr: formatOutputCapture(stderr),
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
proc.on('error', (err) => {
|
||||
clearTimeout(timeoutId)
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
proc.on("error", (err) => {
|
||||
clearTimeout(timeoutId);
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -396,25 +394,26 @@ export async function runPaseoCli(
|
||||
*
|
||||
* This is the main entry point for E2E tests.
|
||||
*/
|
||||
export async function createE2ETestContext(options?: {
|
||||
timeout?: number
|
||||
}): Promise<
|
||||
export async function createE2ETestContext(options?: { timeout?: number }): Promise<
|
||||
TestDaemonContext & {
|
||||
/** Run a paseo CLI command against this daemon */
|
||||
paseo: (args: string[], opts?: { timeout?: number; cwd?: string }) => Promise<{
|
||||
exitCode: number
|
||||
stdout: string
|
||||
stderr: string
|
||||
}>
|
||||
paseo: (
|
||||
args: string[],
|
||||
opts?: { timeout?: number; cwd?: string },
|
||||
) => Promise<{
|
||||
exitCode: number;
|
||||
stdout: string;
|
||||
stderr: string;
|
||||
}>;
|
||||
}
|
||||
> {
|
||||
const ctx = await startTestDaemon({ timeout: options?.timeout })
|
||||
const ctx = await startTestDaemon({ timeout: options?.timeout });
|
||||
|
||||
const paseo = (args: string[], opts?: { timeout?: number; cwd?: string }) =>
|
||||
runPaseoCli(ctx, args, opts)
|
||||
runPaseoCli(ctx, args, opts);
|
||||
|
||||
return {
|
||||
...ctx,
|
||||
paseo,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user