一键导入
test-musicxml
Add or update vexml MusicXML integration tests, validate screenshot output, implement rendering fixes, and selectively update baselines.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Add or update vexml MusicXML integration tests, validate screenshot output, implement rendering fixes, and selectively update baselines.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | test-musicxml |
| description | Add or update vexml MusicXML integration tests, validate screenshot output, implement rendering fixes, and selectively update baselines. |
Use this skill when adding or updating a vexml MusicXML rendering test case, especially when the work involves integration fixtures, screenshots, or baseline updates.
Important: Use the vex test commands shown below, plus selective vex test --update <name> only after reviewing the screenshot output.
First, check whether an existing test in tests/integration/ already covers the use case.
tests/integration/__data__/.If the use case is not already covered, add it to tests/integration/__data__/ — preferably as a new measure inside the existing fixture for that category rather than as a brand-new file.
Bundle by category; treat each measure as a pseudo unit test. A category fixture (e.g. key.musicxml, time.musicxml, note.musicxml, slur.musicxml) is one MusicXML document whose measures each isolate one variant of that category's behavior — the way a unit-test file holds many small cases. The measure is the unit of isolation, not the file. For example, key.musicxml proves a sharp key, a flat key, a mid-system key change, and a no-redraw continuation across M1-M3; slur.musicxml walks nine slur scenarios across nine measures. When adding a new variant of an already-covered category, append a measure to that category's fixture (and a M<n>: bullet to its comment) instead of creating a near-duplicate file. When you find existing same-category fixtures that each test one variant (e.g. key_sharps + key_flats + key_change), consolidate them into one.
When bundling does NOT apply: some things are fixed for a whole document and can't vary per measure — the <part-list> and each part's stave configuration (stave count, tab string count, braces). Those stay as separate category_variant.musicxml files. This is why structure_* (different part-lists) and clef_* (single stave vs grand staff vs 4-/6-line tab) are not bundled: each needs a different part/stave structure, not just a different measure. Rule of thumb: bundle what varies per measure (keys, meters, note/rest/accidental/articulation/beam/slur/tie/tuplet variants, voices); keep separate what needs a different part or stave layout.
Name a fixture that covers a whole category category.musicxml (e.g. key, time, note, slur). Use category_variant.musicxml only when different part/stave structures force more than one file in that category (e.g. clef_tab_4_string, structure_grand_staff). Categories: structure, clef, key, time, note, rest, accidental, measures, …; match the existing files in tests/integration/__data__/.
Register it in tests/integration/render.test.ts by adding testCase('<filename>.musicxml', '<filename>.png') to the TEST_CASES array. Pass any non-default Config as the third argument.
Keep TEST_CASES ordered by increasing rendering complexity. A render implementer should be able to build a correct renderer progressively by going through the tests in array order: basic structure before clefs, clefs before key/time signatures, simple notes/rests before accidentals, measures, beams, chords, ties/slurs, tuplets, articulations, voices, system layout, and broad stress cases. Insert new cases where they fit this progression; the array order is the only ordering — there is no numeric prefix. A bundled category fixture sits in its category's slot; let its most complex measure set the position.
Above each testCase(...) declaration, write a detailed comment describing what the screenshot should render: the clefs, staves, notes, and any distinctive notation or layout (positions, accidentals, beams, slurs, ledger lines, system breaks, …). Describe what is actually drawn so the comment alone tells a reader what to expect without opening the PNG. Match the descriptive style of the surrounding cases.
For cases spanning more than one measure, split the comment by measure for readability. Start with a one-line lead describing the global setup (stave/clef/time signature and any wrap behavior), then add one bulleted line per measure using a stable M<n>: marker (M2-3: for a span). Wrap continuation lines so they align under the bullet text. For multi-voice cases, use inline V<n> markers (e.g. V1, V2) inside each measure bullet. This keeps the comment scannable for humans and greppable for tools, with each M<n> mapping directly to a <measure number="n"> in the fixture. Example:
// Treble stave, 4/4: dotted-note variations.
// - M1: dotted-quarter + eighth pairs (single dots).
// - M2: double-dotted-quarter + sixteenth pairs (double dots).
testCase('dotted_notes.musicxml', 'dotted_notes.png'),
Each measure should test only one thing. Vary one feature per measure and keep everything else stable (pitch, duration, clef); don't vary unrelated musical features within a measure unless the variation is part of what that measure is proving. The fixture as a whole deliberately spans many variants of its category — but each measure isolates exactly one.
Wrong pattern: when testing articulations, do not vary duration or pitch needlessly; use stable, boring notes unless pitch or duration affects the articulation behavior being tested.
Right pattern: when testing beams, varying pitch can be useful if the goal is to show how the beam renders under normal and extreme stem/ledger-line conditions. There should be a clear reason for every extra variation.
Keep each measure as small as practical while still demonstrating its variant, and the fixture as a whole no larger than its variants require.
Keep generated MusicXML fixtures as simple and barebones as possible; inspect nearby existing files and match their minimal structure and style.
Run the integration test command:
vex test
Interpret screenshot results carefully. Screenshot tests can fail or pass for two different reasons:
TODO comment above the testCase(...) explicitly calling out this failure mode, for example: // TODO: False positive: this baseline was probably created from the current render, so it may be accepting an incorrect screenshot. Review the render, then run vex test <name> --update only after the image is confirmed correct. If the user provides a golden-standard image for the case, compare it against vexml's render before accepting. Eventually, the agent must run vex test <name> --update to intentionally accept the reviewed screenshot.TODO comment above the testCase(...) that describes the visual difference in plain language and links to the diff. Do not prescribe a fix unless the root cause is already clear. Prefer wording like: // TODO: True negative: the accepted baseline shows <expected visual>, but the new render shows <actual visual>. Diff: <path-or-link>.Update the implementation in src/ to fill the rendering gap.
CollisionDetector (src/collision.ts):
register the fixed thing as an obstacle (add/addRect), resolve the movable thing
(liftClear to lift above-stave text, pushRightOf to space diagrams), then draw at the
resolved position and register it. Do not add new bespoke magic-offset clearance
logic. Not everything is movable — noteheads, stems, and ties are obstacles, not nudge
targets. Fixed structural placement (page margins, part spacing, bracket offsets,
widget-internal geometry) is exempt — it is deterministic, not clash resolution. See
docs/collision-audit.md for what is and isn't in scope.Run the test command again:
vex test
The target test may still fail. That is useful if it shows the implementation changed the rendered output.
TODO describes a false positive, keep it until the screenshot has been manually reviewed and intentionally accepted with vex test <name> --update.TODO describes a true negative, keep it until the changed screenshot has been explained, fixed, or intentionally accepted.Always run this checklist before accepting or updating a screenshot baseline. Answer these questions from the actual screenshot or diff artifact, not from assumptions about the code:
TODO that names the uncertainty and links to the screenshot or diff artifact.If the target render passes the screenshot review checklist, update only that baseline:
vex test --update <name>
Where <name> is the test title — the screenshot filename passed as the second argument to testCase() in tests/integration/render.test.ts (helper in tests/testing/test-case.ts), e.g. clef_treble.png. The pattern matches by prefix, so clef_treble also matches.
Validate that there are no regressions.
vex test again after the selective baseline update.vex fix after code changes.vex test --clean globally to remove orphaned screenshot baselines. Do not target a single test when cleaning deleted cases.TODO comments for each regression using the false-positive or true-negative language from step 4. Include the plain-language visual difference and the relevant diff path or artifact link.Whenever you need to verbalize a screenshot difference — a regression diff artifact in tests/integration/__diffs__, or a comparison of vexml's current render against a golden-standard image the user provided (common for new test cases) — inspect the original image path(s) directly and describe the difference in plain language.
Do not create transformed derivatives for diff work unless there is no other practical way to understand the artifact. Prefer the original screenshot or diff artifact. For a __diffs__ artifact, remember that the image has old / diff / new vertical sections. For a golden-standard comparison, keep clear which image is the vexml render and which is the golden image.
Avoid running vex test --update for the whole suite unless the change is intentionally global and every affected render has passed the screenshot review checklist. Prefer one-by-one baseline updates after confirming why each render changed.