Overriding Singletons from TSyringe within Jest Tests
18 Jul 2020 - JavaScript, TypeScript, TSyringe, Jest
You might encounter some issues while trying to override singletons from TSyringe in Jest tests. Here is a quick post to help you to fix them.
Quick Overview of TSyringe
Dependency Injection (often abbreviated as D.I.), when correctly used, is one of the tools used to create modular, maintainable & testable applications. Every language has its own D.I. libraries. For example Scala users may use the powerful macros from MacWire.
In TypeScript, we have TSyringe. Here is the associated Hello World (don’t forget to enable decorators & to polyfill the Reflect API):
|
|
Dependency Injection is a design pattern used to implement Inversion of Control. One of the advantage is to not have to manually wire classes together.
Overriding injectables & usage within Jest
The library also allows us to create children dependency injection containers. Then it becomes easy to override some injectables during our tests:
|
|
Note: writing two times Foo
in .register<Foo>(Foo, NewFoo)
is not a mistake. The second one is the injection token
while the first one is here to constraint NewFoo
to have the same shape as Foo
during compilation. The generic type
parameter can be omitted if you don’t want this additional security layer (although recommended).
Issues with Singletons
TSyringe supports singletons, useful if you don’t want to create a new instance every time you call resolve
.
Unfortunately if you want to override a singleton, it will screw up everything, and you will not receive an error/warning from TSyringe (as of 4.3.0). This is because when you register a class as a singleton it is done within the global container (i.e. if you try to override it in a child container, then at the end it is overridden in all containers).
We can easily reproduce it with the following test:
|
|
Here is the associated output from Jest, where we can see the error:
|
|
As mentioned in the documentation we can easily fix this issue by adding the following snippet at the top of our test file:
|
|
Bonus point: if you do not want to add it at the top of all your test files, then you can instead add it to a file
referenced by the setupFilesAfterEnv
option from Jest
🚀.
Thoughts about using Mocks from Jest
Mocks from Jest (Manual & ES6 classes) are really powerful, well-supported & documented. Depending on your needs you may choose between the two strategies or combine them. One nice advantage of TSyringe is the ability to automatically wire all the dependencies in complex applications.