React Testing & Parity Scorecard

Parity with the Blazor portal is enforced by tests at three altitudes: the registry (does the React pack cover the Blazor control vocabulary?), the renderer (do the components actually render and bind?), and the portal end-to-end (do real documentation pages render through the React SPA against a live mesh?).

1. The parity ratchet — render/parity.test.ts

clients/react/src/render/parity.test.ts pins the authoritative Blazor vocabulary: the *Control / *Skin types in src/MeshWeaver.Layout (the $type is the class name minus the suffix). When a new control is added to Layout, its $type is added to the list — and the test fails until the React pack covers it, keeping the port at 1:1:

it("the placeholder long-tail only ever shrinks", () => {
  const pinned: string[] = [];
  expect([...placeholderControlTypes].sort()).toEqual(pinned.sort());
});

Adding a new placeholder fails here — every new control must ship a real implementation. A companion test (the un-placeholdered controls are all real, distinct components) further asserts those five are real, distinct React components, so none may regress to a shared badge.

2. The vitest suites

cd clients/react && npm test        # renderer + controls
cd clients/grpc-web && npm test     # transport + thread submission

In clients/react/src:

Suite Covers
area/pointer.test.ts, area/source.test.ts JSON pointer resolution, RFC 7396 merge-patch, the StaticAreaSource contract (optimistic updates)
render/core.test.tsx The renderer core in jsdom: $type dispatch, skin popping, binding resolution, event emission
render/parity.test.ts The ratchet above
render/gallery.test.tsx Rendering the control gallery
controls/dialog.test.tsx, controls/itemTemplate.test.tsx, controls/threadChat.test.tsx Per-control behavior — the chat suite covers thread watching, queued bubbles, composer gating, submission
theme/theme.test.tsx The Blazor-compatible localStorage contract, mode resolution, cross-instance sync
live/grpcSource.test.ts Folding the live wire: Full snapshots, RFC 6902 patch arrays, JSON-encoded instance keys, event posting

In clients/grpc-web/src: envelope.test.ts (delivery JSON build/parse), connection.test.ts (the Connect+Deliver split, ack, demux), mesh.test.ts (the ops surface), threads.test.ts (the startThread / submitMessage wire shapes and guards).

The server side of the split has its own C# round-trip test: MeshGrpcTransportTest.WebSplit_request_round_trips_via_connect_and_deliver (test/MeshWeaver.Hosting.Grpc.Test) proves a request posted through the unary Deliver comes back down the server-streaming Connect.

3. The E2E scorecard — ReactDocViewsTest

test/MeshWeaver.Portal.E2E.Test/ReactDocViewsTest.cs is the doc-views-through-React scorecard: it drives Playwright at {E2E_BASE_URL}/app/#/{docPath} for every documentation page with embedded interactive examples — the same page list the Blazor-side DocExamplesRenderTest covers — and asserts each page reaches real rendered content through the React SPA over live gRPC-web.

One Playwright detail worth knowing when writing similar tests: never wait for NetworkIdle against the SPA — it holds the gRPC-web Connect stream open for its whole life, so the network never goes idle.

E2E_REACT=true dotnet test test/MeshWeaver.Portal.E2E.Test \
  --filter "FullyQualifiedName~ReactDocViewsTest" --no-restore
Reconnecting…
The server was updated. Reloading the page to pick up the latest version.