Files
makelore/tests/unit/pi-runtime-bundle.test.ts

146 lines
5.4 KiB
TypeScript

// @vitest-environment node
import { afterEach, describe, expect, it } from 'vitest';
import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import YAML from 'yaml';
import {
assertPackageIdentities,
installProductionShrinkwrap,
preparePublishedPackageRoot,
requiredPackageIdentities,
} from '../../scripts/lib/pi-runtime-bundle.mjs';
import { parseBundleArgs } from '../../scripts/bundle-pi-runtime.mjs';
const scratchRoots: string[] = [];
async function scratch(prefix: string): Promise<string> {
const root = await mkdtemp(join(tmpdir(), prefix));
scratchRoots.push(root);
return root;
}
afterEach(async () => {
await Promise.all(scratchRoots.splice(0).map((root) => rm(root, {
recursive: true,
force: true,
maxRetries: 3,
})));
});
describe('Pi runtime production bundler', () => {
it('turns the published root dev mismatch into a reproducible npm 11 production install', async () => {
const root = await scratch('makelore-pi-bundle-mismatch-');
const source = join(root, 'published');
const stage = join(root, 'stage');
await mkdir(source);
await writeFile(join(source, 'package.json'), `${JSON.stringify({
name: '@fixture/pi-runtime',
version: '1.0.0',
devDependencies: { 'missing-from-production-lock': '1.0.0' },
}, null, 2)}\n`);
await writeFile(join(source, 'npm-shrinkwrap.json'), `${JSON.stringify({
name: '@fixture/pi-runtime',
version: '1.0.0',
lockfileVersion: 3,
requires: true,
packages: {
'': { name: '@fixture/pi-runtime', version: '1.0.0' },
},
}, null, 2)}\n`);
const prepared = await preparePublishedPackageRoot(source, stage);
expect(prepared.omittedDevDependencies).toEqual(['missing-from-production-lock']);
expect(JSON.parse(await readFile(join(stage, 'package.json'), 'utf8')))
.not.toHaveProperty('devDependencies');
await expect(installProductionShrinkwrap({
projectRoot: process.cwd(),
stageRoot: stage,
target: { platform: process.platform, arch: process.arch },
})).resolves.toMatchObject({});
}, 15_000);
it('accepts same-version nested-to-root flattening by identity instead of physical lock path', () => {
const shrinkwrap = {
packages: {
'node_modules/p-retry/node_modules/@types/retry': {
version: '0.12.0',
},
},
};
const required = requiredPackageIdentities(shrinkwrap, {
platform: process.platform,
arch: process.arch,
});
expect(required.identities).toEqual(['@types/retry@0.12.0']);
expect(() => assertPackageIdentities(required.identities, [
'@types/retry@0.12.0',
])).not.toThrow();
});
it('keeps target selection explicit and rejects cross-OS staging', () => {
const current = `${process.platform}-${process.arch}`;
expect(parseBundleArgs(['--target', current]).targets).toEqual([
expect.objectContaining({ platform: process.platform, arch: process.arch }),
]);
const foreign = process.platform === 'win32' ? 'linux-x64' : 'win32-x64';
expect(() => parseBundleArgs(['--target', foreign])).toThrow(/must be staged on/);
expect(() => parseBundleArgs(['--target', 'unknown-x64'])).toThrow(/Unsupported/);
});
it('wires every package target to its matching staged Pi runtime', async () => {
const packageJson = JSON.parse(await readFile('package.json', 'utf8')) as {
homepage: string;
scripts: Record<string, string>;
};
const builder = YAML.parse(await readFile('electron-builder.yml', 'utf8')) as Record<
string,
{ extraResources?: Array<{ from: string; to: string }> }
>;
expect(packageJson.scripts.build).toContain('bundle-pi-runtime.mjs --release-targets');
expect(packageJson.scripts.package).toContain('bundle-pi-runtime.mjs --release-targets');
expect(packageJson.scripts['package:stage:win-x64'])
.toContain('bundle-pi-runtime.mjs --target win32-x64');
expect(packageJson.scripts['verify:artifact:pi'])
.toBe('node scripts/verify-pi-product-artifact.mjs');
expect(packageJson.scripts['smoke:pi:real'])
.toBe('node scripts/smoke-pi-real.mjs');
expect(packageJson.scripts['perf:pi:release'])
.toBe('node scripts/run-pi-release-performance.mjs');
expect(packageJson.homepage).toBe('https://git.nianxx.cn/wangxuming/makelore');
expect(builder.mac.extraResources).toContainEqual({
from: 'build/pi-runtime/darwin-${arch}',
to: 'pi-runtime',
filter: ['**/*', '!node_modules{,/**/*}'],
});
expect(builder.mac.extraResources).toContainEqual({
from: 'build/pi-runtime/darwin-${arch}/node_modules',
to: 'pi-runtime/node_modules',
filter: ['**/*'],
});
expect(builder.win.extraResources).toContainEqual({
from: 'build/pi-runtime/win32-${arch}',
to: 'pi-runtime',
filter: ['**/*', '!node_modules{,/**/*}'],
});
expect(builder.win.extraResources).toContainEqual({
from: 'build/pi-runtime/win32-${arch}/node_modules',
to: 'pi-runtime/node_modules',
filter: ['**/*'],
});
expect(builder.linux.extraResources).toContainEqual({
from: 'build/pi-runtime/linux-${arch}',
to: 'pi-runtime',
filter: ['**/*', '!node_modules{,/**/*}'],
});
expect(builder.linux.extraResources).toContainEqual({
from: 'build/pi-runtime/linux-${arch}/node_modules',
to: 'pi-runtime/node_modules',
filter: ['**/*'],
});
});
});