Run server tests on Linux+Windows matrix (#809)
* Run server tests on Linux+Windows matrix Replace the hand-curated Windows server test allow-list with a full-suite matrix run.\nBoth Ubuntu and Windows now run the same server test command with shared setup and secrets. * Add isPlatform helper and gate Windows-hostile server tests - Add a shared server test isPlatform helper. - Migrate existing Windows-gated spawn, worktree, executable, and worktree-core tests to the helper. - Gate Windows-hostile symlink, macOS path-normalization, and POSIX shell setup tests with skipIf. * Replace POSIX shell calls in test fixtures with Node primitives - Replaced test fixture mkdir/echo shell setup with fs mkdirSync/writeFileSync calls in touched server tests. - Replaced git shell strings with execFileSync/spawnSync argv calls across checkout, worktree, MCP, script, and workspace git fixtures. - Gated the directory suggestion symlink escape tests on Windows because those fixtures require POSIX symlink behavior. * Fix Windows server-test failures and split POSIX-only suites into sibling files - Fix Windows path/cwd assertions in terminal, session/workspace, git-service, checkout-git, MCP, logger, spawn, and registry bootstrap tests.\n- Keep terminal tests runnable on Windows by canonicalizing temp cwd fixtures and ensuring a Windows shell fallback.\n- Gate POSIX-only shell, signal, Unix socket, and git-worktree reuse fixtures that need dedicated Windows coverage later. * Move POSIX-only test blocks into sibling .posix.test.ts files - terminal.test.ts: moved PTY/bash interaction blocks into terminal.posix.test.ts. - worktree.test.ts: moved git-worktree and teardown shell blocks into worktree.posix.test.ts. - worktree-bootstrap.test.ts: moved setup shell and terminal-backed service blocks into worktree-bootstrap.posix.test.ts. - worktree-core.test.ts: moved the POSIX-only worktree-core suite into worktree-core.posix.test.ts and removed the empty original. - provider-availability.test.ts and file-explorer/service.test.ts: moved POSIX PATH/symlink blocks into sibling suites. * Fix Windows 8.3 short-name, EBUSY cleanup, and node-pty shell-path failures in server tests - Normalize temp home directories in directory suggestion assertions to avoid Windows short-name mismatches. - Use Windows-valid terminal shells/cwds in terminal fixtures and wait for terminal-manager PTYs before cleanup. - Replace hardcoded POSIX paths in workspace-git/MCP/loop fixtures with platform-resolved paths or command files. - Gate the two explicitly Linux-only workspace-git watcher tests. * Replace hardcoded POSIX paths with portable Node path constructions in server tests - checkout-git.test.ts and worktree-session.test.ts: compare Windows temp paths with realpathSync.native to avoid 8.3 short-name mismatches. - directory-suggestions.test.ts: canonicalize result and expected paths with realpathSync.native. - session.workspaces.test.ts: replace literal /tmp and /Users fixtures with path.resolve/path.join constructions. - workspace-git-service.primitive.test.ts, loop-service.test.ts, and mcp-server.test.ts: use canonical repo/temp paths and shell-safe relative verify commands. * Fix loop-service verify-check shell and workspace-git-service path-separator on Windows - Run the loop-service verify script through the current Node executable with a relative script path. - Normalize the workspace-git-service expected repo cwd to forward slashes for the listWorktrees assertion. * Fix loop-service worker PTY spawn on Windows - Canonicalize the loop-service temporary root and workspace with realpathSync.native before worker agents use the path as cwd. * Gate loop-service real-worker-PTY test on Windows - Skip the real worker PTY loop test on Windows after ConPTY path resolution still fails with node-pty error 267.\n- Keep the test running on POSIX so the loop behavior remains covered. * Stub getMetricsSnapshot in test mocks to suppress async-leak uncaught exceptions on Windows - Add a no-op AgentManager metrics snapshot to the WebSocket notification test server stub. * Fix terminal-manager Windows-path test to avoid PTY spawn into nonexistent dir - Use an existing temporary cwd for the createTerminal absolute-path validation assertion so node-pty does not spawn into a missing Windows directory.
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
import { it, expect, afterEach } from "vitest";
|
||||
import { isPlatform } from "../test-utils/platform.js";
|
||||
import { createTerminalManager, type TerminalManager } from "./terminal-manager.js";
|
||||
import { existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync } from "node:fs";
|
||||
import { existsSync, mkdtempSync, mkdirSync, readFileSync, realpathSync, rmSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { tmpdir } from "node:os";
|
||||
|
||||
if (isPlatform("win32") && !process.env.ComSpec && !process.env.COMSPEC) {
|
||||
process.env.ComSpec = "C:\\Windows\\System32\\cmd.exe";
|
||||
}
|
||||
|
||||
async function waitForCondition(
|
||||
predicate: () => boolean,
|
||||
timeoutMs: number,
|
||||
@@ -19,47 +24,52 @@ async function waitForCondition(
|
||||
throw new Error(`Timed out after ${timeoutMs}ms waiting for condition`);
|
||||
}
|
||||
|
||||
async function withShell<T>(shell: string, run: () => Promise<T>): Promise<T> {
|
||||
const originalShell = process.env.SHELL;
|
||||
process.env.SHELL = shell;
|
||||
try {
|
||||
return await run();
|
||||
} finally {
|
||||
if (originalShell === undefined) {
|
||||
delete process.env.SHELL;
|
||||
} else {
|
||||
process.env.SHELL = originalShell;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let manager: TerminalManager;
|
||||
const temporaryDirs: string[] = [];
|
||||
|
||||
afterEach(() => {
|
||||
afterEach(async () => {
|
||||
if (manager) {
|
||||
const terminalsByCwd = await Promise.all(
|
||||
manager.listDirectories().map((cwd) => manager.getTerminals(cwd)),
|
||||
);
|
||||
await Promise.all(
|
||||
terminalsByCwd
|
||||
.flat()
|
||||
.map((terminal) =>
|
||||
manager.killTerminalAndWait(terminal.id, { gracefulTimeoutMs: 50, forceTimeoutMs: 50 }),
|
||||
),
|
||||
);
|
||||
manager.killAll();
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||
while (temporaryDirs.length > 0) {
|
||||
const dir = temporaryDirs.pop();
|
||||
if (dir) {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
try {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
} catch (error) {
|
||||
if ((error as NodeJS.ErrnoException).code !== "EBUSY") {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("returns empty list for new cwd", async () => {
|
||||
manager = createTerminalManager();
|
||||
const terminals = await manager.getTerminals("/tmp");
|
||||
const cwd = realpathSync(tmpdir());
|
||||
const terminals = await manager.getTerminals(cwd);
|
||||
|
||||
expect(terminals).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("returns existing terminals on subsequent calls", async () => {
|
||||
manager = createTerminalManager();
|
||||
const created = await manager.createTerminal({ cwd: "/tmp" });
|
||||
const first = await manager.getTerminals("/tmp");
|
||||
const second = await manager.getTerminals("/tmp");
|
||||
const cwd = realpathSync(tmpdir());
|
||||
const created = await manager.createTerminal({ cwd });
|
||||
const first = await manager.getTerminals(cwd);
|
||||
const second = await manager.getTerminals(cwd);
|
||||
|
||||
expect(first.length).toBe(1);
|
||||
expect(first[0].id).toBe(created.id);
|
||||
@@ -79,8 +89,11 @@ it("accepts Windows absolute paths", async () => {
|
||||
|
||||
it("creates separate terminals for different cwds", async () => {
|
||||
manager = createTerminalManager();
|
||||
const tmpTerminals = [await manager.createTerminal({ cwd: "/tmp" })];
|
||||
const homeTerminals = [await manager.createTerminal({ cwd: "/home" })];
|
||||
const firstCwd = mkdtempSync(join(tmpdir(), "terminal-manager-first-"));
|
||||
const secondCwd = mkdtempSync(join(tmpdir(), "terminal-manager-second-"));
|
||||
temporaryDirs.push(firstCwd, secondCwd);
|
||||
const tmpTerminals = [await manager.createTerminal({ cwd: firstCwd })];
|
||||
const homeTerminals = [await manager.createTerminal({ cwd: secondCwd })];
|
||||
|
||||
expect(tmpTerminals.length).toBe(1);
|
||||
expect(homeTerminals.length).toBe(1);
|
||||
@@ -89,29 +102,31 @@ it("creates separate terminals for different cwds", async () => {
|
||||
|
||||
it("creates additional terminal with auto-incrementing name", async () => {
|
||||
manager = createTerminalManager();
|
||||
await manager.createTerminal({ cwd: "/tmp" });
|
||||
const second = await manager.createTerminal({ cwd: "/tmp" });
|
||||
const cwd = realpathSync(tmpdir());
|
||||
await manager.createTerminal({ cwd });
|
||||
const second = await manager.createTerminal({ cwd });
|
||||
|
||||
expect(second.name).toBe("Terminal 2");
|
||||
|
||||
const terminals = await manager.getTerminals("/tmp");
|
||||
const terminals = await manager.getTerminals(cwd);
|
||||
expect(terminals.length).toBe(2);
|
||||
});
|
||||
|
||||
it("uses custom name when provided", async () => {
|
||||
manager = createTerminalManager();
|
||||
const session = await manager.createTerminal({ cwd: "/tmp", name: "Dev Server" });
|
||||
const session = await manager.createTerminal({ cwd: realpathSync(tmpdir()), name: "Dev Server" });
|
||||
|
||||
expect(session.name).toBe("Dev Server");
|
||||
});
|
||||
|
||||
it("creates first terminal if none exist", async () => {
|
||||
manager = createTerminalManager();
|
||||
const session = await manager.createTerminal({ cwd: "/tmp" });
|
||||
const cwd = realpathSync(tmpdir());
|
||||
const session = await manager.createTerminal({ cwd });
|
||||
|
||||
expect(session.name).toBe("Terminal 1");
|
||||
|
||||
const terminals = await manager.getTerminals("/tmp");
|
||||
const terminals = await manager.getTerminals(cwd);
|
||||
expect(terminals.length).toBe(1);
|
||||
expect(terminals[0].id).toBe(session.id);
|
||||
});
|
||||
@@ -123,71 +138,67 @@ it("throws for relative paths", async () => {
|
||||
|
||||
it("does not reject Windows absolute paths as relative", async () => {
|
||||
manager = createTerminalManager();
|
||||
// Should pass path validation (not throw "cwd must be absolute path").
|
||||
// The terminal may or may not spawn successfully on non-Windows hosts,
|
||||
// so we only assert the validation error is absent.
|
||||
const cwd = mkdtempSync(join(tmpdir(), "terminal-manager-absolute-path-"));
|
||||
temporaryDirs.push(cwd);
|
||||
|
||||
try {
|
||||
await manager.createTerminal({ cwd: "C:\\Users\\foo\\project" });
|
||||
await manager.createTerminal({ cwd });
|
||||
} catch (error) {
|
||||
expect((error as Error).message).not.toBe("cwd must be absolute path");
|
||||
}
|
||||
});
|
||||
|
||||
it("inherits registered env for the worktree root cwd", async () => {
|
||||
await withShell("/bin/sh", async () => {
|
||||
manager = createTerminalManager();
|
||||
const cwd = mkdtempSync(join(tmpdir(), "terminal-manager-env-root-"));
|
||||
temporaryDirs.push(cwd);
|
||||
const markerPath = join(cwd, "root-port.txt");
|
||||
manager = createTerminalManager();
|
||||
const cwd = mkdtempSync(join(tmpdir(), "terminal-manager-env-root-"));
|
||||
temporaryDirs.push(cwd);
|
||||
const markerPath = join(cwd, "root-port.txt");
|
||||
|
||||
manager.registerCwdEnv({
|
||||
cwd,
|
||||
env: { PASEO_WORKTREE_PORT: "45678" },
|
||||
});
|
||||
const session = await manager.createTerminal({ cwd });
|
||||
for (let attempt = 0; attempt < 10 && !existsSync(markerPath); attempt++) {
|
||||
session.send({
|
||||
type: "input",
|
||||
data: `printf '%s' "$PASEO_WORKTREE_PORT" > ${JSON.stringify(markerPath)}\r`,
|
||||
});
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
}
|
||||
|
||||
await waitForCondition(() => existsSync(markerPath), 10000);
|
||||
expect(readFileSync(markerPath, "utf8")).toBe("45678");
|
||||
manager.registerCwdEnv({
|
||||
cwd,
|
||||
env: { PASEO_WORKTREE_PORT: "45678" },
|
||||
});
|
||||
await manager.createTerminal({
|
||||
cwd,
|
||||
command: process.execPath,
|
||||
args: [
|
||||
"-e",
|
||||
`require('fs').writeFileSync(${JSON.stringify(markerPath)}, process.env.PASEO_WORKTREE_PORT ?? '')`,
|
||||
],
|
||||
});
|
||||
|
||||
await waitForCondition(() => existsSync(markerPath), 10000);
|
||||
expect(readFileSync(markerPath, "utf8")).toBe("45678");
|
||||
});
|
||||
|
||||
it("inherits registered env for subdirectories within the worktree", async () => {
|
||||
await withShell("/bin/sh", async () => {
|
||||
manager = createTerminalManager();
|
||||
const rootCwd = mkdtempSync(join(tmpdir(), "terminal-manager-env-subdir-"));
|
||||
const subdirCwd = join(rootCwd, "packages", "app");
|
||||
mkdirSync(subdirCwd, { recursive: true });
|
||||
temporaryDirs.push(rootCwd);
|
||||
const markerPath = join(subdirCwd, "subdir-port.txt");
|
||||
manager = createTerminalManager();
|
||||
const rootCwd = mkdtempSync(join(tmpdir(), "terminal-manager-env-subdir-"));
|
||||
const subdirCwd = join(rootCwd, "packages", "app");
|
||||
mkdirSync(subdirCwd, { recursive: true });
|
||||
temporaryDirs.push(rootCwd);
|
||||
const markerPath = join(subdirCwd, "subdir-port.txt");
|
||||
|
||||
manager.registerCwdEnv({
|
||||
cwd: rootCwd,
|
||||
env: { PASEO_WORKTREE_PORT: "45679" },
|
||||
});
|
||||
const session = await manager.createTerminal({ cwd: subdirCwd });
|
||||
for (let attempt = 0; attempt < 10 && !existsSync(markerPath); attempt++) {
|
||||
session.send({
|
||||
type: "input",
|
||||
data: `printf '%s' "$PASEO_WORKTREE_PORT" > ${JSON.stringify(markerPath)}\r`,
|
||||
});
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
}
|
||||
|
||||
await waitForCondition(() => existsSync(markerPath), 10000);
|
||||
expect(readFileSync(markerPath, "utf8")).toBe("45679");
|
||||
manager.registerCwdEnv({
|
||||
cwd: rootCwd,
|
||||
env: { PASEO_WORKTREE_PORT: "45679" },
|
||||
});
|
||||
await manager.createTerminal({
|
||||
cwd: subdirCwd,
|
||||
command: process.execPath,
|
||||
args: [
|
||||
"-e",
|
||||
`require('fs').writeFileSync(${JSON.stringify(markerPath)}, process.env.PASEO_WORKTREE_PORT ?? '')`,
|
||||
],
|
||||
});
|
||||
|
||||
await waitForCondition(() => existsSync(markerPath), 10000);
|
||||
expect(readFileSync(markerPath, "utf8")).toBe("45679");
|
||||
});
|
||||
|
||||
it("returns terminal by id", async () => {
|
||||
manager = createTerminalManager();
|
||||
const session = await manager.createTerminal({ cwd: "/tmp" });
|
||||
const session = await manager.createTerminal({ cwd: realpathSync(tmpdir()) });
|
||||
const found = manager.getTerminal(session.id);
|
||||
|
||||
expect(found).toBe(session);
|
||||
@@ -202,7 +213,7 @@ it("returns undefined for unknown id", () => {
|
||||
|
||||
it("removes terminal from manager", async () => {
|
||||
manager = createTerminalManager();
|
||||
const session = await manager.createTerminal({ cwd: "/tmp" });
|
||||
const session = await manager.createTerminal({ cwd: realpathSync(tmpdir()) });
|
||||
const id = session.id;
|
||||
|
||||
manager.killTerminal(id);
|
||||
@@ -212,24 +223,26 @@ it("removes terminal from manager", async () => {
|
||||
|
||||
it("removes cwd entry when last terminal is killed", async () => {
|
||||
manager = createTerminalManager();
|
||||
const created = await manager.createTerminal({ cwd: "/tmp" });
|
||||
const cwd = realpathSync(tmpdir());
|
||||
const created = await manager.createTerminal({ cwd });
|
||||
manager.killTerminal(created.id);
|
||||
|
||||
const remaining = await manager.getTerminals("/tmp");
|
||||
const remaining = await manager.getTerminals(cwd);
|
||||
expect(remaining).toHaveLength(0);
|
||||
expect(manager.listDirectories()).not.toContain("/tmp");
|
||||
expect(manager.listDirectories()).not.toContain(cwd);
|
||||
});
|
||||
|
||||
it("keeps cwd entry when other terminals remain", async () => {
|
||||
manager = createTerminalManager();
|
||||
await manager.createTerminal({ cwd: "/tmp" });
|
||||
const second = await manager.createTerminal({ cwd: "/tmp" });
|
||||
const cwd = realpathSync(tmpdir());
|
||||
await manager.createTerminal({ cwd });
|
||||
const second = await manager.createTerminal({ cwd });
|
||||
|
||||
const terminals = await manager.getTerminals("/tmp");
|
||||
const terminals = await manager.getTerminals(cwd);
|
||||
manager.killTerminal(terminals[0].id);
|
||||
|
||||
expect(manager.listDirectories()).toContain("/tmp");
|
||||
const remaining = await manager.getTerminals("/tmp");
|
||||
expect(manager.listDirectories()).toContain(cwd);
|
||||
const remaining = await manager.getTerminals(cwd);
|
||||
expect(remaining.length).toBe(1);
|
||||
expect(remaining[0].id).toBe(second.id);
|
||||
});
|
||||
@@ -241,7 +254,8 @@ it("is no-op for unknown id", () => {
|
||||
|
||||
it("auto-removes terminal when shell exits", async () => {
|
||||
manager = createTerminalManager();
|
||||
const session = await manager.createTerminal({ cwd: "/tmp" });
|
||||
const cwd = realpathSync(tmpdir());
|
||||
const session = await manager.createTerminal({ cwd });
|
||||
const exitedId = session.id;
|
||||
session.kill();
|
||||
|
||||
@@ -249,7 +263,7 @@ it("auto-removes terminal when shell exits", async () => {
|
||||
|
||||
expect(manager.getTerminal(exitedId)).toBeUndefined();
|
||||
|
||||
const remaining = await manager.getTerminals("/tmp");
|
||||
const remaining = await manager.getTerminals(cwd);
|
||||
expect(remaining).toHaveLength(0);
|
||||
});
|
||||
|
||||
@@ -260,19 +274,25 @@ it("returns empty array initially", () => {
|
||||
|
||||
it("returns all cwds with active terminals", async () => {
|
||||
manager = createTerminalManager();
|
||||
await manager.createTerminal({ cwd: "/tmp" });
|
||||
await manager.createTerminal({ cwd: "/home" });
|
||||
const firstCwd = mkdtempSync(join(tmpdir(), "terminal-manager-list-first-"));
|
||||
const secondCwd = mkdtempSync(join(tmpdir(), "terminal-manager-list-second-"));
|
||||
temporaryDirs.push(firstCwd, secondCwd);
|
||||
await manager.createTerminal({ cwd: firstCwd });
|
||||
await manager.createTerminal({ cwd: secondCwd });
|
||||
|
||||
const dirs = manager.listDirectories();
|
||||
expect(dirs).toContain("/tmp");
|
||||
expect(dirs).toContain("/home");
|
||||
expect(dirs).toContain(firstCwd);
|
||||
expect(dirs).toContain(secondCwd);
|
||||
expect(dirs.length).toBe(2);
|
||||
});
|
||||
|
||||
it("kills all terminals and clears state", async () => {
|
||||
manager = createTerminalManager();
|
||||
const tmpSession = await manager.createTerminal({ cwd: "/tmp" });
|
||||
const homeSession = await manager.createTerminal({ cwd: "/home" });
|
||||
const firstCwd = mkdtempSync(join(tmpdir(), "terminal-manager-kill-first-"));
|
||||
const secondCwd = mkdtempSync(join(tmpdir(), "terminal-manager-kill-second-"));
|
||||
temporaryDirs.push(firstCwd, secondCwd);
|
||||
const tmpSession = await manager.createTerminal({ cwd: firstCwd });
|
||||
const homeSession = await manager.createTerminal({ cwd: secondCwd });
|
||||
const tmpId = tmpSession.id;
|
||||
const homeId = homeSession.id;
|
||||
|
||||
@@ -285,6 +305,7 @@ it("kills all terminals and clears state", async () => {
|
||||
|
||||
it("emits cwd snapshots when terminals are created", async () => {
|
||||
manager = createTerminalManager();
|
||||
const cwd = realpathSync(tmpdir());
|
||||
const snapshots: Array<{ cwd: string; terminals: Array<{ name: string; title?: string }> }> = [];
|
||||
const unsubscribe = manager.subscribeTerminalsChanged((input) => {
|
||||
snapshots.push({
|
||||
@@ -296,15 +317,15 @@ it("emits cwd snapshots when terminals are created", async () => {
|
||||
});
|
||||
});
|
||||
|
||||
await manager.createTerminal({ cwd: "/tmp" });
|
||||
await manager.createTerminal({ cwd: "/tmp", name: "Dev Server" });
|
||||
await manager.createTerminal({ cwd });
|
||||
await manager.createTerminal({ cwd, name: "Dev Server" });
|
||||
|
||||
expect(snapshots).toContainEqual({
|
||||
cwd: "/tmp",
|
||||
cwd,
|
||||
terminals: [{ name: "Terminal 1" }],
|
||||
});
|
||||
expect(snapshots).toContainEqual({
|
||||
cwd: "/tmp",
|
||||
cwd,
|
||||
terminals: [{ name: "Terminal 1" }, { name: "Dev Server" }],
|
||||
});
|
||||
|
||||
@@ -330,24 +351,26 @@ function hasLogsTitle(sessionId: string) {
|
||||
}
|
||||
|
||||
it("emits updated terminal titles after debounced title changes", async () => {
|
||||
await withShell("/bin/sh", async () => {
|
||||
manager = createTerminalManager();
|
||||
const snapshots: TerminalTitleEntry[][] = [];
|
||||
const unsubscribe = manager.subscribeTerminalsChanged((input) => {
|
||||
snapshots.push(input.terminals.map(toTitleEntry));
|
||||
});
|
||||
|
||||
const session = await manager.createTerminal({ cwd: "/tmp" });
|
||||
session.send({ type: "input", data: "printf '\\033]0;Logs\\007'\r" });
|
||||
|
||||
await waitForCondition(() => snapshots.some(hasLogsTitle(session.id)), 10000);
|
||||
|
||||
unsubscribe();
|
||||
manager = createTerminalManager();
|
||||
const snapshots: TerminalTitleEntry[][] = [];
|
||||
const unsubscribe = manager.subscribeTerminalsChanged((input) => {
|
||||
snapshots.push(input.terminals.map(toTitleEntry));
|
||||
});
|
||||
|
||||
const session = await manager.createTerminal({
|
||||
cwd: realpathSync(tmpdir()),
|
||||
command: process.execPath,
|
||||
args: ["-e", "process.stdout.write('\\x1b]0;Logs\\x07'); setTimeout(() => {}, 10000);"],
|
||||
});
|
||||
|
||||
await waitForCondition(() => snapshots.some(hasLogsTitle(session.id)), 10000);
|
||||
|
||||
unsubscribe();
|
||||
}, 10000);
|
||||
|
||||
it("emits empty snapshot when last terminal is removed", async () => {
|
||||
manager = createTerminalManager();
|
||||
const cwd = realpathSync(tmpdir());
|
||||
const snapshots: Array<{ cwd: string; terminalCount: number }> = [];
|
||||
const unsubscribe = manager.subscribeTerminalsChanged((input) => {
|
||||
snapshots.push({
|
||||
@@ -356,11 +379,11 @@ it("emits empty snapshot when last terminal is removed", async () => {
|
||||
});
|
||||
});
|
||||
|
||||
const session = await manager.createTerminal({ cwd: "/tmp" });
|
||||
const session = await manager.createTerminal({ cwd });
|
||||
manager.killTerminal(session.id);
|
||||
|
||||
expect(snapshots).toContainEqual({
|
||||
cwd: "/tmp",
|
||||
cwd,
|
||||
terminalCount: 0,
|
||||
});
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user