mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 17:27:09 +00:00
test(studio): assert the superseded refresh's fetch actually aborts
Closes the coverage gap the independent review flagged: the abort call had no test asserting on it, so a dropped abort() would have stayed green. Also cuts two comment blocks over the repo's 4-line cap.
This commit is contained in:
@@ -258,12 +258,9 @@ export const VariablesPanel = memo(function VariablesPanel({
|
||||
const { refreshKey } = useStudioPlaybackContext();
|
||||
const { readProjectFile, writeProjectFile, fileTree, compositions } = useFileManagerContext();
|
||||
const { domEditSelection } = useDomEditContext();
|
||||
// On the master view (no activeCompPath) the panel targets the project's real
|
||||
// main composition — the first composition in the tree — not a hardcoded
|
||||
// index.html that may not exist. This same path is used for the persist write
|
||||
// target (so an edit never lands in a phantom index.html) AND the handoff
|
||||
// render command. Null only when the project has no composition yet, in which
|
||||
// case sdkSession is also null and the panel is inert.
|
||||
// Master view (no activeCompPath) targets the real main composition, not a
|
||||
// hardcoded index.html — used for both the persist write target and the
|
||||
// handoff render command. Null only when the project has no composition.
|
||||
const effectiveCompPath = activeCompPath ?? resolveMasterCompositionPath(compositions);
|
||||
const previewValues = usePreviewVariablesStore((s) => s.values);
|
||||
const setPreviewValues = usePreviewVariablesStore((s) => s.setValues);
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
/**
|
||||
* Opens the root composition once hydration settles on no selection; fires at most once per
|
||||
* `projectId`. Relies on the caller resetting selection on an in-session project switch
|
||||
* (see `useResetSelectionOnProjectSwitch`) or a stale selection reads as "already open".
|
||||
* Opens the root composition once hydration settles with no selection, at most once per
|
||||
* `projectId`. Caller must reset selection on a project switch (`useResetSelectionOnProjectSwitch`).
|
||||
*/
|
||||
export function useAutoOpenRootComposition({
|
||||
projectId,
|
||||
|
||||
@@ -156,6 +156,64 @@ describe("useFileTree.refreshFileTree", () => {
|
||||
fetchSpy.mockRestore();
|
||||
});
|
||||
|
||||
it("aborts the superseded request's fetch when a newer refresh is issued", async () => {
|
||||
let call = 0;
|
||||
const signals: AbortSignal[] = [];
|
||||
const fetchSpy = vi
|
||||
.spyOn(globalThis, "fetch")
|
||||
.mockImplementation(async (_url, init?: RequestInit) => {
|
||||
call += 1;
|
||||
if (call === 1) {
|
||||
return new Response(
|
||||
JSON.stringify({ files: ["index.html"], compositions: ["index.html"] }),
|
||||
{ status: 200 },
|
||||
);
|
||||
}
|
||||
if (init?.signal) signals.push(init.signal);
|
||||
return new Promise<Response>(() => {});
|
||||
});
|
||||
|
||||
const handleRef = { current: null as Handle | null };
|
||||
const host = document.createElement("div");
|
||||
document.body.append(host);
|
||||
root = createRoot(host);
|
||||
|
||||
await act(async () => {
|
||||
root?.render(
|
||||
<Harness
|
||||
ref={(h) => {
|
||||
handleRef.current = h;
|
||||
}}
|
||||
projectId="project-a"
|
||||
/>,
|
||||
);
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
});
|
||||
|
||||
act(() => {
|
||||
void handleRef.current?.refresh();
|
||||
});
|
||||
await act(async () => {
|
||||
await Promise.resolve();
|
||||
});
|
||||
expect(signals).toHaveLength(1);
|
||||
expect(signals[0].aborted).toBe(false);
|
||||
|
||||
act(() => {
|
||||
void handleRef.current?.refresh();
|
||||
});
|
||||
await act(async () => {
|
||||
await Promise.resolve();
|
||||
});
|
||||
|
||||
expect(signals).toHaveLength(2);
|
||||
expect(signals[0].aborted).toBe(true);
|
||||
expect(signals[1].aborted).toBe(false);
|
||||
|
||||
fetchSpy.mockRestore();
|
||||
});
|
||||
|
||||
it("keeps the prior compositions list when a refresh response omits the field", async () => {
|
||||
let call = 0;
|
||||
const fetchSpy = vi.spyOn(globalThis, "fetch").mockImplementation(async () => {
|
||||
|
||||
Reference in New Issue
Block a user