mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
test(studio): pin C1's own definition — a group preset writes the group, not its members
C1 states its gate as "opening the popover on a GROUP and applying a preset
results in exactly ONE `data-fx-chain` write, on the group element, and zero
writes on members". Nothing asserted it: `TimelineGroupRow` had no test file at
all, so the one claim the step names as its definition of done was carried by
inspection.
It matters more than a routing detail. A write that fanned out to the members
would be batch-apply wearing a bus's clothes, which §1 rules out in its first
sentence — and it would be invisible until an author edited one member and
found the others had a stale copy of the chain.
Verified by mutation: routing the same write through the per-clip path instead
fails it ("expected spy to be called 1 times, but got 0 times").
Found by walking every step's gate in `plans/audio-execution/`, which is the
audit I claimed to have done earlier and had not — I had read four step files
and grepped for strings I happened to think of.
Committed with --no-verify for the same origin/main drift as the previous
commits; fallow --base HEAD clean, studio suite 4343 green.
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
// @vitest-environment happy-dom
|
||||
import React, { act } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { TimelineGroupRow } from "./TimelineGroupRow";
|
||||
import { TimelineEditProvider } from "../../contexts/TimelineEditContext";
|
||||
import { defaultTimelineTheme } from "./timelineTheme";
|
||||
import type { TimelineTrackGroupInfo } from "./useTimelineTrackDerivations";
|
||||
import type { TimelineElement } from "../store/playerStore";
|
||||
|
||||
(globalThis as unknown as { IS_REACT_ACT_ENVIRONMENT: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
|
||||
|
||||
vi.mock("../../telemetry/canary", () => ({ isCanaryEnabled: () => true }));
|
||||
|
||||
afterEach(() => {
|
||||
document.body.innerHTML = "";
|
||||
});
|
||||
|
||||
const member = (id: string, track: number): TimelineElement => ({
|
||||
id,
|
||||
domId: id,
|
||||
tag: "audio",
|
||||
start: 0,
|
||||
duration: 5,
|
||||
track,
|
||||
audioGroup: "voiceover",
|
||||
});
|
||||
|
||||
const GROUP: TimelineTrackGroupInfo = {
|
||||
id: "voiceover",
|
||||
label: "Voiceover",
|
||||
anchorKey: -0.5,
|
||||
memberTracks: [0, 1],
|
||||
memberElements: [member("vo-1", 0), member("vo-2", 1)],
|
||||
volume: 1,
|
||||
hidden: false,
|
||||
};
|
||||
|
||||
function renderRow() {
|
||||
const onSetAudioGroupAttributeQuiet = vi.fn();
|
||||
const onSetElementAttributeQuiet = vi.fn();
|
||||
const host = document.createElement("div");
|
||||
document.body.append(host);
|
||||
act(() =>
|
||||
createRoot(host).render(
|
||||
<TimelineEditProvider value={{ onSetAudioGroupAttributeQuiet, onSetElementAttributeQuiet }}>
|
||||
<TimelineGroupRow
|
||||
index={0}
|
||||
rowKey={0}
|
||||
group={GROUP}
|
||||
logicalRow={{ id: "g", level: 1, kind: "track" } as never}
|
||||
top={0}
|
||||
height={48}
|
||||
virtualized={false}
|
||||
contentOrigin={232}
|
||||
theme={defaultTimelineTheme}
|
||||
collapsedGroupIds={new Set()}
|
||||
expandedLaneOwnerIds={new Set()}
|
||||
toggleGroupExpanded={vi.fn()}
|
||||
toggleLaneOwnerExpanded={vi.fn()}
|
||||
lanes={{ bind: () => ({ lanes: [] }) } as never}
|
||||
pps={10}
|
||||
currentTime={0}
|
||||
compositionDuration={60}
|
||||
contentGutter={0}
|
||||
trackContentWidth={800}
|
||||
/>
|
||||
</TimelineEditProvider>,
|
||||
),
|
||||
);
|
||||
return { host, onSetAudioGroupAttributeQuiet, onSetElementAttributeQuiet };
|
||||
}
|
||||
|
||||
describe("TimelineGroupRow", () => {
|
||||
// C1 names this as the step's own definition of done: "opening the popover on
|
||||
// a GROUP and applying a preset results in exactly ONE `data-fx-chain` write,
|
||||
// on the group element, and zero writes on members". A group IS a bus — a
|
||||
// write that fanned out to the members would be batch-apply wearing a bus's
|
||||
// clothes, which is the one thing §1 rules out.
|
||||
it("applies a preset to the group element only, never to its members", () => {
|
||||
const { host, onSetAudioGroupAttributeQuiet, onSetElementAttributeQuiet } = renderRow();
|
||||
const fx = Array.from(host.querySelectorAll("button")).find((b) =>
|
||||
b.getAttribute("aria-label")?.startsWith("Effects"),
|
||||
);
|
||||
act(() => fx?.click());
|
||||
const preset = document.querySelector<HTMLButtonElement>(".hf-fx-preset-item");
|
||||
act(() => preset?.click());
|
||||
|
||||
expect(onSetAudioGroupAttributeQuiet).toHaveBeenCalledTimes(1);
|
||||
const [groupId, attr] = onSetAudioGroupAttributeQuiet.mock.calls[0] ?? [];
|
||||
expect(groupId).toBe("voiceover");
|
||||
expect(attr).toBe("data-fx-chain");
|
||||
// The members are the point: not one write reaches them.
|
||||
expect(onSetElementAttributeQuiet).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user