mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-04 07:19:52 +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