mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 18:25:13 +08:00
Add a log(message[, data]) method to TestContext and SuiteContext that emits a new test:log event. Unlike test:diagnostic, which is buffered so it is emitted in the order tests are defined, test:log is emitted immediately, in the order tests execute, including under process isolation where it bypasses the per-file declaration order buffer. This gives reporters that render the test tree unbuffered a live, attributed logging channel that captured stdout cannot provide under concurrency. The event carries the message, an optional opaque structured payload that the runner passes through untouched, and the emitting test's name, testId, parentId, nesting, and location. Built-in reporters render it the same way they render test:diagnostic. Signed-off-by: Moses Atlow <moshe@atlow.co.il> PR-URL: https://github.com/nodejs/node/pull/64389 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
81 lines
2.9 KiB
JavaScript
81 lines
2.9 KiB
JavaScript
// Flags: --no-warnings
|
||
import '../common/index.mjs';
|
||
import * as fixtures from '../common/fixtures.mjs';
|
||
import assert from 'node:assert';
|
||
import { spawnSync } from 'node:child_process';
|
||
import { test, run } from 'node:test';
|
||
|
||
const fixture = fixtures.path('test-runner', 'log-events', 'basic.mjs');
|
||
|
||
test('t.log() validates its arguments', (t) => {
|
||
assert.throws(() => t.log(123), { code: 'ERR_INVALID_ARG_TYPE' });
|
||
});
|
||
|
||
test('built-in reporters render test:log like diagnostics', () => {
|
||
const tap = spawnSync(process.execPath, ['--test', '--test-reporter=tap', fixture]);
|
||
assert.match(tap.stdout.toString(), /# hello/);
|
||
assert.match(tap.stdout.toString(), /# suite message/);
|
||
|
||
const spec = spawnSync(process.execPath, ['--test', '--test-reporter=spec', fixture]);
|
||
assert.match(spec.stdout.toString(), /ℹ hello/);
|
||
assert.match(spec.stdout.toString(), /ℹ warned/);
|
||
|
||
const junit = spawnSync(process.execPath, ['--test', '--test-reporter=junit', fixture]);
|
||
assert.match(junit.stdout.toString(), /<!-- hello -->/);
|
||
});
|
||
|
||
test('test:log is emitted immediately with the expected payload', async () => {
|
||
const stream = run({
|
||
files: [fixture],
|
||
isolation: 'none',
|
||
});
|
||
|
||
const logs = [];
|
||
const events = [];
|
||
|
||
stream.on('test:log', (data) => {
|
||
logs.push(data);
|
||
events.push(`log:${data.message}`);
|
||
});
|
||
|
||
stream.on('test:pass', (data) => {
|
||
events.push(`pass:${data.name}`);
|
||
});
|
||
|
||
// eslint-disable-next-line no-unused-vars
|
||
for await (const _ of stream);
|
||
|
||
assert.strictEqual(logs.length, 3);
|
||
|
||
const suiteLog = logs.find((log) => log.message === 'suite message');
|
||
assert.strictEqual(suiteLog.name, 'my suite');
|
||
assert.strictEqual(suiteLog.data, undefined);
|
||
|
||
const hello = logs.find((log) => log.message === 'hello');
|
||
assert.strictEqual(hello.name, 'logger');
|
||
assert.ok(!('level' in hello));
|
||
assert.deepStrictEqual(hello.data, { foo: 1 });
|
||
assert.strictEqual(typeof hello.nesting, 'number');
|
||
assert.strictEqual(typeof hello.testId, 'number');
|
||
assert.strictEqual(typeof hello.parentId, 'number');
|
||
assert.strictEqual(typeof hello.file, 'string');
|
||
assert.strictEqual(typeof hello.line, 'number');
|
||
assert.strictEqual(typeof hello.column, 'number');
|
||
|
||
// The runner does not interpret data; conventions like a level live there.
|
||
const warned = logs.find((log) => log.message === 'warned');
|
||
assert.ok(!('level' in warned));
|
||
assert.deepStrictEqual(warned.data, { level: 'warn', attempt: 2 });
|
||
|
||
// 'logger' logs immediately while its earlier-declared sibling 'slow' is
|
||
// still running, so the log must arrive before slow's buffered test:pass.
|
||
const logIndex = events.indexOf('log:hello');
|
||
const slowPassIndex = events.indexOf('pass:slow');
|
||
assert.notStrictEqual(logIndex, -1);
|
||
assert.notStrictEqual(slowPassIndex, -1);
|
||
assert.ok(
|
||
logIndex < slowPassIndex,
|
||
`test:log should arrive before slow's buffered test:pass; events=${events.join(', ')}`,
|
||
);
|
||
});
|