Skip to content

Testing ​

Check the container ​

Types catch most wiring mistakes, but not all. container.check() validates the rest without building anything:

It throws a HaywireContainerValidationError describing the problem, naming the bindings involved (see Debugging). Export your container, or its module, and check it in a test:

ts
export const 
appModule
=
createModule
(
bind
(
dbUrlId
).
withInstance
('postgres://localhost/app'));
// In a test
createContainer
(
appModule
).
check
();

check() is cached, and every later stage runs it first, so calling it at startup too costs nothing.

Replacing bindings ​

Each test can build its own container: there is no global registry to reset. To swap a real implementation for a fake, use module.replaceBinding(). Adding a second binding for an id is a compile error, so addBinding() can't be used.

ts
const 
fakeDatabase
: Database = {
getRowById
: () => ({
id
: 1 }) };
const
container
=
createContainer
(
appModule
.
replaceBinding
(
bind
(
databaseId
).
withInstance
(
fakeDatabase
))
);

It returns a new module, so appModule is untouched for other tests. The replacement is checked like any other binding:

  • There must already be a binding for the id.
  • It must satisfy everything that depends on the id. A nullable replacement fails if a service needs a non-null value.
  • Its own dependencies must be bound by the rest of the module.
ts
appModule
.
replaceBinding
(bind(databaseId.nullable()).withInstance(null));
Argument of type 'Binding<OutputHaywireId<HaywireId<Database, null, null, false, true, false, false, false>>, [], false>' is not assignable to parameter of type '{ error: "Error: the output is laxer than what depends on it, e.g. it is nullable but a non-null value is needed."; } & Binding<OutputHaywireId<HaywireId<Database, null, null, false, true, false, false, false>>, [], false>'. Property 'error' is missing in type 'Binding<OutputHaywireId<HaywireId<Database, null, null, false, true, false, false, false>>, [], false>' but required in type '{ error: "Error: the output is laxer than what depends on it, e.g. it is nullable but a non-null value is needed."; }'.

For a list, the replacement takes the place of every binding in the list.

The replaced binding's dependencies stay required by the module's types, even if the replacement doesn't use them. In practice the full app module already binds them.