test(workspaces): invoke npm portably on Windows

This commit is contained in:
Mohamed Boudra
2026-08-14 14:34:04 +02:00
parent ff83ca4bdc
commit d35c10a8b5
3 changed files with 48 additions and 12 deletions
@@ -19,9 +19,17 @@ import { describe, expect, test } from "vitest";
const desktopDir = path.resolve(import.meta.dirname, "..");
const repoRoot = path.resolve(desktopDir, "../..");
const execFileAsync = promisify(execFile);
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
const npmCommand = process.platform === "win32" ? process.execPath : "npm";
const npmPrefixArgs =
process.platform === "win32" ? [requireEnvironmentVariable("npm_execpath")] : [];
const prerequisite = "npm run dev:prerequisites";
function requireEnvironmentVariable(name) {
const value = process.env[name];
if (!value) throw new Error(`${name} is required to invoke npm on Windows`);
return value;
}
describe("desktop dev build contract", () => {
test("runs one prerequisite before either platform dev entry point", async () => {
const packageJson = JSON.parse(await readFile(path.join(desktopDir, "package.json"), "utf8"));
@@ -127,10 +135,14 @@ async function createIsolatedBuildCheckout() {
async function runPrerequisite(isolatedRoot) {
try {
await execFileAsync(npmCommand, ["run", "dev:prerequisites", "--workspace=@getpaseo/desktop"], {
cwd: isolatedRoot,
timeout: 60_000,
});
await execFileAsync(
npmCommand,
[...npmPrefixArgs, "run", "dev:prerequisites", "--workspace=@getpaseo/desktop"],
{
cwd: isolatedRoot,
timeout: 60_000,
},
);
} catch (error) {
throw new Error(`${error.stdout ?? ""}\n${error.stderr ?? ""}`, { cause: error });
}
@@ -7,19 +7,31 @@ import assert from "node:assert/strict";
import { promisify } from "node:util";
const run = promisify(execFile);
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
const npmCommand = process.platform === "win32" ? process.execPath : "npm";
const npmPrefixArgs =
process.platform === "win32" ? [requireEnvironmentVariable("npm_execpath")] : [];
const packageRoot = path.resolve(import.meta.dirname, "..");
function requireEnvironmentVariable(name) {
const value = process.env[name];
if (!value) throw new Error(`${name} is required to invoke npm on Windows`);
return value;
}
function runNpm(args, options) {
return run(npmCommand, [...npmPrefixArgs, ...args], options);
}
test("packed helper works from a fresh project without monorepo source fallback", async (t) => {
const root = await mkdtemp(path.join(tmpdir(), "paseo-helper-standalone-"));
t.after(() => rm(root, { recursive: true, force: true }));
const packDirectory = path.join(root, "packs");
const project = path.join(root, "project");
await Promise.all([mkdir(packDirectory), mkdir(project)]);
await run(npmCommand, ["run", "build"], { cwd: packageRoot });
await runNpm(["run", "build"], { cwd: packageRoot });
const packed = JSON.parse(
(
await run(npmCommand, ["pack", "--json", "--pack-destination", packDirectory], {
await runNpm(["pack", "--json", "--pack-destination", packDirectory], {
cwd: packageRoot,
})
).stdout,
@@ -31,7 +43,7 @@ test("packed helper works from a fresh project without monorepo source fallback"
dependencies: { "@getpaseo/workspace-helper": `file:${path.join(packDirectory, packed)}` },
}),
);
await run(npmCommand, ["install", "--ignore-scripts"], { cwd: project });
await runNpm(["install", "--ignore-scripts"], { cwd: project });
await writeFile(path.join(project, "notes.txt"), "before\n");
const imported = JSON.parse(
@@ -33,10 +33,22 @@ import {
} from "../dist/index.js";
const run = promisify(execFile);
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
const npmCommand = process.platform === "win32" ? process.execPath : "npm";
const npmPrefixArgs =
process.platform === "win32" ? [requireEnvironmentVariable("npm_execpath")] : [];
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const examples = JSON.parse(await readFile(path.join(packageRoot, "examples/v1.json"), "utf8"));
function requireEnvironmentVariable(name) {
const value = process.env[name];
if (!value) throw new Error(`${name} is required to invoke npm on Windows`);
return value;
}
function runNpm(args, options) {
return run(npmCommand, [...npmPrefixArgs, ...args], options);
}
test("documented lifecycle, fd3, control, and fd4 examples are exact newline-terminated bytes", () => {
for (const [name, schema] of [
["describeResponse", CommandRuntimeDescribeResponseSchema],
@@ -522,7 +534,7 @@ test("every export condition resolves from a packed standalone install", async (
t.after(() => rm(root, { recursive: true, force: true }));
const pack = JSON.parse(
(
await run(npmCommand, ["pack", "--json", "--ignore-scripts", "--pack-destination", root], {
await runNpm(["pack", "--json", "--ignore-scripts", "--pack-destination", root], {
cwd: packageRoot,
})
).stdout,
@@ -530,7 +542,7 @@ test("every export condition resolves from a packed standalone install", async (
const archive = path.join(root, pack[0].filename);
const installRoot = path.join(root, "standalone");
await mkdir(installRoot);
await run(npmCommand, ["install", "--ignore-scripts", "--no-package-lock", archive], {
await runNpm(["install", "--ignore-scripts", "--no-package-lock", archive], {
cwd: installRoot,
});
const installed = path.join(installRoot, "node_modules/@getpaseo/workspace-runtime-contract");