# Test and preview a Block

Verify behavior, input/output contracts, and sample execution before import.

## Fixtures are part of the package
Include 1–50 fixtures. Each names an input object and the complete expected output object. Defaults and optional ports still follow the declared contract.
```json
[
  {
    "name": "Counts words",
    "input": {
      "text": "  Hello StillMade  "
    },
    "expected": {
      "text": "Hello StillMade",
      "words": 2
    }
  },
  {
    "name": "Empty text",
    "input": {
      "text": "  "
    },
    "expected": {
      "text": "",
      "words": 0
    }
  }
]
```

## Run the fixture suite
```sh
node packages/block-cli/cli.js test ./my-block
```
A test report includes `passed`, `digest`, `sdkVersion`, and individual results. Fixtures execute the real package runtime. Matching JSON output is required; approximate image similarity is not used.

## What to cover
- Ordinary input with a useful, observable result.
- Empty text or minimum-size images, when the contract allows them.
- Boundary values for controls.
- Behavior that preserves unrelated data, colors, or alpha.
- Values that the next Block will actually consume.

## Preview with your own sample
Save a JSON input object as `sample.json` and run:
```sh
node packages/block-cli/cli.js preview ./my-block ./sample.json
```
Use synthetic input in distributed packages. Private project material belongs in local samples, not published fixtures.

## Test offline with stand-ins
StillMade hosts part of what a Block does: hosted operations, saved files,
outside APIs and connections, cloud storage, project reads and assets. On your
own machine, `stillmade-block test`, `run` and `dev` answer these calls with
stand-ins:

- `--mock` turns them on. A folder with `tests/mocks.json` uses them every time,
  including for `pack`, which runs the fixtures first.
- Every hosted operation has a recorded stand-in with the exact shape StillMade
  returns, checked by the same validators the app uses. Text replies read
  `Stand-in reply to: <prompt>`; images are 1024-pixel PNGs (or the requested
  aspect ratio); speech, music and sound effects are short WAV tones; video is a
  one-second MP4; transcripts, research, media analysis, timeline proposals and
  JSON replies (sampled from the Block's schema) are small fixed results. Files
  a stand-in or `files.write` makes can be read back with `files.read`.
- `tests/mocks.json` records your own answers. Every section is optional, and a
  list answers successive calls in order (the last one repeats):

```json
{
  "hosted": {"text.generate": ["First reply", "Second reply"]},
  "actions": {"stock.search": {"results": []}},
  "network": [{"method": "GET", "url": "https://api.github.com/repos/octocat/hello-world/issues*", "status": 200, "json": []}],
  "connections": {"app:openapi:notion/retrievePage": {"properties": {}}},
  "files": {"clip-1": "fixtures/clip.wav"},
  "storage": {"settings": {"runs": 3}},
  "project": {"schemaVersion": 1, "metadata": {"name": "Launch"}},
  "transforms": {"video.cut": {"kind": "video", "assetId": "cut-1", "versionId": "v1", "url": "/api/media/stillmade-mock/cut.mp4", "mimeType": "video/mp4", "width": 320, "height": 180, "duration": 1, "bytes": 2048}}
}
```

| Section | Answers | Value |
| --- | --- | --- |
| `hosted` | `stillmade.hosted.run` and capability Blocks, by operation | The output value the call returns |
| `actions` | `stillmade.actions.run`, by operation | The action result (`{value, failures}` for `media.generate`) |
| `network` | `stillmade.net.fetch` | Recorded responses: method, url (a trailing `*` matches the rest), status, headers and one of `json`, `text` or `base64` |
| `connections` | `stillmade.connections.call`, by `appId/operation` | The JSON result |
| `files` | `files.read`, by asset ID or URL | A path inside the Block folder |
| `storage` | `stillmade.storage` | Values stored before the run |
| `project` | `stillmade.project.read` | A project snapshot |
| `transforms` | `stillmade.media.transform`, by operation | The transform result (`audio.decode` on a WAV file decodes it for real) |

For a capability Block, fixture checks on the model's words (`includes`,
lengths, word counts) are listed as not checked rather than run against a
stand-in; StillMade runs them with a real model when you import the Block.
Media checks (sizes, durations, formats) still run. A run with stand-ins is
never a live verification: reports say `liveVerified: false` and list every
stand-in that answered. Nothing contacts a provider or spends credits.

The same stand-ins are available to your own tests from
`@stillmade/block-sdk/mock-host`: `createMockHost({mocks, readLocalFile,
manifest})` returns `host` (pass it to `createNodeModuleExecutor({files,
host})`), `capability` (pass it to `runPackageAsync` or `testPackage` for a
capability Block), `calls` (what answered each call) and `file(url)` (the bytes
of a stand-in or written file). `standInFixtures(pkg)` returns a capability
Block's fixtures with the checks on the model's words removed and lists them;
`validateMocks(value)` checks a `tests/mocks.json` value;
`sampleJsonSchema(schema)` makes a value that satisfies a JSON schema; and
`mockPng`, `mockWav` and `mockMp4` make the stand-in media. `MOCKS_FILE` is
`tests/mocks.json` and `MOCK_MEDIA_PREFIX` is the URL prefix of stand-in media.

## Admission and workflow tests
The app also scans source and permissions, repeats contract tests in its sandbox, runs a sample, validates outputs, and requires review before installation. After insertion, [rehearse the connected workflow](/docs/project-types/testing); passing one Block’s fixtures alone does not establish workflow compatibility.
