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 task-oriented walkthroughs.
createTestingAdapter @vuqs/core/adapters/testing
Builds a QueryAdapter backed by an in-memory ref, so a composable can run in tests without a router.
function createTestingAdapter(options?: TestingAdapterOptions): TestingAdapterParameters
options?: TestingAdapterOptionssearchParams?: string | URLSearchParams | ParsedQuery: the initial query, default{}. A query string (with or without?), aURLSearchParams, 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 write with the next query and resolved options. Wire it to a spy to assert on URL changes.hasMemory?: boolean: defaultfalse. Whentrue, each write updatesqueryso later reads build on it. Whenfalse,querystays frozen atsearchParamsand each write is independent.defaultOptions?: QueryAdapterDefaultOptions: app-wide defaults at the bottom of the precedence chain.
Returns
adapter: TestingAdapter- A
QueryAdapterwhosequeryis exposed as aRef<ParsedQuery>, so a test can readadapter.query.valueto assert the URL state directly. - Pass it to
installQueryAdapterorprovideQueryAdapter.
- A
Example
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.
function withVuqsTestingAdapter(options?: TestingAdapterOptions): (app: App) => voidParameters
options?: TestingAdapterOptions- The same options as
createTestingAdapter.
- The same options as
Returns
plugin: (app: App) => void- A Vue plugin. When you also need the adapter reference (to read
adapter.query.value), callcreateTestingAdapterand install it yourself instead.
- A Vue plugin. When you also need the adapter reference (to read
Example
import { mount } from '@vue/test-utils'
import { withVuqsTestingAdapter } from '@vuqs/core/adapters/testing'
mount(MyComponent, {
global: { plugins: [withVuqsTestingAdapter({ searchParams: '?count=42' })] },
})resetQueues @vuqs/core/adapters/testing
Clears the module-level update queue shared by every engine, so pending writes from one test do not leak into the next. Takes no arguments and returns nothing.
function resetQueues(): voidExample
import { resetQueues } from '@vuqs/core/adapters/testing'
import { beforeEach } from 'vitest'
beforeEach(() => {
resetQueues()
})Also re-exported from the core (@vuqs/core) for convenience.
Testing-adapter types @vuqs/core/adapters/testing
interface UrlUpdateEvent {
query: ParsedQueryRaw // the query the adapter would write
options: NavigateOptions // the resolved navigation options
}
type OnUrlUpdateFunction = (event: UrlUpdateEvent) => voidisCodecBijective @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.
function isCodecBijective<T>(codec: Codec<T>, serialized: ParsedQueryValue, input: T): booleanParameters
codec: Codec<T>- The codec under test.
serialized: ParsedQueryValue- The codec's canonical serialized form of
input.
- The codec's canonical serialized form of
input: T- The value
serializedshould parse back to, compared bycodec.eq.
- The value
Returns
booleantruewhenserialize(input)equalsserialized,parse(serialized)equalsinput, and both directions round-trip. Otherwise throws, naming the side that broke.
Example
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).
function testSerializeThenParse<T>(codec: Codec<T>, input: T): booleanParameters
codec: Codec<T>- The codec under test.
input: T- The value to serialize and parse back.
Returns
booleantrueon a clean round-trip. Throws if the codec rejects its own serialized output, or if the round-tripped value differs.
Example
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).
function testParseThenSerialize<T>(codec: Codec<T>, serialized: ParsedQueryValue): booleanParameters
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.
- The codec's canonical raw form. A non-canonical input like
Returns
booleantrueon a clean round-trip. Throws ifparserejects the input, or if the re-serialized value differs.
Example
import { testParseThenSerialize } from '@vuqs/core/testing'
expect(testParseThenSerialize(codecs.integer, '42')).toBe(true)
expect(() => testParseThenSerialize(codecs.integer, 'not-a-number')).toThrow()