# Testing ChainRender (Two-Layer Harness)

ChainRender ships a two-layer test harness that catches the two distinct classes of bug in an on-chain-rendering
system: the *deterministic* class (selectors, encoding, exports, config) and the *live* class (CSP, iframe, WebGL,
wallet). Run both around every deploy.

## Layer 1 -- headless integration harness

```bash
npm run test:integration      # node scripts/integration-harness.mjs
```

Runs headless (no wallet/browser/chain needed), exits non-zero on any failure (CI-usable). It verifies the parts
that are pure functions of the code:
- **SDK bundle exports** -- catches a stale bundle (e.g. a missing `buildComposition`).
- **All hardcoded on-chain selectors** vs their canonical signatures -- catches a wrong `metaOf`/`exists`/etc.
- **Encoding** (sceneId, composition, multi-view hashes) vs viem -- catches ABI/encoding drift.
- **Config addresses** -- catches a stale registrar (V2 vs v1).
- **No-CDN invariant** -- catches a CDN dependency that a strict CSP would block.
- **Wallet-call shape** -- catches `wallet.sendTransaction` (viem) vs the EIP-1193 `wallet.request`.

It is proven to catch regressions: injecting a wrong selector makes it fail.

## Layer 2 -- browser smoke test

Open `chainrender-smoke-test.html` **on the deployed server** after each deploy. It checks the live-only surface a
headless harness cannot:
- The SDK bundle loads in a real browser and exports what it should.
- **CSP behaviour** -- whether external CDN scripts are blocked (they should be; on-chain libraries are the path).
- **Sandboxed-iframe execution** -- inline JS draws a canvas (the on-chain-p5 path); the three.js UMD-global path;
  **WebGL** (page + sandbox); **inline SVG + SMIL animation**.
- **Storage** -- IndexedDB round-trip (project store + encryption), localStorage.
- **Chain** -- `window.ethereum.request` present + chainId; raw `fetch` to the RPC; native `DecompressionStream`;
  WebCrypto.

Together the two layers cover roughly the whole path. Neither alone is "full path" -- Layer 1 is the CI gate, Layer 2
is the post-deploy live check.

## The rule

Run `npm run test:integration` **before** every deploy (it fails the build if anything drifted), and open the smoke
test **after** every deploy (it confirms the live environment). This is the safety net around the deploy workflow.


## Related
- **[The Render Pipeline](./render-pipeline.md)** — what the harness verifies end to end.
- **[Rich Media](./rich-media-p5-three.md)** — the p5/three/WebGL/CSP paths the smoke test checks.
- **[Trust Grade](./trust-grade.md)** — the grade the integration harness confirms.
