151 lines · 4.3 KB · TypeScript
RawDownload
import * as NodeServices from "@effect/platform-node/NodeServices";import { assert, it } from "@effect/vitest";import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";import * as Cause from "effect/Cause";import * as Effect from "effect/Effect";import * as Exit from "effect/Exit";import * as Layer from "effect/Layer";import { vi } from "vite-plus/test"; import * as NodePtyAdapter from "./NodePtyAdapter.ts";import * as PtyAdapter from "./PtyAdapter.ts"; const spawn = vi.fn(() => ({  pid: 42,  write: vi.fn(),  resize: vi.fn(),  kill: vi.fn(),  onData: vi.fn(() => ({ dispose: vi.fn() })),  onExit: vi.fn(() => ({ dispose: vi.fn() })),})); vi.mock("node-pty", () => ({ spawn })); const makeTestLayer = (platform: NodeJS.Platform = "win32") =>  NodePtyAdapter.layer.pipe(    Layer.provide(      Layer.mergeAll(        NodeServices.layer,        Layer.succeed(HostProcessPlatform, platform),        Layer.succeed(HostProcessArchitecture, "x64"),      ),    ),  ); const testLayer = makeTestLayer(); for (const platform of ["win32", "linux", "darwin"] as const) {  it.effect(`terminates through node-pty using ${platform} semantics`, () =>    Effect.gen(function* () {      const adapter = yield* PtyAdapter.PtyAdapter;      const process = yield* adapter.spawn({        shell: "test-shell",        cwd: ".",        cols: 80,        rows: 24,        env: {},      });      const nativeProcess = spawn.mock.results.at(-1)!.value;      nativeProcess.kill.mockImplementation((signal?: string) => {        if (platform === "win32" && signal) {          throw new Error("Signals not supported on windows.");        }      });       process.kill("SIGTERM");      process.kill("SIGKILL");      process.kill();       assert.deepEqual(        nativeProcess.kill.mock.calls,        platform === "win32"          ? [[undefined], [undefined], [undefined]]          : [["SIGTERM"], ["SIGKILL"], [undefined]],      );    }).pipe(Effect.provide(makeTestLayer(platform))),  );} it.effect("spawns through the public adapter with the provided host references", () =>  Effect.gen(function* () {    spawn.mockClear();    const adapter = yield* PtyAdapter.PtyAdapter;    const process = yield* adapter.spawn({      shell: "powershell.exe",      args: ["-NoLogo"],      cwd: "C:\\workspace",      cols: 120,      rows: 40,      env: {},    });     assert.equal(process.pid, 42);    assert.equal(spawn.mock.calls.length, 1);    assert.deepEqual(spawn.mock.calls[0], [      "powershell.exe",      ["-NoLogo"],      {        cwd: "C:\\workspace",        cols: 120,        rows: 40,        env: { TERM: "xterm-256color" },        name: "xterm-256color",      },    ]);  }).pipe(Effect.provide(testLayer)),); it.effect("preserves a caller-provided TERM in the spawn env on win32", () =>  Effect.gen(function* () {    spawn.mockClear();    const adapter = yield* PtyAdapter.PtyAdapter;    yield* adapter.spawn({      shell: "powershell.exe",      cwd: "C:\\workspace",      cols: 80,      rows: 24,      env: { TERM: "xterm-direct" },    });     assert.equal(spawn.mock.calls.length, 1);    assert.deepEqual(spawn.mock.calls[0], [      "powershell.exe",      [],      {        cwd: "C:\\workspace",        cols: 80,        rows: 24,        env: { TERM: "xterm-direct" },        name: "xterm-256color",      },    ]);  }).pipe(Effect.provide(testLayer)),); it.effect("reports native module load failures as structured startup defects", () =>  Effect.gen(function* () {    const cause = new Error("native binding could not be loaded");    const exit = yield* NodePtyAdapter.make(() => Promise.reject(cause)).pipe(Effect.exit);     assert.isTrue(Exit.isFailure(exit));    if (Exit.isFailure(exit)) {      assert.isTrue(Cause.hasDies(exit.cause));      const error = Cause.squash(exit.cause);      assert.instanceOf(error, NodePtyAdapter.NodePtyModuleLoadError);      assert.deepInclude(error, {        _tag: "NodePtyModuleLoadError",        platform: "win32",        architecture: "x64",      });      assert.equal(error.message, "Failed to load node-pty for win32-x64.");    }  }).pipe(    Effect.provide(      Layer.mergeAll(        NodeServices.layer,        Layer.succeed(HostProcessPlatform, "win32"),        Layer.succeed(HostProcessArchitecture, "x64"),      ),    ),  ),);