diff --git a/coverage-map.js b/coverage-map.js index d96a3a77..cc716115 100644 --- a/coverage-map.js +++ b/coverage-map.js @@ -1,20 +1,20 @@ const glob = require('glob') const path = require('path') -const rootFiles = ['settings', 'versions']; +const rootFiles = ['settings', 'versions', 'coverage-map']; module.exports = t => { const parts = path.relative(process.cwd(), path.resolve(t)).split(/\\|\//) + const ext = path.extname(t) + const unit = path.basename(parts[1], ext) + if (parts[1] === 'libtap.mjs') return 'lib/tap.mjs' - const unit = path.basename(parts[1], '.js') if (rootFiles.includes(unit)) return `${unit}.js` - if (unit === 'coverage-map') - return [ path.basename(__filename) ] - const cov = glob.sync(`lib/${unit}.js`) + const cov = glob.sync(`lib/${unit}${ext}`) if (!cov.length) return null return cov diff --git a/lib/tla.mjs b/lib/tla.mjs new file mode 100644 index 00000000..50146217 --- /dev/null +++ b/lib/tla.mjs @@ -0,0 +1,37 @@ +import settings from 'libtap/settings'; + +// Defer load of libtap itself until settings are ready +await settings.waitForReady(); + +const tap = await import('libtap'); + +// This cannot be deduplicated with `tap.mjs` +export const { + Test, Spawn, Stdin, + spawn, sub, + todo, skip, only, test, + stdinOnly, stdin, + bailout, + comment, + timeout, + main, + process, + processSubtest, + addAssert, + pragma, + plan, end, + beforeEach, + afterEach, + teardown, + autoend, + pass, fail, ok, notOk, + emits, + error, equal, not, same, notSame, strictSame, strictNotSame, + testdir, fixture, + matchSnapshot, + hasStrict, match, notMatch, type, + expectUncaughtException, throwsArgs, throws, doesNotThrow, + rejects, resolves, resolveMatch, resolveMatchSnapshot +} = tap + +export default tap diff --git a/npm-run-test.js b/npm-run-test.js index a4079f0e..cbf555e1 100644 --- a/npm-run-test.js +++ b/npm-run-test.js @@ -10,6 +10,7 @@ async function runTests() { const t = require('.') const coverageMap = require('./coverage-map.js') const testESM = semver.gte(process.versions.node, '13.10.0') + const testTLA = semver.gte(process.versions.node, '14.8.0') const testFileGlob = testESM ? 'test/**/*.{js,mjs}' : 'test/**/*.js' const esLoaderHook = { NODE_OPTIONS: `${process.env.NODE_OPTIONS || ''} --experimental-loader @istanbuljs/esm-loader-hook` @@ -18,6 +19,10 @@ async function runTests() { t.jobs = os.cpus().length glob.sync(testFileGlob).forEach(file => { + if (file.endsWith('tla.mjs') && !testTLA) { + return; + } + if (process.platform === 'win32' && file.includes('sigterm')) { // TODO: investigate proper Win32 replacements for these tests return; diff --git a/nyc.config.js b/nyc.config.js index 05358a5f..184149f1 100644 --- a/nyc.config.js +++ b/nyc.config.js @@ -2,6 +2,8 @@ const semver = require('semver') +const excludeTLA = semver.lt(process.versions.node, '14.8.0') ? ['!lib/tla.mjs'] : [] + module.exports = { all: true, checkCoverage: process.platform !== 'win32', @@ -13,6 +15,7 @@ module.exports = { include: [ 'settings.js', 'versions.js', - 'lib/**' + 'lib/**', + ...excludeTLA ] } diff --git a/package.json b/package.json index d610ab54..d6dd12d3 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "default": "./lib/tap.js" }, "./settings": "./settings.js", - "./versions": "./versions.js" + "./versions": "./versions.js", + "./tla": "./lib/tla.mjs" }, "engines": { "node": ">=10" diff --git a/settings.js b/settings.js index fe88ff21..61186384 100644 --- a/settings.js +++ b/settings.js @@ -9,6 +9,15 @@ let rmdirRecursiveSync let rmdirRecursive let hasFsRm = false +let settingsResolve +let settingsPromise +function settingsPromiseInitialize() { + if (!settingsPromise) { + settingsPromise = new Promise(resolve => { + settingsResolve = resolve + }) + } +} module.exports = { atTap: false, @@ -62,6 +71,15 @@ module.exports = { output: process.stdout, snapshotFile: (cwd, main, argv) => { return path.resolve(cwd, 'tap-snapshots', main + argv + '.test.cjs') + }, + // This tells `libtap/tla` that settings are prepared + markAsReady() { + settingsPromiseInitialize(); + settingsResolve(); + }, + waitForReady() { + settingsPromiseInitialize() + return settingsPromise; } } diff --git a/tap-snapshots/test/settings.js.test.cjs b/tap-snapshots/test/settings.js.test.cjs index 7474c875..70a5303b 100644 --- a/tap-snapshots/test/settings.js.test.cjs +++ b/tap-snapshots/test/settings.js.test.cjs @@ -8,6 +8,7 @@ exports[`test/settings.js TAP > must match snapshot 1`] = ` Object { "atTap": false, + "markAsReady": Function markAsReady(), "output": "process.stdout", "rimrafNeeded": "version specific", "rmdirRecursive": Function rmdirRecursive(dir, cb), @@ -18,5 +19,6 @@ Object { "internals": Array [], }, "StackUtils": Function StackUtils(classStackUtils), + "waitForReady": Function waitForReady(), } ` diff --git a/tap-snapshots/test/libtap.mjs.test.cjs b/tap-snapshots/test/tap.mjs.test.cjs similarity index 93% rename from tap-snapshots/test/libtap.mjs.test.cjs rename to tap-snapshots/test/tap.mjs.test.cjs index b62d3dc3..19d65156 100644 --- a/tap-snapshots/test/libtap.mjs.test.cjs +++ b/tap-snapshots/test/tap.mjs.test.cjs @@ -5,7 +5,7 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/libtap.mjs TAP libtap > must match snapshot 1`] = ` +exports[`test/tap.mjs TAP libtap > must match snapshot 1`] = ` Array [ "Spawn", "Stdin", diff --git a/test/settings.js b/test/settings.js index dfc1176b..c918a7bc 100644 --- a/test/settings.js +++ b/test/settings.js @@ -50,3 +50,15 @@ t.equal(settings.snapshotFile('cwd', 'main', 'args'), settings.snapshotFile = (cwd, main, args) => [cwd, main, args].join('X') t.equal(settings.snapshotFile('cwd', 'main', 'args'), 'cwdXmainXargs', 'can override snapshotFile setting function') + +let isReady = false +settings.waitForReady().then(() => { + isReady = true; +}) + +t.equal(isReady, false) + +settings.markAsReady() +setTimeout(() => { + t.equal(isReady, true) +}) diff --git a/test/libtap.mjs b/test/tap.mjs similarity index 100% rename from test/libtap.mjs rename to test/tap.mjs diff --git a/test/tla.mjs b/test/tla.mjs new file mode 100644 index 00000000..9a02ec54 --- /dev/null +++ b/test/tla.mjs @@ -0,0 +1,48 @@ +import {promisify} from 'util' + +const delay = promisify(setTimeout) +const expectedLog = [ + 'importing settings', + 'imported settings', + 'watch settings.output', + 'importing tla', + 'flag ready', + 'flaged ready', + 'get settings.output', + 'imported tla' +]; +let log = [] + +log.push('importing settings') +const settings = (await import('libtap/settings')).default +log.push('imported settings') + +let output = process.stdout +let outputRead = 0 +Object.defineProperty(settings, 'output', { + get() { + log.push('get settings.output') + outputRead++ + return output + }, + set(value) { + log.push('set settings.output') + output = value + } +}) +log.push('watch settings.output') + +log.push('importing tla') +const libPromise = import('libtap/tla') +libPromise.then(t => { + log.push('imported tla') + t.same(log, expectedLog) +}) + +await delay(50) + +log.push('flag ready') +settings.markAsReady() +log.push('flaged ready') + +await delay(50);