node/lib/internal/test_runner/tests_stream.js
cjihrig 4e61c22699
test_runner: expose location of tests
This commit adds each test's line and column number to the reporter
output. This will aid in debugging test suite failures when error
stacks are not helpful, test suites are large, or tests have the
same name. This data is also exposed on the spec reporter.

This commit also replaces the filename that was previously being
reported, with the filename where the test actually exists. These
are normally correct, but could be wrong if tests were run from
a file other than the user's entrypoint.

PR-URL: https://github.com/nodejs/node/pull/48975
Fixes: https://github.com/nodejs/node/issues/48457
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
2023-08-11 09:12:49 -04:00

149 lines
2.8 KiB
JavaScript

'use strict';
const {
ArrayPrototypePush,
ArrayPrototypeShift,
Symbol,
} = primordials;
const Readable = require('internal/streams/readable');
const kEmitMessage = Symbol('kEmitMessage');
class TestsStream extends Readable {
#buffer;
#canPush;
constructor() {
super({ __proto__: null, objectMode: true });
this.#buffer = [];
this.#canPush = true;
}
_read() {
this.#canPush = true;
while (this.#buffer.length > 0) {
const obj = ArrayPrototypeShift(this.#buffer);
if (!this.#tryPush(obj)) {
return;
}
}
}
fail(nesting, loc, testNumber, name, details, directive) {
this[kEmitMessage]('test:fail', {
__proto__: null,
name,
nesting,
testNumber,
details,
...loc,
...directive,
});
}
ok(nesting, loc, testNumber, name, details, directive) {
this[kEmitMessage]('test:pass', {
__proto__: null,
name,
nesting,
testNumber,
details,
...loc,
...directive,
});
}
plan(nesting, loc, count) {
this[kEmitMessage]('test:plan', {
__proto__: null,
nesting,
count,
...loc,
});
}
getSkip(reason = undefined) {
return { __proto__: null, skip: reason ?? true };
}
getTodo(reason = undefined) {
return { __proto__: null, todo: reason ?? true };
}
enqueue(nesting, loc, name) {
this[kEmitMessage]('test:enqueue', {
__proto__: null,
nesting,
name,
...loc,
});
}
dequeue(nesting, loc, name) {
this[kEmitMessage]('test:dequeue', {
__proto__: null,
nesting,
name,
...loc,
});
}
start(nesting, loc, name) {
this[kEmitMessage]('test:start', {
__proto__: null,
nesting,
name,
...loc,
});
}
diagnostic(nesting, loc, message) {
this[kEmitMessage]('test:diagnostic', {
__proto__: null,
nesting,
message,
...loc,
});
}
stderr(loc, message) {
this[kEmitMessage]('test:stderr', { __proto__: null, message, ...loc });
}
stdout(loc, message) {
this[kEmitMessage]('test:stdout', { __proto__: null, message, ...loc });
}
coverage(nesting, loc, summary) {
this[kEmitMessage]('test:coverage', {
__proto__: null,
nesting,
summary,
...loc,
});
}
end() {
this.#tryPush(null);
}
[kEmitMessage](type, data) {
this.emit(type, data);
// Disabling as this going to the user-land
// eslint-disable-next-line node-core/set-proto-to-null-in-object
this.#tryPush({ type, data });
}
#tryPush(message) {
if (this.#canPush) {
this.#canPush = this.push(message);
} else {
ArrayPrototypePush(this.#buffer, message);
}
return this.#canPush;
}
}
module.exports = { TestsStream, kEmitMessage };