146 lines
5.4 KiB
TypeScript
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: ['**/*'],
|
|
});
|
|
});
|
|
});
|