Skip to content

Verification matrix ​

A library about honest receipts should be honest about its own evidence. This page says what has been exercised and how, and what has not.

How each layer is tested ​

LayerHow it is testedWhat that does not cover
CoreUnit tests over the mock adapter, with an injected clock and fake timers.Real timers under load, real memory pressure.
Provider adaptersUnit tests over an in-process fake of each SDK, plus a shared conformance suite.Provider backends and native SDK behavior.
Sentry compositionThe installed browser SDK runs in Node through beforeSend, verifying identity and breadcrumbs on a buffered report after an account switch. pnpm test:providers sends its envelopes over its own fetch transport to a loopback receiver: the event on the wire carries the report under the event id the receipt names, and flush returns once the server answered.Browser integrations, sampling, symbolication, native scope behavior, Sentry's own ingestion.
PostHog compositionThe installed posthog-js runs in jsdom with fetch stubbed, and before_send reads each event: the merge over the person and the super properties, the exception steps, and a dropped event. pnpm test:providers lets it send over its own transport to a loopback receiver, and reads the $exception event and its uuid off the wire.Batching, compression, the React Native client, PostHog's own ingestion.
OpenTelemetry compositionThe installed @opentelemetry/sdk-logs runs with an in-memory exporter, checking that every attribute survives the SDK's validation, with the record's severity, body and capture time. pnpm test:services exports over OTLP HTTP to a real OpenTelemetry Collector in Docker and reads back what it wrote, nested attributes included.The protobuf and gRPC exporters, a batching processor, a backend behind the collector.
Bugsnag deliverypnpm test:providers runs the browser notifier of @bugsnag/js in jsdom against a loopback receiver: a report is submitted only once the server answered its delivery, and a refused delivery is failed.The React Native notifier, sessions, Bugsnag's own ingestion.
Provider SDK typingA typecheck-only contract file per adapter assigns the real SDK to the adapter's structural type.SDK versions other than the ones installed here.
HTTP adapterUnit tests over an in-process fake request, standing for the application's own client. pnpm test:providers runs it over fetch against a loopback server: the body and idempotency key on the wire, a 503, and a deadline that abandons the request.A production server, retries in a real client.
React bindingsReal React with Testing Library in jsdom, including Strict Mode, server render and hydration.A real browser, React Native's renderer.
Vue bindingsReal Vue with Vue Test Utils in jsdom, a server render in Node, and hydration of that server markup.A real browser, Nuxt.
Solid bindingsReal Solid with Solid Testing Library in jsdom, and a server render in Node.Hydration itself, a real browser, SolidStart.
Svelte bindingsReal Svelte 5 with Svelte Testing Library in jsdom, a server render in Node, and svelte-check.Hydration itself, a real browser, SvelteKit.
DevtoolsA real shadow root in jsdom, queried by role, and each wrapper rendered through its own binding. The examples' browser tests open it in Chromium through the React, Vue, Solid and Svelte wrappers and check that it lists the destinations.Resizing and pointer dragging in a real browser.
Example applicationsUnit tests in jsdom drive the React, Vue, Solid and Svelte examples through their buttons, and the fixture server over real HTTP. pnpm test:examples drives the four built pages in Chromium with Playwright at 375 and 1280 px. pnpm check:release bundles the Expo app for web, iOS and Android.Other browsers, every real provider SDK: the pages simulate them. The Expo app on a device.
Trace bridgeUnit tests over a fake event source.A real Trace, which is not released.
Published packagesThe packed tarballs are installed into a clean consumer, typechecked, imported and run end to end in Node.Bundlers other than the one used to build, Metro.
DocumentationEvery TypeScript example, except a few marked as fragments, is typechecked against the built packages.Whether an example's output matches its comment.

Provider SDK versions ​

The contract files typecheck against exactly these versions:

SDKPackageVersion checkedDeclared peer range
@sentry/browserflare-sentry10.75.08 to 10
@sentry/react-nativeflare-sentry8.27.06 to 8
@bugsnag/jsflare-bugsnag8.10.07.20 to 8
@bugsnag/react-nativeflare-bugsnag8.10.07.20 to 8
@react-native-firebase/crashlyticsflare-crashlytics26.4.022 to 26
posthog-jsflare-posthog1.434.21.434 to 1.x
posthog-react-nativeflare-posthog-react-native4.75.04.75 to 4.x
@datadog/browser-rumflare-datadog7.13.07
@datadog/mobile-react-nativeflare-datadog-react-native3.7.03
@datadog/browser-logsflare-datadog-logs7.13.07
@opentelemetry/api-logsflare-opentelemetry0.222.00.200 to 0.x

The older versions inside each range have not been typechecked or run here. The range is a statement of intent. If you use one of them and an adapter misbehaves, that is a bug worth reporting.

SDK behavior the adapters rely on ​

These were confirmed by reading the installed SDK source:

  • Sentry's withScope forks the current scope. Sentry separately merges the isolation scope into each event, then runs the fork's event processors. The real SDK test covers this ordering because a single-scope fake cannot prove it.
  • Bugsnag builds each event from a copy of the client state, and runs the notify completion callback with no error even when an onError callback discarded the event.
  • Bugsnag's clearMetadata leaves an emptied section behind.
  • React Native Firebase 26 exposes the modular API that the Crashlytics adapter calls.
  • @sentry/react-native 8 has no isInitialized, and its flush takes no timeout. Its withScope logs an error thrown inside the callback and answers undefined, which the adapter reports as failed.
  • posthog-js assigns a caller's properties over the exception's own, and merges them over its persisted properties and the distinct id on that event only. It attaches the exception steps it buffered only when the caller passes none, and clears them after a capture. The installed SDK test covers this.
  • posthog-react-native defers a capture until the client has loaded its storage, and its distinct id is empty until then. A $groups property on a capture registers groups on the client itself.
  • Datadog RUM merges its global context over an error's own attributes, skips the key __proto__ at any depth, follows cause ten levels deep, and keeps up to 500 calls made before init in a buffer of its own.
  • Datadog React Native flattens attributes into dot paths and drops every object that is neither a plain object nor an array, and the core builds sanitized data as plain objects and arrays. Before initialize, its calls wait in a bounded buffer and resolve at once.
  • Datadog's browser Logs SDK merges a log's own context over the global context and the user, skips __proto__ in that merge, follows cause, and logs "Empty message" for an error without one.
  • OpenTelemetry's @opentelemetry/sdk-logs keeps at most 128 attributes per record by default, and cuts values only past an attributeValueLengthLimit you set. The installed SDK test covers the attributes a report uses.

Reading source is weaker than running it. A fake can share its author's misunderstanding of the SDK.

Hydration ​

Every binding's status readers read idle on the server and until the component is mounted, so that server markup and the first client render agree. For React and Vue a test hydrates real server markup and asserts there is no mismatch. For Solid and Svelte the two halves are pinned separately, one test for what the server renders and one for the first value on the client, because their test setups compile a component for one side only.

Never exercised ​

  • No adapter has been run against its provider's real backend from this repository. The Sentry, PostHog, Bugsnag and HTTP transports have only reached loopback receivers that accept whatever arrives, and OpenTelemetry records only a local collector.
  • Nothing has run on an iOS or Android device, in a simulator or in Hermes. The Expo example is bundled for iOS and Android, and its web export was driven in Chromium against the fixture server once, by hand.
  • Only the example applications have run in a real browser, in Chromium, and over simulated provider SDKs. The devtools' resizing and pointer dragging have not been exercised in a browser.
  • No binding has run inside its meta-framework: Next.js, Nuxt, SolidStart or SvelteKit.
  • Crashlytics' limits of 64 custom keys and 1024 characters per value come from Firebase's documentation. They have not been observed.
  • The HTTP adapter has not been run against a production server.
  • The Datadog browser SDK did not start inside jsdom, so no test runs it. Its fake rests on reading the source, as does the fake of @datadog/browser-logs, which has not run either.
  • posthog-react-native and @datadog/mobile-react-native have never run: both need a React Native runtime.

How the tests themselves were checked ​

Tests were written before the code and watched failing. After each milestone, the code was mutated on purpose, one change at a time, to confirm that a test fails for it. A mutation that survived led to a new test or exposed a bug. This found, among others, a cross-account leak through the ambient mirror of two adapters, which is now covered.

This process is not part of continuous integration. Continuous integration runs the type checks, the linters, the unit tests on two Node and React versions and on one version each of Vue, Solid and Svelte, the provider transport tests, the collector tests in their own workflow, the packed-consumer check and the documentation checks. The examples' browser tests are not part of it.

Checking it yourself ​

sh
pnpm install
pnpm check
pnpm check:release
pnpm test:examples
pnpm test:services

The first command builds the packages and runs formatting, types, lint, the unit tests and the provider transport tests. The second adds the documentation checks, the packed-consumer check and the release metadata check. The third builds the packages and runs the examples' browser tests in Chromium, through @playwright/test. The fourth needs Docker: it starts an OpenTelemetry Collector, runs the service tests against it and stops it again.

Released under the MIT License.