1import { afterEach, beforeEach, describe, expect, it, vi } from "vite-plus/test";
2
3import { createReviewDiffHighlightScheduler } from "./reviewDiffHighlightScheduler";
4
5describe("review diff highlighting while scrolling", () => {
6 beforeEach(() => vi.useFakeTimers());
7 afterEach(() => vi.useRealTimers());
8
9 it("keeps requesting new rows during gradual scrolling through a large diff", () => {
10 const request = vi.fn();
11 const scheduler = createReviewDiffHighlightScheduler(request);
12 for (let firstRowIndex = 1; firstRowIndex <= 1_674; firstRowIndex++) {
13 scheduler.update({ firstRowIndex, lastRowIndex: firstRowIndex + 80 });
14 vi.advanceTimersByTime(16);
15 }
16 expect(request.mock.calls.length).toBeGreaterThan(100);
17 vi.advanceTimersByTime(150);
18 expect(request).toHaveBeenLastCalledWith({ firstRowIndex: 1_674, lastRowIndex: 1_754 });
19 });
20
21 it("highlights the settled viewport even below the movement threshold", () => {
22 const request = vi.fn();
23 const scheduler = createReviewDiffHighlightScheduler(request);
24 scheduler.update({ firstRowIndex: 2, lastRowIndex: 82 });
25 vi.advanceTimersByTime(100);
26 scheduler.update({ firstRowIndex: 3, lastRowIndex: 83 });
27 vi.advanceTimersByTime(100);
28 expect(request).not.toHaveBeenCalled();
29 vi.advanceTimersByTime(50);
30 expect(request).toHaveBeenCalledExactlyOnceWith({ firstRowIndex: 3, lastRowIndex: 83 });
31 });
32
33 it("does not let repeated draw events starve the settled refresh", () => {
34 const request = vi.fn();
35 const scheduler = createReviewDiffHighlightScheduler(request);
36 for (let i = 0; i < 10; i++) {
37 scheduler.update({ firstRowIndex: 1, lastRowIndex: 81 });
38 vi.advanceTimersByTime(30);
39 }
40 expect(request).toHaveBeenCalledExactlyOnceWith({ firstRowIndex: 1, lastRowIndex: 81 });
41 });
42
43 it("requests large jumps and reverse scrolling immediately without stale timers", () => {
44 const request = vi.fn();
45 const scheduler = createReviewDiffHighlightScheduler(request);
46 scheduler.update({ firstRowIndex: 1, lastRowIndex: 81 });
47 scheduler.update({ firstRowIndex: 1_000, lastRowIndex: 1_080 });
48 scheduler.update({ firstRowIndex: 0, lastRowIndex: 80 });
49 vi.runAllTimers();
50 expect(request.mock.calls).toEqual([
51 [{ firstRowIndex: 1_000, lastRowIndex: 1_080 }],
52 [{ firstRowIndex: 0, lastRowIndex: 80 }],
53 ]);
54 });
55
56 it("cancels pending work on disposal and resets the range for a new diff", () => {
57 const request = vi.fn();
58 const scheduler = createReviewDiffHighlightScheduler(request);
59 scheduler.update({ firstRowIndex: 1, lastRowIndex: 81 });
60 scheduler.cancel();
61 vi.runAllTimers();
62 expect(request).not.toHaveBeenCalled();
63 scheduler.update({ firstRowIndex: 1_000, lastRowIndex: 1_080 });
64 request.mockClear();
65 scheduler.update({ firstRowIndex: 1_001, lastRowIndex: 1_081 });
66 scheduler.reset();
67 vi.runAllTimers();
68 expect(request).not.toHaveBeenCalled();
69 scheduler.update({ firstRowIndex: 1, lastRowIndex: 81 });
70 expect(request).not.toHaveBeenCalled();
71 vi.advanceTimersByTime(150);
72 expect(request).toHaveBeenCalledExactlyOnceWith({ firstRowIndex: 1, lastRowIndex: 81 });
73 });
74});