Skip to content

Commit 07322bd

Browse files
committed
test: add comprehensive unit tests for useAutoApprovalState hook
- Test hasEnabledOptions computation with various toggle combinations - Test effectiveAutoApprovalEnabled logic - Test memoization behavior - Test edge cases including partial objects and non-boolean values - Ensure 100% coverage of the hook's functionality
1 parent 38c5d8c commit 07322bd

File tree

1 file changed

+282
-0
lines changed

1 file changed

+282
-0
lines changed
Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
import { renderHook } from "@testing-library/react"
2+
import { useAutoApprovalState } from "../useAutoApprovalState"
3+
4+
describe("useAutoApprovalState", () => {
5+
describe("hasEnabledOptions", () => {
6+
it("should return false when all toggles are false", () => {
7+
const toggles = {
8+
alwaysAllowReadOnly: false,
9+
alwaysAllowWrite: false,
10+
alwaysAllowExecute: false,
11+
alwaysAllowBrowser: false,
12+
alwaysAllowMcp: false,
13+
alwaysAllowModeSwitch: false,
14+
alwaysAllowSubtasks: false,
15+
alwaysApproveResubmit: false,
16+
alwaysAllowFollowupQuestions: false,
17+
alwaysAllowUpdateTodoList: false,
18+
}
19+
20+
const { result } = renderHook(() => useAutoApprovalState(toggles, true))
21+
22+
expect(result.current.hasEnabledOptions).toBe(false)
23+
})
24+
25+
it("should return false when all toggles are undefined", () => {
26+
const toggles = {
27+
alwaysAllowReadOnly: undefined,
28+
alwaysAllowWrite: undefined,
29+
alwaysAllowExecute: undefined,
30+
alwaysAllowBrowser: undefined,
31+
alwaysAllowMcp: undefined,
32+
alwaysAllowModeSwitch: undefined,
33+
alwaysAllowSubtasks: undefined,
34+
alwaysApproveResubmit: undefined,
35+
alwaysAllowFollowupQuestions: undefined,
36+
alwaysAllowUpdateTodoList: undefined,
37+
}
38+
39+
const { result } = renderHook(() => useAutoApprovalState(toggles, true))
40+
41+
expect(result.current.hasEnabledOptions).toBe(false)
42+
})
43+
44+
it("should return true when at least one toggle is true", () => {
45+
const toggles = {
46+
alwaysAllowReadOnly: true,
47+
alwaysAllowWrite: false,
48+
alwaysAllowExecute: false,
49+
alwaysAllowBrowser: false,
50+
alwaysAllowMcp: false,
51+
alwaysAllowModeSwitch: false,
52+
alwaysAllowSubtasks: false,
53+
alwaysApproveResubmit: false,
54+
alwaysAllowFollowupQuestions: false,
55+
alwaysAllowUpdateTodoList: false,
56+
}
57+
58+
const { result } = renderHook(() => useAutoApprovalState(toggles, true))
59+
60+
expect(result.current.hasEnabledOptions).toBe(true)
61+
})
62+
63+
it("should return true when multiple toggles are true", () => {
64+
const toggles = {
65+
alwaysAllowReadOnly: true,
66+
alwaysAllowWrite: true,
67+
alwaysAllowExecute: true,
68+
alwaysAllowBrowser: false,
69+
alwaysAllowMcp: false,
70+
alwaysAllowModeSwitch: false,
71+
alwaysAllowSubtasks: false,
72+
alwaysApproveResubmit: false,
73+
alwaysAllowFollowupQuestions: false,
74+
alwaysAllowUpdateTodoList: false,
75+
}
76+
77+
const { result } = renderHook(() => useAutoApprovalState(toggles, true))
78+
79+
expect(result.current.hasEnabledOptions).toBe(true)
80+
})
81+
82+
it("should return true when all toggles are true", () => {
83+
const toggles = {
84+
alwaysAllowReadOnly: true,
85+
alwaysAllowWrite: true,
86+
alwaysAllowExecute: true,
87+
alwaysAllowBrowser: true,
88+
alwaysAllowMcp: true,
89+
alwaysAllowModeSwitch: true,
90+
alwaysAllowSubtasks: true,
91+
alwaysApproveResubmit: true,
92+
alwaysAllowFollowupQuestions: true,
93+
alwaysAllowUpdateTodoList: true,
94+
}
95+
96+
const { result } = renderHook(() => useAutoApprovalState(toggles, true))
97+
98+
expect(result.current.hasEnabledOptions).toBe(true)
99+
})
100+
})
101+
102+
describe("effectiveAutoApprovalEnabled", () => {
103+
it("should return false when autoApprovalEnabled is false regardless of toggles", () => {
104+
const toggles = {
105+
alwaysAllowReadOnly: true,
106+
alwaysAllowWrite: true,
107+
alwaysAllowExecute: true,
108+
}
109+
110+
const { result } = renderHook(() => useAutoApprovalState(toggles, false))
111+
112+
expect(result.current.effectiveAutoApprovalEnabled).toBe(false)
113+
})
114+
115+
it("should return false when autoApprovalEnabled is undefined regardless of toggles", () => {
116+
const toggles = {
117+
alwaysAllowReadOnly: true,
118+
alwaysAllowWrite: true,
119+
alwaysAllowExecute: true,
120+
}
121+
122+
const { result } = renderHook(() => useAutoApprovalState(toggles, undefined))
123+
124+
expect(result.current.effectiveAutoApprovalEnabled).toBe(false)
125+
})
126+
127+
it("should return false when autoApprovalEnabled is true but no toggles are enabled", () => {
128+
const toggles = {
129+
alwaysAllowReadOnly: false,
130+
alwaysAllowWrite: false,
131+
alwaysAllowExecute: false,
132+
alwaysAllowBrowser: false,
133+
alwaysAllowMcp: false,
134+
alwaysAllowModeSwitch: false,
135+
alwaysAllowSubtasks: false,
136+
alwaysApproveResubmit: false,
137+
alwaysAllowFollowupQuestions: false,
138+
alwaysAllowUpdateTodoList: false,
139+
}
140+
141+
const { result } = renderHook(() => useAutoApprovalState(toggles, true))
142+
143+
expect(result.current.effectiveAutoApprovalEnabled).toBe(false)
144+
})
145+
146+
it("should return true when autoApprovalEnabled is true and at least one toggle is enabled", () => {
147+
const toggles = {
148+
alwaysAllowReadOnly: true,
149+
alwaysAllowWrite: false,
150+
alwaysAllowExecute: false,
151+
}
152+
153+
const { result } = renderHook(() => useAutoApprovalState(toggles, true))
154+
155+
expect(result.current.effectiveAutoApprovalEnabled).toBe(true)
156+
})
157+
})
158+
159+
describe("memoization", () => {
160+
it("should not recompute hasEnabledOptions when toggles object reference changes but values are the same", () => {
161+
const initialToggles = {
162+
alwaysAllowReadOnly: true,
163+
alwaysAllowWrite: false,
164+
}
165+
166+
const { result, rerender } = renderHook(
167+
({ toggles, autoApprovalEnabled }) => useAutoApprovalState(toggles, autoApprovalEnabled),
168+
{
169+
initialProps: {
170+
toggles: initialToggles,
171+
autoApprovalEnabled: true,
172+
},
173+
},
174+
)
175+
176+
const firstHasEnabledOptions = result.current.hasEnabledOptions
177+
const firstEffectiveAutoApprovalEnabled = result.current.effectiveAutoApprovalEnabled
178+
179+
// Create new object with same values
180+
const newToggles = {
181+
alwaysAllowReadOnly: true,
182+
alwaysAllowWrite: false,
183+
}
184+
185+
rerender({ toggles: newToggles, autoApprovalEnabled: true })
186+
187+
// The computed values should be the same due to memoization
188+
expect(result.current.hasEnabledOptions).toBe(firstHasEnabledOptions)
189+
expect(result.current.effectiveAutoApprovalEnabled).toBe(firstEffectiveAutoApprovalEnabled)
190+
})
191+
192+
it("should recompute when toggle values change", () => {
193+
const initialToggles = {
194+
alwaysAllowReadOnly: true,
195+
alwaysAllowWrite: false,
196+
}
197+
198+
const { result, rerender } = renderHook(
199+
({ toggles, autoApprovalEnabled }) => useAutoApprovalState(toggles, autoApprovalEnabled),
200+
{
201+
initialProps: {
202+
toggles: initialToggles,
203+
autoApprovalEnabled: true,
204+
},
205+
},
206+
)
207+
208+
expect(result.current.hasEnabledOptions).toBe(true)
209+
expect(result.current.effectiveAutoApprovalEnabled).toBe(true)
210+
211+
// Change toggle values
212+
const newToggles = {
213+
alwaysAllowReadOnly: false,
214+
alwaysAllowWrite: false,
215+
}
216+
217+
rerender({ toggles: newToggles, autoApprovalEnabled: true })
218+
219+
expect(result.current.hasEnabledOptions).toBe(false)
220+
expect(result.current.effectiveAutoApprovalEnabled).toBe(false)
221+
})
222+
223+
it("should recompute effectiveAutoApprovalEnabled when autoApprovalEnabled changes", () => {
224+
const toggles = {
225+
alwaysAllowReadOnly: true,
226+
alwaysAllowWrite: false,
227+
}
228+
229+
const { result, rerender } = renderHook(
230+
({ toggles, autoApprovalEnabled }) => useAutoApprovalState(toggles, autoApprovalEnabled),
231+
{
232+
initialProps: {
233+
toggles,
234+
autoApprovalEnabled: true,
235+
},
236+
},
237+
)
238+
239+
expect(result.current.effectiveAutoApprovalEnabled).toBe(true)
240+
241+
rerender({ toggles, autoApprovalEnabled: false })
242+
243+
expect(result.current.effectiveAutoApprovalEnabled).toBe(false)
244+
})
245+
})
246+
247+
describe("edge cases", () => {
248+
it("should handle partial toggle objects", () => {
249+
const toggles = {
250+
alwaysAllowReadOnly: true,
251+
// Other properties are optional
252+
}
253+
254+
const { result } = renderHook(() => useAutoApprovalState(toggles, true))
255+
256+
expect(result.current.hasEnabledOptions).toBe(true)
257+
expect(result.current.effectiveAutoApprovalEnabled).toBe(true)
258+
})
259+
260+
it("should handle empty toggle object", () => {
261+
const toggles = {}
262+
263+
const { result } = renderHook(() => useAutoApprovalState(toggles, true))
264+
265+
expect(result.current.hasEnabledOptions).toBe(false)
266+
expect(result.current.effectiveAutoApprovalEnabled).toBe(false)
267+
})
268+
269+
it("should handle mixed truthy/falsy values correctly", () => {
270+
const toggles = {
271+
alwaysAllowReadOnly: 1 as any, // truthy non-boolean
272+
alwaysAllowWrite: "" as any, // falsy non-boolean
273+
alwaysAllowExecute: null as any, // falsy non-boolean
274+
alwaysAllowBrowser: "yes" as any, // truthy non-boolean
275+
}
276+
277+
const { result } = renderHook(() => useAutoApprovalState(toggles, true))
278+
279+
expect(result.current.hasEnabledOptions).toBe(true) // Because some values are truthy
280+
})
281+
})
282+
})

0 commit comments

Comments
 (0)