-
-
Notifications
You must be signed in to change notification settings - Fork 32.3k
test_runner: write timestamp as first line in watch mode #59153
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
test_runner: write timestamp as first line in watch mode #59153
Conversation
Ensure that the timestamp emitted by TestsStream#timeStamp() is always written as the first line when watch mode is active. This improves clarity in test restarts under --watch, making logs easier to follow. Refs: nodejs#57206
Review requested:
|
// This event emitter logs a timestamp whenever a test restarts because of changes in any related files. | ||
timeStamp(type, data) { | ||
process.stdout.write(`\n[${new Date().toLocaleString('en-GB').replace(',', '')}] INFO: Test restarted\n`); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should emit an event, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, timestamp event.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to call kEmitMessage in order to actually emit the event.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh, I see. I will correct that.
something like this:
opts.root.reporterkEmitMessage;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not quite, in the timeStamp
function, you should call this[kEmitMessage]
. Look at the other methods for reference
// Emit the 'test:restarted' event if a timeStamp reporter is available. | ||
if (opts.root?.reporter?.timeStamp) { | ||
opts.root.reporter.timeStamp('test:restarted', { __proto__: null, file }); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a case where timeStamp won't be callable? I don't think so?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, there is no case, because it is only called when the --watch flag is used, and the only condition for it to be triggered is when there is a change in the test file or the file being tested.
But what if there is no actual change in the test case result? It still runs regardless.
This goes beyond the scope of this issue. I would have to modify the working process of file_watcher.js for the --watch flag so that --watch would not be triggered unless there is a change in the actual test result — based on a comparison with the previous result (from the code being tested).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you misunderstood. I'm saying you don't need the if
clause since there isn't a case where that function isn't callable (it's never undefined)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, yeah, it is never undefined. I will take that out.
Thanks for the feedback.
is this not something that needs to be worked on tho?
But what if there is no actual change in the test case result? It still runs regardless.\nThis goes beyond the scope of this issue. I would have to modify the working process of file_watcher.js for the --watch flag so that --watch would not be triggered unless there is a change in the actual test result — based on a comparison with the previous result (from the code being tested).
common.mustCall(() => { | ||
reporter.timeStamp('test:restarted', { file: 'dummy.js' }); | ||
})(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are calling the mustCall, you should make the event's callback the mustCall instead (on(something, common.mustCall())
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you are right. I would also have to add about three lines of code that make actual changes to the file being tested.
But this cuts off the test and restarts it. There no way for me to make an actual change to the file being tested without the test execution not generating an error.
Previous Detail: this run on --watch
Here is the previous test code I wrote:
const fs = require('fs');
const { run } = require('internal/test_runner/runner');
const { parseCommandLine } = require('internal/test_runner/utils');
const { join } = require('path');
const common = require('../common');
const assert = require('assert');
const testFile = join(__dirname, '../fixtures/test-runner/test_only.js');
const options = {
...parseCommandLine(),
globPatterns: [testFile],
watch: true,
isolation: 'process',
cwd: __dirname,
};
const reporter = run(options);
let timeStampCalled = false;
reporter.timeStamp = common.mustCall((type, data) => {
assert.strictEqual(type, 'test:restarted');
assert.ok(data.file);
timeStampCalled = true;
});
reporter.on('test:summary', common.mustCall((data) => {
assert.ok(data);
assert.ok(typeof data.success === 'boolean');
assert.ok(timeStampCalled, 'Expected timeStamp to be called before summary');
}));
// Trigger file change after 500ms to activate watch mode
setTimeout(() => {
fs.appendFileSync(testFile, '\n');
}, 500);
// Failsafe timeout
setTimeout(() => {
if (!timeStampCalled) {
console.error('[Test] FAIL: timeStamp() was not called in time');
process.exit(1);
}
}, 3000);
if (opts.root?.reporter?.timeStamp) { | ||
opts.root.reporter.timeStamp('test:restarted', { __proto__: null, file }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @OkunadeNaheem , we already have the restart event being dispatched here
node/lib/internal/test_runner/runner.js
Line 525 in 97dbb79
opts.root.reporter[kEmitMessage]('test:watch:restarted'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do I utilise the timestamp feature?
Tho I saw that some changes were made by @JacopoPatroclo but I did not see how to utilise, so I thought the changes was not a solution for the timestamp feature.
timeStamp(type, data) { | ||
process.stdout.write(`\n[${new Date().toLocaleString('en-GB').replace(',', '')}] INFO: Test restarted\n`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that this logic should be placed as part of the reporters, as a user might want to avoid this message in their report
// Flags: --expose-internals | ||
'use strict'; | ||
|
||
const common = require('../common'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that we might want to test the output of the runner instead of the TestsStream
itself!
I added an event emitter ->timestamp in tests_stream.js file and then call the event emitter timestamp whenever the --watch is triggered through restartTestFile() in runner.js file
timestamp eventemitter being called then logs the timestamp message(current date and time) in this format
[21/07/2025 21:24:13] INFO: Test restarted
Refs: #57206