1import { afterEach, beforeEach, describe, expect, it, vi } from "vite-plus/test";
2
3import {
4 createDelayedStatus,
5 STATUS_MIN_VISIBLE_MS,
6 STATUS_SHOW_DELAY_MS,
7 type ShownStatus,
8} from "./delayedStatus.ts";
9
10function track() {
11 const changes: Array<ShownStatus<string> | null> = [];
12 const status = createDelayedStatus<string>((shown) => changes.push(shown));
13 return { changes, status };
14}
15
16describe("createDelayedStatus", () => {
17 beforeEach(() => {
18 vi.useFakeTimers();
19 });
20 afterEach(() => {
21 vi.useRealTimers();
22 });
23
24 it("never shows a status that clears before the show delay", () => {
25 const { changes, status } = track();
26 status.update("a", "syncing");
27 vi.advanceTimersByTime(STATUS_SHOW_DELAY_MS - 1);
28 status.update("a", null);
29 vi.runAllTimers();
30
31 expect(changes).toEqual([]);
32 });
33
34 it("holds each shown status for the minimum time, then hides it at once", () => {
35 const { changes, status } = track();
36 status.update("a", "loading");
37 vi.advanceTimersByTime(STATUS_SHOW_DELAY_MS);
38 expect(changes).toEqual([{ key: "a", value: "loading" }]);
39
40 // A new label gets its own full hold, even during the first label's hold.
41 vi.advanceTimersByTime(1);
42 status.update("a", "syncing");
43 status.update("a", null);
44 vi.advanceTimersByTime(STATUS_MIN_VISIBLE_MS - 1);
45 expect(changes.at(-1)).toEqual({ key: "a", value: "syncing" });
46 vi.advanceTimersByTime(1);
47 expect(changes.at(-1)).toBeNull();
48
49 status.update("a", "syncing");
50 vi.advanceTimersByTime(STATUS_SHOW_DELAY_MS + STATUS_MIN_VISIBLE_MS);
51 status.update("a", null);
52 expect(changes.at(-1)).toBeNull();
53 });
54
55 it("drops the shown status at once when the key changes", () => {
56 const { changes, status } = track();
57 status.update("a", "syncing");
58 vi.advanceTimersByTime(STATUS_SHOW_DELAY_MS);
59 status.update("b", "syncing");
60 expect(changes.at(-1)).toBeNull();
61
62 vi.advanceTimersByTime(STATUS_SHOW_DELAY_MS);
63 expect(changes.at(-1)).toEqual({ key: "b", value: "syncing" });
64 });
65});