summaryrefslogtreecommitdiff
path: root/apps/web/src/actions/__tests__/freeze-frame-store.test.ts
blob: 94e1566e3ab77684661e171a1c6b3e49fae320db (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { beforeEach, describe, expect, test } from "bun:test";
import {
	DEFAULT_FREEZE_DURATION_SECONDS,
	isValidFreezeDuration,
	MAX_FREEZE_DURATION_SECONDS,
	useFreezeFrameStore,
} from "../freeze-frame-store";

function resetStore() {
	useFreezeFrameStore.setState({
		isOpen: false,
		lastDurationSeconds: DEFAULT_FREEZE_DURATION_SECONDS,
		resolver: null,
	});
}

describe("freeze-frame store", () => {
	beforeEach(() => {
		resetStore();
	});

	describe("isValidFreezeDuration", () => {
		test("accepts positive durations up to the max, including decimals", () => {
			expect(isValidFreezeDuration({ seconds: 3 })).toBe(true);
			expect(isValidFreezeDuration({ seconds: 2.5 })).toBe(true);
			expect(isValidFreezeDuration({ seconds: 0.1 })).toBe(true);
			expect(
				isValidFreezeDuration({ seconds: MAX_FREEZE_DURATION_SECONDS }),
			).toBe(true);
		});

		test("rejects non-positive, over-max, and non-finite durations", () => {
			expect(isValidFreezeDuration({ seconds: 0 })).toBe(false);
			expect(isValidFreezeDuration({ seconds: -1 })).toBe(false);
			expect(isValidFreezeDuration({ seconds: 600.1 })).toBe(false);
			expect(isValidFreezeDuration({ seconds: Number.NaN })).toBe(false);
			expect(isValidFreezeDuration({ seconds: Number.POSITIVE_INFINITY })).toBe(
				false,
			);
		});
	});

	describe("requestDuration", () => {
		test("opens the dialog and resolves with the confirmed seconds", async () => {
			const promise = useFreezeFrameStore.getState().requestDuration();
			expect(useFreezeFrameStore.getState().isOpen).toBe(true);

			useFreezeFrameStore.getState().confirmDuration({ seconds: 5 });

			await expect(promise).resolves.toBe(5);
			expect(useFreezeFrameStore.getState().isOpen).toBe(false);
		});

		test("remembers the confirmed duration as the last-used value", async () => {
			const promise = useFreezeFrameStore.getState().requestDuration();
			useFreezeFrameStore.getState().confirmDuration({ seconds: 5 });
			await promise;

			expect(useFreezeFrameStore.getState().lastDurationSeconds).toBe(5);
		});

		test("resolves null on cancel and keeps the last-used duration", async () => {
			useFreezeFrameStore.setState({ lastDurationSeconds: 7 });

			const promise = useFreezeFrameStore.getState().requestDuration();
			expect(useFreezeFrameStore.getState().isOpen).toBe(true);

			useFreezeFrameStore.getState().cancelDuration();

			await expect(promise).resolves.toBeNull();
			expect(useFreezeFrameStore.getState().isOpen).toBe(false);
			expect(useFreezeFrameStore.getState().lastDurationSeconds).toBe(7);
		});

		test("ignores an invalid confirm and leaves the dialog open", () => {
			useFreezeFrameStore.getState().requestDuration();

			useFreezeFrameStore.getState().confirmDuration({ seconds: 0 });
			useFreezeFrameStore.getState().confirmDuration({ seconds: 601 });

			expect(useFreezeFrameStore.getState().isOpen).toBe(true);
			expect(useFreezeFrameStore.getState().lastDurationSeconds).toBe(
				DEFAULT_FREEZE_DURATION_SECONDS,
			);
		});

		test("a new request supersedes a pending one by cancelling it", async () => {
			const first = useFreezeFrameStore.getState().requestDuration();
			const second = useFreezeFrameStore.getState().requestDuration();

			await expect(first).resolves.toBeNull();
			expect(useFreezeFrameStore.getState().isOpen).toBe(true);

			useFreezeFrameStore.getState().confirmDuration({ seconds: 2 });
			await expect(second).resolves.toBe(2);
		});
	});
});