# Testing and versions

> Lint in the sandbox as you type, run fixtures against mocks, then save, approve, activate and roll back.

Source: https://shopfa.st/docs/plugins/testing

## Lint

The workbench compiles your draft in the sandbox as you type and reports, with line numbers:

- syntax errors;
- names the sandbox does not have (`os`, `io`, `require`, `load`…), with what to use instead;
- globals written or read at load time (declare them `local`);
- missing hook functions for the plugin's kind;
- loops with no way out;
- `manifest.json` problems, checked against the same schema the API uses.

Saving refuses a draft with errors. Warnings do not block.

## Fixtures

A fixture is a sample input with what you expect back. Edit them in `fixtures.json` next to your code:

```json
[
  {
    "name": "Accepts a signed callback",
    "hook": "verify_callback",
    "input": { "method": "POST", "headers": { "x-signature": "…" }, "query": {}, "body": "{…}" },
    "settings": { "webhook_secret": "whsec_test" },
    "http": [{ "url": "https://api.example-pay.com/*", "method": "POST", "status": 200, "body": "{\"id\":\"pay_42\"}" }],
    "kv": { "invoice:5521": "{\"amount\":2499}" },
    "expect": { "status": "paid", "amount_minor": 2499 },
    "expectError": null
  }
]
```

- `expect` is a **partial** match: every key you list must equal the output (arrays by position).
- `expectError` expects the run to fail with a message containing that text.
- `http` mocks answer `http.fetch`; a URL ending in `*` matches by prefix. **Tests never reach the network**: a request
  no mock matches fails.
- `kv` seeds an in-memory store that is thrown away after the run. Secrets come from the fixture's `settings`, never
  from the store's real secrets.

**Run tests** (⌘↵) runs the unsaved draft. Each result shows the output, the HTTP calls, the logs and the run's
metrics (wall time, CPU, instructions, peak memory). Templates and catalog packages come with fixtures that pass.

## Versions

**Save version** (⌘S) stores the source and manifest as a new immutable version with a note. Then:

- **Activate** a version to make it live. If its permissions differ from what was approved, the owner or an admin
  approves them in the same step.
- **Roll back** by activating an older version. It is instant.
- **Turn off** stops the plugin; its versions, settings and data stay.

Every run (tests and live) is kept for 14 days with its version, status, error, logs and metrics.
