Skip to content

Commit a622d9b

Browse files
authored
test: Move relevant e2e tests to be unit tests (#802)
1 parent ab99d7d commit a622d9b

File tree

10 files changed

+542
-221
lines changed

10 files changed

+542
-221
lines changed

.vscode/settings.json

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
{
2+
"editor.tabSize": 2,
3+
"editor.insertSpaces": true,
24
"githubPullRequests.queries": [
35
{
46
"label": "Backlog",

packages/e2e/next/cypress/e2e/clearOnDefault.cy.js

-10
This file was deleted.

packages/e2e/next/cypress/e2e/repro-599.cy.js

-18
This file was deleted.

packages/e2e/next/src/app/app/clearOnDefault/page.tsx

-60
This file was deleted.

packages/e2e/next/src/app/app/repro-599/page.tsx

-27
This file was deleted.

packages/nuqs/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@
156156
"@types/react": "catalog:react19",
157157
"@types/react-dom": "catalog:react19",
158158
"@vitejs/plugin-react": "^4.3.3",
159+
"@vitest/coverage-v8": "^2.1.8",
159160
"next": "15.0.3",
160161
"react": "catalog:react19",
161162
"react-dom": "catalog:react19",
+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import { act, renderHook } from '@testing-library/react'
2+
import { describe, expect, it, vi } from 'vitest'
3+
import {
4+
withNuqsTestingAdapter,
5+
type OnUrlUpdateFunction
6+
} from './adapters/testing'
7+
import { parseAsArrayOf, parseAsJson, parseAsString } from './parsers'
8+
import { useQueryState } from './useQueryState'
9+
10+
describe('useQueryState: referential equality', () => {
11+
const defaults = {
12+
str: 'foo',
13+
obj: { initial: 'state' },
14+
arr: [
15+
{
16+
initial: 'state'
17+
}
18+
]
19+
}
20+
21+
const useTestHookWithDefaults = (
22+
{ defaultValue } = { defaultValue: defaults.str }
23+
) => {
24+
const str = useQueryState('str', parseAsString.withDefault(defaultValue))
25+
const obj = useQueryState(
26+
'obj',
27+
parseAsJson<any>(x => x).withDefault(defaults.obj)
28+
)
29+
const arr = useQueryState(
30+
'arr',
31+
parseAsArrayOf(parseAsJson<any>(x => x)).withDefault(defaults.arr)
32+
)
33+
return { str, obj, arr }
34+
}
35+
36+
it('should have referential equality on default values', () => {
37+
const { result } = renderHook(useTestHookWithDefaults, {
38+
wrapper: withNuqsTestingAdapter()
39+
})
40+
const { str, obj, arr } = result.current
41+
expect(str[0]).toBe(defaults.str)
42+
expect(obj[0]).toBe(defaults.obj)
43+
expect(arr[0]).toBe(defaults.arr)
44+
expect(arr[0][0]).toBe(defaults.arr[0])
45+
})
46+
47+
it('should keep referential equality when resetting to defaults', async () => {
48+
const { result } = renderHook(useTestHookWithDefaults, {
49+
wrapper: withNuqsTestingAdapter({
50+
searchParams: {
51+
str: 'foo',
52+
obj: '{"hello":"world"}',
53+
arr: '{"obj":true},{"arr":true}'
54+
}
55+
})
56+
})
57+
await act(() => {
58+
const { str, arr, obj } = result.current
59+
str[1](null)
60+
obj[1](null)
61+
return arr[1](null)
62+
})
63+
const { str, arr, obj } = result.current
64+
expect(str[0]).toBe(defaults.str)
65+
expect(obj[0]).toBe(defaults.obj)
66+
expect(arr[0]).toBe(defaults.arr)
67+
expect(arr[0][0]).toBe(defaults.arr[0])
68+
})
69+
70+
it('should keep referential equality when unrelated keys change', async () => {
71+
const { result } = renderHook(useTestHookWithDefaults, {
72+
wrapper: withNuqsTestingAdapter({
73+
searchParams: {
74+
str: 'foo',
75+
obj: '{"hello":"world"}'
76+
// Keep arr as default
77+
}
78+
})
79+
})
80+
const initialObj = result.current.obj[0]
81+
const initialArr = result.current.arr[0]
82+
await act(() => {
83+
const { str } = result.current
84+
return str[1]('bar')
85+
})
86+
const { str, obj, arr } = result.current
87+
expect(str[0]).toBe('bar')
88+
expect(obj[0]).toBe(initialObj)
89+
expect(arr[0]).toBe(initialArr)
90+
})
91+
92+
it('should keep referential equality when default changes for another key', () => {
93+
const { result, rerender } = renderHook(useTestHookWithDefaults, {
94+
wrapper: withNuqsTestingAdapter()
95+
})
96+
expect(result.current.str[0]).toBe('foo')
97+
rerender({ defaultValue: 'b' })
98+
const { str, obj, arr } = result.current
99+
expect(str[0]).toBe('b')
100+
expect(obj[0]).toBe(defaults.obj)
101+
expect(arr[0]).toBe(defaults.arr)
102+
expect(arr[0][0]).toBe(defaults.arr[0])
103+
})
104+
})
105+
106+
describe('useQueryState: clearOnDefault', () => {
107+
it('honors clearOnDefault: true by default', async () => {
108+
const onUrlUpdate = vi.fn<OnUrlUpdateFunction>()
109+
const { result } = renderHook(
110+
() => useQueryState('test', parseAsString.withDefault('default')),
111+
{
112+
wrapper: withNuqsTestingAdapter({
113+
searchParams: '?test=init',
114+
onUrlUpdate
115+
})
116+
}
117+
)
118+
await act(() => result.current[1]('default'))
119+
expect(onUrlUpdate).toHaveBeenCalledOnce()
120+
expect(onUrlUpdate.mock.calls[0]![0].queryString).toEqual('')
121+
})
122+
123+
it('supports clearOnDefault: false (hook level)', async () => {
124+
const onUrlUpdate = vi.fn<OnUrlUpdateFunction>()
125+
const useTestHook = () =>
126+
useQueryState(
127+
'a',
128+
parseAsString.withDefault('default').withOptions({
129+
clearOnDefault: false
130+
})
131+
)
132+
const { result } = renderHook(useTestHook, {
133+
wrapper: withNuqsTestingAdapter({
134+
searchParams: '?a=init',
135+
onUrlUpdate
136+
})
137+
})
138+
await act(() => result.current[1]('default'))
139+
expect(onUrlUpdate).toHaveBeenCalledOnce()
140+
expect(onUrlUpdate.mock.calls[0]![0].queryString).toEqual('?a=default')
141+
})
142+
143+
it('supports clearOnDefault: false (call level)', async () => {
144+
const onUrlUpdate = vi.fn<OnUrlUpdateFunction>()
145+
const useTestHook = () =>
146+
useQueryState(
147+
'a',
148+
parseAsString.withDefault('default').withOptions({
149+
clearOnDefault: true
150+
})
151+
)
152+
const { result } = renderHook(useTestHook, {
153+
wrapper: withNuqsTestingAdapter({
154+
searchParams: '?a=init',
155+
onUrlUpdate
156+
})
157+
})
158+
await act(() => result.current[1]('default', { clearOnDefault: false }))
159+
expect(onUrlUpdate).toHaveBeenCalledOnce()
160+
expect(onUrlUpdate.mock.calls[0]![0].queryString).toEqual('?a=default')
161+
})
162+
})

0 commit comments

Comments
 (0)