How Sounding works
A trial is one named behavior check in a real Sails runtime.
Sounding keeps the standard test() API. The docs use trial as the term for one test case.
If you want the full concept model, read Trials.
Sounding works by booting a real Sails app, creating deterministic setup for the current trial, and exposing the helpers that match the layer under test.
The runtime in five steps
1. Sounding boots your app
When a trial starts, Sounding boots your Sails app in test mode and exposes its public testing runtime on sails.sounding.
The hook is intentionally conservative about when it activates. By default, Sounding only boots when sounding.environments includes the current Sails environment, and the default list is ['test'].
That runtime is where the rest of the system hangs together:
- app lifecycle
- world loading
- auth helpers
- mailbox capture
- request and browser orchestration
2. Sounding resolves a datastore strategy
Sounding supports three datastore modes:
managedprovisions a temporarysails-sqlitedatastore under.tmp/dbinherituses the app's existing test datastore configexternalvalidates and uses a separately managed test datastore
Tests keep the same helper, request, and browser APIs regardless of the selected mode.
3. Sounding loads a world
Sounding loads a named world from tests/factories and tests/scenarios.
If you want those layers in detail, read Factories, Scenarios, and Worlds.
That means:
- factories define the primitive record shapes
- traits express meaningful variants like
publisherorsubscriber - scenarios compose those pieces into a situation like
issue-accessorpublisher-editor - the resolved world is what the trial actually uses
A world includes:
- actors such as guests, publishers, subscribers, or admins
- records like issues, subscriptions, teams, or unlocks
- the relationships between them
- the current business situation the trial cares about
Use readable handles like current.users.subscriber and current.issues.gatedIssue, not vague keys like user1 or record2.
4. Sounding furnishes the right test surface
Each trial receives the real Sails runtime plus the helpers that match the layer under test.
One part of that surface is transport:
- virtual requests through
sails.request()when we want fast, app-aware trials - real HTTP requests when parity with the live HTTP stack matters more
If you want the full request and visit surface, read Request clients and transport.
Transport selection resolves in this order:
- a per-call override like
get('/health', { transport: 'http' }) - a per-trial override like
test('...', { transport: 'http' }, ...) - the default from
config/sounding.js
And when a trial wants to stay explicit without changing every alias, it should be able to scope a client with sails.sounding.request.using('http').
From there, the furnished context stays simple:
sailsis the real app runtimesails.helpers,sails.models, andsails.configstay canonicalsails.soundingexposes worlds, mailbox capture, and request orchestration- top-level aliases like
get(),post(), andvisit()exist for the most common flows visit()understands Inertia-specific request headers like partial reloads without introducing a second testing API- browser-capable trials can additionally destructure
page
5. Sounding reports what mattered
When a trial fails, the output should identify:
- which world was loaded
- which actor was in play
- which request or browser step failed
- which part of app state was relevant
As a hook, Sounding can access
As a Sails hook, Sounding can understand and expose:
- helpers
- actions
- policies
- routes
- Waterline models
- sessions and auth
- Inertia responses
- jobs and realtime over time
What a trial context means
A trial is the behavior being proved. A trial context is the single object Sounding passes into test() so a behavior can be proved inside a real app runtime.
It is the environment the current trial runs inside:
sailsis the real app runtimesails.helpers,sails.models,sails.config, andsails.hooksstay canonicalsails.soundingexposes Sounding-specific capabilities like the world engine, mailbox, and request orchestration- top-level aliases like
get(),post(), andvisit()exist only as ergonomic shortcuts expectis always available for assertions
When the docs say “trial context,” they mean the real Sails runtime plus a small set of testing helpers.
Core conventions
Sounding is built around a few simple conventions:
sailsis the real runtime object in every trialsails.soundingis where Sounding-specific capabilities live- top-level aliases like
get()andpost()are conveniences, not a separate system - worlds describe business situations, not random fixtures
- heavier tools should only appear when a trial really needs them