Use in CI
Run the same application test on a fresh World for each CI job, with exact dependencies and cleanup after success or failure. This example uses published packages and ordinary CLI commands; no platform account, private GitHub action or real vendor key is needed.
Save a test that uses the real SDK
Use Node 22.6 or newer and npm in an empty directory. Save package.json:
{
"name": "ci-app",
"private": true,
"type": "module",
"dependencies": { "stripe": "17.7.0" },
"devDependencies": {
"@volter/world": "3.0.63",
"@volter/twin-stripe": "3.0.1"
}
}Save .env.example with an empty credential:
STRIPE_SECRET_KEY=Save ci.test.mjs:
import { test } from 'node:test';
import assert from 'node:assert/strict';
import Stripe from 'stripe';
test('the real SDK creates and reads a customer', async () => {
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
const made = await stripe.customers.create({ email: 'ci@example.com' });
assert.equal((await stripe.customers.retrieve(made.id)).email, 'ci@example.com');
assert.equal((await stripe.customers.list({ email: 'ci@example.com' })).data.length, 1);
});
test('an untwinned destination is refused by the cooperating client', async () => {
await assert.rejects(fetch('https://api.example.com/v1/anything'));
});Install and generate the config locally; review the detected vendor before keeping it:
npm install
npx volter world init --name ci-appCommit package.json, package-lock.json, and the project-owned config, seeds and handlers in
.volter/. Its ignore file keeps running state out. Installation needs registry access.
Walk the job locally
npx volter world up --sandbox
npx volter world clock set 2026-01-15T12:00:00Z
npx volter world run -- node --test --test-reporter=tap ci.test.mjs# pass 2
# fail 0Sandbox mode refuses untwinned destinations in cooperating clients. It is not enforced network isolation for arbitrary binaries. The second assertion exercises a Node fetch refusal; see sandbox mode for the boundary.
npx volter world log
npx volter world downcustomer.create
Stopped ci-appThis local walkthrough exercises the commands. It does not establish that a hosted CI workflow has run or that repository settings are configured.
Put the commands in GitHub Actions
Save this as .github/workflows/world-tests.yml in your application repository:
name: World tests
on: [push, pull_request]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 24 }
- run: npm ci
- run: npx volter world up --sandbox
- run: npx volter world clock set 2026-01-15T12:00:00Z
- run: npx volter world run -- node --test --test-reporter=tap ci.test.mjs
- run: npx volter world log
if: failure()
- run: npx volter world down
if: always()This is application CI, not the catalog's assessment or publication workflow. Each fresh
checkout gets its own local simulated World. On a self-hosted runner with retained state,
reset the task-owned World deliberately before the next suite; ordinary up resumes it.
Stop app consumers before teardown. Use separate checkout roots for shards that need isolated data.
Parallel workers
Use the isolated CI workers cookbook for a downloadable two-worker example. Each worker installs from the same lockfile into its own fresh temporary checkout root, initializes a uniquely named World, freezes its own clock and runs the same assertion. Separate names alone are insufficient if application state is shared.
The script stops each World in finally, attempts teardown after a failed boot, preserves diagnostics and returns nonzero when either work or teardown fails. Browser suites should give each worker its own app service, database and session too; one shared APP_URL defeats that isolation. On hosted Actions, use a matrix with a fresh runner checkout per job and keep the existing if: always() cleanup step.
Work from a team's World
If your tests need shared history instead of synthetic defaults, work from a shared World. That flow requires the shared URL and an appropriately scoped token supplied by your team; it is separate from the credential-free local job above. Use the hosted product explains platform access. Run a full stack adds application services and browser tests to the local job.