This repository has been archived on 2026-10-08. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
maestro/web/src/previewSchedule.test.ts
T
Miguel PalhasandClaude Opus 5 6075a177f5 perf(maestro): drop the sidebar preview delay
The pane waited 150 ms on hover and 60 ms on a keyboard step before
following the sidebar highlight, so every preview paid for the fast walk
it might have been. Replace both with a leading-edge 120 ms gap: the
first move shows at once, a burst is coalesced to its start and its end.

The row's own hover no longer eases either — `background` was on a 120 ms
transition, which is what read as lag on the row itself.

The sidebar also rebuilt its whole tree on every `SessionUpdated`, a
couple of times a minute per live session, dropping `:hover` from the row
under the pointer. Refreshes that change nothing structural now patch the
activity rail and meta line into the standing rows instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 13:36:51 +01:00

93 lines
2.7 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { createPreviewSchedule, PREVIEW_MIN_GAP_MS } from "./previewSchedule.js";
/** Hand-driven clock + timer queue, so the schedule is asserted without waiting. */
function harness() {
let now = 1_000;
const timers = new Map<number, { at: number; fn: () => void }>();
let nextHandle = 1;
const emitted: (string | null)[] = [];
const schedule = createPreviewSchedule((id) => emitted.push(id), {
now: () => now,
setTimer: (fn, ms) => {
const h = nextHandle++;
timers.set(h, { at: now + ms, fn });
return h;
},
clearTimer: (h) => {
timers.delete(h);
},
});
/** Advance the clock, firing any timer that comes due. */
const advance = (ms: number) => {
now += ms;
for (const [h, t] of [...timers]) {
if (t.at <= now) {
timers.delete(h);
t.fn();
}
}
};
return { schedule, emitted, advance };
}
describe("preview schedule", () => {
it("shows the first preview immediately", () => {
const { schedule, emitted } = harness();
schedule("s1");
expect(emitted).toEqual(["s1"]);
});
it("coalesces a burst into one trailing preview", () => {
const { schedule, emitted, advance } = harness();
// A pointer sweep across the list, or j held down: every row in between
// is walked well inside one gap.
schedule("s1");
schedule("s2");
schedule("s3");
expect(emitted).toEqual(["s1"]);
advance(PREVIEW_MIN_GAP_MS);
expect(emitted).toEqual(["s1", "s3"]);
});
it("shows the next preview immediately once the gap has passed", () => {
const { schedule, emitted, advance } = harness();
schedule("s1");
advance(PREVIEW_MIN_GAP_MS);
schedule("s2");
expect(emitted).toEqual(["s1", "s2"]);
});
it("drops a superseded trailing preview rather than replaying it", () => {
const { schedule, emitted, advance } = harness();
schedule("s1");
schedule("s2");
schedule("s1"); // back where we started inside the same gap
advance(PREVIEW_MIN_GAP_MS);
// s1 is already on screen, so the trailing edge has nothing to do.
expect(emitted).toEqual(["s1"]);
});
it("clears through the same gap, so leaving and re-entering does not blink", () => {
const { schedule, emitted, advance } = harness();
schedule("s1");
schedule(null); // pointer crosses the gap between two rows
schedule("s2");
advance(PREVIEW_MIN_GAP_MS);
expect(emitted).toEqual(["s1", "s2"]);
});
it("cancel drops a pending trailing preview", () => {
const { schedule, emitted, advance } = harness();
schedule("s1");
schedule("s2");
schedule.cancel();
advance(PREVIEW_MIN_GAP_MS);
expect(emitted).toEqual(["s1"]);
});
});