I recently encountered a unit test that looked like this.
The use of branching and conditionals in tests is an anti-pattern since we want tests to be predictable, each test to focus on a single code execution path and generally keep things simple.
The obvious solution is to replace the conditional with
.to.not.be.undefined or the catch-all
.to.exist (less cognitive overhead). So why was this code written using an
throw in the first place?
The answer is that asserting existence of the object here causes TypeScript
error TS2532: Object is possibly 'undefined'..
This is because the implementation in chai creates an assertion object and evaluates it, then an error is thrown if the assertion fails. TypeScript can’t infer that the
.to.exist check will throw if the object is null.
This is not a new problem and a proposal for asserting control flow has been discussed in TypeScript#8655 and an implementation proposed in TypeScript#32695.
Assert Not Null
The first solution is a more elegant variation if the original
Unfortunately, TypeScript as of now doesn’t infer the conditional inside a function, either, so, you need to wrap the call and ensure it returns an object to make this option work.
We get an error instead of an assertion.
We can augment
assertNotNull with an
expect to get a proper assertion failure instead of an error.
The result is better.
Casting a Type
We can cast the result of
reticulate() and TypeScript will happily let us by.
This is problematic. If the signature of
reticulate() were to change, we would just be forcing the response to pretend to be a
Spline, getting no new compile-time errors and leaving nonsensical tests.
Finally, we can use TypeScript
! and explicitly check
This is my preferred method, but requires disabling
strictNullChecks in tests (read more about this here).
The result, in my opinion, is the cleanest.
- stackoverflow#57066536: How can I avoid an if/else in TypeScript with mocha and undefined returns?
- sample code from above
- TypeScript#8655: Control flow based type narrowing for assert(…) calls.
- TypeScript#32695: A proposed