Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 25 additions & 12 deletions packages/cli/src/utils/npxCommand.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { execFileSync } from "node:child_process";
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { delimiter, join } from "node:path";
import { describe, expect, it } from "vitest";
import { buildNpmCommand, buildNpxCommand } from "./npxCommand.js";

Expand All @@ -14,18 +17,28 @@ describe("buildNpxCommand", () => {
});
});

// Real npx cold-start on Windows CI routinely exceeds vitest's 5s default,
// making this smoke test flaky. Give it generous headroom (it still asserts
// a real version string, so it isn't reduced to a tautology by mocking).
it("executes the host npx version check through the resolved command", () => {
const npx = buildNpxCommand(["--version"]);
const version = execFileSync(npx.command, npx.args, {
encoding: "utf8",
timeout: 30_000,
}).trim();

expect(version).toMatch(/^\d+\.\d+\.\d+/);
}, 60_000);
// Runs the built command for real against a stub `npx` placed first on PATH, so the
// cmd.exe -> npx.cmd resolution is exercised without the host's npx or the network.
it("resolves and runs the npx shim through the built command", () => {
const dir = mkdtempSync(join(tmpdir(), "hf-npx-stub-"));
try {
if (process.platform === "win32") {
writeFileSync(join(dir, "npx.cmd"), "@echo 9.9.9\r\n");
} else {
writeFileSync(join(dir, "npx"), "#!/bin/sh\necho 9.9.9\n", { mode: 0o755 });
}
const pathKey = Object.keys(process.env).find((k) => k.toLowerCase() === "path") ?? "PATH";
const npx = buildNpxCommand(["--version"]);
const out = execFileSync(npx.command, npx.args, {
encoding: "utf8",
timeout: 15_000,
env: { ...process.env, [pathKey]: `${dir}${delimiter}${process.env[pathKey] ?? ""}` },
});
expect(out.trim()).toBe("9.9.9");
} finally {
rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
}
});
});

describe("buildNpmCommand", () => {
Expand Down
Loading