sxy-test-runner 2.5.4 → 2.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +40 -16
- package/dist/cli/lib/agentReport.d.ts +1 -0
- package/dist/cli/lib/agentReport.js +3 -0
- package/dist/cli/lib/agentReport.js.map +1 -1
- package/dist/cli/lib/esmGraphReload.d.ts +5 -0
- package/dist/cli/lib/esmGraphReload.js +24 -0
- package/dist/cli/lib/esmGraphReload.js.map +1 -0
- package/dist/cli/lib/esmTreeReload.d.ts +4 -0
- package/dist/cli/lib/esmTreeReload.js +62 -0
- package/dist/cli/lib/esmTreeReload.js.map +1 -0
- package/dist/cli/lib/handleUserInput.d.ts +2 -2
- package/dist/cli/lib/handleUserInput.js +13 -6
- package/dist/cli/lib/handleUserInput.js.map +1 -1
- package/dist/cli/lib/listenToUser.d.ts +2 -2
- package/dist/cli/lib/listenToUser.js.map +1 -1
- package/dist/cli/lib/loadTestFile.d.ts +0 -1
- package/dist/cli/lib/loadTestFile.js +23 -8
- package/dist/cli/lib/loadTestFile.js.map +1 -1
- package/dist/cli/lib/makeDependencyGraph.d.ts +1 -0
- package/dist/cli/lib/makeDependencyGraph.js +34 -15
- package/dist/cli/lib/makeDependencyGraph.js.map +1 -1
- package/dist/cli/lib/reRunManager.js +4 -6
- package/dist/cli/lib/reRunManager.js.map +1 -1
- package/dist/cli/lib/runTests.js +7 -2
- package/dist/cli/lib/runTests.js.map +1 -1
- package/dist/cli/lib/showTestResultsSummary.d.ts +1 -1
- package/dist/cli/lib/showTestResultsSummary.js +5 -1
- package/dist/cli/lib/showTestResultsSummary.js.map +1 -1
- package/dist/cli/lib/statusFile.js +20 -1
- package/dist/cli/lib/statusFile.js.map +1 -1
- package/dist/cli/lib/watchFilesAndRunTestsNodeWatch.js +3 -4
- package/dist/cli/lib/watchFilesAndRunTestsNodeWatch.js.map +1 -1
- package/dist/cli/watch.js +14 -1
- package/dist/cli/watch.js.map +1 -1
- package/dist/describe.js +5 -3
- package/dist/describe.js.map +1 -1
- package/dist/meta.js +2 -1
- package/dist/meta.js.map +1 -1
- package/dist/registration.d.ts +4 -0
- package/dist/registration.js +34 -0
- package/dist/registration.js.map +1 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.js.map +1 -1
- package/package.json +5 -2
- package/readme.md +15 -122
- package/dist/packages/esmReload.d.ts +0 -11
- package/dist/packages/esmReload.js +0 -43
- package/dist/packages/esmReload.js.map +0 -1
package/dist/cli/watch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/cli/watch.ts"],"names":[],"mappings":"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","sourcesContent":["\nimport type { OutFn } from '../types.js'\nimport type { AllowedArguments } from './cliTypes.js'\nimport type { Concurrency } from './lib/runTests.js'\nimport type { DependencyGraph } from './lib/makeDependencyGraph.js'\nimport chalk from '../packages/chalk.js'\nimport { packageName } from '../config.js'\nimport { out, debug } from '../output.js'\nimport { setEnv, setAgentEnv } from './lib/setEnv.js'\nimport { findingTestsMessage } from './lib/findingTestsMessage.js'\nimport { foundTestsMessage } from './lib/foundTestsMessage.js'\n//import { isTest } from './lib/isTest.js'\nimport { makeRunManagerState } from './lib/makeWatchRunState.js'\nimport { makeReRunManager } from './lib/reRunManager.js'\nimport { alwaysCacheBust } from './lib/alwaysCacheBust.js'\n\n\nexport type StopFn = () => void\n\nexport async function watch(): Promise<void> {\n await doWatch()\n await new Promise<void>(() => {})\n}\n\n// input is injectable so tests never read the terminal their runner is also reading\nexport async function doWatch(input: NodeJS.ReadStream = process.stdin): Promise<StopFn> {\n const startTime = new Date().getTime()\n\n const { parseCommandLineArguments } = await import('./lib/parseCommandLineArguments.js')\n const allowedClArguments: AllowedArguments = {\n 'config': {\n flag: 'c',\n hasValue: true\n },\n 'test-files': {\n flag: 't',\n hasValue: true,\n isGlob: true\n },\n 'filter': {\n flag: 'f',\n hasValue: true,\n isGlob: true\n },\n 'filter-it': {\n flag: 'i',\n hasValue: true\n },\n 'filter-describe': {\n flag: 'd',\n hasValue: true\n },\n 'status-file': {\n flag: 's',\n hasValue: true\n },\n 'agent': {\n hasValue: false\n },\n 'compact': {\n hasValue: false\n }\n }\n const clArguments = parseCommandLineArguments(allowedClArguments)\n //debug('clArguments', clArguments)\n\n // agent mode owns stdout, so the banner and every later message below is routed through\n // agentOut - a sink in agent mode. Under the flag, init is announced before the config\n // loads, so a reader sees the process is alive even if startup is slow.\n const agentFlag = clArguments.agent === true\n const {\n agentInit, agentFound, agentRunStart, agentDone, agentWatching, agentSilentOut\n } = await import('./lib/agentReport.js')\n agentInit(agentFlag)\n // the config can still turn agent mode on, so this is settled once it has loaded\n let agentMode = agentFlag\n const agentOut: OutFn = (...texts) => { if (!agentMode) out(...texts) }\n\n setEnv()\n\n const stopFns: StopFn[] = []\n\n const { loadConfig } = await import('./lib/loadConfig.js')\n const userConfig = (typeof clArguments.config === 'string')\n ? await loadConfig(clArguments.config)\n : await loadConfig()\n\n if ('test-files' in clArguments) {\n const testFilesPattern = clArguments['test-files']\n if (typeof testFilesPattern !== 'string' || testFilesPattern === '') {\n throw new Error('No pattern specified for --test-files or -t argument')\n }\n userConfig.tests = testFilesPattern\n }\n\n if ('filter' in clArguments) {\n const filter = clArguments.filter\n if (typeof filter !== 'string' || filter === '') {\n throw new Error('No pattern specified for --filter or -f argument')\n }\n userConfig.testsFilter = filter\n }\n\n if ('status-file' in clArguments) {\n const statusFile = clArguments['status-file']\n if (typeof statusFile !== 'string' || statusFile === '') {\n throw new Error('No file path specified for --status-file or -s argument')\n }\n userConfig.watch = { ...userConfig.watch, statusFile }\n }\n\n const filterIt = clArguments['filter-it']\n const filterDescribe = clArguments['filter-describe']\n if (filterIt === true || filterIt === '') throw new Error('No substring specified for --filter-it')\n if (filterDescribe === true || filterDescribe === '') {\n throw new Error('No substring specified for --filter-describe')\n }\n const executionFilters = { it: filterIt, describe: filterDescribe }\n\n const { applyConfigDefaults } = await import('./lib/applyConfigDefaults.js')\n const config = applyConfigDefaults(userConfig)\n if (agentFlag) config.agent = true\n else if (config.agent) agentInit(true) // set by the config: announced once it has loaded\n agentMode = config.agent\n setAgentEnv(agentMode)\n const runsOut = (agentMode) ? agentSilentOut : undefined\n agentOut(chalk.brightblue`[${packageName}]...`)\n if (clArguments.compact === true) config.compact = true\n // there is no watch flag for it, and a config file must not enable it here: a truncated\n // run would still report covers=all, and failing files would drop out of `failing`\n config.failFast = false\n\n // not silenced in agent mode - a config error is fatal, so losing the message is worse\n // than breaking the one-line-per-event contract\n const { validateConfig } = await import('./lib/validateConfig.js')\n validateConfig(config)\n\n // no run has finished yet, so the status file starts at -1 rather than stale\n const { resetStatusFile, statusCodes, writeStatusFile } = await import('./lib/statusFile.js')\n resetStatusFile(config)\n\n const { doUserSetup } = await import('./lib/doUserSetup.js')\n await doUserSetup(config, agentOut)\n\n // watch mode never reaches an end of its own, so teardown only gets a chance on the way\n // out. Registered here so it pairs with the setup above and covers the initial run too.\n const { doUserTeardown } = await import('./lib/doUserTeardown.js')\n const { registerShutdownHandlers } = await import('./lib/shutdown.js')\n \n const unregisterShutdownHandlers = registerShutdownHandlers(config, {\n teardown: doUserTeardown,\n exit: code => process.exit(code)\n })\n stopFns.push(unregisterShutdownHandlers)\n\n agentOut(chalk.brightblue(findingTestsMessage(config)))\n const { findTestFiles } = await import('./lib/findTestFiles.js')\n const testFiles = await findTestFiles(config)\n debug(testFiles)\n agentFound(config, testFiles.size)\n\n // store failing tests so we can re-run them.\n const failingTests: string[] = []\n \n const concurrency: Concurrency = { limit: -1 }\n\n const reRunManager = makeReRunManager(\n null,\n makeRunManagerState({\n allTestFiles: testFiles,\n lastTestFiles: testFiles\n }),\n runsOut\n )\n\n process.setSourceMapsEnabled(true) // enable source mapping\n\n if (testFiles.size > 0) agentOut(chalk.brightblue(foundTestsMessage(testFiles.size)))\n\n // the graph is only consulted to narrow a run, so with evaluation off building it is pure\n // cost - and it is the slowest part of startup on a large suite. Built even with no tests,\n // so tests created later are recorded in it.\n let dependencyGraph: DependencyGraph | null = null\n if (config.watch.dependencyEvaluation) {\n const { makeDependencyGraph } = await import('./lib/makeDependencyGraph.js')\n if (testFiles.size > 0) agentOut(chalk.brightblue`finding initial dependencies...`)\n dependencyGraph = makeDependencyGraph(config, testFiles)\n }\n\n // live before the first test runs, for two reasons. A change landing during the initial\n // run (a compiler emit, typically) is seen rather than lost. And the watcher starts on a\n // quiet loop: node-watch probes for native recursive support with a 200ms timeout, and a\n // loop busy running tests fails the probe, so it falls back to a sync walk of every\n // directory - which then starved the tests' own timers (a 10ms interval fired once in 45ms)\n const { watchFilesAndRunTests } = await import('./lib/watchFilesAndRunTests.js')\n const stopWatcher = await watchFilesAndRunTests(\n config,\n //testFiles,\n dependencyGraph,\n failingTests, // CHECK this should also be in state\n reRunManager,\n //watchRunState,\n runsOut,\n executionFilters\n )\n stopFns.push(stopWatcher)\n\n const { runTests } = await import('./lib/runTests.js')\n let initialTestRun: Promise<boolean | null> | null = null\n if (testFiles.size > 0) {\n if (config.watch.runAllOnStartup) {\n agentOut(chalk.brightblue`running initial tests...`)\n initialTestRun = runTests(\n config, testFiles,\n reRunManager,\n concurrency,\n (alwaysCacheBust) ? 'refresh' : 'cached',\n runsOut, executionFilters\n ).then(testsResult => {\n const time = new Date().getTime() - startTime\n //await new Promise((resolve) => setTimeout(resolve, 100))\n agentOut(chalk.grey`\\n${time.toLocaleString()}ms`)\n return testsResult\n })\n reRunManager.state.currentRun = initialTestRun\n }\n } else {\n agentOut(chalk.orange`no test files found`)\n writeStatusFile(config, statusCodes.couldNotRun, 'no test files found')\n // still reported as a run, so a reader waiting on a done line always gets one\n const run = agentRunStart(config, 0)\n agentDone(\n config, run, statusCodes.couldNotRun, 'no test files found',\n null, new Date().getTime() - startTime, 0\n )\n }\n\n // announced once the initial run is over, so `watching` marks a real milestone: startup is\n // complete and the watcher is live. A failed run is reported by listenToUser below.\n if (initialTestRun !== null) await initialTestRun.catch(() => null)\n\n agentOut(chalk.brightblue`watching...`)\n agentWatching(config, testFiles.size)\n\n const { listenToUser } = await import('./lib/listenToUser.js')\n const disposeTty = listenToUser(\n reRunManager,\n files => () => {\n return runTests(config, files, reRunManager, concurrency, 'refresh', runsOut, executionFilters)\n },\n config.watch.ttyActionsOnKeypress,\n initialTestRun,\n input,\n runsOut\n )\n stopFns.push(disposeTty)\n\n const dispose = () => {\n for (const stop of stopFns) {\n stop()\n }\n stopFns.length = 0 // Idempotencize\n }\n return dispose\n\n\n // (async () => {\n // await new Promise<void>(() => {})\n // })()\n //await new Promise<void>(() => {})\n}\n"]}
|
|
1
|
+
{"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/cli/watch.ts"],"names":[],"mappings":"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","sourcesContent":["\nimport type { OutFn } from '../types.js'\nimport type { AllowedArguments } from './cliTypes.js'\nimport type { Concurrency } from './lib/runTests.js'\nimport type { DependencyGraph } from './lib/makeDependencyGraph.js'\nimport chalk from '../packages/chalk.js'\nimport { packageName } from '../config.js'\nimport { out, debug } from '../output.js'\nimport { setEnv, setAgentEnv } from './lib/setEnv.js'\nimport { findingTestsMessage } from './lib/findingTestsMessage.js'\nimport { foundTestsMessage } from './lib/foundTestsMessage.js'\n//import { isTest } from './lib/isTest.js'\nimport { makeRunManagerState } from './lib/makeWatchRunState.js'\nimport { makeReRunManager } from './lib/reRunManager.js'\nimport { alwaysCacheBust } from './lib/alwaysCacheBust.js'\n\n\nexport type StopFn = () => void\n\nexport async function watch(): Promise<void> {\n await doWatch()\n await new Promise<void>(() => {})\n}\n\n// input is injectable so tests never read the terminal their runner is also reading\nexport async function doWatch(input: NodeJS.ReadStream = process.stdin): Promise<StopFn> {\n const startTime = new Date().getTime()\n\n const { parseCommandLineArguments } = await import('./lib/parseCommandLineArguments.js')\n const allowedClArguments: AllowedArguments = {\n 'config': {\n flag: 'c',\n hasValue: true\n },\n 'test-files': {\n flag: 't',\n hasValue: true,\n isGlob: true\n },\n 'filter': {\n flag: 'f',\n hasValue: true,\n isGlob: true\n },\n 'filter-it': {\n flag: 'i',\n hasValue: true\n },\n 'filter-describe': {\n flag: 'd',\n hasValue: true\n },\n 'status-file': {\n flag: 's',\n hasValue: true\n },\n 'agent': {\n hasValue: false\n },\n 'compact': {\n hasValue: false\n }\n }\n const clArguments = parseCommandLineArguments(allowedClArguments)\n //debug('clArguments', clArguments)\n\n // agent mode owns stdout, so the banner and every later message below is routed through\n // agentOut - a sink in agent mode. Under the flag, init is announced before the config\n // loads, so a reader sees the process is alive even if startup is slow.\n const agentFlag = clArguments.agent === true\n const {\n agentInit, agentFound, agentRunStart, agentDone, agentWatching, agentSilentOut\n } = await import('./lib/agentReport.js')\n agentInit(agentFlag)\n // the config can still turn agent mode on, so this is settled once it has loaded\n let agentMode = agentFlag\n const agentOut: OutFn = (...texts) => { if (!agentMode) out(...texts) }\n\n setEnv()\n\n const stopFns: StopFn[] = []\n\n const { loadConfig } = await import('./lib/loadConfig.js')\n const userConfig = (typeof clArguments.config === 'string')\n ? await loadConfig(clArguments.config)\n : await loadConfig()\n\n if ('test-files' in clArguments) {\n const testFilesPattern = clArguments['test-files']\n if (typeof testFilesPattern !== 'string' || testFilesPattern === '') {\n throw new Error('No pattern specified for --test-files or -t argument')\n }\n userConfig.tests = testFilesPattern\n }\n\n if ('filter' in clArguments) {\n const filter = clArguments.filter\n if (typeof filter !== 'string' || filter === '') {\n throw new Error('No pattern specified for --filter or -f argument')\n }\n userConfig.testsFilter = filter\n }\n\n if ('status-file' in clArguments) {\n const statusFile = clArguments['status-file']\n if (typeof statusFile !== 'string' || statusFile === '') {\n throw new Error('No file path specified for --status-file or -s argument')\n }\n userConfig.watch = { ...userConfig.watch, statusFile }\n }\n\n const filterIt = clArguments['filter-it']\n const filterDescribe = clArguments['filter-describe']\n if (filterIt === true || filterIt === '') throw new Error('No substring specified for --filter-it')\n if (filterDescribe === true || filterDescribe === '') {\n throw new Error('No substring specified for --filter-describe')\n }\n const executionFilters = { it: filterIt, describe: filterDescribe }\n\n const { applyConfigDefaults } = await import('./lib/applyConfigDefaults.js')\n const config = applyConfigDefaults(userConfig)\n if (agentFlag) config.agent = true\n else if (config.agent) agentInit(true) // set by the config: announced once it has loaded\n agentMode = config.agent\n setAgentEnv(agentMode)\n const runsOut = (agentMode) ? agentSilentOut : undefined\n agentOut(chalk.brightblue`[${packageName}]...`)\n if (clArguments.compact === true) config.compact = true\n // there is no watch flag for it, and a config file must not enable it here: a truncated\n // run would still report covers=all, and failing files would drop out of `failing`\n config.failFast = false\n\n // not silenced in agent mode - a config error is fatal, so losing the message is worse\n // than breaking the one-line-per-event contract\n const { validateConfig } = await import('./lib/validateConfig.js')\n validateConfig(config)\n\n // no run has finished yet, so the status file starts at -1 rather than stale\n const { resetStatusFile, statusCodes, writeStatusFile } = await import('./lib/statusFile.js')\n resetStatusFile(config)\n\n const { doUserSetup } = await import('./lib/doUserSetup.js')\n await doUserSetup(config, agentOut)\n\n // watch mode never reaches an end of its own, so teardown only gets a chance on the way\n // out. Registered here so it pairs with the setup above and covers the initial run too.\n const { doUserTeardown } = await import('./lib/doUserTeardown.js')\n const { registerShutdownHandlers } = await import('./lib/shutdown.js')\n \n const unregisterShutdownHandlers = registerShutdownHandlers(config, {\n teardown: doUserTeardown,\n exit: code => process.exit(code)\n })\n stopFns.push(unregisterShutdownHandlers)\n\n agentOut(chalk.brightblue(findingTestsMessage(config)))\n const { findTestFiles } = await import('./lib/findTestFiles.js')\n const testFiles = await findTestFiles(config)\n debug(testFiles)\n agentFound(config, testFiles.size)\n\n // store failing tests so we can re-run them.\n const failingTests: string[] = []\n \n const concurrency: Concurrency = { limit: -1 }\n\n const reRunManager = makeReRunManager(\n null,\n makeRunManagerState({\n allTestFiles: testFiles,\n lastTestFiles: testFiles\n }),\n runsOut\n )\n\n process.setSourceMapsEnabled(true) // enable source mapping\n\n if (testFiles.size > 0) agentOut(chalk.brightblue(foundTestsMessage(testFiles.size)))\n\n // the graph is only consulted to narrow a run, so with evaluation off building it is pure\n // cost - and it is the slowest part of startup on a large suite. Built even with no tests,\n // so tests created later are recorded in it.\n let dependencyGraph: DependencyGraph | null = null\n if (config.watch.dependencyEvaluation) {\n const { makeDependencyGraph } = await import('./lib/makeDependencyGraph.js')\n if (testFiles.size > 0) agentOut(chalk.brightblue`finding initial dependencies...`)\n dependencyGraph = makeDependencyGraph(config, testFiles)\n }\n\n // registered before anything loads, so a rerun reloads only what the graph says changed\n if (dependencyGraph !== null) {\n const graph = dependencyGraph\n const { registerGraphReload } = await import('./lib/esmGraphReload.js')\n const { handle } = registerGraphReload(file => graph.versionOf(file))\n stopFns.push(() => handle.deregister())\n } else {\n // todo: one instance per run; until then each test file reloads its whole graph\n const { registerTreeReload } = await import('./lib/esmTreeReload.js')\n const handle = registerTreeReload()\n stopFns.push(() => handle.deregister())\n }\n\n // live before the first test runs, for two reasons. A change landing during the initial\n // run (a compiler emit, typically) is seen rather than lost. And the watcher starts on a\n // quiet loop: node-watch probes for native recursive support with a 200ms timeout, and a\n // loop busy running tests fails the probe, so it falls back to a sync walk of every\n // directory - which then starved the tests' own timers (a 10ms interval fired once in 45ms)\n const { watchFilesAndRunTests } = await import('./lib/watchFilesAndRunTests.js')\n const stopWatcher = await watchFilesAndRunTests(\n config,\n //testFiles,\n dependencyGraph,\n failingTests, // CHECK this should also be in state\n reRunManager,\n //watchRunState,\n runsOut,\n executionFilters\n )\n stopFns.push(stopWatcher)\n\n const { runTests } = await import('./lib/runTests.js')\n let initialTestRun: Promise<boolean | null> | null = null\n if (testFiles.size > 0) {\n if (config.watch.runAllOnStartup) {\n agentOut(chalk.brightblue`running initial tests...`)\n initialTestRun = runTests(\n config, testFiles,\n reRunManager,\n concurrency,\n (alwaysCacheBust) ? 'refresh' : 'cached',\n runsOut, executionFilters\n ).then(testsResult => {\n const time = new Date().getTime() - startTime\n //await new Promise((resolve) => setTimeout(resolve, 100))\n agentOut(chalk.grey`\\n${time.toLocaleString()}ms`)\n return testsResult\n })\n reRunManager.state.currentRun = initialTestRun\n }\n } else {\n agentOut(chalk.orange`no test files found`)\n writeStatusFile(config, statusCodes.couldNotRun, 'no test files found')\n // still reported as a run, so a reader waiting on a done line always gets one\n const run = agentRunStart(config, 0)\n agentDone(\n config, run, statusCodes.couldNotRun, 'no test files found',\n null, new Date().getTime() - startTime, 0\n )\n }\n\n // announced once the initial run is over, so `watching` marks a real milestone: startup is\n // complete and the watcher is live. A failed run is reported by listenToUser below.\n if (initialTestRun !== null) await initialTestRun.catch(() => null)\n\n agentOut(chalk.brightblue`watching...`)\n agentWatching(config, testFiles.size)\n\n const { listenToUser } = await import('./lib/listenToUser.js')\n const disposeTty = listenToUser(\n reRunManager,\n files => {\n return runTests(config, files, reRunManager, concurrency, 'refresh', runsOut, executionFilters)\n },\n config.watch.ttyActionsOnKeypress,\n initialTestRun,\n input,\n runsOut\n )\n stopFns.push(disposeTty)\n\n const dispose = () => {\n for (const stop of stopFns) {\n stop()\n }\n stopFns.length = 0 // Idempotencize\n }\n return dispose\n\n\n // (async () => {\n // await new Promise<void>(() => {})\n // })()\n //await new Promise<void>(() => {})\n}\n"]}
|
package/dist/describe.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import chalk from './packages/chalk.js';
|
|
2
2
|
import { checkMeta } from './checkMeta.js';
|
|
3
3
|
import { debug } from './output.js';
|
|
4
|
+
import { registrationFor } from './registration.js';
|
|
4
5
|
export function describe(theThing, testsOrMeta, possiblyTests) {
|
|
5
6
|
if (!global.__sxy_test_runner__) {
|
|
6
7
|
throw new Error('sxy-test-runner describe() was called, but the test framework has not initialized.'
|
|
@@ -8,8 +9,9 @@ export function describe(theThing, testsOrMeta, possiblyTests) {
|
|
|
8
9
|
+ ', instead of running \'pnpm sxy-test-runner\'');
|
|
9
10
|
// todo - maybe we can initialise the framework and just run only this test file
|
|
10
11
|
}
|
|
11
|
-
const
|
|
12
|
-
|
|
12
|
+
const registration = registrationFor(global.__sxy_test_runner__);
|
|
13
|
+
const thisDescribeCounter = registration.describeCounter;
|
|
14
|
+
registration.describeCounter++;
|
|
13
15
|
let meta = undefined;
|
|
14
16
|
let tests;
|
|
15
17
|
if (testsOrMeta === undefined) {
|
|
@@ -23,7 +25,7 @@ export function describe(theThing, testsOrMeta, possiblyTests) {
|
|
|
23
25
|
meta = testsOrMeta;
|
|
24
26
|
tests = possiblyTests; // eslint-disable-line @typescript-eslint/no-unsafe-type-assertion
|
|
25
27
|
}
|
|
26
|
-
|
|
28
|
+
registration.describes.push({
|
|
27
29
|
counter: thisDescribeCounter,
|
|
28
30
|
thing: theThing,
|
|
29
31
|
meta,
|
package/dist/describe.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"describe.js","sourceRoot":"","sources":["../src/describe.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,qBAAqB,CAAA;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"describe.js","sourceRoot":"","sources":["../src/describe.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,qBAAqB,CAAA;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACnC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAOnD,MAAM,UAAU,QAAQ,CACpB,QAAgB,EAAE,WAA4C,EAAE,aAAgC;IAEhG,IAAI,CAAC,MAAM,CAAC,mBAAmB,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACX,oFAAoF;cAClF,0DAA0D;cAC1D,+CAA+C,CACpD,CAAA;QACD,gFAAgF;IACpF,CAAC;IAED,MAAM,YAAY,GAAG,eAAe,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAA;IAChE,MAAM,mBAAmB,GAAG,YAAY,CAAC,eAAe,CAAA;IACxD,YAAY,CAAC,eAAe,EAAE,CAAA;IAE9B,IAAI,IAAI,GAAG,SAAS,CAAA;IACpB,IAAI,KAAK,CAAA;IACT,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,2CAA2C,QAAQ,IAAI,CAAC,CAAA;IAC5E,CAAC;SAAM,IAAI,OAAO,WAAW,KAAK,UAAU,EAAE,CAAC;QAC3C,KAAK,GAAG,WAAW,CAAA;IACvB,CAAC;SAAM,CAAC;QACJ,SAAS,CAAC,aAAa,QAAQ,IAAI,EAAE,WAAW,EAAE,CAAC,eAAe,EAAE,iBAAiB,CAAC,CAAC,CAAA;QACvF,IAAI,GAAG,WAAW,CAAA;QAClB,KAAK,GAAG,aAAiC,CAAA,CAAC,kEAAkE;IAChH,CAAC;IACD,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC;QACxB,OAAO,EAAE,mBAAmB;QAC5B,KAAK,EAAE,QAAQ;QACf,IAAI;QACJ,KAAK;KACR,CAAC,CAAA;IAEF,KAAK,CACD,KAAK,CAAC,SAAS,CAAA,GAAG,mBAAmB,GAAG;UAClC,KAAK,CAAC,SAAS,CAAA,aAAa,GAAG,KAAK,CAAC,UAAU,CAAA,GAAG,QAAQ,IAAI,CACvE,CAAA;AACL,CAAC","sourcesContent":["\nimport type { DescribeCallback } from './types.js'\nimport chalk from './packages/chalk.js'\nimport { checkMeta } from './checkMeta.js'\nimport { debug } from './output.js'\nimport { registrationFor } from './registration.js'\n\n\nexport type DescribeMeta = { parallelTests: boolean } | { sequentialTests: boolean }\n\nexport function describe(theThing: string, tests: DescribeCallback): void\nexport function describe(theThing: string, meta: DescribeMeta, tests: DescribeCallback): void\nexport function describe(\n theThing: string, testsOrMeta: DescribeCallback | DescribeMeta, possiblyTests?: DescribeCallback\n): void {\n if (!global.__sxy_test_runner__) {\n throw new Error(\n 'sxy-test-runner describe() was called, but the test framework has not initialized.'\n + ' This might be because you have run a test file directly'\n + ', instead of running \\'pnpm sxy-test-runner\\''\n )\n // todo - maybe we can initialise the framework and just run only this test file\n }\n\n const registration = registrationFor(global.__sxy_test_runner__)\n const thisDescribeCounter = registration.describeCounter\n registration.describeCounter++\n\n let meta = undefined\n let tests\n if (testsOrMeta === undefined) {\n throw new Error(`callback argument missing for describe('${theThing}')`)\n } else if (typeof testsOrMeta === 'function') {\n tests = testsOrMeta\n } else {\n checkMeta(`describe('${theThing}')`, testsOrMeta, ['parallelTests', 'sequentialTests'])\n meta = testsOrMeta\n tests = possiblyTests as DescribeCallback // eslint-disable-line @typescript-eslint/no-unsafe-type-assertion\n }\n registration.describes.push({\n counter: thisDescribeCounter,\n thing: theThing,\n meta,\n tests\n })\n\n debug(\n chalk.lightgrey`${thisDescribeCounter})`\n + chalk.lightgrey` Done with ` + chalk.brightblue`${theThing}\\n`\n )\n}\n"]}
|
package/dist/meta.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { checkMeta } from './checkMeta.js';
|
|
2
|
+
import { registrationFor } from './registration.js';
|
|
2
3
|
export function meta(theMeta) {
|
|
3
4
|
if (!global.__sxy_test_runner__) {
|
|
4
5
|
throw new Error('sxy-test-runner meta() was called, but the test framework has not initialized.'
|
|
@@ -6,6 +7,6 @@ export function meta(theMeta) {
|
|
|
6
7
|
+ ', instead of running \'pnpm sxy-test-runner\'');
|
|
7
8
|
}
|
|
8
9
|
checkMeta('meta()', theMeta, ['parallelDescribes', 'sequentialDescribes']);
|
|
9
|
-
global.__sxy_test_runner__.fileMeta = theMeta;
|
|
10
|
+
registrationFor(global.__sxy_test_runner__).fileMeta = theMeta;
|
|
10
11
|
}
|
|
11
12
|
//# sourceMappingURL=meta.js.map
|
package/dist/meta.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta.js","sourceRoot":"","sources":["../src/meta.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"meta.js","sourceRoot":"","sources":["../src/meta.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAOnD,MAAM,UAAU,IAAI,CAAC,OAAiB;IAClC,IAAI,CAAC,MAAM,CAAC,mBAAmB,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACX,gFAAgF;cAC9E,0DAA0D;cAC1D,+CAA+C,CACpD,CAAA;IACL,CAAC;IAED,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC,mBAAmB,EAAE,qBAAqB,CAAC,CAAC,CAAA;IAE1E,eAAe,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,QAAQ,GAAG,OAAO,CAAA;AAClE,CAAC","sourcesContent":["\nimport { checkMeta } from './checkMeta.js'\nimport { registrationFor } from './registration.js'\n\n\nexport type FileMeta\n = { parallelDescribes: boolean }\n | { sequentialDescribes: boolean }\n\nexport function meta(theMeta: FileMeta): void {\n if (!global.__sxy_test_runner__) {\n throw new Error(\n 'sxy-test-runner meta() was called, but the test framework has not initialized.'\n + ' This might be because you have run a test file directly'\n + ', instead of running \\'pnpm sxy-test-runner\\''\n )\n }\n\n checkMeta('meta()', theMeta, ['parallelDescribes', 'sequentialDescribes'])\n\n registrationFor(global.__sxy_test_runner__).fileMeta = theMeta\n}\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { FileRegistration, SxyTestRunnerGlobal } from './types.js';
|
|
2
|
+
export declare function withoutQuery(url: string): string;
|
|
3
|
+
export declare function registrationFor(registry: SxyTestRunnerGlobal): SxyTestRunnerGlobal | FileRegistration;
|
|
4
|
+
//# sourceMappingURL=registration.d.ts.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { getCallSites } from 'node:util';
|
|
2
|
+
const maxCallSites = 200;
|
|
3
|
+
export function withoutQuery(url) {
|
|
4
|
+
const parsed = new URL(url);
|
|
5
|
+
parsed.search = '';
|
|
6
|
+
parsed.hash = '';
|
|
7
|
+
return parsed.href;
|
|
8
|
+
}
|
|
9
|
+
// the URL of the module whose top level this call comes from - each module evaluates on a stack
|
|
10
|
+
// of its own, so a module imported by the test file never has the test file beneath it
|
|
11
|
+
function topLevelUrl(fallback) {
|
|
12
|
+
// the module URLs as loaded - with --enable-source-maps they would otherwise name the source
|
|
13
|
+
const sites = getCallSites(maxCallSites, { sourceMap: false });
|
|
14
|
+
// a stack this deep may have lost its outermost frames
|
|
15
|
+
if (sites.length >= maxCallSites)
|
|
16
|
+
return fallback;
|
|
17
|
+
return sites.findLast(site => site.scriptName.startsWith('file:'))?.scriptName ?? fallback;
|
|
18
|
+
}
|
|
19
|
+
// where a describe or meta call registers: the registry itself outside a test file load, as
|
|
20
|
+
// when describe is called directly, otherwise the registration of the module that made it
|
|
21
|
+
export function registrationFor(registry) {
|
|
22
|
+
if (registry.files === undefined || registry.loadingUrl === undefined)
|
|
23
|
+
return registry;
|
|
24
|
+
const url = topLevelUrl(registry.loadingUrl);
|
|
25
|
+
const key = withoutQuery(url);
|
|
26
|
+
let registration = registry.files.get(key);
|
|
27
|
+
// a newer evaluation of the same file replaces what an older one registered
|
|
28
|
+
if (registration?.url !== url) {
|
|
29
|
+
registration = { url, describes: [], describeCounter: 1 };
|
|
30
|
+
registry.files.set(key, registration);
|
|
31
|
+
}
|
|
32
|
+
return registration;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=registration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registration.js","sourceRoot":"","sources":["../src/registration.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAKxC,MAAM,YAAY,GAAG,GAAG,CAAA;AAExB,MAAM,UAAU,YAAY,CAAC,GAAW;IACpC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;IAC3B,MAAM,CAAC,MAAM,GAAG,EAAE,CAAA;IAClB,MAAM,CAAC,IAAI,GAAG,EAAE,CAAA;IAChB,OAAO,MAAM,CAAC,IAAI,CAAA;AACtB,CAAC;AAED,gGAAgG;AAChG,uFAAuF;AACvF,SAAS,WAAW,CAAC,QAAgB;IACjC,6FAA6F;IAC7F,MAAM,KAAK,GAAG,YAAY,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAA;IAC9D,uDAAuD;IACvD,IAAI,KAAK,CAAC,MAAM,IAAI,YAAY;QAAE,OAAO,QAAQ,CAAA;IACjD,OAAO,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,EAAE,UAAU,IAAI,QAAQ,CAAA;AAC9F,CAAC;AAED,4FAA4F;AAC5F,0FAA0F;AAC1F,MAAM,UAAU,eAAe,CAAC,QAA6B;IACzD,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS,IAAI,QAAQ,CAAC,UAAU,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAA;IAEtF,MAAM,GAAG,GAAG,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAA;IAC5C,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,CAAA;IAC7B,IAAI,YAAY,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC1C,4EAA4E;IAC5E,IAAI,YAAY,EAAE,GAAG,KAAK,GAAG,EAAE,CAAC;QAC5B,YAAY,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,EAAE,eAAe,EAAE,CAAC,EAAE,CAAA;QACzD,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,CAAA;IACzC,CAAC;IACD,OAAO,YAAY,CAAA;AACvB,CAAC","sourcesContent":["\nimport { getCallSites } from 'node:util'\n\nimport type { FileRegistration, SxyTestRunnerGlobal } from './types.js'\n\n\nconst maxCallSites = 200\n\nexport function withoutQuery(url: string): string {\n const parsed = new URL(url)\n parsed.search = ''\n parsed.hash = ''\n return parsed.href\n}\n\n// the URL of the module whose top level this call comes from - each module evaluates on a stack\n// of its own, so a module imported by the test file never has the test file beneath it\nfunction topLevelUrl(fallback: string): string {\n // the module URLs as loaded - with --enable-source-maps they would otherwise name the source\n const sites = getCallSites(maxCallSites, { sourceMap: false })\n // a stack this deep may have lost its outermost frames\n if (sites.length >= maxCallSites) return fallback\n return sites.findLast(site => site.scriptName.startsWith('file:'))?.scriptName ?? fallback\n}\n\n// where a describe or meta call registers: the registry itself outside a test file load, as\n// when describe is called directly, otherwise the registration of the module that made it\nexport function registrationFor(registry: SxyTestRunnerGlobal): SxyTestRunnerGlobal | FileRegistration {\n if (registry.files === undefined || registry.loadingUrl === undefined) return registry\n\n const url = topLevelUrl(registry.loadingUrl)\n const key = withoutQuery(url)\n let registration = registry.files.get(key)\n // a newer evaluation of the same file replaces what an older one registered\n if (registration?.url !== url) {\n registration = { url, describes: [], describeCounter: 1 }\n registry.files.set(key, registration)\n }\n return registration\n}\n"]}
|
package/dist/types.d.ts
CHANGED
|
@@ -79,10 +79,18 @@ export type It = {
|
|
|
79
79
|
should: string;
|
|
80
80
|
test: (parcel: TestParcel) => void | Promise<void>;
|
|
81
81
|
};
|
|
82
|
+
export interface FileRegistration {
|
|
83
|
+
url: string;
|
|
84
|
+
describes: Describe[];
|
|
85
|
+
describeCounter: number;
|
|
86
|
+
fileMeta?: FileMeta;
|
|
87
|
+
}
|
|
82
88
|
export interface SxyTestRunnerGlobal {
|
|
83
89
|
describes: Describe[];
|
|
84
90
|
describeCounter: number;
|
|
85
91
|
fileMeta?: FileMeta;
|
|
92
|
+
files?: Map<string, FileRegistration>;
|
|
93
|
+
loadingUrl?: string;
|
|
86
94
|
}
|
|
87
95
|
declare global {
|
|
88
96
|
var __sxy_test_runner__: SxyTestRunnerGlobal | undefined;
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,2EAA2E;AAC3E,2EAA2E;AAC3E,2EAA2E;AAC3E,+EAA+E","sourcesContent":["\n// Shared types for the test-run data model, user config, and CLI plumbing.\n// The config/result shapes are inferred from usage across the old awaitful\n// source (defaultConfig.js, validateConfig.js, init.js's template, and the\n// run*/parseDescribe/showTestResult modules) - there was no prior type source.\n\nimport type { FileMeta } from './meta.js'\nimport type { DescribeMeta } from './describe.js'\n\n\nexport type ExecutionMode = 'parallel' | 'sequential'\nexport type GlobPattern = string | string[]\n\nexport interface ExecutionConfig {\n files: ExecutionMode\n describes: ExecutionMode\n tests: ExecutionMode\n}\n\n// path to write the latest watch run status to, or false to write none\nexport type StatusFileConfig = string | false\n\nexport interface WatchConfig {\n watchFilesBase: string\n watchFiles: GlobPattern\n watchFilesIgnore: GlobPattern\n runAllOnStartup: boolean\n reRunFailingTests: boolean\n // map a changed file to the tests that import it. Off, any watched change runs everything\n dependencyEvaluation: boolean\n ttyActionsOnKeypress: boolean\n statusFile: StatusFileConfig\n}\n\nexport type TaskExports = Record<string, unknown>\nexport type ConfigTaskFn = (parcel?: TaskExports) => TaskExports | void | Promise<TaskExports | void>\n// a task may also be a file path (relative to the project root) to dynamically import\nexport type ConfigTask = ConfigTaskFn | string\nexport type ConfigTasks = ConfigTask | ConfigTask[]\n\nexport interface FinalConfig {\n testsBase: string\n tests: GlobPattern\n testsFilter?: string\n testsIgnore: GlobPattern\n setup?: ConfigTasks\n beforeEachFile?: ConfigTasks\n afterEachFile?: ConfigTasks\n beforeEachDescribe?: ConfigTasks\n afterEachDescribe?: ConfigTasks\n beforeEachTest?: ConfigTasks\n afterEachTest?: ConfigTasks\n teardown?: ConfigTasks\n showErrorTrace: boolean\n compact: boolean\n // repeat a failed run's failures above the tallies, where scrolling has not buried them\n restateFailures: boolean\n // report the run as single agent readable lines instead of the usual output\n agent: boolean\n // the most characters of error text on each agent fail line; Infinity for no limit\n agentLineLengthLimit: number\n // stop the run at the first failing test, erroring describe or unloadable test file.\n // Set by `once --fail-fast` only: it describes one invocation, not a project, and in\n // watch mode it would silently truncate runs that report themselves as covering\n // everything\n failFast: boolean\n execution: ExecutionConfig\n watch: WatchConfig\n}\n\nexport type UserConfig = Partial<\n Omit<FinalConfig, 'testsFilter' | 'failFast' | 'execution' | 'watch'>\n> & {\n execution?: Partial<ExecutionConfig>\n watch?: Partial<WatchConfig>\n}\n\nexport type UserConfigInternal = UserConfig\n & Partial<Pick<FinalConfig, 'testsFilter' | 'failFast'>>\n\n\n// -- test-run data model --------------------------------------------------\n\nexport type TestParcel = TaskExports\n\nexport interface DescribeParcel extends TaskExports {\n it: (should: string, test: (parcel: TestParcel) => void | Promise<void>) => void\n test: (should: string, test: (parcel: TestParcel) => void | Promise<void>) => void\n afterDescribe: (func: () => void | Promise<void>) => void\n beforeEachTest: (func: () => TaskExports | void | Promise<TaskExports | void>) => void\n afterEachTest: (func: () => void | Promise<void>) => void\n}\n\nexport type DescribeCallback = (parcel: DescribeParcel) => void | Promise<void>\n\n\n\nexport interface ParsedDescribe {\n its: It[]\n beforeDescribeExports: TaskExports\n afterDescribeFunc?: () => void | Promise<void>\n beforeEachTestFunc?: () => TaskExports | void | Promise<TaskExports | void>\n afterEachTestFunc?: () => void | Promise<void>\n error?: unknown\n}\n\n// export interface TestError extends Error {\n// actual?: unknown\n// expected?: unknown\n// }\n\n\n\n\n\n\n\n\n\n\nexport type DependencyTrees = Record<string, string[]>\n\nexport type OutFn = (...texts: unknown[]) => void\n\n\n\n// -- globals ----------------------------------------------------------------\n\nexport type Describe = {\n counter: number\n thing: string\n meta?: DescribeMeta\n tests: DescribeCallback\n}\n\nexport type It = {\n counter: number\n should: string\n test: (parcel: TestParcel) => void | Promise<void>\n}\n\nexport interface SxyTestRunnerGlobal {\n describes: Describe[]\n describeCounter: number\n fileMeta?: FileMeta\n}\ndeclare global {\n var __sxy_test_runner__: SxyTestRunnerGlobal | undefined\n var __sxyt_commandLineArguments: string[]\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,2EAA2E;AAC3E,2EAA2E;AAC3E,2EAA2E;AAC3E,+EAA+E","sourcesContent":["\n// Shared types for the test-run data model, user config, and CLI plumbing.\n// The config/result shapes are inferred from usage across the old awaitful\n// source (defaultConfig.js, validateConfig.js, init.js's template, and the\n// run*/parseDescribe/showTestResult modules) - there was no prior type source.\n\nimport type { FileMeta } from './meta.js'\nimport type { DescribeMeta } from './describe.js'\n\n\nexport type ExecutionMode = 'parallel' | 'sequential'\nexport type GlobPattern = string | string[]\n\nexport interface ExecutionConfig {\n files: ExecutionMode\n describes: ExecutionMode\n tests: ExecutionMode\n}\n\n// path to write the latest watch run status to, or false to write none\nexport type StatusFileConfig = string | false\n\nexport interface WatchConfig {\n watchFilesBase: string\n watchFiles: GlobPattern\n watchFilesIgnore: GlobPattern\n runAllOnStartup: boolean\n reRunFailingTests: boolean\n // map a changed file to the tests that import it. Off, any watched change runs everything\n dependencyEvaluation: boolean\n ttyActionsOnKeypress: boolean\n statusFile: StatusFileConfig\n}\n\nexport type TaskExports = Record<string, unknown>\nexport type ConfigTaskFn = (parcel?: TaskExports) => TaskExports | void | Promise<TaskExports | void>\n// a task may also be a file path (relative to the project root) to dynamically import\nexport type ConfigTask = ConfigTaskFn | string\nexport type ConfigTasks = ConfigTask | ConfigTask[]\n\nexport interface FinalConfig {\n testsBase: string\n tests: GlobPattern\n testsFilter?: string\n testsIgnore: GlobPattern\n setup?: ConfigTasks\n beforeEachFile?: ConfigTasks\n afterEachFile?: ConfigTasks\n beforeEachDescribe?: ConfigTasks\n afterEachDescribe?: ConfigTasks\n beforeEachTest?: ConfigTasks\n afterEachTest?: ConfigTasks\n teardown?: ConfigTasks\n showErrorTrace: boolean\n compact: boolean\n // repeat a failed run's failures above the tallies, where scrolling has not buried them\n restateFailures: boolean\n // report the run as single agent readable lines instead of the usual output\n agent: boolean\n // the most characters of error text on each agent fail line; Infinity for no limit\n agentLineLengthLimit: number\n // stop the run at the first failing test, erroring describe or unloadable test file.\n // Set by `once --fail-fast` only: it describes one invocation, not a project, and in\n // watch mode it would silently truncate runs that report themselves as covering\n // everything\n failFast: boolean\n execution: ExecutionConfig\n watch: WatchConfig\n}\n\nexport type UserConfig = Partial<\n Omit<FinalConfig, 'testsFilter' | 'failFast' | 'execution' | 'watch'>\n> & {\n execution?: Partial<ExecutionConfig>\n watch?: Partial<WatchConfig>\n}\n\nexport type UserConfigInternal = UserConfig\n & Partial<Pick<FinalConfig, 'testsFilter' | 'failFast'>>\n\n\n// -- test-run data model --------------------------------------------------\n\nexport type TestParcel = TaskExports\n\nexport interface DescribeParcel extends TaskExports {\n it: (should: string, test: (parcel: TestParcel) => void | Promise<void>) => void\n test: (should: string, test: (parcel: TestParcel) => void | Promise<void>) => void\n afterDescribe: (func: () => void | Promise<void>) => void\n beforeEachTest: (func: () => TaskExports | void | Promise<TaskExports | void>) => void\n afterEachTest: (func: () => void | Promise<void>) => void\n}\n\nexport type DescribeCallback = (parcel: DescribeParcel) => void | Promise<void>\n\n\n\nexport interface ParsedDescribe {\n its: It[]\n beforeDescribeExports: TaskExports\n afterDescribeFunc?: () => void | Promise<void>\n beforeEachTestFunc?: () => TaskExports | void | Promise<TaskExports | void>\n afterEachTestFunc?: () => void | Promise<void>\n error?: unknown\n}\n\n// export interface TestError extends Error {\n// actual?: unknown\n// expected?: unknown\n// }\n\n\n\n\n\n\n\n\n\n\nexport type DependencyTrees = Record<string, string[]>\n\nexport type OutFn = (...texts: unknown[]) => void\n\n\n\n// -- globals ----------------------------------------------------------------\n\nexport type Describe = {\n counter: number\n thing: string\n meta?: DescribeMeta\n tests: DescribeCallback\n}\n\nexport type It = {\n counter: number\n should: string\n test: (parcel: TestParcel) => void | Promise<void>\n}\n\n// what one evaluation of a module registered, from the exact URL it was evaluated as\nexport interface FileRegistration {\n url: string\n describes: Describe[]\n describeCounter: number\n fileMeta?: FileMeta\n}\n\nexport interface SxyTestRunnerGlobal {\n describes: Describe[]\n describeCounter: number\n fileMeta?: FileMeta\n // set while loading test files: registrations filed by the module whose top level made them,\n // so a test file imported by another is credited to itself, keyed by URL without its query\n files?: Map<string, FileRegistration>\n // the URL the test file is being imported as, for a call whose top level cannot be found\n loadingUrl?: string\n}\ndeclare global {\n var __sxy_test_runner__: SxyTestRunnerGlobal | undefined\n var __sxyt_commandLineArguments: string[]\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sxy-test-runner",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.5",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"homepage": "https://github.com/RobertSandiford/sxy-test-runner",
|
|
6
6
|
"repository": {
|
|
@@ -64,17 +64,20 @@
|
|
|
64
64
|
"eslint-config-tungsten-flat": "^0.3.4",
|
|
65
65
|
"eslint-plugin-imports-regulation": "0.2.4",
|
|
66
66
|
"eslint-plugin-start-end-lines": "^0.1.0",
|
|
67
|
+
"eslint-plugin-use-disposables": "^0.1.1",
|
|
67
68
|
"mocha": "^9.2.2",
|
|
68
69
|
"mocha-steps": "^1.3.0",
|
|
69
70
|
"nodemon": "^2.0.22",
|
|
70
71
|
"sinon": "^12.0.1",
|
|
71
72
|
"sinon-chai": "^3.7.0",
|
|
73
|
+
"sxy-assert": "^0.1.13",
|
|
72
74
|
"typescript": "^6.0.3"
|
|
73
75
|
},
|
|
74
76
|
"scripts": {
|
|
75
77
|
"build": "tscmon",
|
|
76
78
|
"build-once": "tscmon --once",
|
|
77
79
|
"time-dep-graph": "node bench/depGraph.ts",
|
|
80
|
+
"time-reload": "node bench/reload.ts",
|
|
78
81
|
"dev-mon": "cross-env NODE_OPTIONS=\"--experimental-specifier-resolution=node\" nodemon --experimental-specifier-resolution=node --watch dist/cli --watch dist/cli/lib --watch sxy-test-runner.config.js --watch sxy-loader.config.js dist/cli/index.js",
|
|
79
82
|
"dev-mon-input": "cross-env NODE_OPTIONS=\"--experimental-specifier-resolution=node\" nodemon --no-stdin --experimental-specifier-resolution=node --watch dist/cli --watch dist/cli/lib --watch sxy-test-runner.config.js --watch sxy-loader.config.js dist/cli/index.js",
|
|
80
83
|
"dev": "cross-env NODE_OPTIONS=\"--experimental-specifier-resolution=node\" node --experimental-specifier-resolution=node dist/cli/index.js",
|
|
@@ -116,7 +119,7 @@
|
|
|
116
119
|
"unit-test-add-exports": "mocha --watch --parallel --config unitTesting/.mocharc.cjs --watch-files dist,unitTesting dist/**/addExports.unitTest.js",
|
|
117
120
|
"unit-test-describe": "mocha --watch --parallel --config unitTesting/.mocharc.cjs --watch-files dist,unitTesting dist/**/describe.unitTest.js",
|
|
118
121
|
"unit-test-run-tests": "mocha --watch --parallel --config unitTesting/.mocharc.cjs --watch-files dist,unitTesting dist/**/runTests.unitTest.js",
|
|
119
|
-
"unit-test-esm-reload": "mocha --watch --parallel --config unitTesting/.mocharc.cjs --watch-files dist,unitTesting dist/**/
|
|
122
|
+
"unit-test-esm-reload": "mocha --watch --parallel --config unitTesting/.mocharc.cjs --watch-files dist,unitTesting dist/**/esmTreeReload.unitTest.js",
|
|
120
123
|
"unit-test-user-input": "mocha --watch --parallel --config unitTesting/.mocharc.cjs --watch-files dist,unitTesting dist/**/handleUserInput.unitTest.js dist/**/listenToUser.unitTest.js",
|
|
121
124
|
"mocha-trial": "mocha --watch --parallel --config unitTesting/.mocharc.cjs --watch-files dist,unitTesting dist/**/runTest.unitTest.js"
|
|
122
125
|
}
|
package/readme.md
CHANGED
|
@@ -74,18 +74,18 @@ This will create a config in your project folder. It can be moved to a folder na
|
|
|
74
74
|
}
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
The other config options
|
|
77
|
+
The other config options are fairly well explained in the config. More info on them later.
|
|
78
78
|
|
|
79
79
|
### 4. Run
|
|
80
80
|
|
|
81
81
|
```
|
|
82
82
|
npx sxy-test-runner
|
|
83
83
|
```
|
|
84
|
-
|
|
84
|
+
*`sxyt` and `sxy-test` are aliases for sxy-test-runner and can be used instead*
|
|
85
85
|
|
|
86
86
|
("npx" can be omitted in package.json scripts)
|
|
87
87
|
|
|
88
|
-
sxy-test-runner runs watch mode, re-running only relevant tests, by default.
|
|
88
|
+
`sxy-test-runner` runs watch mode, re-running only relevant tests, by default.
|
|
89
89
|
|
|
90
90
|
While watch mode is idle, enter `r` or `l` to re-run the last set of tests, `a` to run
|
|
91
91
|
all tests again, or `f` to re-run the currently failing tests.
|
|
@@ -115,70 +115,16 @@ npx sxy-test-runner once --filter "**/users/**"
|
|
|
115
115
|
`--test-files` and `--filter` can be combined: the former replaces the configured test
|
|
116
116
|
pattern, then the latter filters the discovered files.
|
|
117
117
|
|
|
118
|
-
`--filter-describe` and `--filter-it` filter
|
|
119
|
-
have loaded. sxy-test-runner gives each test file a fresh ESM instance and propagates it
|
|
120
|
-
through that file's static dependency graph, bypassing the ordinary ESM cache. Loading a
|
|
121
|
-
large set of files and filtering their describes or tests afterward can therefore be much
|
|
122
|
-
slower than filtering files first. Prefer `--filter` when a file glob can select the work
|
|
123
|
-
you need, and use the name filters for further narrowing within those files.
|
|
118
|
+
`--filter-describe` and `--filter-it` filter describes and tests by name.
|
|
124
119
|
|
|
125
|
-
To
|
|
126
|
-
`watch.statusFile` in the config. This is for anything watching the suite from outside - a
|
|
127
|
-
script, a notifier, an agent - that would otherwise have to read the terminal:
|
|
128
|
-
|
|
129
|
-
```
|
|
130
|
-
npx sxy-test-runner --status-file .sxyt-status
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
The first line is a status code, a `-`, and a short description. The second is the time the
|
|
134
|
-
run finished, then the summary, then any failures, and the run's duration last:
|
|
135
|
-
|
|
136
|
-
```
|
|
137
|
-
1 - 2 tests failed
|
|
138
|
-
2026-08-03 20:14:52 +01:00
|
|
139
|
-
Tests: 8/10
|
|
140
|
-
Items: 4/5
|
|
141
|
-
Test Files: 1/2
|
|
142
|
-
Failures:
|
|
143
|
-
f: tests/users.test.js
|
|
144
|
-
d: creating a user
|
|
145
|
-
t: rejects a duplicate email
|
|
146
|
-
e: AssertionError: expected 409 to equal 200
|
|
147
|
-
t: sends a welcome email
|
|
148
|
-
e: Error: connect ECONNREFUSED 127.0.0.1:2525
|
|
149
|
-
1,204ms
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
Failures nest as `f:` file, `d:` describe, `t:` test, `e:` error - one line each. Diffs, logs
|
|
153
|
-
and stack traces stay in the terminal.
|
|
154
|
-
|
|
155
|
-
| code | meaning |
|
|
156
|
-
| --- | --- |
|
|
157
|
-
| -1 | watch mode has started, but no run has finished |
|
|
158
|
-
| 0 | everything passed |
|
|
159
|
-
| 1 | tests ran and failed |
|
|
160
|
-
| 2 | the run died partway - a test file would not load, or a describe threw |
|
|
161
|
-
| 3 | nothing ran - no test files were found, or the filters matched nothing |
|
|
162
|
-
|
|
163
|
-
Watch mode writes the `-1` status on startup, so a status left over from a previous session
|
|
164
|
-
is never read as the current one. Each write goes to a temporary file and is renamed into
|
|
165
|
-
place, so a poller only ever sees a complete status.
|
|
166
|
-
|
|
167
|
-
Name the file `.sxys` and the VS Code extension in
|
|
168
|
-
[`vscode-sxyt-status/`](vscode-sxyt-status) will colour it - green when the run passed, red
|
|
169
|
-
where it did not.
|
|
170
|
-
|
|
171
|
-
To specific an alternate config, use -c or --config
|
|
120
|
+
To specify an alternate config, use -c or --config
|
|
172
121
|
```
|
|
173
|
-
npx sxy-test-runner --config
|
|
122
|
+
npx sxy-test-runner --config sxyt.alternate.config.js
|
|
174
123
|
```
|
|
175
124
|
|
|
176
125
|
## Reporting for an agent
|
|
177
126
|
|
|
178
|
-
`--agent` replaces the usual output with
|
|
179
|
-
process's stdout rather than a terminal. It works in both modes. In `once` it leaves only
|
|
180
|
-
the failures and the summary - passing tests are not listed - and the exit code is
|
|
181
|
-
unchanged, so the run stays usable in CI:
|
|
127
|
+
`--agent` replaces the usual (verbose) output with lines for key events - e.g. startup, failures, and completion.
|
|
182
128
|
|
|
183
129
|
```
|
|
184
130
|
npx sxy-test-runner once --agent
|
|
@@ -192,77 +138,28 @@ npx sxy-test-runner once --agent
|
|
|
192
138
|
[sxyt] done | n=1 | status=failed | desc=1 test failed | tests=2/3 | items=1/2 | files=1/2 | failing=1 | ms=150
|
|
193
139
|
```
|
|
194
140
|
|
|
195
|
-
Every line is one complete event: `[sxyt] <event>` followed by ` | <key>=<value>` pairs.
|
|
196
|
-
Newlines in free text are collapsed and any `|` becomes `/`, so one event never spans two
|
|
197
|
-
lines. In watch mode the stream continues with `change`, further `run`/`done` pairs, and a
|
|
198
|
-
`watching` line once the watcher is live.
|
|
199
|
-
|
|
200
|
-
`failing` counts the test files still known to be failing across the whole session, and
|
|
201
|
-
`covers` says what the run was built from, so a partial re-run cannot be mistaken for a
|
|
202
|
-
clean suite. `status` is one of `passed`, `failed`, `aborted` (a test file would not load, or
|
|
203
|
-
a describe threw) or `could-not-run` - the same states as the status file table above, named
|
|
204
|
-
rather than numbered. It is not the process exit code: read that from the process.
|
|
205
|
-
|
|
206
|
-
Each failure's error message is cut at 500 characters. Set `agentLineLengthLimit` in the
|
|
207
|
-
config to change that, or to `Infinity` to keep messages whole.
|
|
208
|
-
|
|
209
141
|
Agent mode also sets the environment variables `SXYT_AGENT` and `SXY_TEST_RUNNER_AGENT` to
|
|
210
142
|
`true`, so setup code and tests can tell they are running under it.
|
|
211
143
|
|
|
212
|
-
## Stopping at the first failure
|
|
213
|
-
|
|
214
|
-
`-x` or `--fail-fast` stops a `once` run at the first failing test, erroring describe, or
|
|
215
|
-
test file that will not load. The failure is reported in full and nothing further starts;
|
|
216
|
-
`afterEach*` hooks and `teardown` still run:
|
|
217
|
-
|
|
218
|
-
```
|
|
219
|
-
npx sxy-test-runner once --fail-fast
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
The tallies then count only what ran, so the summary ends with `stopped at the first
|
|
223
|
-
failure (failFast)`. There is no watch equivalent, and no config option - it describes a
|
|
224
|
-
single run rather than a project.
|
|
225
|
-
|
|
226
|
-
## Unrecognised options
|
|
227
|
-
|
|
228
|
-
`--help` (`-h`) and `--version` (`-v`) work on any command and take over from it, so
|
|
229
|
-
`once --help` describes `once` rather than running the suite.
|
|
230
|
-
|
|
231
|
-
An option that the command does not accept is an error: the command exits without running
|
|
232
|
-
anything, rather than warning and carrying on. A typo like `--fitler-it` would otherwise
|
|
233
|
-
quietly run the whole suite and report a pass. Options are per-command, so `--fail-fast`
|
|
234
|
-
belongs to `once` and `--status-file` to `watch`. Run `npx sxy-test-runner help`, or add
|
|
235
|
-
`--help` to any command, for the current list.
|
|
236
|
-
|
|
237
144
|
# How it works
|
|
238
145
|
|
|
239
|
-
sxy-test-runner runs all tests inside one node process
|
|
240
|
-
|
|
241
|
-
Because of this, be careful with globals, which will be shared.
|
|
146
|
+
sxy-test-runner runs all tests inside one node process. Be careful with globals, which will be shared.
|
|
242
147
|
|
|
243
148
|
While tests are running, `NODE_ENV` defaults to `test` when it was not already set.
|
|
244
149
|
`SXYT` and `SXY_TEST_RUNNER` are both set to `true`, allowing configuration and application
|
|
245
150
|
code to detect sxy-test-runner specifically. In agent mode, `SXYT_AGENT` and
|
|
246
151
|
`SXY_TEST_RUNNER_AGENT` are also set to `true`.
|
|
247
152
|
|
|
248
|
-
###
|
|
153
|
+
### Caching modules
|
|
249
154
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
`._cached_.`
|
|
155
|
+
In watch mode modules will be reloaded as needed. With `watch.dependencyEvaluation: false` everything will be reloaded on each run.
|
|
156
|
+
|
|
157
|
+
To force a file never to be reloaded, insert `._cached_.` into its filename, like:
|
|
253
158
|
|
|
254
159
|
```js
|
|
255
160
|
import { database } from './fixtures/database._cached_.js'
|
|
256
161
|
```
|
|
257
162
|
|
|
258
|
-
The module then uses Node's normal process-wide module cache, so every test file receives
|
|
259
|
-
the same exported values. JavaScript and TypeScript module extensions are supported; in
|
|
260
|
-
TypeScript `NodeNext` source, import the emitted `._cached_.js` name as usual.
|
|
261
|
-
|
|
262
|
-
Cached modules remain loaded for the full one-off run or watch process. Avoid unsynchronised
|
|
263
|
-
mutable state when tests run in parallel, and explicitly clean up shared resources such as
|
|
264
|
-
servers or database connections.
|
|
265
|
-
|
|
266
163
|
## Execution modes
|
|
267
164
|
|
|
268
165
|
**execution** settings let you choose whether to run test files, describe blocks, and individual tests sequentially or in parallel.
|
|
@@ -271,17 +168,13 @@ If working with globals you may want to use sequential only, to avoid conflicts
|
|
|
271
168
|
|
|
272
169
|
Sequential mode also allows console log output to be displayed correctly with each test. Running in parallel mode does not allow log output to be matched up to each test, due to the use of a global override on console.log (other console output methods such as console.trace() are not covered currently)
|
|
273
170
|
|
|
274
|
-
If your code is isolated, and
|
|
171
|
+
If your code is isolated, and asynchronous, you can use parallel execution modes to radically speed up your tests, at the expense of the points mentioned above.
|
|
275
172
|
|
|
276
173
|
## Dependencies
|
|
277
174
|
|
|
278
175
|
Dynamic imports will not be detected and will not trigger test re-runs.
|
|
279
176
|
|
|
280
|
-
To re-run every test on any watched
|
|
281
|
-
to `false`. The dependency analysis is then skipped entirely - no trees are built at startup,
|
|
282
|
-
which is the slowest part of it on a large suite - and the blind spot above stops mattering,
|
|
283
|
-
because nothing is being predicted. On a small or fast suite this is often the better
|
|
284
|
-
setting; on a large one it trades a slower re-run for a complete one.
|
|
177
|
+
To re-run every test on any change in the watched files instead set `watch.dependencyEvaluation: false`
|
|
285
178
|
|
|
286
179
|
## Failing test re-running
|
|
287
180
|
|
|
@@ -372,5 +265,5 @@ describe('something', ({it, beforeEachTest, afterEachTest, afterDescribe}) => {
|
|
|
372
265
|
These start at 20 to stay clear of Node's reserved codes (1-14) and of signal exits
|
|
373
266
|
(over 128), so a non-zero code is always sxy-test's own.
|
|
374
267
|
|
|
375
|
-
It
|
|
268
|
+
It could also crash due to exceptions without giving any of these codes, in which case Node
|
|
376
269
|
supplies the code - usually `1` for an uncaught exception.
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
interface ResolveContext {
|
|
2
|
-
parentURL?: string;
|
|
3
|
-
}
|
|
4
|
-
interface ResolveResult {
|
|
5
|
-
url: string;
|
|
6
|
-
[key: string]: unknown;
|
|
7
|
-
}
|
|
8
|
-
type NextResolve = (specifier: string, context: ResolveContext) => ResolveResult | Promise<ResolveResult>;
|
|
9
|
-
export declare function resolve(specifier: string, context: ResolveContext, nextResolve: NextResolve): Promise<ResolveResult>;
|
|
10
|
-
export {};
|
|
11
|
-
//# sourceMappingURL=esmReload.d.ts.map
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { isBuiltin, register } from 'node:module';
|
|
2
|
-
const cachedModulePattern = /\._cached_\.(?:[cm]?js|[cm]?ts|jsx|tsx)$/i;
|
|
3
|
-
let reloadId = 0;
|
|
4
|
-
function isLoaderInstance() {
|
|
5
|
-
return new URL(import.meta.url).searchParams.has('loader');
|
|
6
|
-
}
|
|
7
|
-
function isThisModule(url) {
|
|
8
|
-
const candidate = new URL(url);
|
|
9
|
-
const current = new URL(import.meta.url);
|
|
10
|
-
candidate.search = '';
|
|
11
|
-
current.search = '';
|
|
12
|
-
return candidate.href === current.href;
|
|
13
|
-
}
|
|
14
|
-
function isCachedModule(url) {
|
|
15
|
-
return cachedModulePattern.test(url.pathname);
|
|
16
|
-
}
|
|
17
|
-
export async function resolve(specifier, context, nextResolve) {
|
|
18
|
-
const result = await nextResolve(specifier, context);
|
|
19
|
-
if (isThisModule(result.url) || isBuiltin(result.url) || context.parentURL === undefined) {
|
|
20
|
-
return result;
|
|
21
|
-
}
|
|
22
|
-
const url = new URL(result.url);
|
|
23
|
-
// A *._cached_.js/ts module and its dependency graph use Node's ordinary
|
|
24
|
-
// process-wide module cache instead of inheriting the test file instance.
|
|
25
|
-
if (isCachedModule(url))
|
|
26
|
-
return result;
|
|
27
|
-
const parentUrl = new URL(context.parentURL);
|
|
28
|
-
const instance = url.searchParams.get('reload') === ''
|
|
29
|
-
? `sxy-test-runner-reload-${reloadId++}`
|
|
30
|
-
: parentUrl.searchParams.get('sxyt-instance');
|
|
31
|
-
if (instance === null)
|
|
32
|
-
return result;
|
|
33
|
-
url.searchParams.delete('reload');
|
|
34
|
-
url.searchParams.set('sxyt-instance', instance);
|
|
35
|
-
return {
|
|
36
|
-
...result,
|
|
37
|
-
url: url.href
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
if (!isLoaderInstance()) {
|
|
41
|
-
register(`${import.meta.url}?loader`);
|
|
42
|
-
}
|
|
43
|
-
//# sourceMappingURL=esmReload.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"esmReload.js","sourceRoot":"","sources":["../../src/packages/esmReload.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAqCjD,MAAM,mBAAmB,GAAG,2CAA2C,CAAA;AAEvE,IAAI,QAAQ,GAAG,CAAC,CAAA;AAEhB,SAAS,gBAAgB;IACrB,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;AAC9D,CAAC;AAED,SAAS,YAAY,CAAC,GAAW;IAC7B,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;IAC9B,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACxC,SAAS,CAAC,MAAM,GAAG,EAAE,CAAA;IACrB,OAAO,CAAC,MAAM,GAAG,EAAE,CAAA;IACnB,OAAO,SAAS,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,CAAA;AAC1C,CAAC;AAED,SAAS,cAAc,CAAC,GAAQ;IAC5B,OAAO,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;AACjD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CACzB,SAAiB,EACjB,OAAuB,EACvB,WAAwB;IAExB,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IAEpD,IAAI,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACvF,OAAO,MAAM,CAAA;IACjB,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IAE/B,yEAAyE;IACzE,0EAA0E;IAC1E,IAAI,cAAc,CAAC,GAAG,CAAC;QAAE,OAAO,MAAM,CAAA;IAEtC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IAC5C,MAAM,QAAQ,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE;QAClD,CAAC,CAAC,0BAA0B,QAAQ,EAAE,EAAE;QACxC,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA;IAEjD,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,MAAM,CAAA;IAEpC,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IACjC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAA;IAE/C,OAAO;QACH,GAAG,MAAM;QACT,GAAG,EAAE,GAAG,CAAC,IAAI;KAChB,CAAA;AACL,CAAC;AAED,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC;IACtB,QAAQ,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAA;AACzC,CAAC","sourcesContent":["\nimport { isBuiltin, register } from 'node:module'\n\n\n/*\n * Based on esm-reload by Marcel Laverdet and Pierre-Yves Gérardy.\n *\n * ISC License\n *\n * Copyright 2024 Marcel Laverdet & Pierre-Yves Gérardy\n *\n * Permission to use, copy, modify, and/or distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\ninterface ResolveContext {\n parentURL?: string\n}\n\ninterface ResolveResult {\n url: string\n [key: string]: unknown\n}\n\ntype NextResolve = (\n specifier: string,\n context: ResolveContext\n) => ResolveResult | Promise<ResolveResult>\n\nconst cachedModulePattern = /\\._cached_\\.(?:[cm]?js|[cm]?ts|jsx|tsx)$/i\n\nlet reloadId = 0\n\nfunction isLoaderInstance(): boolean {\n return new URL(import.meta.url).searchParams.has('loader')\n}\n\nfunction isThisModule(url: string): boolean {\n const candidate = new URL(url)\n const current = new URL(import.meta.url)\n candidate.search = ''\n current.search = ''\n return candidate.href === current.href\n}\n\nfunction isCachedModule(url: URL): boolean {\n return cachedModulePattern.test(url.pathname)\n}\n\nexport async function resolve(\n specifier: string,\n context: ResolveContext,\n nextResolve: NextResolve\n): Promise<ResolveResult> {\n const result = await nextResolve(specifier, context)\n\n if (isThisModule(result.url) || isBuiltin(result.url) || context.parentURL === undefined) {\n return result\n }\n\n const url = new URL(result.url)\n\n // A *._cached_.js/ts module and its dependency graph use Node's ordinary\n // process-wide module cache instead of inheriting the test file instance.\n if (isCachedModule(url)) return result\n\n const parentUrl = new URL(context.parentURL)\n const instance = url.searchParams.get('reload') === ''\n ? `sxy-test-runner-reload-${reloadId++}`\n : parentUrl.searchParams.get('sxyt-instance')\n\n if (instance === null) return result\n\n url.searchParams.delete('reload')\n url.searchParams.set('sxyt-instance', instance)\n\n return {\n ...result,\n url: url.href\n }\n}\n\nif (!isLoaderInstance()) {\n register(`${import.meta.url}?loader`)\n}\n"]}
|