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.
[
{
"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
node packages/block-cli/cli.js test ./my-blockA 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:
node packages/block-cli/cli.js preview ./my-block ./sample.jsonUse 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:
--mockturns them on. A folder withtests/mocks.jsonuses 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.jsonrecords your own answers. Every section is optional, and a
list answers successive calls in order (the last one repeats):
{
"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; passing one Block’s fixtures alone does not establish workflow compatibility.