Skip to content

Commit ad21c6b

Browse files
committed
test: add unit tests for useControlledState to validate controlled and uncontrolled behavior
1 parent 6aed6da commit ad21c6b

File tree

2 files changed

+80
-1
lines changed

2 files changed

+80
-1
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { ref, nextTick } from 'vue';
2+
import { useControlledState } from '../index';
3+
// NOTE: These tests are for Vitest. Ensure 'vi' is available globally.
4+
5+
describe('useControlledState', () => {
6+
it('should use defaultValue when uncontrolled', () => {
7+
const value = ref(undefined);
8+
const [state, setValue] = useControlledState(value, 1);
9+
expect(state.value).toBe(1);
10+
setValue(2);
11+
expect(state.value).toBe(2);
12+
});
13+
14+
it('should use value when controlled', () => {
15+
const value = ref(5);
16+
const [state, setValue] = useControlledState(value, 1);
17+
expect(state.value).toBe(5);
18+
setValue(10);
19+
// Should not update state, still controlled by value
20+
expect(state.value).toBe(5);
21+
value.value = 8;
22+
expect(state.value).toBe(8);
23+
});
24+
25+
it('should call onChange when value changes (uncontrolled)', () => {
26+
const value = ref(undefined);
27+
const onChange = vi.fn();
28+
const setValue = useControlledState(value, 1, onChange)[1];
29+
setValue(3);
30+
expect(onChange).toHaveBeenCalledWith(3);
31+
setValue(3);
32+
// Should not call onChange again for same value
33+
expect(onChange).toHaveBeenCalledTimes(1);
34+
setValue(4);
35+
expect(onChange).toHaveBeenCalledWith(4);
36+
expect(onChange).toHaveBeenCalledTimes(2);
37+
});
38+
39+
it('should call onChange when value changes (controlled)', () => {
40+
const value = ref(2);
41+
const onChange = vi.fn();
42+
useControlledState(value, 1, onChange)[1](5);
43+
expect(onChange).toHaveBeenCalledWith(5);
44+
expect(value.value).toBe(2);
45+
value.value = 6;
46+
expect(value.value).toBe(6);
47+
});
48+
49+
it('should warn and call onChange for function callback', () => {
50+
const value = ref(undefined);
51+
const onChange = vi.fn();
52+
const [state, setValue] = useControlledState(value, 1, onChange);
53+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
54+
setValue((prev: number) => prev + 1);
55+
expect(warnSpy).toHaveBeenCalledWith(
56+
'Function callbacks are not supported. See: https://github.com/adobe/react-spectrum/issues/2320'
57+
);
58+
expect(state.value).toBe(2);
59+
expect(onChange).toHaveBeenCalledWith(2);
60+
warnSpy.mockRestore();
61+
});
62+
63+
it('should warn when switching between controlled and uncontrolled', async () => {
64+
const value = ref<number | undefined>(undefined);
65+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
66+
useControlledState(value, 1);
67+
value.value = 10;
68+
await nextTick();
69+
expect(warnSpy).toHaveBeenCalledWith(
70+
expect.stringContaining('WARN: Component changed from uncontrolled to controlled')
71+
);
72+
value.value = undefined;
73+
await nextTick();
74+
expect(warnSpy).toHaveBeenCalledWith(
75+
expect.stringContaining('WARN: Component changed from controlled to uncontrolled')
76+
);
77+
warnSpy.mockRestore();
78+
});
79+
});

packages/hooks/src/useCookieState/__tests__/index.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ describe('useCookieState', () => {
2020
const [message, setMessage] = useCookieState('test', {
2121
defaultValue: undefined,
2222
})
23-
expect(message.value).toBeUndefined
23+
expect(message.value).toBeUndefined()
2424

2525
setMessage('false')
2626
expect(message.value).toEqual('false')

0 commit comments

Comments
 (0)