-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtest.mjs
More file actions
103 lines (91 loc) · 6.48 KB
/
Copy pathtest.mjs
File metadata and controls
103 lines (91 loc) · 6.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#!/usr/bin/env node
/**
* test.mjs — dependency-free contract test (no MCP SDK needed, runs in CI).
*
* Verifies the runtime, the generated manifest, the type definitions and
* package.json all agree — the manifest is the single source of truth and must
* never drift from Galaxy.list().
*/
import { readFileSync, existsSync, statSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
import { createRequire } from 'node:module';
const here = dirname(fileURLToPath(import.meta.url));
const require = createRequire(import.meta.url);
const read = (f) => readFileSync(join(here, f), 'utf8');
let fails = 0;
const ok = (c, m) => { if (c) console.log(' ✓ ' + m); else { console.error(' ✗ ' + m); fails++; } };
const Galaxy = require('./galaxy.js');
const manifest = JSON.parse(read('galaxy.manifest.json'));
const pkg = JSON.parse(read('package.json'));
const dts = read('galaxy.d.ts');
console.log('runtime');
ok(typeof Galaxy.version === 'string', 'Galaxy.version is a string (' + Galaxy.version + ')');
ok(typeof Galaxy.create === 'function' && typeof Galaxy.list === 'function' && typeof Galaxy.defaults === 'function', 'public API present (create / list / defaults)');
ok(typeof Galaxy.scrollScene === 'function', 'scrollScene API present (cinematic scroll sequences)');
const runtimeNames = Galaxy.list();
const COUNT = manifest.animations.length;
ok(runtimeNames.length === COUNT, 'runtime and manifest agree on the animation count (' + COUNT + ')');
// A floor, not a literal: catches accidental deletion without breaking on every
// addition. Raise it when a release intentionally removes animations.
ok(runtimeNames.length >= 80, 'no animations were lost (>= 80, got ' + runtimeNames.length + ')');
console.log('WebGL2 tier');
const src = read('galaxy.js');
ok(/function registerShader\(/.test(src), 'registerShader (WebGL2 sugar) is present');
ok(/webgl2/.test(src), 'a WebGL2 context is requested for shader animations');
ok(/glPosterFallback/.test(src), 'shader surfaces fall back to a 2D poster when WebGL2 is missing');
// A canvas returns the same context object every time, so losing it would poison
// any later mount on that canvas. This bit us on ReactOmega; keep it locked here.
ok(!/loseContext/.test(src), 'the library never force-loses a WebGL context');
console.log('three.js tier (optional, must stay optional)');
ok(/function registerThree\(/.test(src), 'registerThree (three.js sugar) is present');
ok(/function threeRenderer\(/.test(src) && /function threeDispose\(/.test(src), 'the three helpers are present');
ok(typeof Galaxy.rendererOf === 'function' && typeof Galaxy.useThree === 'function', 'rendererOf / useThree are on the public API');
const threeNames = runtimeNames.filter((n) => Galaxy.rendererOf(n) === 'three');
ok(threeNames.length >= 6, 'the three.js scenes are registered (>= 6, got ' + threeNames.length + ')');
ok(manifest.animations.every((a) => ['2d', 'webgl2', 'three'].includes(a.renderer)), 'every manifest animation declares a known renderer tier');
ok(
threeNames.every((n) => manifest.optionalDependency.usedBy.includes(n)),
'the manifest lists every three scene under optionalDependency.usedBy'
);
// The whole promise of the tier: `three` must never become a real dependency.
ok(!(pkg.dependencies && pkg.dependencies.three), 'three is NOT a package dependency');
// "Zero dependencies" has always meant the *browser runtime*: galaxy.js pulls in
// nothing at load time. (The package's own deps belong to the optional MCP
// server, which never runs in a browser.) Assert the real claim, not a broader
// one that was never true.
ok(!/\brequire\s*\(/.test(src), 'the browser runtime requires nothing at load time');
ok(!/^\s*import\s+[^(]/m.test(src), 'the browser runtime has no static imports');
// It must load lazily, not at parse time: a static import would cost every page.
ok(!/^\s*import\s+.*['"]three/m.test(src), 'three is not statically imported');
ok(/import\(/.test(src), 'three is loaded by dynamic import');
// Terser drops unreachable code. When nothing referenced the tier it vanished
// from the bundle entirely and Galaxy.useThree silently became a no-op, so the
// shipped artifact is checked, not just the source.
const min = read('galaxy.min.js');
ok(/import\(/.test(min), 'the minified bundle keeps the dynamic import');
ok(/cdn\.jsdelivr\.net\/npm\/three/.test(min), 'the minified bundle keeps the three.js URL');
ok(threeNames.every((n) => min.includes(n)), 'the minified bundle keeps every three scene name');
console.log('version agreement');
ok(Galaxy.version === manifest.version, 'manifest version matches runtime');
ok(pkg.version === manifest.version, 'package.json version matches manifest (' + pkg.version + ')');
console.log('manifest <-> runtime sync');
const manifestNames = manifest.animations.map((a) => a.name);
ok(manifestNames.length === runtimeNames.length, 'manifest animation count matches runtime');
ok(runtimeNames.every((n) => manifestNames.includes(n)), 'every runtime animation is in the manifest');
ok(manifest.animations.every((a) => a.name && a.desc && a.options), 'every manifest animation has name + desc + options');
ok(manifest.components.length === 13 && manifest.components.every((c) => c.name && c.desc && c.usage), '13 components, each with name + desc + usage');
console.log('counts agree across files');
ok(new RegExp(COUNT + ' canvas').test(pkg.description), 'package.json description states the real count (' + COUNT + ')');
const dtsCount = (dts.match(/AnimationType\s*=([\s\S]*?);/)[1].match(/"[a-zA-Z]+"/g) || []).length;
ok(dtsCount === COUNT, 'galaxy.d.ts declares every animation in AnimationType (' + COUNT + ', got ' + dtsCount + ')');
ok(new RegExp(COUNT + ' canvas').test(read('llms.txt')), 'llms.txt states the real count (' + COUNT + ')');
console.log('cdn points at the minified bundles');
ok(/galaxy\.min\.js/.test(manifest.cdn.js) && /galaxy\.min\.css/.test(manifest.cdn.css), 'manifest cdn references galaxy.min.* ');
ok(pkg.unpkg === 'galaxy.min.js' && pkg.jsdelivr === 'galaxy.min.js', 'package unpkg/jsdelivr point at galaxy.min.js');
console.log('build artifacts (if present)');
if (existsSync(join(here, 'galaxy.min.js'))) {
ok(statSync(join(here, 'galaxy.min.js')).size < statSync(join(here, 'galaxy.js')).size, 'galaxy.min.js is smaller than galaxy.js');
} else { ok(true, 'galaxy.min.js not built yet (run npm run build:min) — skipped'); }
console.log(fails === 0 ? '\nPASS — runtime, manifest, types and package agree.' : `\nFAIL — ${fails} check(s) failed.`);
process.exit(fails === 0 ? 0 : 1);