Strict Mode & Manual Registration
By default, @artstesh/postboy-testing runs in non‑strict mode: you can fire, subscribe, or execute any message type without pre‑registration. It’s quick and perfect for getting started.
Strict mode flips this — every message type must be explicitly registered in the mock registry before use. This mirrors a disciplined production setup where all types are known upfront, and it catches configuration mistakes early.
Enabling strict mode
Pass { strict: true } to the PostboyWorld constructor:
If a message type is not registered, any attempt to use it (fire, sub, exec) will throw an error from the underlying PostboyService. That error points you directly to the missing registration.
world.registry – your registration toolbox
In strict mode you still can use given functions 'cause they register the appropriate messages, but also, for specific cases, world.registry becomes your assistant during the Arrange phase. It’s an instance of PostboyAbstractRegistrator bound to the mock namespace, and it provides all the standard registration methods you’d use in production.
recordSubject(type)
Registers a plain Subject for fire‑and‑forget messages and callback messages.
Use this for most PostboyGenericMessage and PostboyCallbackMessage types.
recordReplay(type, bufferSize?)
Registers a ReplaySubject that replays the last bufferSize messages to any new subscriber. The default buffer size is 1.
Ideal for events that represent state (e.g., “current user”) where late subscribers still need the latest value.
recordBehavior(type, initialValue?)
Registers a BehaviorSubject that requires an initial value and emits the current value to new subscribers.
recordExecutor(type, handlerFn)
Registers an executor (a synchronous operation) with a handler function.
You can also register a handler class via recordHandler, but for mocking, a direct function is usually more convenient.
recordWithPipe(type, subject, pipeFactory?)
The most flexible option: register a custom Subject (or any Observable) and optionally apply an RxJS pipe.
This is an advanced feature — you’ll rarely need it in tests, but it’s there for edge cases.
A complete strict‑mode test
Here’s how a test looks when every type is registered explicitly:
Without the recordSubject and recordExecutor calls, the test would fail with a registration error — saving you from a silent misconfiguration.
When to use strict mode
Strict mode is particularly valuable when:
Your production code uses a
PostboyAbstractRegistratorto register all messages upfront, and you want the test to validate that every used type is properly declared.You want to catch typos in message type references (e.g., importing the wrong constructor).
Multiple developers work on the same codebase, and you want an automatic guard against missing registrations.
You treat your tests as partial integration checks that mirror the real bus wiring.
For quick unit tests that isolate a single class, non‑strict mode is often sufficient. Both modes are fully supported — choose what fits your team’s testing philosophy.
Best practices
Register inside
beforeEach— keep the registration close to the test setup so it’s clear which types are needed.Don’t over‑register — only declare types the test actually uses. This keeps each test’s dependency list explicit.
Remember cleanup —
world.dispose()removes the mock namespace and all registrations. No lingering state across tests.
Next steps
You now understand how to enforce strict registration. Combine this knowledge with:
Then: full assertion API – all verification methods in detail.
Given: mock setup – learn how to mock callbacks, executors, and pre‑sent events.
Async testing with
waiter— wait for events in strict‑mode tests.Recipes — real‑world patterns with explicit registration.