sveltelean Query
Version v0.2.0

Import

import
import { createTestClient, reply, route, mswHandlers } from '@svelte-lean/query/testing';

Usage

src/lib/api/members.test.ts
// src/lib/api/members.test.ts
import { createMutation, createQuery } from '@svelte-lean/query';
import { createTestClient, reply } from '@svelte-lean/query/testing';
import { expect, test } from 'vitest';
import { createMember, listMembers } from '$api/members';

test('a refused invite marks the field and refetches nothing', async () => {
	const t = createTestClient();
	t.mock(listMembers, { rows: [], total: 0, page: 1, perPage: 20, lastPage: 1 }, { latency: 50 });
	t.mock(createMember, () => reply.validation({ email: 'taken' }));

	const list = createQuery(listMembers, () => ({}));
	const save = createMutation(createMember);
	t.observe(() => list.data);
	await t.advance(50);

	await save
		.run({ name: 'Mei', email: 'mei@harbor.studio', team: 'Design', role: 'member' })
		.catch(() => {});
	expect(save.error?.fields?.fields.email).toEqual(['taken']);
	expect(t.calls(listMembers)).toHaveLength(1);
	expect(t.findings()).toEqual([]);
	t.dispose();
});

Size

Production Vite builds of a small consumer entry, Svelte external. A marginal row is the bytes the entry adds over the row it names.

BuildOvergzipbrotliBudget (gzip)
testing (not shipped)–18878 B17235 B19300 B

Read from packages/query/artifacts/size.json. Every entry and its method: Performance.

Functions

Test clients, replies, MSW interop and doubles.

Exports

Runtime exports of the entry.

NameTypeDefaultDescription
# createTestClient (init?: TestClientInit) => TestClient–A fresh realm client per test; dispose it with using or t.dispose().
# mock TestClient['mock']–t.mock on the installed test client.
# reply object–Scripted answers: errors of each kind, raw bodies, meta, sequences, deferred and never.
# route (endpoint, handler, options?: MockOptions) => MswRoute–A typed handler for one endpoint, for mswHandlers() or t.mock(route).
# mswHandlers (http: MswHttpLike, base: string, routes: MswRoute[], options?: { profile? }) => unknown[]–MSW handlers built with the application's own msw http namespace; answers go through the profile.
# prng (seed: number) => () => number–A seeded random function (retry jitter in tests).
# fakeSource (options?: { ready?: 'auto' | 'manual' }) => FakeLiveSource–A LiveSource double: emit events, confirm subscriptions, report the connection.
# memoryStore () => PersistStore–A PersistStore in memory.
# persistStoreSuite (factory) => PersistStoreCase[]–The contract cases a PersistStore must pass; run them in any test runner.

reply

Members of reply; a handler returns one instead of a value.

NameTypeDefaultDescription
# network () => Reply–A network failure.
# timeout () => Reply–A timeout.
# http (status, init?: { message?, code?, retryAfter? }) => Reply–An HTTP error; 401 and 403 are forbidden, 422 validation.
# validation (fields, message?) => Reply–A 422 with field messages typed by the mutation body.
# refused (init?: { code?, message? }) => Reply–An application refusal inside a 200.
# forbidden (status?: 401 | 403) => Reply–Access withdrawn.
# parse () => Reply–An answer that fails its schema.
# never () => Reply–No answer at all.
# meta (value, meta: ResponseMeta) => Reply–A value with response meta (server-driven freshness).
# raw (status, body, headers?) => Reply–A raw body read through the profile.
# sequence (...steps) => handler–One step per call; the last repeats.
# deferred () => Deferred–A handler the test resolves or rejects by hand.

Options

TestClientInit and the mock options.

TestClientInit

Every ClientInit option except transport, clock, environment and parts, plus these.

NameTypeDefaultDescription
# parts EnginePart[] | 'lazy'allPartsEvery engine part is included up front (no loading step on the virtual clock); 'lazy' tests the path where each part arrives after the engine first asks for it.
# clock 'virtual' | 'real''virtual'real turns latency into real time (demos).
# start numberDate.UTC(2026, 0, 1)Virtual epoch.
# seed number1PRNG seed for retry jitter.
# unhandled 'error' | 'pending''error'What a request with no mock does.
# visible booleantrueInitial visibility.
# online booleantrueInitial network state.
# profile Profile–Wire mode: mocks answer server-shaped bodies through the profile.
# ssr boolean–Server mode: no realm client, inert scheduler, no retries.

MockOptions

The third argument of t.mock() and route().

NameTypeDefaultDescription
# latency Duration | ((call) => Duration)0Virtual latency.
# when (params) => boolean–Only answer matching calls.
# times number–Then fall back to the previous mock.
# ignoreAbort boolean–Resolve even after abort (tests the sequence guard).

Test client

TestClient extends Client with these members.

TestClient

Time moves only when the test moves it.

NameTypeDefaultDescription
# mock (endpoint, handler, options?) => void–Answer an endpoint: a value, a reply, or a function of the call; typed by the endpoint.
# calls (endpoint?) => Call[]–The call log, of one endpoint or all.
# pending () => PendingCall[]–Calls without an answer yet.
# advance (time: Duration) => Promise<void>–Move the virtual clock and settle what is due.
# flush () => Promise<void>–Settle what is due now.
# now () => number–The virtual time.
# observe (read: () => unknown) => () => void–Read a result in a reactive context, as a component would.
# seedEntry (endpoint, params, value, options?) => void–Put a value in the cache without a request.
# hide () => void–The document becomes hidden.
# show () => void–The document becomes visible.
# disconnect () => void–The network goes offline.
# reconnect () => void–The network comes back.
# findings () => Finding[]–Development findings; devtools() runs in every test client.
# dispose () => void–Stop the client.

Call

One entry of the call log.

NameTypeDefaultDescription
# params P–The params or input.
# cause Cause | 'mutation'–Why it was sent.
# priority 'high' | 'auto' | 'low'–Fetch priority.
# attempt number–1, then retries.
# scope Scope–The scope.
# sentAt number–Virtual send time.
# settledAt number | undefined–Virtual settle time.
# outcome 'pending' | 'success' | 'error' | 'aborted'–How it ended.
# error QueryError | undefined–The error, when it failed.

Guide

How to use it, with examples: Testing. All entry points: Svelte Lean Query.