A transport and the spy on its request, as
createMockHttpClient builds them.
An in-memory SettingManager and the spies on its writes, as
createSettingStore builds them.
The deliberate type-breach boundary — and a suite's only one: call
sites hand over values the compiled types rightly refuse (wire
payloads carrying fields the schema forbids, partial doubles standing
in for rich runtime records) because that refusal is the behavior
under test. Prefer an honest shape where one exists (mock, a
typed vi.fn signature, a zod parse); reach for cast only when the
type error is the point. The value comes back untouched, typed
never so it is assignable anywhere.
An HttpError carrying a minimal request snapshot and an empty response body — the shape the resilience policies and the session mechanism branch on.
A Logger whose two channels are vitest mocks.
Spin up a transport and a vitest spy on its request method in one
call. The class is a parameter because each SDK's transport is its
own thin HttpClient subclass — the one seating its redaction
vocabulary, and the one its instanceof resolver accepts.
An HttpError for a server-side status, messaged
Status <code>.
An in-memory SettingManager over a seeded map, with spies on
its writes. unset is delegated only on request, so a suite can
model both host shapes the setting decorator distinguishes.
An HttpError for a 401, messaged Unauthorized.
Narrows a possibly-absent value, throwing where it is absent.
The partial-double boundary: hands the overrides back as the full type, so a test names the members it exercises and nothing else.
Build a fetch-compatible Response covering the surface
HttpClient.request relies on: .status, .ok, .text() (through
parseBody), and — through readHeaders — .headers.entries() and
.headers.getSetCookie(). Nothing in the client reads
.headers.get(). A null-body status (204, 205, 304) gets the null
body the Response constructor insists on.
Routes Temporal.Now.instant() through the mocked Date.now().
temporal-polyfill v1 delegates to the native Temporal when the
runtime ships one (Node 26+), and native Temporal.Now reads the
real clock directly, bypassing vi.setSystemTime (which only patches
Date) — so a test that freezes or advances time must also route the
instant through the mocked clock. Under the polyfilled implementation
the spy is a behavioral no-op. Restore it with
vi.mocked(Temporal.Now.instant).mockRestore() next to
vi.useRealTimers().
The zoned twin of mockTemporalNowInstant, for the
Temporal.Now.zonedDateTimeISO() reads a consumer anchors its
zone-aware windows on. Restore it with
vi.mocked(Temporal.Now.zonedDateTimeISO).mockRestore() next to
vi.useRealTimers().
The vitest-backed helpers every consuming SDK's suite carried as a hand-maintained twin of this package's own — the type-breach and partial-double boundaries, the logger and setting-store doubles, the transport spy, the fetch
Responsemock, theHttpErrorfactories and the native-Temporalclock spies. It runs inside the consumer's vitest process:vitestis imported here and declared nowhere, because the SDKs install this package as a PRODUCTION dependency of the Homey apps, and a peer — optional or not — would put the test framework on the device. The root barrel never re-exports this module for the same reason.