Sabbagh's Blagh
The Software blog of a Development Journeyman

Typescript, Jest and Express - Oh my!

July 15, 2022

tagged: typescript, jest, unit testing

Jest is fun but also somewhat terrifying Thanks to Hello I'm Nik for making this photo available freely on unsplash 🎁

So we have an app at work that uses express on the backend. Works pretty well, does the job. But one small problem - no unit tests.

Time to get to work

I grit my teeth in preparation, knowing that setting up jest with typescript is a pain. But somebody's gotta do it. So I'm documenting this for future iterations of myself.

I'm using Jest here because mocking is great fun and really easy, and the termianl output is color-coded and doesn't require me to open up some late-2010's html.

@node/types beware

One hiccup that took me a while to resolve was that I implicitly (unintentionally, accidentally?) upped the @node/types npm package from 16.xx to 18.xx , which had the immediate effect of deleting my node_modules/@types directory. This feat was performed with such clandestine machination that no npm command I knew could restore those packages. I ended up deleting my local copy and pulling the repo again.

We're using node 16 in the project so maybe the node versions have to correlate with the node types versions? I don't know, but didn't stick around to ask.

Types and Jest

Jest does not come out-of-the-box with type definitions, so we have to install @types/jest separately. We'll also install ts-jest, which transforms our typescript-written tests into javascript for Jest to understand.

Jest can be configured with either a jest.config.ts/js or inside of package.json. I use the latter and mine looks like this:

// ...
// other package.json things
// ...
"jest": {
    "preset": "ts-jest",
    "verbose": true, 
    "collectCoverage": true,
    "coverageReporters": [
      "json",
      "text"
    ],
    "globals": {
      "ts-jest": {
        "tsconfig": "tsconfig.test.json"
      }
    }
}

The collectCoverage and coverageReporters tags are for nice charts on our build server, on which I may do a separate post later.

Note that ts-jest can be configured with its own tsconfig, not the default one that's sitting in your project. Which was a necessity for my project. I could not manage to run tests and the app code via the same tsconfig. The crux of the issue from my understanding is that two tags in the tsconfig, namely types and typeRoots, cannot both be used. Or at least, I could not get them to work properly together.

Here's the tsconfig.test.json:

{
  "extends": "",
  "compilerOptions": {
    "typeRoots": [
      "./types",
      "./node_modules/@types"
    ],
    "types": ["jest"],
    "esModuleInterop": true
  }
}

Here's the tsconfig documentation for Typescript that deals with these two properties.

Even if there is a way to get the two to play nicely in the same file, in doing so I'd be compiling jest types into our bundled app, which I don't want in any case.

Well, with that wrinkle ironed out (or at least ironed over) the last step is to get our test scripts written. Here are mine:

"scripts": {
    "test": "npx jest'",
    "test:watch": "npx jest --watch"
}

Voila! You can run a npm run test or npm run test:watch and you should see your tests run with success.

Here's the output of running the tests:

Jest wee

I'll add another post sometime with how I used Jest to mock out a database and some RxJS Observables to test our interface to Cosmos DB.

© Copyright 2024 Sabbagh's Blagh. Powered with by CreativeDesignsGuru