In-source testing using Node.js Test Runner
As a general recommendation, I suggest using tsx
to transpile TypeScript files while running tests. cfg-test
also provides presets for using either ts-node
or swc
as the transpiler. Naturally, these can be customised to fit your needs.
Node.js >=18.19.0
npm i -D cfg-test tsx typescript
/your-project
├─ src
│ ├─ lib.ts
│ └─ env.d.ts
├─ package.json
└─ tsconfig.json
// src/lib.ts
// the implementation
export function addOne(a: number): number {
return a + 1
}
// in-source test suites
if (cfgTest && cfgTest.url === import.meta.url) {
const { assert, describe, test } = cfgTest
describe("addOne", () => {
test("it works", () => {
assert.equal(addOne(2), 3)
})
})
}
// src/env.d.ts
/// <reference types="cfg-test/globals" />
// package.json
{
"type": "module",
"scripts": {
"test": "tsx --import cfg-test --test ./src/**/*.ts"
},
"devDependencies": {
"cfg-test": "latest",
"tsx": "latest",
"typescript": "latest"
}
}
// tsconfig.json
{
"compilerOptions": {
"module": "NodeNext",
"moduleResolution": "NodeNext",
},
"include": [
"./src/**/*",
],
}
Then you can start to test.
npm test
Node.js | Transpiler | Type | Link |
---|---|---|---|
^18.19 | swc | ESM | examples/node18/swc/esm |
CommonJS | examples/node18/swc/cjs | ||
ts-node | ESM | examples/node18/ts-node/esm | |
CommonJS | examples/node18/ts-node/cjs | ||
tsx | ESM | examples/node18/tsx/esm | |
CommonJS | examples/node18/tsx/cjs | ||
20.x | swc | ESM | examples/node20/swc/esm |
CommonJS | examples/node20/swc/cjs | ||
ts-node | ESM | examples/node20/ts-node/esm | |
CommonJS | examples/node20/ts-node/cjs | ||
tsx | ESM | examples/node20/tsx/esm | |
CommonJS | examples/node20/tsx/cjs | ||
22.x | swc | ESM | examples/node22/swc/esm |
CommonJS | examples/node22/swc/cjs | ||
ts-node | ESM | examples/node22/ts-node/esm | |
CommonJS | examples/node22/ts-node/cjs | ||
tsx | ESM | examples/node22/tsx/esm | |
CommonJS | examples/node22/tsx/cjs |
import {
// {
// NODE_ENV: "test",
// CFG_TEST: "true",
// }
testEnv,
// {
// CFG_TEST: "false",
// CFG_TEST_URL: undefined,
// CFG_TEST_FILE: undefined,
// CFG_TEST_WATCH: "false",
// }
buildEnv,
// {
// "process.env.NODE_ENV": "\"test\"",
// "process.env.CFG_TEST": "\"true\"",
// }
testDefine,
// {
// cfgTest: "undefined",
// "process.env.CFG_TEST": "\"false\"",
// "process.env.CFG_TEST_URL": "undefined",
// "process.env.CFG_TEST_FILE": "undefined",
// "process.env.CFG_TEST_WATCH": "\"false\"",
// }
buildDefine,
} from "cfg-test/define"
import { buildDefine } from "cfg-test/define"
import { build } from "esbuild"
build({
define: {
...buildDefine,
"process.env.NODE_ENV": "\"production\"",
},
// other options
})
// vite.config.ts
import { buildDefine } from "cfg-test/define"
import { defineConfig } from "vite"
export default defineConfig({
define: {
...buildDefine,
"process.env.NODE_ENV": "\"production\"",
},
// other options
})
// rollup.config.js
import replace from "@rollup/plugin-replace"
import { buildDefine } from "cfg-test/define"
export default {
plugins: [
replace({
...buildDefine,
"process.env.NODE_ENV": "\"production\"",
}),
],
// other options
}
import { buildDefine } from "cfg-test/define"
const definePlugin = new webpack.DefinePlugin({
...buildDefine,
"process.env.NODE_ENV": "\"production\"",
})
Loaders can be added via the configuration file.
Specify the path to the configuration file in the environment variable CFG_TEST_CFG. The default value is a comma-separated list of paths: .config/cfg-test.json
, .config/cfg-test/config.json
, config/cfg-test/config
, config/cfg-test
, and cfg-test
.
// .config/cfg-test.json, .config/cfg-test/config.json,
// config/cfg-test.json, config/cfg-test/config.json, cfg-test.json
// or process.env.CFG_TEST_CFG="<your-config-path>"
{
// Additonal environment variables
"env": {
"MY_CUSTOM_ENV": "true"
},
"globals": {
// Additional global variables
"__DEV__": true
},
// Additional require modules
"require": [
"./path/to/require.js"
],
// Additional import modules
"import": [
"./path/to/import.js"
]
}