Testing
- Unit — vitest (
vp test) for the protocol codec, plugin router, RPC messenger, and transports; JUnit for the Kotlin host; XCTest for the Swift host. - Type check —
tsc --noEmit(part ofvp check). - Integration — Playwright e2e against the mock transport exercising the
real binary protocol (
npm run test:e2e:web). - Multi-instance harness — a dev harness hosting N worklet instances behind
a management server, asserting per-instance isolation + lifecycle
(
npm run test:e2e:harness). - Native end-to-end —
npm run test:iosruns the Swift host’s XCTest suite plus a UI test on the iOS simulator (discovery list, Ping / Payload Echo / Roundtrip / Storage permission); the Android emulator job runs theReferenceJourneyTestWebView journey. - Host invariants —
security.android.test.tsandsecurity.apple.test.tsread the host sources and manifests for thedocs/security.md§5 invariants;error-codes-parity.test.tschecks that the Kotlin and SwiftErrorCodesmatchcore/messages.
Real-stack e2e (loopback origin)
Section titled “Real-stack e2e (loopback origin)”The mock-transport suite proves the protocol, not the real stack. The consumer app additionally runs an end-to-end pass over the built web app served by the worklet’s own loopback server — the same-origin topology that runs on device.
- Boot the worklet serving the built web app. Build the web app, bundle
the worklet entry, and start it with the web-assets directory mounted at
/(dev mode:createWorkletRuntime({ webAssets, deviceMode: false }), auth off, port 8080). - Drive Playwright against the loopback origin —
http://127.0.0.1:8080, not the Vite dev server. The page, its WebSocket (same-origin cookie login), and its media URLs all come from one server, exactly like on device. - Assert every rendered photo actually decoded. Wait for
img.complete && img.naturalWidth > 0on every<img>; a 200 response with corrupt bytes fails here becausenaturalWidthstays0. - Assert no console errors. Fail the spec on any
console.erroror uncaught exception.
const errors: string[] = [];page.on('console', (msg) => { if (msg.type() === 'error') errors.push(msg.text());});page.on('pageerror', (err) => errors.push(String(err)));
await page.goto('http://127.0.0.1:8080/');
await expect .poll(() => page .locator('img') .evaluateAll((imgs) => imgs.every((img) => img.complete && img.naturalWidth > 0), ), ) .toBe(true);expect(errors).toEqual([]);This catches regressions a mock suite cannot: corrupt served images, directive
crashes in the real render tree (e.g. dereferencing a useStore marker — see
Web Rendering), and stuck-loading wedges that only
appear against the real backend.
Contract test
Section titled “Contract test”contract.test.ts freezes the package.json exports keys, the exported
value names of each @ekrooh/bare subpath, and the built type surface
(dist/*.d.mts, snapshotted in api/public-api.d.mts.snap), so an accidental
break of a stability boundary fails CI as a test, not a review note. After an
intended, reviewed change: npm run build:pkg && npm run api:snapshot. The
Kotlin API (android/api/bare-host.api, ./gradlew :bare-host:apiDump) and
the Swift API (ios/public-api.swift.snap, vp test security.apple.test.ts -u)
are pinned the same way.
npm run build:pkg # compile dist/ — prerequisitevp check # format + lint + type-checkvp test # unit testsnpm run docs:check # docs links, imports, snippet type-checknpm run test:e2e:web