DEV Community

Cover image for The ultimate Node Test Runner + TypeScript + ENV variables guide
Bosco Domingo
Bosco Domingo

Posted on • Updated on

The ultimate Node Test Runner + TypeScript + ENV variables guide

TL;DR

Check the GitHub Gist I made

Introduction

This also works in a monorepo ;). If you're working on a single project, adapt the paths accordingly. The expected folder structure is the following:

ts-project/
├── tsconfig.json
└── apps/
    └── app-1/
        ├── tsconfig.json
        ├── package.json
        └── test/
            └── tsconfig.json
Enter fullscreen mode Exit fullscreen mode

This allows modern IDEs to detect the different configs per folder and correctly adapt to them. It also allows for shared/common TS options + custom ones per app.

Dependencies

First install tsx and glob:

# Use whatever package manager you prefer
pnpm add -D tsx glob

# For a single app in a monorepo
# pnpm add -F your-app -D tsx glob

# For the global package.json in a monorepo
# pnpm add -wD tsx glob
Enter fullscreen mode Exit fullscreen mode

Environment variables

Assuming you want environment variable control, create a .env and a .env.test at the root of the app you want to configure (optional, since Node throws an error if they don't exist, although I'm working on it and you can use --env-file-if-exists from Node 22.9.0 onwards in such cases).

Scripts

Add this to your app's package.json:

Node >=22.9.0 (if you want optionality for the .env files)

"scripts": {
    //...
    "test": "glob -c \"tsx --env-file-if-exists .env --env-file-if-exists .env.test --test --test-reporter spec \" \"./test/**/*.test.ts\"",
    //...
}
Enter fullscreen mode Exit fullscreen mode

Node < 22.9.0:

"scripts": {
    //...
    "test": "glob -c \"tsx --env-file .env --env-file .env.test --test --test-reporter spec \" \"./test/**/*.test.ts\"",
    //...
}
Enter fullscreen mode Exit fullscreen mode

What that test script does is:

  1. load your .env and .env.test files (the latter overwrites the former in case of conflict),
  2. asks glob to process the "./test/**/*.test.ts\" (which will load all Typescript files in the ./test folder ending in .test.ts),
  3. runs the tests via tsx with a human-readable output (--test-reporter spec). This last step is equivalent to node --import tsx --test.

TS Configs

Finally, adapt your tsconfig.jsons to include your tests if you want imports, linting and others:

// app-1/tsconfig.json
// Needed because VS Code and other IDEs
// use it to decide which files to
// apply the base config's rules
{
    "extends": "../../tsconfig.json", // Base monorepo tsconfig
    "compilerOptions": {
//      If "outDir": "${configDir}/dist", not already present
//      in the base config. Otherwise you can delete `compilerOptions`
        "outDir": "./dist"
    },
    "include": ["./src/**/*"],
}
Enter fullscreen mode Exit fullscreen mode
// app-1/test/tsconfig.json
{
    "extends": "../tsconfig.json", // Your app's tsconfig (file above). Can also be the base monorepo tsconfig
    "compilerOptions": {
        "noEmit": true,
        "allowImportingTsExtensions": true
        // These don't work with Node Test Runner, but do with Bun. Purely optional QoL
        // "baseUrl": ".", 
        // "paths": {
        //  "@src/*": ["../src/*"]
        //},
    },
    "include": ["./**/*"]
}
Enter fullscreen mode Exit fullscreen mode

Final words

And that should be it, really. Hope it is of help when setting up your TypeScript testing environment!

For more information on setup and other user's info, check this GitHub issue.

I also made a GitHub Gist to go along with this guide which will probably be more up-to-date than this article. Check it out just in case!


Changelog

Update 2024-09-18: My PR adding --env-file-if-exists landed and was released in Node 22.9.0, so if you are using any version equal or higher, you can use that new flag for the env files! I've updated the post accordingly

Update 2024-09-23: Updated the tsconfig.jsons to use a better structure based on my own experience:

Note: I have come up with a better way for tsconfig.jsons setup, find it in the aforementioned Gist. The reason for this is having the baseUrl and paths set up in your tsconfig.json will also affect imports in the source code, which doesn't work with Node (but does with Bun) plus it works better to have a base app/tsconfig.json and a app/test/tsconfig.json (at least with VS Code).

Top comments (0)