Files
nexu-io--open-design/apps/daemon/tests/terminals.spawn-helper.test.ts
wehub-resource-sync 070959e133
landing-page-staging / Deploy landing page to staging (push) Has been skipped
landing-page-ci / Validate landing page (push) Failing after 4s
visual-baseline / Capture visual baselines (push) Has been cancelled
bake-plugin-previews / Bake plugin previews (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:00:47 +08:00

52 lines
1.8 KiB
TypeScript

import fs from 'node:fs';
import { afterEach, describe, expect, it } from 'vitest';
import {
createTerminalService,
ensureSpawnHelperExecutable,
spawnHelperCandidatePaths,
} from '../src/terminals.js';
/**
* Regression for the "无法启动终端会话" / "Could not start the terminal session"
* report: pnpm unpacks node-pty's prebuilt `spawn-helper` without the execute
* bit, so the first `pty.spawn()` dies with "posix_spawnp failed." and the
* launcher toast fires. `terminals.create()` must self-heal that bit so a fresh
* PTY actually spawns.
*
* macOS/Linux only — on win32 ConPTY has no spawn-helper and there is nothing to
* repair (`spawnHelperCandidatePaths()` is empty there).
*/
const helperPath = spawnHelperCandidatePaths().find((p) => fs.existsSync(p)) ?? null;
const describeIfHelper = helperPath ? describe : describe.skip;
describeIfHelper('terminal spawn-helper executable repair', () => {
afterEach(() => {
// Leave the shared node_modules artifact executable regardless of outcome,
// so a failure here can't cascade into every other terminal test.
if (helperPath) ensureSpawnHelperExecutable();
});
it('spawns a PTY even when the prebuilt spawn-helper lost its +x bit', async () => {
// Reproduce the post-`pnpm install` state: helper present but mode 0644.
fs.chmodSync(helperPath!, 0o644);
expect(fs.statSync(helperPath!).mode & 0o111).toBe(0);
const terminals = createTerminalService();
const session = await terminals.create({
projectId: 'p-spawn-helper',
cwd: process.cwd(),
});
try {
expect(session.status).toBe('running');
expect(typeof session.pty.pid).toBe('number');
// The repair ran as part of create() → loadPty().
expect(fs.statSync(helperPath!).mode & 0o100).not.toBe(0);
} finally {
terminals.kill(session, 'SIGTERM');
}
});
});