|
| 1 | +// Flags: --expose-internals |
| 2 | +import * as common from '../common/index.mjs'; |
| 3 | +import { describe, it } from 'node:test'; |
| 4 | +import { spawn } from 'node:child_process'; |
| 5 | +import { writeFileSync } from 'node:fs'; |
| 6 | +import util from 'internal/util'; |
| 7 | +import tmpdir from '../common/tmpdir.js'; |
| 8 | +import assert from 'node:assert'; |
| 9 | + |
| 10 | + |
| 11 | +if (common.isIBMi) |
| 12 | + common.skip('IBMi does not support `fs.watch()`'); |
| 13 | + |
| 14 | +tmpdir.refresh(); |
| 15 | + |
| 16 | +function getCoverageFixtureReport() { |
| 17 | + |
| 18 | + const report = [ |
| 19 | + '# start of coverage report', |
| 20 | + '# ---------------------------------------------------------------', |
| 21 | + '# file | line % | branch % | funcs % | uncovered lines', |
| 22 | + '# ---------------------------------------------------------------', |
| 23 | + '# dependency.js | 100.00 | 100.00 | 100.00 | ', |
| 24 | + '# dependency.mjs | 100.00 | 100.00 | 100.00 | ', |
| 25 | + '# test.js | 100.00 | 100.00 | 100.00 | ', |
| 26 | + '# ---------------------------------------------------------------', |
| 27 | + '# all files | 100.00 | 100.00 | 100.00 |', |
| 28 | + '# ---------------------------------------------------------------', |
| 29 | + '# end of coverage report', |
| 30 | + ].join('\n'); |
| 31 | + |
| 32 | + |
| 33 | + if (common.isWindows) { |
| 34 | + return report.replaceAll('/', '\\'); |
| 35 | + } |
| 36 | + |
| 37 | + return report; |
| 38 | +} |
| 39 | + |
| 40 | +const fixtureContent = { |
| 41 | + 'dependency.js': 'module.exports = {};', |
| 42 | + 'dependency.mjs': 'export const a = 1;', |
| 43 | + 'test.js': ` |
| 44 | +const test = require('node:test'); |
| 45 | +require('./dependency.js'); |
| 46 | +import('./dependency.mjs'); |
| 47 | +import('data:text/javascript,'); |
| 48 | +test('test has ran');`, |
| 49 | +}; |
| 50 | +const fixturePaths = Object.keys(fixtureContent) |
| 51 | + .reduce((acc, file) => ({ ...acc, [file]: tmpdir.resolve(file) }), {}); |
| 52 | +Object.entries(fixtureContent) |
| 53 | + .forEach(([file, content]) => writeFileSync(fixturePaths[file], content)); |
| 54 | + |
| 55 | +async function testWatch({ fileToUpdate, file }) { |
| 56 | + const ran1 = util.createDeferredPromise(); |
| 57 | + const ran2 = util.createDeferredPromise(); |
| 58 | + const child = spawn(process.execPath, |
| 59 | + ['--watch', '--test', '--experimental-test-coverage', |
| 60 | + file ? fixturePaths[file] : undefined].filter(Boolean), |
| 61 | + { encoding: 'utf8', stdio: 'pipe', cwd: tmpdir.path }); |
| 62 | + let stdout = ''; |
| 63 | + |
| 64 | + child.stdout.on('data', (data) => { |
| 65 | + stdout += data.toString(); |
| 66 | + const testRuns = stdout.match(/ - test has ran/g); |
| 67 | + if (testRuns?.length >= 1) ran1.resolve(); |
| 68 | + if (testRuns?.length >= 2) ran2.resolve(); |
| 69 | + }); |
| 70 | + |
| 71 | + await ran1.promise; |
| 72 | + const content = fixtureContent[fileToUpdate]; |
| 73 | + const path = fixturePaths[fileToUpdate]; |
| 74 | + const interval = setInterval(() => writeFileSync(path, content), common.platformTimeout(1000)); |
| 75 | + await ran2.promise; |
| 76 | + clearInterval(interval); |
| 77 | + child.kill(); |
| 78 | + return stdout; |
| 79 | +} |
| 80 | + |
| 81 | +describe('test runner watch mode with coverage report', () => { |
| 82 | + it('should support running test file', async () => { |
| 83 | + const stdout = await testWatch({ file: 'test.js', fileToUpdate: 'test.js' }); |
| 84 | + assert(stdout.includes(getCoverageFixtureReport())); |
| 85 | + }); |
| 86 | +}); |
0 commit comments