YouBothAgent▾
You — Business rules and flows you own. Read these yourself.
Both — Know the idea; your agent follows the details.
Agent — Conventions and references your agent follows. Look up as needed.
General▾
Interface▾
Observability▾
Testing
In an Akan app, start testing from signals. A signal test checks the real business flow through the generated
fetch before you spend time on UI details.Words used on this page
TermDescription
signal test
A test that calls your endpoints through the generated
fetch, against a real test server.fixture
A reusable function that prepares what a test needs, such as a record or a signed-in user.
agent
A test user bundled with a
fetch that is already signed in as that user.Always two files
A signal suite is always two files, and the split is not a matter of taste:
Fixtures
<model>.signal.spec.tsReusable fixtures built on
sampleOf(cnst.XInput), each with a declared return type and no assertions. Other modules import from it.Assertions
<model>.signal.test.tsdescribe("<Model> Signal"), let fixtures at describe scope, one beforeAll, and it blocks in story order.- Both files sit beside the module they cover. For example,
lib/article/holdsarticle.signal.spec.tsandarticle.signal.test.ts. - One fetch reaches the whole flow. Signup, permission, validation and state transitions are all checked through it.
Steps
Spec File: Building Fixtures
A spec file builds agents and sample data. The
fetch it hands back is flat, so a call reads agent.fetch.createArticle(...), never a namespace per model.akanjs/test helperDescription
getOrSetupSignalTestFetch
Returns the test server's signed-out
fetch, starting the server on the first call.sampleOf
Fills every field of a constant class with a sample value, using the field's default when set.
sample
Makes one random value at a time, such as an email or a string of a given length.
Changes the test server's settings, covered in the Test File section below.
1. Agent types live in one place
Agent types are re-exported and re-typed only in
lib/user/user.signal.spec.ts. It binds the shared agents to your app's fetch:apps/myapp/lib/user/user.signal.spec.ts
- Import agent types from here only. Other specs and tests import
UserAgentandAdminAgentfrom../user/user.signal.spec, not from the lib that owns them. - An agent is a signed-up user with a signed-in fetch.
getUserAgentWithPhonereturns{ user, fetch, accessToken, userInput }, andgetUserAgentWithPassworddoes the same with an email and password. - Two users in one file? Call
getUserAgentWithPassword()twice. Each call signs up a new random email, while a secondgetUserAgentWithPhone()reuses the same phone number and fails.
2. The model's fixtures
A model's spec builds on those agents. Every fixture declares its return type:
apps/myapp/lib/article/article.signal.spec.ts
- Override only what the test is about. Spread
sampleOf(...)and change one field, likestatus: "draft". - The guest fetch is signed out.
getOrSetupSignalTestFetch()returns the plainfetch, which is how a test plays a visitor.
Test File: Writing Assertions
The test file carries every assertion. Fixtures are
let bindings at describe scope, so each it picks up where the previous one left off:apps/myapp/lib/article/article.signal.test.ts
- One
beforeAllprepares the cast. Agents are created once and shared by everyit. itblocks run in story order. Create, then publish, then try what must be refused.- A refusal is
await expect(p).rejects.toThrow(). When a guard refuses the call, thefetchpromise rejects. - Each test file starts on an empty database. Files get their own test server, so they never see each other's data.
Changing the test server
The test server uses an in-memory SQLite database by default. To change a setting, call
configureSignalTest at the top of the test file:apps/myapp/lib/article/article.signal.test.ts
storage"memory" | "tempFile"default "memory"
tempFile keeps SQLite in a temporary file instead of memory, deleted after the run.portnumberdefault 38080 + worker id
The port the test server listens on.
- Call it before any fixture runs. Once the test server has started,
configureSignalTestthrows.
What To Test
A signal test file usually covers these five kinds of behaviour:
KindExamples
Happy path
Create, update, publish, archive.
Permission
A guest cannot publish, the owner can edit, an admin can remove.
Validation
Missing title, invalid date, duplicated
accountId.State transition
draft to published, pending to approved.External dependency
File upload, payment callback, message publish.
Command
Run tests from the workspace root with
akan test. It prepares the target, then runs bun test --isolate inside it:Terminal
<target>app | lib | pkg
The app, library or package to test, such as
myapp or shared.--writebooleandefault true
false skips writing generated code before an app's tests run.Running in another database mode
A signal suite runs in
single mode. To run it in multiple or cluster, name the mode and the services it needs:Terminal
multipleneedsAKAN_TEST_REDIS_URL,clusteralsoAKAN_TEST_POSTGRES_URL. Each test file starts on an emptied Redis database and a Postgres schema of its own, dropped afterwards.- The Postgres user must be able to create schemas and roles. The one
akan dbup --mode clusterstarts can. - Only
AKAN_TEST_DATABASE_MODEpicks the mode. AnAKAN_DATABASE_MODEleft in your shell does not reach the suite.
Which command to use
Command
Signal tests
apps · libs
Package tests
pkgs
Use
akan test <target>
✓
✓
Run from the workspace root. It passes
--isolate for you.bun test --isolate
✓
Fine inside a package directory, but a signal test cannot find its app this way.
Never
bun test
Without
--isolate, test files share one global object and break each other.✓WorksDoes not work
Signal test target is not configured.means a signal test ran withoutakan test. Run it again throughakan test <app-or-lib>.


Never run plain
bun test. Without --isolate, every test file shares one global object and dozens of tests fail from cross-file state pollution. bunfig.toml's [test] isolate is not honored, and running it from the workspace root also breaks subprocess stdio pipes.Tips
- Create data through signals when possible. The test then follows the same rules as the app.
- Keep the spec free of assertions. A fixture that asserts fails somebody else's suite, for a reason their file does not show.
- Test one important behaviour per
itblock. A failure then names exactly what broke.