| // Flags: --expose-internals |
| import * as common from '../common/index.mjs'; |
| import { describe, it } from 'node:test'; |
| import assert from 'node:assert'; |
| import { spawn } from 'node:child_process'; |
| import { writeFileSync } from 'node:fs'; |
| import tmpdir from '../common/tmpdir.js'; |
| |
| if (common.isIBMi) |
| common.skip('IBMi does not support `fs.watch()`'); |
| |
| if (common.isAIX) |
| common.skip('folder watch capability is limited in AIX.'); |
| |
| tmpdir.refresh(); |
| |
| // Set up test files and dependencies |
| const fixtureContent = { |
| 'dependency.js': 'module.exports = {};', |
| 'test.js': ` |
| const test = require('node:test'); |
| require('./dependency.js'); |
| test('first test has ran');`, |
| 'test-2.js': ` |
| const test = require('node:test'); |
| require('./dependency.js'); |
| test('second test has ran');`, |
| }; |
| |
| const fixturePaths = Object.fromEntries(Object.keys(fixtureContent) |
| .map((file) => [file, tmpdir.resolve(file)])); |
| |
| Object.entries(fixtureContent) |
| .forEach(([file, content]) => writeFileSync(fixturePaths[file], content)); |
| |
| describe('test runner watch mode with more complex setup', () => { |
| it('should re-run appropriate tests when dependencies change', async () => { |
| // Start the test runner in watch mode |
| const child = spawn(process.execPath, |
| ['--watch', '--test'], |
| { encoding: 'utf8', stdio: 'pipe', cwd: tmpdir.path }); |
| |
| let currentRunOutput = ''; |
| const testRuns = []; |
| |
| const firstRunCompleted = Promise.withResolvers(); |
| const secondRunCompleted = Promise.withResolvers(); |
| const thirdRunCompleted = Promise.withResolvers(); |
| const fourthRunCompleted = Promise.withResolvers(); |
| |
| child.stdout.on('data', (data) => { |
| const str = data.toString(); |
| currentRunOutput += str; |
| |
| if (/duration_ms\s\d+/.test(str)) { |
| // Test run has completed |
| testRuns.push(currentRunOutput); |
| currentRunOutput = ''; |
| switch (testRuns.length) { |
| case 1: |
| firstRunCompleted.resolve(); |
| break; |
| case 2: |
| secondRunCompleted.resolve(); |
| break; |
| case 3: |
| thirdRunCompleted.resolve(); |
| break; |
| case 4: |
| fourthRunCompleted.resolve(); |
| break; |
| } |
| } |
| }); |
| |
| // Wait for the initial test run to complete |
| await firstRunCompleted.promise; |
| |
| // Modify 'dependency.js' to trigger re-run of both tests |
| writeFileSync(fixturePaths['dependency.js'], 'module.exports = { modified: true };'); |
| |
| // Wait for the second test run to complete |
| await secondRunCompleted.promise; |
| |
| // Modify 'test.js' to trigger re-run of only 'test.js' |
| writeFileSync(fixturePaths['test.js'], ` |
| const test = require('node:test'); |
| require('./dependency.js'); |
| test('first test has ran again');`); |
| |
| // Wait for the third test run to complete |
| await thirdRunCompleted.promise; |
| |
| // Modify 'dependency.js' again to trigger re-run of both tests |
| writeFileSync(fixturePaths['dependency.js'], 'module.exports = { modified: true, again: true };'); |
| |
| // Wait for the fourth test run to complete |
| await fourthRunCompleted.promise; |
| |
| // Kill the child process |
| child.kill(); |
| |
| // Analyze the test runs |
| assert.strictEqual(testRuns.length, 4); |
| |
| // First test run - Both tests should run |
| const firstRunOutput = testRuns[0]; |
| assert.match(firstRunOutput, /first test has ran/); |
| assert.match(firstRunOutput, /second test has ran/); |
| |
| // Second test run - We have modified 'dependency.js' only, so both tests should re-run |
| const secondRunOutput = testRuns[1]; |
| assert.match(secondRunOutput, /first test has ran/); |
| assert.match(secondRunOutput, /second test has ran/); |
| |
| // Third test run - We have modified 'test.js' only |
| const thirdRunOutput = testRuns[2]; |
| assert.match(thirdRunOutput, /first test has ran again/); |
| assert.doesNotMatch(thirdRunOutput, /second test has ran/); |
| |
| // Fourth test run - We have modified 'dependency.js' again, so both tests should re-run |
| const fourthRunOutput = testRuns[3]; |
| assert.match(fourthRunOutput, /first test has ran again/); |
| assert.match(fourthRunOutput, /second test has ran/); |
| }); |
| }); |