Files
jp-editor/test/m3.test.mjs
T

75 lines
4.3 KiB
JavaScript

import test from "node:test";
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import { parseJpwabc } from "../dist/domain/jpwabc.js";
import { modelFromParse, createEmptyDocument, rational, createNoteEvent } from "../dist/domain/score-model.js";
import { DeterministicFontMeasurementProvider } from "../dist/layout/font-measure.js";
import { DEFAULT_PAPER_CONFIG, layoutDocument, layoutSummary } from "../dist/layout/layout-engine.js";
import { probeSvg, renderSnapshotSvg } from "../dist/layout/svg-renderer.js";
async function kangdingModel() {
const bytes = await readFile("research/jpw7/demo/JP-Word练习曲-歌曲-康定情歌.jpwabc");
return modelFromParse(parseJpwabc(bytes), { fileName: "康定情歌.jpwabc" });
}
test("M3 waits for fonts, produces fixed A4 geometry and the 16-measure/6-line baseline", async () => {
const provider = new DeterministicFontMeasurementProvider();
const snapshot = await layoutDocument(await kangdingModel(), DEFAULT_PAPER_CONFIG, provider);
const summary = layoutSummary(snapshot);
assert.deepEqual(snapshot.pageSizeMm, { width: 210, height: 297 });
assert.deepEqual(snapshot.contentRectMm, { x: 20, y: 20, width: 170, height: 257 });
assert.equal(summary.pageCount, 1);
assert.equal(summary.lineCount, 6);
assert.equal(summary.measureCount, 16);
assert.ok(snapshot.fontMeasurements.length > 0);
assert.ok(snapshot.fontMeasurements.every((measurement) => measurement.loaded === true));
assert.equal(snapshot.pages[0].widthMm, 210);
assert.equal(snapshot.pages[0].heightMm, 297);
});
test("M3 layout is deterministic for identical model, config and measurement provider", async () => {
const model = await kangdingModel();
const first = await layoutDocument(model, DEFAULT_PAPER_CONFIG, new DeterministicFontMeasurementProvider());
const second = await layoutDocument(model, DEFAULT_PAPER_CONFIG, new DeterministicFontMeasurementProvider());
assert.equal(first.deterministicKey, second.deterministicKey);
assert.deepEqual(first.pages, second.pages);
assert.deepEqual(first.warnings, second.warnings);
});
test("M3 reports an unbreakable over-wide measure instead of clipping it", async () => {
const document = createEmptyDocument("overflow-document");
const event = createNoteEvent("wide-event", 1, rational(1));
event.source = { raw: "X".repeat(800), range: null };
document.voices.push({ id: "wide-voice", name: "宽小节", sectionId: null, visible: true, measures: [{ id: "wide-measure", ordinal: 0, beats: rational(1), events: [event] }] });
const snapshot = await layoutDocument(document, DEFAULT_PAPER_CONFIG, new DeterministicFontMeasurementProvider());
const warning = snapshot.warnings.find((item) => item.code === "MEASURE_OVERFLOW");
assert.ok(warning);
assert.equal(warning.severity, "error");
assert.equal(snapshot.measures["wide-measure"].overflow, true);
});
test("M3 SVG renderer preserves A4 physical units, semantic IDs and layer separation", async () => {
const snapshot = await layoutDocument(await kangdingModel(), DEFAULT_PAPER_CONFIG, new DeterministicFontMeasurementProvider());
const [svg] = renderSnapshotSvg(snapshot);
const probe = probeSvg(svg);
assert.equal(probe.width, "210mm");
assert.equal(probe.height, "297mm");
assert.equal(probe.viewBox, "0 0 21000 29700");
assert.equal(probe.pageNumber, 1);
assert.equal(probe.hasScoreLayer, true);
assert.equal(probe.hasAssistiveLayer, false);
assert.ok(probe.dataIds.length >= Object.keys(snapshot.symbols).length);
const titleFontSize = Number(svg.match(/data-role="document-id"[^>]*font-size="([0-9.]+)"/)?.[1] ?? 0);
const noteFontSize = Number(svg.match(/data-kind="note"[^>]*>[\s\S]*?font-size="([0-9.]+)"/)?.[1] ?? 0);
assert.ok(titleFontSize > 100);
assert.ok(noteFontSize > 100);
const accessibleProbe = probeSvg(renderSnapshotSvg(snapshot, true)[0]);
assert.equal(accessibleProbe.hasAssistiveLayer, true);
});
test("M3 overflow and orphan diagnostics are visible in the snapshot, not hidden by renderer", async () => {
const snapshot = await layoutDocument(await kangdingModel(), DEFAULT_PAPER_CONFIG, new DeterministicFontMeasurementProvider());
assert.ok(snapshot.warnings.some((warning) => warning.code === "ORPHANED_ATTACHMENT"));
assert.ok(snapshot.pages.every((page) => page.widthMm === 210 && page.heightMm === 297));
});