Skip to content

API: testing ​

Utilities for testing code that uses vuqs. Both subpaths are dev-only: they are never imported by your app code. See the Testing guide for examples.

createTestingAdapter @vuqs/core/adapters/testing ​

Builds a QueryAdapter backed by an in-memory ref, so a composable can run in tests without a router.

ts
function createTestingAdapter(options?: TestingAdapterOptions): TestingAdapter

Parameters

  • options?: TestingAdapterOptions
    • searchParams?: string | URLSearchParams | ParsedQuery: the initial query, default {}. A query string (with or without ?), a URLSearchParams, or a query object. Dot-notation keys nest into objects the way the core resolves paths; repeated keys collapse into arrays.
    • onUrlUpdate?: OnUrlUpdateFunction: invoked once per flushed navigation with the next query and resolved options. Several coalesced transactions produce one callback. Wire it to a spy to assert on URL changes.
    • hasMemory?: boolean: default false. When true, each navigation updates query so later reads build on it. When false, query stays frozen at searchParams and each navigation is independent.
    • defaultOptions?: QueryAdapterDefaultOptions: app-wide defaults at the bottom of the precedence chain.

Returns

  • adapter: TestingAdapter
    • A QueryAdapter whose query is exposed as a Ref<ParsedQuery>, so a test can read adapter.query.value to assert the URL state directly.
    • resetQueue(): void discards this adapter's pending optimistic writes and scheduled navigation. Fresh adapter instances are isolated automatically.
    • Pass it to installQueryAdapter or provideQueryAdapter.

Example

ts
import { codecs, installQueryAdapter, useQueryState } from '@vuqs/core'
import { createTestingAdapter } from '@vuqs/core/adapters/testing'
import { createApp } from 'vue'

const adapter = createTestingAdapter({ searchParams: '?count=42' })
const app = createApp({})
installQueryAdapter(app, adapter)

const count = app.runWithContext(() => useQueryState('count', codecs.integer.withDefault(0)))
expect(count.value).toBe(42)

withVuqsTestingAdapter @vuqs/core/adapters/testing ​

Returns a Vue plugin that builds a testing adapter and installs it on an app, for use with @vue/test-utils' global.plugins.

ts
function withVuqsTestingAdapter(options?: TestingAdapterOptions): (app: App) => void

Parameters

Returns

  • plugin: (app: App) => void
    • A Vue plugin. When you also need the adapter reference (to read adapter.query.value), call createTestingAdapter and install it yourself instead.

Example

ts
import { mount } from '@vue/test-utils'
import { withVuqsTestingAdapter } from '@vuqs/core/adapters/testing'

mount(MyComponent, {
  global: { plugins: [withVuqsTestingAdapter({ searchParams: '?count=42' })] },
})

resetQueue @vuqs/core/adapters/testing ​

Clears pending writes for one testing adapter. Use it only when a test reuses an adapter and needs to discard a scheduled navigation. A new adapter owns a fresh runtime and needs no global cleanup.

ts
interface TestingAdapter {
  resetQueue(): void
}

Example

ts
import { createTestingAdapter } from '@vuqs/core/adapters/testing'

const adapter = createTestingAdapter()
// Schedule a write through a composable using adapter.
adapter.resetQueue()

Testing-adapter types @vuqs/core/adapters/testing ​

ts
interface UrlUpdateEvent {
  query: ParsedQueryRaw // the query the adapter would write
  options: NavigateOptions // the resolved navigation options
}

type OnUrlUpdateFunction = (event: UrlUpdateEvent) => void

isCodecBijective @vuqs/core/testing ​

The full bijectivity check for a custom codec: both round-trip directions hold, and the serialized/parsed forms match the expected values.

ts
function isCodecBijective<T>(codec: Codec<T>, serialized: ParsedQueryValue, input: T): boolean

Parameters

  • codec: Codec<T>
    • The codec under test.
  • serialized: ParsedQueryValue
    • The codec's canonical serialized form of input.
  • input: T
    • The value serialized should parse back to, compared by codec.eq.

Returns

  • boolean
    • true when serialize(input) equals serialized, parse(serialized) equals input, and both directions round-trip. Otherwise throws, naming the side that broke.

Example

ts
import { isCodecBijective } from '@vuqs/core/testing'

expect(isCodecBijective(codecs.integer, '42', 42)).toBe(true)
expect(() => isCodecBijective(codecs.integer, '42', 47)).toThrow()

testSerializeThenParse @vuqs/core/testing ​

Checks one direction: parse(serialize(input)) equals input (by codec.eq).

ts
function testSerializeThenParse<T>(codec: Codec<T>, input: T): boolean

Parameters

  • codec: Codec<T>
    • The codec under test.
  • input: T
    • The value to serialize and parse back.

Returns

  • boolean
    • true when the round-trip succeeds. Throws if the codec rejects its own serialized output, or if the round-tripped value differs.

Example

ts
import { testSerializeThenParse } from '@vuqs/core/testing'

expect(testSerializeThenParse(codecs.integer, 42)).toBe(true)
expect(() => testSerializeThenParse(codecs.integer, Number.NaN)).toThrow()

testParseThenSerialize @vuqs/core/testing ​

Checks the other direction: serialize(parse(serialized)) equals serialized (structurally).

ts
function testParseThenSerialize<T>(codec: Codec<T>, serialized: ParsedQueryValue): boolean

Parameters

  • codec: Codec<T>
    • The codec under test.
  • serialized: ParsedQueryValue
    • The codec's canonical raw form. A non-canonical input like '007' round-trips to '7' and is reported as a mismatch by design.

Returns

  • boolean
    • true when the round-trip succeeds. Throws if parse rejects the input, or if the re-serialized value differs.

Example

ts
import { testParseThenSerialize } from '@vuqs/core/testing'

expect(testParseThenSerialize(codecs.integer, '42')).toBe(true)
expect(() => testParseThenSerialize(codecs.integer, 'not-a-number')).toThrow()

Released under the MIT License.