Skip to content

Commit

Permalink
test_runner: ensure test watcher picks up new test files
Browse files Browse the repository at this point in the history
  • Loading branch information
pmarchini committed Aug 7, 2024
1 parent b95eac5 commit b23a410
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 4 deletions.
19 changes: 17 additions & 2 deletions lib/internal/test_runner/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ function createTestFileList(patterns) {

function filterExecArgv(arg, i, arr) {
return !ArrayPrototypeIncludes(kFilterArgs, arg) &&
!ArrayPrototypeSome(kFilterArgValues, (p) => arg === p || (i > 0 && arr[i - 1] === p) || StringPrototypeStartsWith(arg, `${p}=`));
!ArrayPrototypeSome(kFilterArgValues, (p) => arg === p || (i > 0 && arr[i - 1] === p) || StringPrototypeStartsWith(arg, `${p}=`));
}

function getRunArgs(path, { forceExit, inspectPort, testNamePatterns, testSkipPatterns, only }) {
Expand Down Expand Up @@ -166,7 +166,7 @@ class FileTest extends Test {
if (firstSpaceIndex === -1) return false;
const secondSpaceIndex = StringPrototypeIndexOf(comment, ' ', firstSpaceIndex + 1);
return secondSpaceIndex === -1 &&
ArrayPrototypeIncludes(kDiagnosticsFilterArgs, StringPrototypeSlice(comment, 0, firstSpaceIndex));
ArrayPrototypeIncludes(kDiagnosticsFilterArgs, StringPrototypeSlice(comment, 0, firstSpaceIndex));
}
#handleReportItem(item) {
const isTopLevel = item.data.nesting === 0;
Expand Down Expand Up @@ -416,7 +416,22 @@ function watchFiles(testFiles, opts) {
const watcher = new FilesWatcher({ __proto__: null, debounce: 200, mode: 'filter', signal: opts.signal });
const filesWatcher = { __proto__: null, watcher, runningProcesses, runningSubtests };
opts.root.harness.watching = true;
// Watch for created/deleted files in the current directory
const allFilesWatcher = new FilesWatcher({ __proto__: null, debounce: 200, mode: 'all', signal: opts.signal });
allFilesWatcher.watchPath(process.cwd());
allFilesWatcher.on('changed', ({ owners, eventType }) => {
if (eventType === 'rename') {
const updatedTestFiles = createTestFileList(opts.globPatterns);

const newFiles = ArrayPrototypeFilter(updatedTestFiles, (x) => !ArrayPrototypeIncludes(testFiles, x));

testFiles = updatedTestFiles;
newFiles.forEach((newFile) => {
watcher.emit('changed', { __proto__: null, owners: new SafeSet().add(newFile), eventType: 'rename' });
});
}
});
// Watch for changes in current filtered files
watcher.on('changed', ({ owners, eventType }) => {
if (!opts.hasFiles && eventType === 'rename') {
const updatedTestFiles = createTestFileList(opts.globPatterns);
Expand Down
3 changes: 3 additions & 0 deletions test/parallel/test-runner-run.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { join } from 'node:path';
import { describe, it, run } from 'node:test';
import { dot, spec, tap } from 'node:test/reporters';
import assert from 'node:assert';
import { EventEmitter } from 'events';

EventEmitter.setMaxListeners(35);

const testFixtures = fixtures.path('test-runner');

Expand Down
39 changes: 37 additions & 2 deletions test/parallel/test-runner-watch-mode.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,18 @@ function refresh() {
.forEach(([file, content]) => writeFileSync(fixturePaths[file], content));
}

async function testWatch({ fileToUpdate, file, action = 'update' }) {
async function testWatch({
fileToUpdate,
file,
action = 'update',
fileToCreate
}) {
const ran1 = util.createDeferredPromise();
const ran2 = util.createDeferredPromise();
const child = spawn(process.execPath,
['--watch', '--test', file ? fixturePaths[file] : undefined].filter(Boolean),
{ encoding: 'utf8', stdio: 'pipe', cwd: tmpdir.path });
{ encoding: 'utf8', stdio: 'pipe', cwd: tmpdir.path }
);
let stdout = '';
let currentRun = '';
const runs = [];
Expand Down Expand Up @@ -111,9 +117,34 @@ async function testWatch({ fileToUpdate, file, action = 'update' }) {
}
};

const testCreate = async () => {
await ran1.promise;
const newFilePath = tmpdir.resolve(fileToCreate);
const interval = setInterval(
() => writeFileSync(
newFilePath,
'module.exports = {};'
),
common.platformTimeout(1000)
);
await ran2.promise;
runs.push(currentRun);
clearInterval(interval);
child.kill();
await once(child, 'exit');

for (const run of runs) {
assert.match(run, /# tests 1/);
assert.match(run, /# pass 1/);
assert.match(run, /# fail 0/);
assert.match(run, /# cancelled 0/);
}
};

action === 'update' && await testUpdate();
action === 'rename' && await testRename();
action === 'delete' && await testDelete();
action === 'create' && await testCreate();
}

describe('test runner watch mode', () => {
Expand Down Expand Up @@ -141,4 +172,8 @@ describe('test runner watch mode', () => {
it('should not throw when delete a watched test file', { skip: common.isAIX }, async () => {
await testWatch({ fileToUpdate: 'test.js', action: 'delete' });
});

it('should run new tests when a new file is created in the watched directory', async () => {
await testWatch({ action: 'create', fileToCreate: 'new-test-file.test.js' });
});
});

0 comments on commit b23a410

Please sign in to comment.