Repository navigation
Global setup file for native node test runner #49732
Description
Activity
- addedfeature requestIssues requesting new Node.js features.Issues requesting new Node.js features.
on Sep 20, 2023 You should run it via 'node --require ts-node/register setup.ts'.
I use similar solution - kind of wrapper around 'run' function to setup different reporters (CI / local run), collect coverage with c8, globs for .ts files, additional loaders, etc. Because this wrapper is a package with 'bin' script named 'test', I can run tests via 'yarn test'.
Also, adding your own config (as an example, to exclude some files from coverage) is a few lines:
// wrapper let config; try { config = await import('test.config.js'); } catch { config = { /* default */ }; } run(/* your test config */) // config export default { // anything you may need }
Reacted by Benjamin Gruenbaum and Jakub ValaYeah this is just a syntax thing,
node --require ts-node/register setup.tsas it invokes the runner programatically.If you build useful stuff on top of the native test runner or notice missing features please do tell us and put it on npm if you're comfortable with it being open source :)
Reacted by Jakub ValaIf you build useful stuff on top of the native test runner or notice missing features please do tell us and put it on npm if you're comfortable with it being open source :)
In my case it's an internal and very specific package created to keep some (a lot of...) defaults inside. I believe when we get native coverage reporter (with source maps & lcov output) and globs, such wrappers will be redundant for most of us. Only one thing may be really required - some way to organize reporters (but we already have .env support, right?).
Right, and since the programatic invocation is just a Node.js file you can use whatever you want for config there :)
Yeah this is just a syntax thing,
node --require ts-node/register setup.tsas it invokes the runner programatically.If you build useful stuff on top of the native test runner or notice missing features please do tell us and put it on npm if you're comfortable with it being open source :)
Sure I'll try to come up with something
Reopening as you also can't do global teardown
Reacted by Michał Drobniak, Carlos Eduardo Hidalgo, Vito Macchia, Enzo Testa and Sergey Bekrinactually you can do:
const {tap} = require('node:test/reporters'); const process = require('node:process'); const path = require("node:path"); const {run} = require("node:test"); const {finished} = require('node:stream'); const stream = run({ files: ['./src/a.test.js', './src/b.test.js'], concurrency: false, setup: () => { console.log('setup'); } }) .compose(tap); finished(stream, () => { console.log('teardown'); }); stream.pipe(process.stdout);
But it's only for when using
runI think we should document it thoughReacted by Ernest Dolog, Luis Naranjo, Carlos Eduardo Hidalgo, urosctd, Simon Martín, Enzo Testa, reno1979 and Leonardo RaeleThere has been some discussion about Node.js as a whole supporting a configuration file. I'm not sure if that will lead to anything, but having a separate file for just the test runner would not be great.
Reacted by Moshe Atlow, Benjamin Gruenbaum, Tobias Nießen, Ernest Dolog and Michał Drobniak- addedtest_runnerIssues and PRs related to the test runner subsystem.Issues and PRs related to the test runner subsystem.
on Sep 28, 2023 But it's only for when using
runI think we should document it thoughWould be awesome to have it documented. What would be even better is to have it working with some sort of file detection, like:
files: [Application.baseDir + '/__tests__/**/*.test.ts'],My global test setup is the following:
/** * The Global Test Runner * ========= * Provides global test setup. * * Because of node test runners concurrency this is elemental. */ import './framework.setup'; import {run} from 'node:test'; import process from 'node:process'; import {tap} from 'node:test/reporters'; import {Application} from '#app/application'; const stream = run({ files: [ Application.baseDir + '/__tests__/e2e/auction-api.resolver.test.ts', Application.baseDir + '/__tests__/e2e/user-api.resolver.test.ts', Application.baseDir + '/__tests__/unit/logger.unit.test.ts', ], /** * As after integration, and e2e tests we truncate databases * This should not happen paralelly, unless we figure a way to only delete the data added at that test with a one-liner * Switch on concurrency locally for unit tests and such */ concurrency: false, }).compose(tap); stream.pipe(process.stdout);I have a couple of test suites coming. Would be nice, if all tests unit-integration-e2e could be imported with a one-liner.
Reacted by Michał Drobniak16 remaining items
So as mentioned in #54675, in Node 22.9 I managed to achieve
globalSetupandglobalTeardownfeature by using test isolationnoneandbeforehooknode --import ./globalHooks.mjs --experimental-test-isolation=none --test 'src/**/*.test.js'
globalHooks.mjs`import { after, before } from 'node:test';
before(async () => {
await startDockerContainers();
});after(async () => {
await closeDatabaseConnections();
await stopDockerContainers();
});
Works as expected 🎉 also with TypeScript (I need to test TS with ESM more though)Does it mean that adding
globalSetupandglobalTeardownhooks tonode:testis not needed anymore? I would say not necessarily. Sinceprocessis the default isolation mode, I guess people may still have a need for them. What do you think?This doesn't work as expected with async setup when
beforeis used in other tests modules:tsx --import ./tests/node/globalHooks.ts --experimental-test-isolation=none --test './**/*.test.{js,ts}'globalHooks.tsimport { after, before } from 'node:test'; async function setupDatabase() { // some async stuff }; async function seedDatabase() { // some async stuff }; async function closeDatabaseConnection() { // some async stuff }; before(async () => { console.log('before all'); await setupDatabase(); await seedDatabase(); console.log('database ready'); }); after(async () => { console.log('after all'); await closeDatabaseConnection(); console.log('connection closed'); });someFunction.test.tsimport { after, before, suite, test } from 'node:test'; async function createSomeDatabaseObjects() { // async stuff, must run after resetDatabase() }; before(async () => { console.log('before suite'); await createSomeDatabaseObjects(); // fails, database isn't ready yet console.log('database objects created'); }); after(async () => { console.log('after suite'); }); suite("Suite of someFunction", () => { test("someFunction should work as expected", () => { // some tests }); });Output:
before all before suite // should run after database ready database ready after all connection closed after suite // should run before after allAny idea? (for moment, I'm avoid using
beforeandafterin tests modules but it's quite annoying...)I found that wrapping whole module in a main
suiteworks, albeit it's nowhere written in docs that sub-suites are allowed.someFunction.test.tsimport { after, before, suite, test } from 'node:test'; async function createSomeDatabaseObjects() { // async stuff, must run after resetDatabase() }; suite("Suite of module someFunction", () => { before(async () => { console.log('before suite'); await createSomeDatabaseObjects(); // fails, database isn't ready yet console.log('database objects created'); }); after(async () => { console.log('after suite'); }); suite("Suite of someFunction", () => { test("someFunction should work as expected", () => { // some tests }); }); // other suites and tests });Output:
before all database ready before suite // ok after suite // ok after all connection closedReacted by Dieter OberkoflerThere has been no activity on this feature request for 5 months. To help maintain relevant open issues, please add the never-stale
Issues and PRs exempt from automated stale handling. label or close this issue if it should be closed. If not, the issue will be automatically closed 6 months after the last non-automated comment.
For more information on how the project manages feature requests, please consult the feature request management document.- addedstaleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
on Sep 9, 2025 - removedstaleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
on Sep 9, 2025 I found that wrapping whole module in a main
suiteworks, albeit it's nowhere written in docs that sub-suites are allowed.This would clearly be be most convenient way to solve this if all tests are in a single source file but in my use case i have multiple files that expect some resources to be available and later be be disposed.
I resolved my use case by using something like
node --import ./tests/global_hooks.ts --experimental-test-isolation=none --test --test-concurrency=1 "./tests/**/*.test.ts"but still believe that Node.js could offer a better DX by offering a configuration option to explicitly define setup and teardown like other test runner:- Jest: globalSetup and globalTeardown
- Mocha: global setup and teardown fixtures
- Vitest: globalSetup file defined in config
- Playwright: globalSetup and globalTeardown files defined in config
Reacted by Enzo TestaI resolved my use case by using something like
node --import ./tests/global_hooks.ts --experimental-test-isolation=none --test --test-concurrency=1 "./tests/**/*.test.ts"but still believe that Node.js could offer a better DX by offering a configuration option to explicitly define setup and teardown like other test runner:- Jest: globalSetup and globalTeardown
- Mocha: global setup and teardown fixtures
- Vitest: globalSetup file defined in config
- Playwright: globalSetup and globalTeardown files defined in config
Hey @doberkofler actually we now provide https://nodejs.org/api/test.html#global-setup-and-teardown!
Reacted by Jocelyn BadgleyReacted by Michał Drobniak@pmarchini that's great, thank you, but it also means yet another flag I'm having to include in my test command just to get the suite to work. Has anyone talked about a config file for all this stuff?
Hey @Twipped, we’ve introduced a new experimental feature: https://nodejs.org/api/cli.html#--experimental-config-fileconfig
.
With the experimental config file, it's possible to avoid setting all the flags via the CLI.@pmarchini excellent, thank you!
@pmarchini I've been trying to get tests to run using the
globalSetupandglobalTeardownfunctions, and I've noticed thatglobalTeardownsometimes begins to execute before all test files are finished executing without--test-concurrency=1set. Is this a known issue?Hey @alxmrtn, thanks for reporting it!
Could I please ask you to verify whether it's only a matter of output, or if the teardown actually happens before all tests complete?e.g., I would expect test failures if the DB really gets wiped before the completion of dependent tests.
(I've noticed issues with the order of the printed output before, so I'm wondering if that's the case!)
Note: I'm closing this issue, as the feature request has been completed.
If what you're reporting is actually a bug, I will ask you to open an issue with a minimal repro@pmarchini let me add some more db heavy tests and get back to you. if I keep seeing it I'll open up an issue - thanks!
Reacted by Pietro Marchini
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsAwaiting Triage

What is the problem this feature will solve?
I'm sorry if there's already such a feature and I haven't found a way how to solve this. Basically what I'm looking for is to run some function that would run beofre all the tests and setup the environment. So far the only way how to setup some environment is doing it with the run function but that is only limited for each test suite from what I've tried. I would love to have the have some setup file in the way how does it work for example in jest or mocha or other testing framework.
What is the feature you are proposing to solve the problem?
Have a
setup.js/setup.tsfile that will run before all the tests, you would somehow specify in command that starts the tests this setup file.What alternatives have you considered?
node version:
v20.6.1npm version:
9.8.1I've tried this setup file
setup.tssuite.test.tsand I'm running this command to execute tests:
node --require ts-node/register --testbut neither the setup.ts file is executed nor the suite.test.ts file is executed