mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-23 01:32:40 +00:00
161 lines
5.6 KiB
JavaScript
161 lines
5.6 KiB
JavaScript
import { execFile } from "node:child_process";
|
|
import {
|
|
access,
|
|
cp,
|
|
mkdir,
|
|
mkdtemp,
|
|
readFile,
|
|
rm,
|
|
stat,
|
|
symlink,
|
|
utimes,
|
|
writeFile,
|
|
} from "node:fs/promises";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { promisify } from "node:util";
|
|
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" ? 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"));
|
|
const devScript = await readFile(path.join(import.meta.dirname, "dev.sh"), "utf8");
|
|
|
|
expect(packageJson.scripts.predev).toBe(prerequisite);
|
|
expect(packageJson.scripts["predev:win"]).toBe(prerequisite);
|
|
expect(packageJson.scripts["dev:prerequisites"]).toBe(
|
|
"npm --prefix ../.. run build:server-deps && npm --prefix ../.. run build --workspace=@getpaseo/server",
|
|
);
|
|
expect(packageJson.scripts.dev).toBe("./scripts/dev.sh");
|
|
expect(packageJson.scripts["dev:win"]).toBe("powershell ./scripts/dev.ps1");
|
|
expect(devScript.indexOf("npm run build:main")).toBeLessThan(
|
|
devScript.indexOf('exec node "$SCRIPT_DIR/dev-runner.mjs"'),
|
|
);
|
|
});
|
|
|
|
test("builds the private runtime fixture before renderer acceptance", async () => {
|
|
const packageJson = JSON.parse(await readFile(path.join(desktopDir, "package.json"), "utf8"));
|
|
|
|
expect(packageJson.scripts["pretest:e2e:renderer"]).toBe(
|
|
"npm --prefix ../.. run build:workspace-runtime-fixture",
|
|
);
|
|
});
|
|
|
|
test("the public prerequisite repairs missing and stale server artifacts in an isolated checkout", async () => {
|
|
const isolatedRoot = await createIsolatedBuildCheckout();
|
|
const staleServerExport = path.join(
|
|
isolatedRoot,
|
|
"packages/server/dist/server/server/exports.js",
|
|
);
|
|
const staleSourceExport = path.join(isolatedRoot, "packages/server/src/server/exports.ts");
|
|
const missingServerExport = path.join(
|
|
isolatedRoot,
|
|
"packages/server/dist/server/server/session.js",
|
|
);
|
|
const missingSourceExport = path.join(isolatedRoot, "packages/server/src/server/session.ts");
|
|
|
|
await mkdir(path.dirname(staleServerExport), { recursive: true });
|
|
await writeFile(staleServerExport, "// stale isolated artifact\n");
|
|
const staleTime = new Date(0);
|
|
await utimes(staleServerExport, staleTime, staleTime);
|
|
|
|
try {
|
|
await runPrerequisite(isolatedRoot);
|
|
await expect(access(missingServerExport)).resolves.toBeUndefined();
|
|
expect(await readFile(staleServerExport, "utf8")).not.toContain("stale isolated artifact");
|
|
expect((await stat(staleServerExport)).mtimeMs).toBeGreaterThanOrEqual(
|
|
(await stat(staleSourceExport)).mtimeMs,
|
|
);
|
|
expect((await stat(missingServerExport)).mtimeMs).toBeGreaterThanOrEqual(
|
|
(await stat(missingSourceExport)).mtimeMs,
|
|
);
|
|
} finally {
|
|
await rm(isolatedRoot, {
|
|
recursive: true,
|
|
force: true,
|
|
maxRetries: 5,
|
|
retryDelay: 100,
|
|
});
|
|
}
|
|
}, 130_000);
|
|
});
|
|
|
|
async function createIsolatedBuildCheckout() {
|
|
const isolatedRoot = await mkdtemp(path.join(os.tmpdir(), "paseo-desktop-build-contract-"));
|
|
const packageDirectories = [
|
|
"packages/client",
|
|
"packages/desktop",
|
|
"packages/highlight",
|
|
"packages/plugin",
|
|
"packages/protocol",
|
|
"packages/relay",
|
|
"packages/server",
|
|
"packages/workspace-runtime-contract",
|
|
"packages/workspace-helper",
|
|
];
|
|
|
|
try {
|
|
await Promise.all([
|
|
...["package.json", "package-lock.json", "tsconfig.base.json", "tsconfig.json"].map((file) =>
|
|
cp(path.join(repoRoot, file), path.join(isolatedRoot, file)),
|
|
),
|
|
cp(path.join(repoRoot, "scripts"), path.join(isolatedRoot, "scripts"), {
|
|
recursive: true,
|
|
}),
|
|
...packageDirectories.map(async (relativeDirectory) => {
|
|
const target = path.join(isolatedRoot, relativeDirectory);
|
|
await mkdir(path.dirname(target), { recursive: true });
|
|
await cp(path.join(repoRoot, relativeDirectory), target, {
|
|
recursive: true,
|
|
filter: (source) =>
|
|
!source.endsWith(`${path.sep}dist`) &&
|
|
!source.endsWith(`${path.sep}node_modules`) &&
|
|
!source.endsWith(`${path.sep}test-results`),
|
|
});
|
|
}),
|
|
]);
|
|
await symlink(path.join(repoRoot, "node_modules"), path.join(isolatedRoot, "node_modules"));
|
|
await Promise.all(
|
|
packageDirectories.map((relativeDirectory) =>
|
|
symlink(
|
|
path.join(repoRoot, relativeDirectory, "node_modules"),
|
|
path.join(isolatedRoot, relativeDirectory, "node_modules"),
|
|
),
|
|
),
|
|
);
|
|
return isolatedRoot;
|
|
} catch (error) {
|
|
await rm(isolatedRoot, { recursive: true, force: true });
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async function runPrerequisite(isolatedRoot) {
|
|
try {
|
|
await execFileAsync(
|
|
npmCommand,
|
|
[...npmPrefixArgs, "run", "dev:prerequisites", "--workspace=@getpaseo/desktop"],
|
|
{
|
|
cwd: isolatedRoot,
|
|
timeout: 120_000,
|
|
},
|
|
);
|
|
} catch (error) {
|
|
throw new Error(`${error.stdout ?? ""}\n${error.stderr ?? ""}`, { cause: error });
|
|
}
|
|
}
|