Skip to content

Commit

Permalink
test: Move relevant e2e tests to be unit tests (#802)
Browse files Browse the repository at this point in the history
  • Loading branch information
franky47 authored Dec 11, 2024
1 parent ab99d7d commit a622d9b
Show file tree
Hide file tree
Showing 10 changed files with 542 additions and 221 deletions.
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
{
"editor.tabSize": 2,
"editor.insertSpaces": true,
"githubPullRequests.queries": [
{
"label": "Backlog",
Expand Down
10 changes: 0 additions & 10 deletions packages/e2e/next/cypress/e2e/clearOnDefault.cy.js

This file was deleted.

18 changes: 0 additions & 18 deletions packages/e2e/next/cypress/e2e/repro-599.cy.js

This file was deleted.

60 changes: 0 additions & 60 deletions packages/e2e/next/src/app/app/clearOnDefault/page.tsx

This file was deleted.

27 changes: 0 additions & 27 deletions packages/e2e/next/src/app/app/repro-599/page.tsx

This file was deleted.

1 change: 1 addition & 0 deletions packages/nuqs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@
"@types/react": "catalog:react19",
"@types/react-dom": "catalog:react19",
"@vitejs/plugin-react": "^4.3.3",
"@vitest/coverage-v8": "^2.1.8",
"next": "15.0.3",
"react": "catalog:react19",
"react-dom": "catalog:react19",
Expand Down
162 changes: 162 additions & 0 deletions packages/nuqs/src/useQueryState.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import { act, renderHook } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import {
withNuqsTestingAdapter,
type OnUrlUpdateFunction
} from './adapters/testing'
import { parseAsArrayOf, parseAsJson, parseAsString } from './parsers'
import { useQueryState } from './useQueryState'

describe('useQueryState: referential equality', () => {
const defaults = {
str: 'foo',
obj: { initial: 'state' },
arr: [
{
initial: 'state'
}
]
}

const useTestHookWithDefaults = (
{ defaultValue } = { defaultValue: defaults.str }
) => {
const str = useQueryState('str', parseAsString.withDefault(defaultValue))
const obj = useQueryState(
'obj',
parseAsJson<any>(x => x).withDefault(defaults.obj)
)
const arr = useQueryState(
'arr',
parseAsArrayOf(parseAsJson<any>(x => x)).withDefault(defaults.arr)
)
return { str, obj, arr }
}

it('should have referential equality on default values', () => {
const { result } = renderHook(useTestHookWithDefaults, {
wrapper: withNuqsTestingAdapter()
})
const { str, obj, arr } = result.current
expect(str[0]).toBe(defaults.str)
expect(obj[0]).toBe(defaults.obj)
expect(arr[0]).toBe(defaults.arr)
expect(arr[0][0]).toBe(defaults.arr[0])
})

it('should keep referential equality when resetting to defaults', async () => {
const { result } = renderHook(useTestHookWithDefaults, {
wrapper: withNuqsTestingAdapter({
searchParams: {
str: 'foo',
obj: '{"hello":"world"}',
arr: '{"obj":true},{"arr":true}'
}
})
})
await act(() => {
const { str, arr, obj } = result.current
str[1](null)
obj[1](null)
return arr[1](null)
})
const { str, arr, obj } = result.current
expect(str[0]).toBe(defaults.str)
expect(obj[0]).toBe(defaults.obj)
expect(arr[0]).toBe(defaults.arr)
expect(arr[0][0]).toBe(defaults.arr[0])
})

it('should keep referential equality when unrelated keys change', async () => {
const { result } = renderHook(useTestHookWithDefaults, {
wrapper: withNuqsTestingAdapter({
searchParams: {
str: 'foo',
obj: '{"hello":"world"}'
// Keep arr as default
}
})
})
const initialObj = result.current.obj[0]
const initialArr = result.current.arr[0]
await act(() => {
const { str } = result.current
return str[1]('bar')
})
const { str, obj, arr } = result.current
expect(str[0]).toBe('bar')
expect(obj[0]).toBe(initialObj)
expect(arr[0]).toBe(initialArr)
})

it('should keep referential equality when default changes for another key', () => {
const { result, rerender } = renderHook(useTestHookWithDefaults, {
wrapper: withNuqsTestingAdapter()
})
expect(result.current.str[0]).toBe('foo')
rerender({ defaultValue: 'b' })
const { str, obj, arr } = result.current
expect(str[0]).toBe('b')
expect(obj[0]).toBe(defaults.obj)
expect(arr[0]).toBe(defaults.arr)
expect(arr[0][0]).toBe(defaults.arr[0])
})
})

describe('useQueryState: clearOnDefault', () => {
it('honors clearOnDefault: true by default', async () => {
const onUrlUpdate = vi.fn<OnUrlUpdateFunction>()
const { result } = renderHook(
() => useQueryState('test', parseAsString.withDefault('default')),
{
wrapper: withNuqsTestingAdapter({
searchParams: '?test=init',
onUrlUpdate
})
}
)
await act(() => result.current[1]('default'))
expect(onUrlUpdate).toHaveBeenCalledOnce()
expect(onUrlUpdate.mock.calls[0]![0].queryString).toEqual('')
})

it('supports clearOnDefault: false (hook level)', async () => {
const onUrlUpdate = vi.fn<OnUrlUpdateFunction>()
const useTestHook = () =>
useQueryState(
'a',
parseAsString.withDefault('default').withOptions({
clearOnDefault: false
})
)
const { result } = renderHook(useTestHook, {
wrapper: withNuqsTestingAdapter({
searchParams: '?a=init',
onUrlUpdate
})
})
await act(() => result.current[1]('default'))
expect(onUrlUpdate).toHaveBeenCalledOnce()
expect(onUrlUpdate.mock.calls[0]![0].queryString).toEqual('?a=default')
})

it('supports clearOnDefault: false (call level)', async () => {
const onUrlUpdate = vi.fn<OnUrlUpdateFunction>()
const useTestHook = () =>
useQueryState(
'a',
parseAsString.withDefault('default').withOptions({
clearOnDefault: true
})
)
const { result } = renderHook(useTestHook, {
wrapper: withNuqsTestingAdapter({
searchParams: '?a=init',
onUrlUpdate
})
})
await act(() => result.current[1]('default', { clearOnDefault: false }))
expect(onUrlUpdate).toHaveBeenCalledOnce()
expect(onUrlUpdate.mock.calls[0]![0].queryString).toEqual('?a=default')
})
})
Loading

0 comments on commit a622d9b

Please sign in to comment.