I’ve started using ts-jest for a project at work and have really enjoyed it. It works great because you can write your tests in TypeScript and ts-jest will just compile on-the-fly then run your tests like you would expect. However, tests can easily become unreadable or harder-to-read (which isn’t limited to ts-jest, of course).

Improving Readability

In order to make the tests more readable, I am creating generic functions that I can re-use in my test cases. Here’s a test for a function that checks whether or not a string is empty:

test("Is Empty", () => {
    expect(isEmpty(" ")).toBe(true)
})

That looks fine, but once you have lots of tests even simple cases done over-and-over can make reading them as a whole much harder. So I wrapped the generic part of my tests into a re-usable function:

const expectIsEmpty = testValue => () => expect(isEmpty(testValue)).toBe(true)

Then, my tests look like:

 test("Empty String 1", expectIsEmpty(""))
 test("Empty String 2", expectIsEmpty(""))
 test("Empty String 3", expectIsEmpty(""))
 test("Empty String 4", expectIsEmpty(""))
// etc...

In this case, there is no more nesting in my tests and I can quickly read them line-by-line. By creating a function that returns another function (which has the value to test “pre-loaded” by using a closure), the tests become much more easy to read. It’s now easy to skim through the tests and get an overview of the full coverage.

Covering All Cases

I usually make two re-usable functions which represent a pass (ex. toBe(true)) vs. a fail(ex. toBe(false)):

const expectIsEmpty = testValue => () => expect(isEmpty(testValue)).toBe(true)
const expectIsNotEmpty = testValue => () => expect(isEmpty(testValue)).toBe(false)

For complex tests that have a large piece of common processing, this can improve their readability significantly. It’s not always possible to reduce a complex test to one line, but in cases where you can it does make reading a full unit test really quick and understandable. And, it makes them alot easier to maintain / extend since all (or most of) your implementation is in one place.