Files
SpineViewer/tests/setup-pose-zoom.test.js
2026-09-19 15:02:27 +08:00

49 lines
2.4 KiB
JavaScript

'use strict';
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const vm = require('node:vm');
const roots = ['.', 'release/UNIVERSAL_SpineViewer'];
function functionBody(source, name, nextName) {
const start = source.indexOf(`\tfunction ${name}(`);
const end = source.indexOf(`\n\tfunction ${nextName}(`, start + 1);
assert.ok(start >= 0 && end > start, `missing function ${name}`);
return source.slice(start, end);
}
for (const root of roots) {
const viewerPath = path.join(root, 'viewer/spine.html');
const html = fs.readFileSync(viewerPath, 'utf8');
const css = fs.readFileSync(path.join(root, 'viewer/spine.css'), 'utf8');
const script = html.match(/<script>([\s\S]*?)<\/script>/)[1];
new vm.Script(script);
assert.match(script, /const SETUP_POSE_INDEX = -1;/);
assert.match(script, /let currentAnim = SETUP_POSE_INDEX[\s\S]*let playing = false/);
assert.match(script, /setupItem\.dataset\.index = String\(SETUP_POSE_INDEX\)/);
assert.match(script, /showSetupPose\(\);\s*captureStableFitBounds\(\);\s*fitToCanvas\(\);/);
assert.match(script, /state\.clearTracks[\s\S]*skeleton\.setToSetupPose/);
assert.match(script, /if \(idx === SETUP_POSE_INDEX\)[\s\S]*showSetupPose\(\)/);
const fit = functionBody(script, 'fitToCanvas', 'draw');
assert.match(fit, /const bounds = stableFitBounds;/);
assert.doesNotMatch(fit, /getBounds\(/, 'wheel/resize fitting must not sample an animated frame');
assert.match(fit, /fitScale = zoom;/, 'wheel zoom must still work before a drawable stable bound exists');
const capture = functionBody(script, 'captureStableFitBounds', 'fitToCanvas');
assert.match(capture, /getBounds\(skeleton\)/);
assert.match(script, /async function setAnimationByName[\s\S]*if \(!stableFitBounds\)[\s\S]*measureVisibleBounds\(skeleton, geometryBounds, 1[\s\S]*captureStableFitBounds\(bounds\)/);
assert.match(css, /#status \{\s*position: absolute; left: 50%;[^}]*transform: translateX\(-50%\)/, 'status notice must be horizontally centered');
const manifest = JSON.parse(fs.readFileSync(path.join(root, 'manifest.json'), 'utf8'));
for (const language of manifest.languages) {
const locale = JSON.parse(fs.readFileSync(path.join(root, '_locales', language + '.json'), 'utf8'));
assert.equal(locale.viewer.setupPose, 'Setup Pose', `${root}/${language} must keep the Spine term untranslated`);
}
}
console.log('PASS: Setup Pose is the default still frame and zoom uses stable bounds');