deer-flow/frontend/tests/unit/core/dom/render-activity.dom.test.ts
DanielWalnut 459dd78707
perf(frontend): bound delivery, bundles, and long-running UI work (#4622)
* docs: design frontend performance remediation

* docs: plan frontend performance remediation

* test(frontend): add route asset performance budgets

* perf(nginx): compress textual responses safely

* perf(frontend): lazy load case study media

* perf(frontend): bound static demo file tracing

* perf(frontend): restore static locale boundaries

* perf(frontend): defer closed workspace panels

* perf(frontend): split editors and deduplicate highlighting

* perf(frontend): index incremental message derivation

* perf(frontend): stabilize paged history cache policy

* perf(frontend): bound streaming markdown renders

* perf(frontend): virtualize message history

* perf(frontend): bound and virtualize chat lists

* perf(frontend): suspend inactive decorative animation

* perf(browser): stream latest frames as binary

* perf(artifacts): stream bounded text previews

* docs: finalize performance runtime boundaries

* style(backend): apply test formatting

* fix(frontend): keep translation functions client-side

* perf(frontend): defer decorative animation bundles

* test(frontend): lock optimized route budgets

* fix: harden frontend performance boundaries

* test(frontend): update i18n provider fixture

* fix(frontend): preserve sidebar pagination position

* style(backend): format artifact range test
2026-08-01 22:19:59 +08:00

138 lines
3.6 KiB
TypeScript

import { afterEach, describe, expect, it, rs } from "@rstest/core";
import { observeRenderActivity } from "@/core/dom/render-activity";
class IntersectionObserverMock {
static instances: IntersectionObserverMock[] = [];
callback: IntersectionObserverCallback;
disconnect = rs.fn();
observe = rs.fn();
constructor(callback: IntersectionObserverCallback) {
this.callback = callback;
IntersectionObserverMock.instances.push(this);
}
emit(isIntersecting: boolean) {
this.callback(
[{ isIntersecting } as IntersectionObserverEntry],
this as never,
);
}
}
class MediaQueryListMock {
matches = false;
addEventListener = rs.fn();
removeEventListener = rs.fn();
private listener?: (event: MediaQueryListEvent) => void;
constructor() {
this.addEventListener.mockImplementation(
(_type: string, listener: (event: MediaQueryListEvent) => void) => {
this.listener = listener;
},
);
}
emit(matches: boolean) {
this.matches = matches;
this.listener?.({ matches } as MediaQueryListEvent);
}
}
describe("observeRenderActivity", () => {
afterEach(() => {
IntersectionObserverMock.instances = [];
rs.restoreAllMocks();
rs.unstubAllGlobals();
});
it("pauses for hidden documents and offscreen elements, then cleans up", () => {
rs.stubGlobal("IntersectionObserver", IntersectionObserverMock);
let hidden = false;
rs.spyOn(document, "hidden", "get").mockImplementation(() => hidden);
const removeEventListener = rs.spyOn(document, "removeEventListener");
const states: boolean[] = [];
const cleanup = observeRenderActivity(
document.createElement("div"),
(active) => {
states.push(active);
},
);
const observer = IntersectionObserverMock.instances[0]!;
expect(states).toEqual([true]);
observer.emit(false);
expect(states).toEqual([true, false]);
observer.emit(true);
hidden = true;
document.dispatchEvent(new Event("visibilitychange"));
expect(states).toEqual([true, false, true, false]);
hidden = false;
document.dispatchEvent(new Event("visibilitychange"));
expect(states.at(-1)).toBe(true);
cleanup();
expect(observer.disconnect).toHaveBeenCalledOnce();
expect(removeEventListener).toHaveBeenCalledWith(
"visibilitychange",
expect.any(Function),
);
});
it("pauses animations while reduced motion is requested", () => {
const mediaQuery = new MediaQueryListMock();
rs.stubGlobal(
"matchMedia",
rs.fn(() => mediaQuery),
);
const states: boolean[] = [];
const cleanup = observeRenderActivity(
document.createElement("div"),
(active) => states.push(active),
);
expect(matchMedia).toHaveBeenCalledWith("(prefers-reduced-motion: reduce)");
expect(states).toEqual([true]);
mediaQuery.emit(true);
expect(states).toEqual([true, false]);
mediaQuery.emit(false);
expect(states).toEqual([true, false, true]);
cleanup();
expect(mediaQuery.removeEventListener).toHaveBeenCalledWith(
"change",
expect.any(Function),
);
});
it("can preserve visible content while reduced motion is requested", () => {
const mediaQuery = new MediaQueryListMock();
mediaQuery.matches = true;
rs.stubGlobal(
"matchMedia",
rs.fn(() => mediaQuery),
);
const states: boolean[] = [];
const cleanup = observeRenderActivity(
document.createElement("div"),
(active) => states.push(active),
true,
false,
);
expect(states).toEqual([true]);
expect(matchMedia).not.toHaveBeenCalled();
cleanup();
});
});