node
node copied to clipboard
In source / inline tests
What is the problem this feature will solve?
Sometimes you want to test a small utility function and would like to colocate the tests inside the same file as the library instead of using a separate file.
import assert from "node:assert/strict";
import test from "node:test";
export const ping = () => "pong";
// ping implementation and its tests live in the same file
test("ping", (_t) => {
assert.equal(ping(), "pong");
});
What is the feature you are proposing to solve the problem?
vitest solves this problem by having the test runner add a property to import.meta
and using it to conditionally run tests.
https://vitest.dev/guide/in-source.html
// src/index.js
// the implementation
export function add(...args) {
return args.reduce((a, b) => a + b, 0)
}
// in-source test suites
if (import.meta.vitest) {
const { it, expect } = import.meta.vitest
it('add', () => {
expect(add()).toBe(0)
expect(add(1)).toBe(1)
expect(add(1, 2, 3)).toBe(6)
})
}
I am not sure if it's the best way to achieve this but it's one way.
What alternatives have you considered?
No response
This has come up before and did not get an enthusiastic response: https://github.com/nodejs/node/issues/45771.
You can already do the same thing like this:
if (process.env.NODE_ENV === 'test') {
const test = require('node:test');
// test things
}
Code coverage may not easily reflect how much it is covered this way, the percentage will be misleading.
Fair enough. You're welcome to open a PR and see how it is received. Just to warn you ahead of time, I think you'll need to add a new CLI flag to support this in the way you're asking for, and I can envision people pushing back on that for such a niche feature.
There has been no activity on this feature request for 5 months and it is unlikely to be implemented. It will be 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.
I solved this by using/abusing process.env.NODE_TEST_CONTEXT
so the inline tests only run when --test
is used. Is there a better condition to use? Out of the box, process.env.NODE_ENV
is undefined
when using --tests
so you can't switch on it.
-
node ping.js
: Does nothing (as expected) -
node --test ping.js
: Runs the tests (as expected)
ping.js
const test = require('node:test');
const assert = require('assert');
function ping() {
return 'pong';
}
// Only run tests when using `--test` flag
if (process.env.NODE_TEST_CONTEXT) {
test('ping', () => {
assert.strictEqual(ping(), 'pong');
});
}
module.exports = ping;
I use if (process.env.NODE_ENV === "test" && require.main === module) {
"use strict";
function addTwo(a) {
return internalAdder(a, 2);
}
if (process.env.NODE_ENV === "test" && require.main === module) {
const assert = require("node:assert/strict");
const { test } = require("node:test");
test("addTwo()", () => {
assert.equal(addTwo(4), 6);
});
}
function internalAdder(a, b) {
return a + b;
}
if (process.env.NODE_ENV === "test" && require.main === module) {
const assert = require("node:assert/strict");
const { test } = require("node:test");
test("internal", () => {
assert.equal(internalAdder(2, 2), 4);
});
test("float magic", () => {
assert.equal(internalAdder(0.1, 0.2), 0.30000000000000004);
});
}
module.exports = { addTwo };
And run the tests using test_runner.js
"use strict";
const fg = require("fast-glob").sync;
const { spec } = require("node:test/reporters");
const { run } = require("node:test");
process.env.NODE_ENV = "test";
const source = ["src/**/*.js", "test/**/*.test.js"];
const ignore = [];
const files = fg(source, { ignore })
files = fg(source, { ignore });
// console.log(files);
run({ files })
.on("test:fail", () => {
process.exitCode = 1;
})
.compose(new spec())
.pipe(process.stdout);
It doesn't seem like this has gained any traction (for the second time - #45771), so I'm going to close this. Anyone is free to open a PR implementing this though.