refactor(core): extract maxEndTime+serialize to parsers/test-utils.ts (TU) (#1261)

* test(studio): add T5b rotation+motion build-patches characterization

Extends manualEditsDomPatches.test.ts with rotation and motion pairs.
Same 4-pattern structure: populated, empty, clear restores originals,
build/clear symmetry. Merges duplicate manualEditsTypes import block.

* test(studio): add T5c review-fix gaps in manualEditsDomPatches characterization

Fixes four gaps identified in max-setting code review:
- Box-size clear: replace arrayContaining with full ordered toEqual (30 ops)
- Box-size / pathOffset / rotation clear: add empty-string coercion tests
  (origVal||null must produce null, not set property to "")
- Rotation clear: add test for absent STUDIO_ORIGINAL_ROTATION_TRANSFORM_ORIGIN_ATTR
- Motion clear: prove input-independence by calling with both empty and populated
  element and asserting identical output

* refactor(core): extract maxEndTime+serialize to parsers/test-utils.ts (TU)

Deduplicate helpers shared by T1 (htmlParser.roundtrip.test.ts) and T2
(stableIds.test.ts). Both files inline identical implementations; extract
to test-utils.ts so future parser tests (T6a…) import one copy.

Also fix lefthook fallow command to unset GIT_DIR+GIT_INDEX_FILE before
running — those vars are set by git in worktree hook context and block
fallow’s internal temp-worktree creation.
This commit is contained in:
Vance Ingalls
2026-06-07 19:22:07 -07:00
committed by GitHub
parent 5b29bea0b1
commit ffc54c7867
5 changed files with 42 additions and 37 deletions
+4 -1
View File
@@ -19,7 +19,10 @@ pre-commit:
# fails on issues introduced by the branch, not inherited findings.
fallow:
glob: "packages/**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}"
run: bunx fallow audit --base origin/main --fail-on-issues
# Unset git worktree env vars: fallow creates a temp worktree internally and
# GIT_DIR/GIT_INDEX_FILE (set by git in worktree hook context) break that.
# env -u is safe in non-worktree contexts (no-op when var is unset).
run: env -u GIT_DIR -u GIT_INDEX_FILE -u GIT_WORK_TREE bunx fallow audit --base origin/main --fail-on-issues
filesize:
# Scoped to packages/studio — the 600 LOC limit is a studio architecture
# standard enforced as part of the App.tsx decomposition work. Player and
@@ -9,25 +9,8 @@ import { existsSync, readdirSync, readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { parseHtml } from "./htmlParser.js";
import { maxEndTime, serialize } from "./test-utils.js";
import { generateHyperframesHtml } from "../generators/hyperframes.js";
import type { ParsedHtml } from "./htmlParser.js";
function maxEndTime(elements: ParsedHtml["elements"]): number {
if (elements.length === 0) return 0;
return Math.max(...elements.map((e) => e.startTime + e.duration));
}
function serialize(parsed: ParsedHtml): string {
// Fixed compositionId prevents Date.now() churn from masking structural instability.
// The compositionId generation instability itself is tracked as R1 (stable hf- ids).
return generateHyperframesHtml(parsed.elements, maxEndTime(parsed.elements), {
compositionId: "test-comp",
resolution: parsed.resolution,
styles: parsed.styles ?? undefined,
keyframes: parsed.keyframes,
stageZoomKeyframes: parsed.stageZoomKeyframes,
});
}
describe("T1 — parse→serialize round-trip (DOM/timing)", () => {
it("preserves element count and ids through one round-trip", () => {
+1 -17
View File
@@ -13,23 +13,7 @@
*/
import { describe, expect, it } from "vitest";
import { parseHtml } from "./htmlParser.js";
import { generateHyperframesHtml } from "../generators/hyperframes.js";
import type { ParsedHtml } from "./htmlParser.js";
function maxEndTime(elements: ParsedHtml["elements"]): number {
if (elements.length === 0) return 0;
return Math.max(...elements.map((e) => e.startTime + e.duration));
}
function serialize(parsed: ParsedHtml): string {
return generateHyperframesHtml(parsed.elements, maxEndTime(parsed.elements), {
compositionId: "test-comp",
resolution: parsed.resolution,
styles: parsed.styles ?? undefined,
keyframes: parsed.keyframes,
stageZoomKeyframes: parsed.stageZoomKeyframes,
});
}
import { serialize } from "./test-utils.js";
describe("T2 — stable element ids (spec for R1)", () => {
// --- Spec (red until R1) ---
+28
View File
@@ -0,0 +1,28 @@
/**
* Shared test utilities for parser test suites (T1, T2, T6…).
* Import from here rather than duplicating helpers across test files.
*
* Not part of the public package exports — consumed only by *.test.ts files.
*/
import { generateHyperframesHtml } from "../generators/hyperframes.js";
import type { ParsedHtml } from "./htmlParser.js";
export function maxEndTime(elements: ParsedHtml["elements"]): number {
if (elements.length === 0) return 0;
return Math.max(...elements.map((e) => e.startTime + e.duration));
}
/**
* Round-trip serialize helper.
* Fixed compositionId prevents Date.now() churn from masking structural instability.
* The compositionId generation instability itself is tracked as R1 (stable hf- ids).
*/
export function serialize(parsed: ParsedHtml): string {
return generateHyperframesHtml(parsed.elements, maxEndTime(parsed.elements), {
compositionId: "test-comp",
resolution: parsed.resolution,
styles: parsed.styles ?? undefined,
keyframes: parsed.keyframes,
stageZoomKeyframes: parsed.stageZoomKeyframes,
});
}
+8 -1
View File
@@ -15,5 +15,12 @@
},
"files": ["src/runtime/mediaVolumeEnvelope.ts"],
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "src/tests", "src/runtime", "**/*.test.ts"]
"exclude": [
"node_modules",
"dist",
"src/tests",
"src/runtime",
"**/*.test.ts",
"src/parsers/test-utils.ts"
]
}