107 lines
5.5 KiB
JavaScript
107 lines
5.5 KiB
JavaScript
// GitHub #531 / #530: the player zip must not ship a package.json whose `npm test` is a silent green, and the
|
|
// Markdown it ships must not keep relative links to files the zip does not contain. The repository copies stay as they
|
|
// are; tools/package.mjs rewrites the staged copies. These tests call that rewrite directly (no zip, no browser).
|
|
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { existsSync, readFileSync } from 'node:fs';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import {
|
|
PLAYER_MARKDOWN, PLAYER_NPM_SCRIPTS, playerPackageJson, playerPackageProblems, releaseTag, rewritePlayerDoc,
|
|
selectTracked, trackedFiles,
|
|
} from '../tools/package.mjs';
|
|
|
|
const ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
const pkg = JSON.parse(readFileSync(path.join(ROOT, 'package.json'), 'utf8'));
|
|
const DISHONEST = ['test', 'golden', 'golden:update', 'build-data', 'check:imports', 'ci', 'package', 'package:lite', 'lint', 'typecheck'];
|
|
const KEPT = [...PLAYER_NPM_SCRIPTS, 'dev'];
|
|
|
|
test('release tags drop a trailing -dev and keep an already released version', () => {
|
|
assert.equal(releaseTag('0.2.5-dev'), 'v0.2.5');
|
|
assert.equal(releaseTag('0.2.4'), 'v0.2.4');
|
|
assert.equal(releaseTag('9.9.9'), 'v9.9.9');
|
|
});
|
|
|
|
test('the packaged package.json keeps only scripts whose node files ship', () => {
|
|
const shipped = selectTracked(trackedFiles(ROOT)).keep;
|
|
const next = playerPackageJson(pkg, shipped);
|
|
for (const name of DISHONEST) assert.equal(next.scripts[name], undefined, name);
|
|
for (const name of KEPT) assert.equal(next.scripts[name], pkg.scripts[name], name);
|
|
assert.deepEqual(Object.keys(next), Object.keys(pkg));
|
|
assert.deepEqual(playerPackageProblems(pkg, shipped), []);
|
|
assert.equal(pkg.scripts.test, 'node --test', 'the repository package.json still runs the suite');
|
|
assert.equal(pkg.scripts.lint, 'eslint .');
|
|
const keys = Object.keys(next);
|
|
assert.deepEqual(keys.filter((k) => k !== 'scripts'), Object.keys(pkg).filter((k) => k !== 'scripts'));
|
|
});
|
|
|
|
test('a script with no shipped node file is dropped, including a bare node --test', () => {
|
|
const shipped = new Set(['server/index.js', 'tools/vendor.mjs']);
|
|
const next = playerPackageJson({
|
|
name: 'x', version: '1.0.0',
|
|
scripts: {
|
|
start: 'node server/index.js',
|
|
dev: 'node --watch server/index.js',
|
|
test: 'node --test',
|
|
named: 'node --test test/a.test.js',
|
|
lint: 'eslint .',
|
|
both: 'node tools/vendor.mjs && node tools/missing.mjs',
|
|
vendor: 'node tools/vendor.mjs',
|
|
},
|
|
}, shipped);
|
|
assert.deepEqual(Object.keys(next.scripts).sort(), ['dev', 'start', 'vendor']);
|
|
assert.ok(playerPackageProblems({ scripts: { start: 'node server/missing.js', setup: 'node tools/setup.mjs', doctor: 'node tools/doctor.mjs', launch: 'node scripts/launch.mjs', postinstall: 'node tools/vendor.mjs', vendor: 'node tools/vendor.mjs', assets: 'node tools/vendor.mjs' } }, shipped).length > 0);
|
|
});
|
|
|
|
function linkTarget(from, href) {
|
|
const raw = href.split('#')[0];
|
|
const dir = path.posix.dirname(from);
|
|
return path.posix.normalize(path.posix.join(dir, raw));
|
|
}
|
|
|
|
test('packaged copies of the shipped docs point unshipped relative links at the release tag', () => {
|
|
const shipped = new Set(selectTracked(trackedFiles(ROOT)).keep);
|
|
const version = pkg.version;
|
|
const tag = releaseTag(version);
|
|
const host = 'https://github.com/sganggs/Stronghold-Protocol';
|
|
const focus = new Set(['README.md', 'docs/PLAYING.md', 'docs/DEPLOY.md']);
|
|
let fileRewrites = 0;
|
|
assert.ok(PLAYER_MARKDOWN.includes('README.md') && PLAYER_MARKDOWN.includes('docs/PLAYING.md') && PLAYER_MARKDOWN.includes('docs/DEPLOY.md'));
|
|
for (const rel of PLAYER_MARKDOWN) {
|
|
const md = readFileSync(path.join(ROOT, rel), 'utf8');
|
|
for (const m of md.matchAll(/\]\(([^)\s]+)\)/g)) {
|
|
const href = m[1];
|
|
if (/^(?:[a-z][a-z0-9+.-]*:|#)/i.test(href)) continue;
|
|
const target = linkTarget(rel, href);
|
|
const onDisk = target.startsWith('..') ? null : path.join(ROOT, target);
|
|
const releaseLatest = /^(?:\.\.\/)+releases\/latest$/.test(target);
|
|
assert.ok(releaseLatest || (onDisk && existsSync(onDisk)), `${rel} source link ${href} (${target})`);
|
|
}
|
|
const next = rewritePlayerDoc(md, rel, shipped, version);
|
|
assert.equal(rewritePlayerDoc(next, rel, shipped, version), next, `${rel} rewrite is idempotent`);
|
|
const before = [...md.matchAll(/(!?\[[^\]]*\]\()([^)\s]+)\)/g)];
|
|
const after = [...next.matchAll(/(!?\[[^\]]*\]\()([^)\s]+)\)/g)];
|
|
assert.equal(before.length, after.length, rel);
|
|
for (let i = 0; i < after.length; i++) {
|
|
const href = after[i][2];
|
|
if (/^(?:[a-z][a-z0-9+.-]*:|#)/i.test(href)) {
|
|
if (before[i][2] !== href) assert.ok(href.startsWith(`${host}/`), `${rel} ${before[i][2]} → ${href}`);
|
|
continue;
|
|
}
|
|
const target = linkTarget(rel, href);
|
|
assert.ok(!target.startsWith('..') && shipped.has(target), `${rel} still links to ${href} (${target}), which the zip does not ship`);
|
|
}
|
|
if (!focus.has(rel)) continue;
|
|
for (let i = 0; i < before.length; i++) {
|
|
if (before[i][2] === after[i][2]) continue;
|
|
if (/\.(?:png|jpe?g|gif|webp|svg)(?:#|$)/i.test(before[i][2])) {
|
|
assert.match(after[i][2], new RegExp(`^${host}/raw/${tag}/`));
|
|
} else {
|
|
fileRewrites++;
|
|
assert.match(after[i][2], new RegExp(`^${host}/(?:blob/${tag}/|releases/)`));
|
|
}
|
|
}
|
|
}
|
|
assert.ok(fileRewrites >= 23, `README / PLAYING / DEPLOY rewrote ${fileRewrites} file links, want at least 23`);
|
|
});
|