mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-09-30 12:39:42 +02:00
Merge pull request #241 from Lint111/fix/mobile-test-vendor
test(mobile): serve the xterm vendor bundles the browser suite needs
This commit is contained in:
@@ -21,6 +21,8 @@
|
|||||||
"test:watch": "vitest --config config/vitest.config.ts",
|
"test:watch": "vitest --config config/vitest.config.ts",
|
||||||
"test:coverage": "vitest run --config config/vitest.config.ts --coverage",
|
"test:coverage": "vitest run --config config/vitest.config.ts --coverage",
|
||||||
"test:ci": "vitest run --config config/vitest.ci.config.ts",
|
"test:ci": "vitest run --config config/vitest.ci.config.ts",
|
||||||
|
"pretest:mobile": "node scripts/prepare-test-vendor.mjs",
|
||||||
|
"test:mobile": "vitest run --config test/mobile/vitest.config.ts",
|
||||||
"check:frontend-syntax": "node scripts/check-frontend-syntax.mjs",
|
"check:frontend-syntax": "node scripts/check-frontend-syntax.mjs",
|
||||||
"fix:node-pty": "node scripts/fix-node-pty.mjs",
|
"fix:node-pty": "node scripts/fix-node-pty.mjs",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* Populate `src/web/public/vendor/` with the browser bundles the mobile tests need.
|
||||||
|
*
|
||||||
|
* The mobile suite (test/mobile/**) drives a real browser against a WebServer
|
||||||
|
* started from TypeScript source, so fastify-static serves
|
||||||
|
* `join(__dirname, 'public')` = `src/web/public` — NOT `dist/web/public`, where
|
||||||
|
* `npm run build` puts the vendor bundles. Every `/vendor/xterm*` request 404s,
|
||||||
|
* so `Terminal` is never defined, `initTerminal()` never runs, and every test
|
||||||
|
* touching `app.terminal` dies with `Cannot read properties of null`.
|
||||||
|
*
|
||||||
|
* That stayed invisible because config/vitest.ci.config.ts excludes
|
||||||
|
* `test/mobile/**`, so CI never ran the suite.
|
||||||
|
*
|
||||||
|
* Mirrors the vendor steps in scripts/build.mjs, targeting the source tree.
|
||||||
|
* Same inputs and output names, so the page markup needs no test-only branch.
|
||||||
|
* `src/web/public/vendor/` is gitignored, so these stay build artifacts.
|
||||||
|
*
|
||||||
|
* Idempotent: skips outputs already newer than their source.
|
||||||
|
*/
|
||||||
|
import { execFileSync } from 'node:child_process';
|
||||||
|
import { appendFileSync, copyFileSync, existsSync, mkdirSync, statSync } from 'node:fs';
|
||||||
|
import { dirname, join, resolve } from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
|
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
||||||
|
const OUT = join(ROOT, 'src', 'web', 'public', 'vendor');
|
||||||
|
const NM = join(ROOT, 'node_modules');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Every `vendor/` asset index.html requests, minus the two already committed
|
||||||
|
* (dompurify, marked). Kept in sync with scripts/build.mjs steps 3-4 — a missing
|
||||||
|
* entry here is a 404 that silently disables the terminal in tests.
|
||||||
|
*
|
||||||
|
* mode: 'copy' | 'minify' | 'bundle'
|
||||||
|
*/
|
||||||
|
const ASSETS = [
|
||||||
|
{ src: join(NM, '@xterm/xterm/css/xterm.css'), out: 'xterm.css', mode: 'copy' },
|
||||||
|
{ src: join(NM, '@xterm/xterm/lib/xterm.js'), out: 'xterm.min.js', mode: 'minify' },
|
||||||
|
{ src: join(NM, '@xterm/addon-fit/lib/addon-fit.js'), out: 'xterm-addon-fit.min.js', mode: 'minify' },
|
||||||
|
{
|
||||||
|
src: join(NM, '@xterm/addon-serialize/lib/addon-serialize.js'),
|
||||||
|
out: 'xterm-addon-serialize.min.js',
|
||||||
|
mode: 'minify',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: join(NM, '@xterm/addon-unicode11/lib/addon-unicode11.js'),
|
||||||
|
out: 'xterm-addon-unicode11.min.js',
|
||||||
|
mode: 'minify',
|
||||||
|
},
|
||||||
|
{ src: join(NM, '@xterm/addon-webgl/lib/addon-webgl.js'), out: 'xterm-addon-webgl.min.js', mode: 'copy' },
|
||||||
|
{
|
||||||
|
src: join(ROOT, 'packages/xterm-zerolag-input/src/zerolag-input-addon.ts'),
|
||||||
|
out: 'xterm-zerolag-input.js',
|
||||||
|
mode: 'bundle',
|
||||||
|
globalName: 'XtermZerolagInput',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function isFresh(src, dest) {
|
||||||
|
if (!existsSync(dest)) return false;
|
||||||
|
try {
|
||||||
|
return statSync(dest).mtimeMs >= statSync(src).mtimeMs;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdirSync(OUT, { recursive: true });
|
||||||
|
|
||||||
|
let built = 0;
|
||||||
|
let skipped = 0;
|
||||||
|
for (const asset of ASSETS) {
|
||||||
|
const dest = join(OUT, asset.out);
|
||||||
|
if (!existsSync(asset.src)) {
|
||||||
|
console.error(`[test-vendor] missing input: ${asset.src}\n run \`npm install\` first`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
if (isFresh(asset.src, dest)) {
|
||||||
|
skipped += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (asset.mode === 'copy') {
|
||||||
|
copyFileSync(asset.src, dest);
|
||||||
|
} else if (asset.mode === 'minify') {
|
||||||
|
execFileSync('npx', ['esbuild', asset.src, '--minify', `--outfile=${dest}`], { stdio: 'inherit' });
|
||||||
|
} else {
|
||||||
|
execFileSync(
|
||||||
|
'npx',
|
||||||
|
[
|
||||||
|
'esbuild',
|
||||||
|
asset.src,
|
||||||
|
'--bundle',
|
||||||
|
'--minify',
|
||||||
|
'--format=iife',
|
||||||
|
`--global-name=${asset.globalName}`,
|
||||||
|
`--outfile=${dest}`,
|
||||||
|
],
|
||||||
|
{ stdio: 'inherit' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
built += 1;
|
||||||
|
|
||||||
|
// The zerolag bundle exports only `XtermZerolagInput`. app.js constructs
|
||||||
|
// `new LocalEchoOverlay(terminal)` directly, so scripts/build.mjs appends
|
||||||
|
// global aliases after esbuild — without them initTerminal() throws
|
||||||
|
// `LocalEchoOverlay is not defined` at the point it builds the overlay, and
|
||||||
|
// every later step (including the mobile touch handlers) silently never runs.
|
||||||
|
if (asset.out === 'xterm-zerolag-input.js') {
|
||||||
|
appendFileSync(
|
||||||
|
dest,
|
||||||
|
'\n// Global aliases for browser usage\n' +
|
||||||
|
'if(typeof window!=="undefined"){' +
|
||||||
|
'window.ZerolagInputAddon=XtermZerolagInput.ZerolagInputAddon;' +
|
||||||
|
'window.LocalEchoOverlay=class extends XtermZerolagInput.ZerolagInputAddon{' +
|
||||||
|
'constructor(terminal){' +
|
||||||
|
'super({prompt:{type:"character",char:"\\u276f",offset:2}});' +
|
||||||
|
'this.activate(terminal);' +
|
||||||
|
'}' +
|
||||||
|
'};' +
|
||||||
|
'}\n'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`[test-vendor] ${built} built, ${skipped} up to date -> src/web/public/vendor/`);
|
||||||
Reference in New Issue
Block a user