# Testing your work (/docs/build/testing)



There is no separate test harness for blocks and integrations. Your verification loop is the running app. What matters is exercising the states your code will actually meet in production: real config, missing config, and both platforms.

## Run it where it will run [#run-it-where-it-will-run]

Test on **both platforms** before calling anything done. Layout, safe areas, keyboard behavior, and native modules all differ between iOS and Android, and a block that looks right on one can clip or crash on the other.

```bash
pnpm run-ios
pnpm run-android
```

## Exercise every config state [#exercise-every-config-state]

Blocks are configured by people, from the dashboard, so your block will eventually render with config you did not anticipate. Walk it through:

* **Full config** — everything your schema documents, filled in.
* **Partial config** — optional fields missing.
* **Empty or missing config** — the block just placed, nothing filled in yet.

A block must **fail soft**: when required config is missing, return `null` (optionally with a `console.warn`) rather than crashing the screen. A thrown render error takes the whole screen down with it.

```tsx
const source = useBlockSettings(block) as PromoBannerConfig
if (!source?.title) {
  console.warn(`[promo-banner] missing required config`)
  return null
}
```

## Test against a draft theme [#test-against-a-draft-theme]

Make config changes on a **draft** theme, never the live one — the live theme is what real shoppers see. Place your block on a draft, iterate on its `source`/`style`/`options` there, and only hand off once it behaves across the states above. [Config and theme](/docs/concepts/config-and-theme) explains the draft model.

## Verify trackers end to end [#verify-trackers-end-to-end]

For analytics trackers, local behavior is not proof. The events must arrive on your platform:

1. Run the app with your integration's settings configured.
2. Exercise the flows behind your event whitelist: view a product, add to cart, purchase.
3. Confirm each event arrives **once**, under the mapped name, with the payload you expect, in your platform's live-events or debugger view.

Remember: an unset whitelist means no events are forwarded at all. If nothing arrives, check the whitelist before anything else. [Analytics trackers](/docs/build/analytics-trackers) covers the details.

## Pre-handoff checklist [#pre-handoff-checklist]

Before you publish a package or hand work back to Appbrew:

* Works on iOS **and** Android.
* Handles full, partial, and empty config without crashing.
* No new console errors or warnings in a normal session.
* Every merchant-facing setting your manifest declares is documented, with what happens when it is unset.
* For trackers: events verified end to end on your platform.
* README updated: what the package does, its settings, its metafield requirements if any.

When all boxes tick, you are ready to [publish your package](/docs/ship/publishing-packages) or request a release.
