sxy-test-runner 2.4.0 → 2.4.2

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 CHANGED
@@ -119,6 +119,12 @@ describes or tests afterward can therefore be much slower than file filtering. P
119
119
  Test discovery uses Node's built-in glob implementation. Patterns are resolved relative to
120
120
  `testsBase`, and ignore patterns are resolved from that same base.
121
121
 
122
+ Write directory ignores as `**/node_modules/**`, not `**/node_modules/**/*`. The trailing
123
+ `/*` requires a segment after the directory, so the directory itself never matches and the
124
+ globber walks the whole tree before discarding it rather than pruning it. On a real nested
125
+ `node_modules` that measured 1,524ms versus 20ms for one `findTestFiles()` scan. The two
126
+ forms exclude exactly the same files, so it costs nothing to prefer the shorter one.
127
+
122
128
  ## Test lifecycle and data flow
123
129
 
124
130
  All test files run in one Node.js process. A test file is imported with a fresh
@@ -254,9 +260,17 @@ immediately on keypress in a TTY session.
254
260
  Changes that arrive while a run is in flight are folded into the next run rather than
255
261
  queueing a run each, so a burst of edits produces one rerun covering all of them.
256
262
 
263
+ `watch.dependencyEvaluation` (default `true`) controls that mapping from a changed file to
264
+ the tests to run. Set it to `false` and the analysis is skipped entirely - no trees are
265
+ built at startup, and **any** watched change reruns every test. That trades a slower rerun
266
+ for two things: startup stops paying for dependency analysis, which is the slowest part of
267
+ it on a large suite, and the blind spots below stop mattering, because nothing is being
268
+ predicted. On a small or fast suite it is often the better setting.
269
+
257
270
  Important limitations:
258
271
 
259
- - Dynamic imports are not found by dependency analysis.
272
+ - Dynamic imports are not found by dependency analysis, so a test reached only that way is
273
+ not rerun when its dependency changes. `watch.dependencyEvaluation: false` avoids this.
260
274
  - All reruns still share one long-lived process.
261
275
  - A fresh ESM instance reloads the test's static module graph, but unrelated global state
262
276
  and external resources remain the test author's responsibility.
@@ -353,7 +367,7 @@ generalises:
353
367
 
354
368
  | covers | the run contained |
355
369
  | --- | --- |
356
- | `all` | every discovered test file - the startup run, or `a` from the keyboard |
370
+ | `all` | every discovered test file - the startup run, `a` from the keyboard, or any change when `watch.dependencyEvaluation` is off |
357
371
  | `changed+failing` | the changed files and every file still failing (`watch.reRunFailingTests` on, the default) |
358
372
  | `changed` | only the changed files (`watch.reRunFailingTests` off) |
359
373
  | `last` | the previous run's file set |
@@ -373,7 +387,8 @@ maps it to a test. Either half can miss:
373
387
  - Even for a watched file, the changed-to-test mapping is the static import graph, so it
374
388
  misses dynamic imports and anything reached through a `._cached_.*` boundary. A test file
375
389
  that was neither changed nor already failing is not re-run, so a break in it never reaches
376
- `failing`.
390
+ `failing`. Setting `watch.dependencyEvaluation: false` removes this gap - every watched
391
+ change then reruns everything, and those runs report `covers=all`.
377
392
 
378
393
  So `failing=0` means "nothing is known to be broken", not "everything passes", and silence
379
394
  means "no watched file changed", not "still green". To actually verify the suite, use a run
@@ -423,6 +438,7 @@ export default {
423
438
  watchFilesIgnore: '**/node_modules/**',
424
439
  runAllOnStartup: true,
425
440
  reRunFailingTests: true,
441
+ dependencyEvaluation: true,
426
442
  ttyActionsOnKeypress: false,
427
443
  statusFile: false,
428
444
  agent: false
package/dist/cli/init.js CHANGED
@@ -59,7 +59,7 @@ export default {
59
59
  ],
60
60
 
61
61
  // glob pattern or array of patterns of test files to ignore
62
- testsIgnore: ['**/node_modules/**/*'],
62
+ testsIgnore: ['**/node_modules/**'],
63
63
 
64
64
  // whether to show the full error trace when an error occurs in a test file
65
65
  showErrorTrace: false,
@@ -115,7 +115,7 @@ export default {
115
115
  watchFiles: '**/*.js',
116
116
 
117
117
  //// glob filter or array of globl filters of files to ignore
118
- watchFilesIgnore: '**/node_modules/**/*',
118
+ watchFilesIgnore: '**/node_modules/**',
119
119
 
120
120
  // run all tests when starting the watcher
121
121
  runAllOnStartup: true,
@@ -123,6 +123,10 @@ export default {
123
123
  // re run all previously failed tests on each test run, until they pass
124
124
  reRunFailingTests: true,
125
125
 
126
+ // evaluate the dependencies of each test file, and re-run that test file only when they change.
127
+ // Set this to false to re-run everything on any change
128
+ dependencyEvaluation: true,
129
+
126
130
  // run watch mode keyboard commands immediately, without waiting for Enter
127
131
  ttyActionsOnKeypress: false,
128
132
 
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,KAAK,MAAM,sBAAsB,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACrF,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAClC,OAAO,EAAE,MAAM,IAAI,CAAA;AAEnB,MAAM,UAAU,IAAI;IAChB,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;IAEhC,KAAK,MAAM,cAAc,IAAI,eAAe,EAAE,CAAC;QAC3C,KAAK,MAAM,cAAc,IAAI,eAAe,EAAE,CAAC;YAC3C,IAAI,GAAG,CAAA;YACP,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE,cAAc,EAAE,cAAc,GAAG,KAAK,CAAC,CAAA;YAC9D,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACrB,mBAAmB,CAAC,GAAG,CAAC,CAAA;YAC5B,CAAC;YACD,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE,cAAc,EAAE,cAAc,GAAG,MAAM,CAAC,CAAA;YAC/D,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACrB,mBAAmB,CAAC,GAAG,CAAC,CAAA;YAC5B,CAAC;YACD,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE,cAAc,EAAE,cAAc,GAAG,MAAM,CAAC,CAAA;YAC/D,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACrB,mBAAmB,CAAC,GAAG,CAAC,CAAA;YAC5B,CAAC;QACL,CAAC;IACL,CAAC;IAED,SAAS,mBAAmB,CAAC,GAAW;QACpC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAA,IAAI,WAAW,yCAAyC,GAAG,EAAE;cACvE,kEAAkE,OAAO,SAAS,CAAC,CAAA;IAC7F,CAAC;IAED,MAAM,0BAA0B,GAAG,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAA;IACnE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,0BAA0B,CAAC,EAAE,CAAC;QAC7C,GAAG,CAAC,KAAK,CAAC,MAAM,CAAA,IAAI,WAAW,2CAA2C;cACpE,gEAAgE;cAChE,iFAAiF,CAAC,CAAA;IAC5F,CAAC;IAED,MAAM,cAAc,GAAG,EAAE,CAAC,YAAY,CAAC,0BAA0B,EAAE,MAAM,CAAC,CAAA;IAC1E,mEAAmE;IACnE,MAAM,WAAW,GAAsB,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAA;IAEjE,MAAM,gBAAgB,GAAG,CAAC,WAAW,CAAC,IAAI,KAAK,QAAQ,CAAC;QACpD,aAAa;QACb,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;QACxE,SAAS;QACT,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAA;IAE7E,MAAM,aAAa,GACvB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8FE,CAAA;IAEE,EAAE,CAAC,aAAa,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAA;IAEjD,GAAG,CAAC,KAAK,CAAC,WAAW,CAAA,IAAI,WAAW,sBAAsB,GAAG,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAA;AAC9F,CAAC","sourcesContent":["import { join } from 'path'\nimport chalk from '../packages/chalk.js'\nimport { packageName, cliName, configFileNames, configLocations } from '../config.js'\nimport { out } from '../output.js'\nimport fs from 'fs'\n\nexport function init(): void {\n const projectDir = process.cwd()\n\n for (const configLocation of configLocations) {\n for (const configFileName of configFileNames) {\n let loc\n loc = join(projectDir, configLocation, configFileName + '.js')\n if (fs.existsSync(loc)) {\n configAlreadyExists(loc)\n }\n loc = join(projectDir, configLocation, configFileName + '.cjs')\n if (fs.existsSync(loc)) {\n configAlreadyExists(loc)\n }\n loc = join(projectDir, configLocation, configFileName + '.mjs')\n if (fs.existsSync(loc)) {\n configAlreadyExists(loc)\n }\n }\n }\n\n function configAlreadyExists(loc: string): void {\n out(chalk.orange`[${packageName}] A matching config already exists at ${loc}`\n + `\\nPlease remove this config before generating a new one with \\`${cliName} init\\``)\n }\n\n const projectPackageJsonLocation = join(projectDir, 'package.json')\n if (!fs.existsSync(projectPackageJsonLocation)) {\n out(chalk.orange`[${packageName}] No package.json exists in this location`\n + '\\nPlease initialise the package with `yarn init` on `npm init`'\n + ' before running this command, and run this command from the project root folder')\n }\n\n const packageJsonRaw = fs.readFileSync(projectPackageJsonLocation, 'utf8')\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const packageJson: { type?: string } = JSON.parse(packageJsonRaw)\n\n const targetConfigName = (packageJson.type === 'module')\n // ES6 module\n ? join(projectDir, configLocations[0] ?? '', configFileNames[0] + '.js')\n // common\n : join(projectDir, configLocations[0] ?? '', configFileNames[0] + '.mjs')\n\n const defaultConfig =\n`\n// @ts-check\n\n/** @satisfies {import('sxy-test-runner').Config} */\nexport default {\n\n // base folder for tests match and ignore patterns\n testsBase: '.',\n\n // glob pattern or array of glob patterns of test files\n tests: [\n '**/*.sxyt.{js,mjs,jsx}',\n '**/*.test.{js,mjs,jsx}',\n '**/*.spec.{js,mjs,jsx}',\n '**/tests?/*.{js,mjs,jsx}',\n '**/__tests?__/*.{js,mjs,jsx}'\n ],\n\n // glob pattern or array of patterns of test files to ignore\n testsIgnore: ['**/node_modules/**/*'],\n\n // whether to show the full error trace when an error occurs in a test file\n showErrorTrace: false,\n\n // tasks to run on startup\n // accepts a function, file location (relative to project base), or array of functions and or files\n setup: undefined,\n\n // tasks to run before each test file is run\n beforeEachFile: undefined,\n\n // tasks to run after each test file is run\n afterEachFile: undefined,\n\n // tasks to run before each describe block is processed\n // if the function returns an object with named properties, or the file exports named exports,\n // these will be passed to the callback function in argument 0, and can be access by destructruing e.g.\n // describe('thing', ({exportA, exportB}) => { it('should', ...) })\n beforeEachDescribe: undefined,\n\n // tasks to run after each describe block\n afterEachDescribe: undefined,\n\n // tasks to run before each it/test block\n // function returns and file exports will be passed to the it/test block as with describe above, e.g.\n // it('should', ({exportA, exportB}) => { assert('something') })\n beforeEachTest: undefined,\n\n // tasks to run after each it/test block\n afterEachTest: undefined,\n\n // how to execute the different parts of test files\n execution: {\n\n // run test files in 'parallel' or 'sequential'ly\n files: 'sequential',\n\n // run describe blocks within a test file in 'parallel' or 'sequential'ly\n describes: 'sequential',\n\n // run it/test blocks within a describe blocks in 'parallel' or 'sequential'ly\n tests: 'sequential'\n\n },\n\n // watch mode configurations\n watch: {\n\n //// the base directory to watch files in\n watchFilesBase: '.',\n\n //// glob filter or array of glob filters of files to watch\n watchFiles: '**/*.js',\n\n //// glob filter or array of globl filters of files to ignore\n watchFilesIgnore: '**/node_modules/**/*',\n\n // run all tests when starting the watcher\n runAllOnStartup: true,\n\n // re run all previously failed tests on each test run, until they pass\n reRunFailingTests: true,\n\n // run watch mode keyboard commands immediately, without waiting for Enter\n ttyActionsOnKeypress: false,\n\n // file to write the latest run status to, or false for none\n statusFile: false,\n\n // report the session as single agent readable lines instead of the usual output\n agent: false,\n\n },\n\n}`\n\n fs.writeFileSync(targetConfigName, defaultConfig)\n\n out(chalk.mediumgreen`[${packageName}] Created config at ` + chalk.blue(targetConfigName))\n}\n"]}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,KAAK,MAAM,sBAAsB,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACrF,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAClC,OAAO,EAAE,MAAM,IAAI,CAAA;AAEnB,MAAM,UAAU,IAAI;IAChB,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;IAEhC,KAAK,MAAM,cAAc,IAAI,eAAe,EAAE,CAAC;QAC3C,KAAK,MAAM,cAAc,IAAI,eAAe,EAAE,CAAC;YAC3C,IAAI,GAAG,CAAA;YACP,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE,cAAc,EAAE,cAAc,GAAG,KAAK,CAAC,CAAA;YAC9D,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACrB,mBAAmB,CAAC,GAAG,CAAC,CAAA;YAC5B,CAAC;YACD,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE,cAAc,EAAE,cAAc,GAAG,MAAM,CAAC,CAAA;YAC/D,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACrB,mBAAmB,CAAC,GAAG,CAAC,CAAA;YAC5B,CAAC;YACD,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE,cAAc,EAAE,cAAc,GAAG,MAAM,CAAC,CAAA;YAC/D,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACrB,mBAAmB,CAAC,GAAG,CAAC,CAAA;YAC5B,CAAC;QACL,CAAC;IACL,CAAC;IAED,SAAS,mBAAmB,CAAC,GAAW;QACpC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAA,IAAI,WAAW,yCAAyC,GAAG,EAAE;cACvE,kEAAkE,OAAO,SAAS,CAAC,CAAA;IAC7F,CAAC;IAED,MAAM,0BAA0B,GAAG,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAA;IACnE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,0BAA0B,CAAC,EAAE,CAAC;QAC7C,GAAG,CAAC,KAAK,CAAC,MAAM,CAAA,IAAI,WAAW,2CAA2C;cACpE,gEAAgE;cAChE,iFAAiF,CAAC,CAAA;IAC5F,CAAC;IAED,MAAM,cAAc,GAAG,EAAE,CAAC,YAAY,CAAC,0BAA0B,EAAE,MAAM,CAAC,CAAA;IAC1E,mEAAmE;IACnE,MAAM,WAAW,GAAsB,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAA;IAEjE,MAAM,gBAAgB,GAAG,CAAC,WAAW,CAAC,IAAI,KAAK,QAAQ,CAAC;QACpD,aAAa;QACb,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;QACxE,SAAS;QACT,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAA;IAE7E,MAAM,aAAa,GACvB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkGE,CAAA;IAEE,EAAE,CAAC,aAAa,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAA;IAEjD,GAAG,CAAC,KAAK,CAAC,WAAW,CAAA,IAAI,WAAW,sBAAsB,GAAG,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAA;AAC9F,CAAC","sourcesContent":["import { join } from 'path'\nimport chalk from '../packages/chalk.js'\nimport { packageName, cliName, configFileNames, configLocations } from '../config.js'\nimport { out } from '../output.js'\nimport fs from 'fs'\n\nexport function init(): void {\n const projectDir = process.cwd()\n\n for (const configLocation of configLocations) {\n for (const configFileName of configFileNames) {\n let loc\n loc = join(projectDir, configLocation, configFileName + '.js')\n if (fs.existsSync(loc)) {\n configAlreadyExists(loc)\n }\n loc = join(projectDir, configLocation, configFileName + '.cjs')\n if (fs.existsSync(loc)) {\n configAlreadyExists(loc)\n }\n loc = join(projectDir, configLocation, configFileName + '.mjs')\n if (fs.existsSync(loc)) {\n configAlreadyExists(loc)\n }\n }\n }\n\n function configAlreadyExists(loc: string): void {\n out(chalk.orange`[${packageName}] A matching config already exists at ${loc}`\n + `\\nPlease remove this config before generating a new one with \\`${cliName} init\\``)\n }\n\n const projectPackageJsonLocation = join(projectDir, 'package.json')\n if (!fs.existsSync(projectPackageJsonLocation)) {\n out(chalk.orange`[${packageName}] No package.json exists in this location`\n + '\\nPlease initialise the package with `yarn init` on `npm init`'\n + ' before running this command, and run this command from the project root folder')\n }\n\n const packageJsonRaw = fs.readFileSync(projectPackageJsonLocation, 'utf8')\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const packageJson: { type?: string } = JSON.parse(packageJsonRaw)\n\n const targetConfigName = (packageJson.type === 'module')\n // ES6 module\n ? join(projectDir, configLocations[0] ?? '', configFileNames[0] + '.js')\n // common\n : join(projectDir, configLocations[0] ?? '', configFileNames[0] + '.mjs')\n\n const defaultConfig =\n`\n// @ts-check\n\n/** @satisfies {import('sxy-test-runner').Config} */\nexport default {\n\n // base folder for tests match and ignore patterns\n testsBase: '.',\n\n // glob pattern or array of glob patterns of test files\n tests: [\n '**/*.sxyt.{js,mjs,jsx}',\n '**/*.test.{js,mjs,jsx}',\n '**/*.spec.{js,mjs,jsx}',\n '**/tests?/*.{js,mjs,jsx}',\n '**/__tests?__/*.{js,mjs,jsx}'\n ],\n\n // glob pattern or array of patterns of test files to ignore\n testsIgnore: ['**/node_modules/**'],\n\n // whether to show the full error trace when an error occurs in a test file\n showErrorTrace: false,\n\n // tasks to run on startup\n // accepts a function, file location (relative to project base), or array of functions and or files\n setup: undefined,\n\n // tasks to run before each test file is run\n beforeEachFile: undefined,\n\n // tasks to run after each test file is run\n afterEachFile: undefined,\n\n // tasks to run before each describe block is processed\n // if the function returns an object with named properties, or the file exports named exports,\n // these will be passed to the callback function in argument 0, and can be access by destructruing e.g.\n // describe('thing', ({exportA, exportB}) => { it('should', ...) })\n beforeEachDescribe: undefined,\n\n // tasks to run after each describe block\n afterEachDescribe: undefined,\n\n // tasks to run before each it/test block\n // function returns and file exports will be passed to the it/test block as with describe above, e.g.\n // it('should', ({exportA, exportB}) => { assert('something') })\n beforeEachTest: undefined,\n\n // tasks to run after each it/test block\n afterEachTest: undefined,\n\n // how to execute the different parts of test files\n execution: {\n\n // run test files in 'parallel' or 'sequential'ly\n files: 'sequential',\n\n // run describe blocks within a test file in 'parallel' or 'sequential'ly\n describes: 'sequential',\n\n // run it/test blocks within a describe blocks in 'parallel' or 'sequential'ly\n tests: 'sequential'\n\n },\n\n // watch mode configurations\n watch: {\n\n //// the base directory to watch files in\n watchFilesBase: '.',\n\n //// glob filter or array of glob filters of files to watch\n watchFiles: '**/*.js',\n\n //// glob filter or array of globl filters of files to ignore\n watchFilesIgnore: '**/node_modules/**',\n\n // run all tests when starting the watcher\n runAllOnStartup: true,\n\n // re run all previously failed tests on each test run, until they pass\n reRunFailingTests: true,\n\n // evaluate the dependencies of each test file, and re-run that test file only when they change. \n // Set this to false to re-run everything on any change\n dependencyEvaluation: true,\n\n // run watch mode keyboard commands immediately, without waiting for Enter\n ttyActionsOnKeypress: false,\n\n // file to write the latest run status to, or false for none\n statusFile: false,\n\n // report the session as single agent readable lines instead of the usual output\n agent: false,\n\n },\n\n}`\n\n fs.writeFileSync(targetConfigName, defaultConfig)\n\n out(chalk.mediumgreen`[${packageName}] Created config at ` + chalk.blue(targetConfigName))\n}\n"]}
@@ -61,9 +61,15 @@ function runScope(config) {
61
61
  case 'all': return 'all';
62
62
  case 'last': return 'last';
63
63
  case 'failed': return 'failing';
64
- // the reRunFailingTests case is the one worth spelling out: without it a run says
65
- // nothing about files that were already failing
66
- case 'auto': return (config.watch.reRunFailingTests) ? 'changed+failing' : 'changed';
64
+ case 'auto': {
65
+ // with dependency evaluation off a change runs the whole suite, so an auto run
66
+ // carries the same weight as a startup one
67
+ if (!config.watch.dependencyEvaluation)
68
+ return 'all';
69
+ // the reRunFailingTests case is the one worth spelling out: without it a run says
70
+ // nothing about files that were already failing
71
+ return (config.watch.reRunFailingTests) ? 'changed+failing' : 'changed';
72
+ }
67
73
  default: return 'changed';
68
74
  }
69
75
  }
@@ -1 +1 @@
1
- {"version":3,"file":"agentReport.js","sourceRoot":"","sources":["../../../src/cli/lib/agentReport.ts"],"names":[],"mappings":"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","sourcesContent":["import { out as mainOut } from '../../output.js'\n\nimport type { FinalConfig, TestsResultsSummary } from '../../types.js'\nimport type { FailureEntry } from './failureEntries.js'\nimport type { RunType } from './reRunManager.js'\nimport type { StatusCode } from './statusFile.js'\n\n// Agent mode reports a watch session as a stream of single lines, for a reader tailing the\n// process rather than watching the terminal. Every line is one complete event:\n//\n// [sxyt] <event> | <key>=<value> | <key>=<value>\n//\n// Values are never quoted, so free text is flattened to keep the grammar intact - one event\n// can never span two lines, and a stray `|` can never look like a field boundary.\n\nconst prefix = '[sxyt]'\n\nexport type RunReason = RunType | 'startup'\n\nlet runCounter = 0\n// requestRun sets this before handing a run to runTests; the initial run never goes through\n// the queue, so 'startup' is the right default\nlet nextRunReason: RunReason = 'startup'\n\ntype Field = [string, string | number]\n\nfunction emit(event: string, fields: Field[] = []): void {\n mainOut(prefix + ` ${event}` + fields.map(([key, value]) => ` | ${key}=${value}`).join(''))\n}\n\n// newlines would split one event across two lines, and a `|` would read as a field boundary\nfunction flatten(text: string): string {\n return text.replace(/\\s*[\\r\\n]+\\s*/g, ' ').replace(/\\|/g, '/').trim()\n}\n\nexport function agentEnabled(config: FinalConfig): boolean {\n return config.watch.agent\n}\n\n// the process is up, before the config is even loaded - so a slow startup is\n// distinguishable from one that never began. Takes the flag rather than the config for that\n// reason, and resets the counters so repeated in process sessions start from 1.\nexport function agentInit(enabled: boolean): void {\n runCounter = 0\n nextRunReason = 'startup'\n if (!enabled) return\n emit('init', [['pid', process.pid]])\n}\n\nexport function agentFound(config: FinalConfig, files: number): void {\n if (!agentEnabled(config)) return\n emit('found', [['files', files]])\n}\n\nexport function agentSetRunReason(reason: RunReason): void {\n nextRunReason = reason\n}\n\n// claims the next run number and announces the run, so a reader knows work is in flight\n// before any result arrives\nexport function agentRunStart(config: FinalConfig, files: number): number {\n if (!agentEnabled(config)) return 0\n runCounter++\n emit('run', [\n ['n', runCounter],\n ['files', files],\n ['why', nextRunReason],\n ['covers', runScope(config)]\n ])\n return runCounter\n}\n\n// what the run was built from. A reader needs this to know how far the run's own `code`\n// generalises - only a run covering everything can speak for the whole suite.\nfunction runScope(config: FinalConfig): string {\n switch (nextRunReason) {\n case 'startup':\n case 'all': return 'all'\n case 'last': return 'last'\n case 'failed': return 'failing'\n // the reRunFailingTests case is the one worth spelling out: without it a run says\n // nothing about files that were already failing\n case 'auto': return (config.watch.reRunFailingTests) ? 'changed+failing' : 'changed'\n default: return 'changed'\n }\n}\n\n// failures are emitted before the run's done line, so done is a complete end of run marker\nexport function agentFailure(config: FinalConfig, run: number, entry: FailureEntry): void {\n if (!agentEnabled(config)) return\n emit('fail', [\n ['n', run],\n ['file', flatten(entry.file)],\n ...(entry.describe === undefined)\n ? []\n : [['describe', flatten(entry.describe)] as Field],\n ...(entry.test === undefined) ? [] : [['test', flatten(entry.test)] as Field],\n ['error', flatten(entry.error)]\n ])\n}\n\n// `failing` counts the test files still failing across the whole session, not just this\n// run. A watch re-run usually covers only the changed files, so its own tallies can read as\n// a clean pass while the suite is still broken elsewhere.\nexport function agentDone(\n config: FinalConfig,\n run: number,\n code: StatusCode,\n description: string,\n summary: TestsResultsSummary | null,\n durationMs: number,\n failingFiles: number\n): void {\n if (!agentEnabled(config)) return\n emit('done', [\n ['n', run],\n ['code', code],\n ['desc', flatten(description)],\n ...(summary === null) ? [] : [\n ['tests', `${summary.itsPasses}/${summary.itsTotal}`] as Field,\n ['items', `${summary.describesPasses}/${summary.describesTotal}`] as Field,\n ['files', `${summary.passes}/${summary.total}`] as Field\n ],\n ['failing', failingFiles],\n ['ms', durationMs]\n ])\n}\n\nexport function agentWatching(config: FinalConfig, files: number): void {\n if (!agentEnabled(config)) return\n emit('watching', [['files', files]])\n}\n\nexport function agentChange(config: FinalConfig, file: string, event: string): void {\n if (!agentEnabled(config)) return\n emit('change', [['file', flatten(file)], ['event', flatten(event)]])\n}\n\n// agent mode owns stdout, so the ordinary coloured output is routed into a sink\nexport function agentSilentOut(): void {\n // deliberately nothing - the agent lines are the whole stream\n}\n"]}
1
+ {"version":3,"file":"agentReport.js","sourceRoot":"","sources":["../../../src/cli/lib/agentReport.ts"],"names":[],"mappings":"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","sourcesContent":["import { out as mainOut } from '../../output.js'\n\nimport type { FinalConfig, TestsResultsSummary } from '../../types.js'\nimport type { FailureEntry } from './failureEntries.js'\nimport type { RunType } from './reRunManager.js'\nimport type { StatusCode } from './statusFile.js'\n\n// Agent mode reports a watch session as a stream of single lines, for a reader tailing the\n// process rather than watching the terminal. Every line is one complete event:\n//\n// [sxyt] <event> | <key>=<value> | <key>=<value>\n//\n// Values are never quoted, so free text is flattened to keep the grammar intact - one event\n// can never span two lines, and a stray `|` can never look like a field boundary.\n\nconst prefix = '[sxyt]'\n\nexport type RunReason = RunType | 'startup'\n\nlet runCounter = 0\n// requestRun sets this before handing a run to runTests; the initial run never goes through\n// the queue, so 'startup' is the right default\nlet nextRunReason: RunReason = 'startup'\n\ntype Field = [string, string | number]\n\nfunction emit(event: string, fields: Field[] = []): void {\n mainOut(prefix + ` ${event}` + fields.map(([key, value]) => ` | ${key}=${value}`).join(''))\n}\n\n// newlines would split one event across two lines, and a `|` would read as a field boundary\nfunction flatten(text: string): string {\n return text.replace(/\\s*[\\r\\n]+\\s*/g, ' ').replace(/\\|/g, '/').trim()\n}\n\nexport function agentEnabled(config: FinalConfig): boolean {\n return config.watch.agent\n}\n\n// the process is up, before the config is even loaded - so a slow startup is\n// distinguishable from one that never began. Takes the flag rather than the config for that\n// reason, and resets the counters so repeated in process sessions start from 1.\nexport function agentInit(enabled: boolean): void {\n runCounter = 0\n nextRunReason = 'startup'\n if (!enabled) return\n emit('init', [['pid', process.pid]])\n}\n\nexport function agentFound(config: FinalConfig, files: number): void {\n if (!agentEnabled(config)) return\n emit('found', [['files', files]])\n}\n\nexport function agentSetRunReason(reason: RunReason): void {\n nextRunReason = reason\n}\n\n// claims the next run number and announces the run, so a reader knows work is in flight\n// before any result arrives\nexport function agentRunStart(config: FinalConfig, files: number): number {\n if (!agentEnabled(config)) return 0\n runCounter++\n emit('run', [\n ['n', runCounter],\n ['files', files],\n ['why', nextRunReason],\n ['covers', runScope(config)]\n ])\n return runCounter\n}\n\n// what the run was built from. A reader needs this to know how far the run's own `code`\n// generalises - only a run covering everything can speak for the whole suite.\nfunction runScope(config: FinalConfig): string {\n switch (nextRunReason) {\n case 'startup':\n case 'all': return 'all'\n case 'last': return 'last'\n case 'failed': return 'failing'\n case 'auto': {\n // with dependency evaluation off a change runs the whole suite, so an auto run\n // carries the same weight as a startup one\n if (!config.watch.dependencyEvaluation) return 'all'\n // the reRunFailingTests case is the one worth spelling out: without it a run says\n // nothing about files that were already failing\n return (config.watch.reRunFailingTests) ? 'changed+failing' : 'changed'\n }\n default: return 'changed'\n }\n}\n\n// failures are emitted before the run's done line, so done is a complete end of run marker\nexport function agentFailure(config: FinalConfig, run: number, entry: FailureEntry): void {\n if (!agentEnabled(config)) return\n emit('fail', [\n ['n', run],\n ['file', flatten(entry.file)],\n ...(entry.describe === undefined)\n ? []\n : [['describe', flatten(entry.describe)] as Field],\n ...(entry.test === undefined) ? [] : [['test', flatten(entry.test)] as Field],\n ['error', flatten(entry.error)]\n ])\n}\n\n// `failing` counts the test files still failing across the whole session, not just this\n// run. A watch re-run usually covers only the changed files, so its own tallies can read as\n// a clean pass while the suite is still broken elsewhere.\nexport function agentDone(\n config: FinalConfig,\n run: number,\n code: StatusCode,\n description: string,\n summary: TestsResultsSummary | null,\n durationMs: number,\n failingFiles: number\n): void {\n if (!agentEnabled(config)) return\n emit('done', [\n ['n', run],\n ['code', code],\n ['desc', flatten(description)],\n ...(summary === null) ? [] : [\n ['tests', `${summary.itsPasses}/${summary.itsTotal}`] as Field,\n ['items', `${summary.describesPasses}/${summary.describesTotal}`] as Field,\n ['files', `${summary.passes}/${summary.total}`] as Field\n ],\n ['failing', failingFiles],\n ['ms', durationMs]\n ])\n}\n\nexport function agentWatching(config: FinalConfig, files: number): void {\n if (!agentEnabled(config)) return\n emit('watching', [['files', files]])\n}\n\nexport function agentChange(config: FinalConfig, file: string, event: string): void {\n if (!agentEnabled(config)) return\n emit('change', [['file', flatten(file)], ['event', flatten(event)]])\n}\n\n// agent mode owns stdout, so the ordinary coloured output is routed into a sink\nexport function agentSilentOut(): void {\n // deliberately nothing - the agent lines are the whole stream\n}\n"]}
@@ -7,7 +7,7 @@ export const defaultConfig = {
7
7
  '**/tests?/*.{js,mjs,jsx}',
8
8
  '**/__tests?__/*.{js,mjs,jsx}'
9
9
  ],
10
- testsIgnore: ['**/node_modules/**/*'],
10
+ testsIgnore: ['**/node_modules/**'],
11
11
  showErrorTrace: false,
12
12
  compact: false,
13
13
  execution: {
@@ -18,9 +18,10 @@ export const defaultConfig = {
18
18
  watch: {
19
19
  watchFilesBase: '.',
20
20
  watchFiles: '**/*.js',
21
- watchFilesIgnore: '**/node_modules/**/*',
21
+ watchFilesIgnore: '**/node_modules/**',
22
22
  runAllOnStartup: true,
23
23
  reRunFailingTests: true,
24
+ dependencyEvaluation: true,
24
25
  ttyActionsOnKeypress: false,
25
26
  statusFile: false,
26
27
  agent: false
@@ -1 +1 @@
1
- {"version":3,"file":"defaultConfig.js","sourceRoot":"","sources":["../../../src/cli/lib/defaultConfig.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,aAAa,GAAgB;IACtC,SAAS,EAAE,GAAG;IACd,KAAK,EAAE;QACH,wBAAwB;QACxB,wBAAwB;QACxB,wBAAwB;QACxB,0BAA0B;QAC1B,8BAA8B;KACjC;IACD,WAAW,EAAE,CAAC,sBAAsB,CAAC;IACrC,cAAc,EAAE,KAAK;IACrB,OAAO,EAAE,KAAK;IACd,SAAS,EAAE;QACP,KAAK,EAAE,YAAY;QACnB,SAAS,EAAE,YAAY;QACvB,KAAK,EAAE,YAAY;KACtB;IACD,KAAK,EAAE;QACH,cAAc,EAAE,GAAG;QACnB,UAAU,EAAE,SAAS;QACrB,gBAAgB,EAAE,sBAAsB;QACxC,eAAe,EAAE,IAAI;QACrB,iBAAiB,EAAE,IAAI;QACvB,oBAAoB,EAAE,KAAK;QAC3B,UAAU,EAAE,KAAK;QACjB,KAAK,EAAE,KAAK;KACf;CACJ,CAAA","sourcesContent":["import type { FinalConfig } from '../../types.js'\n\nexport const defaultConfig: FinalConfig = {\n testsBase: '.',\n tests: [\n '**/*.sxyt.{js,mjs,jsx}',\n '**/*.test.{js,mjs,jsx}',\n '**/*.spec.{js,mjs,jsx}',\n '**/tests?/*.{js,mjs,jsx}',\n '**/__tests?__/*.{js,mjs,jsx}'\n ],\n testsIgnore: ['**/node_modules/**/*'],\n showErrorTrace: false,\n compact: false,\n execution: {\n files: 'sequential',\n describes: 'sequential',\n tests: 'sequential'\n },\n watch: {\n watchFilesBase: '.',\n watchFiles: '**/*.js',\n watchFilesIgnore: '**/node_modules/**/*',\n runAllOnStartup: true,\n reRunFailingTests: true,\n ttyActionsOnKeypress: false,\n statusFile: false,\n agent: false\n }\n}\n"]}
1
+ {"version":3,"file":"defaultConfig.js","sourceRoot":"","sources":["../../../src/cli/lib/defaultConfig.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,aAAa,GAAgB;IACtC,SAAS,EAAE,GAAG;IACd,KAAK,EAAE;QACH,wBAAwB;QACxB,wBAAwB;QACxB,wBAAwB;QACxB,0BAA0B;QAC1B,8BAA8B;KACjC;IACD,WAAW,EAAE,CAAC,oBAAoB,CAAC;IACnC,cAAc,EAAE,KAAK;IACrB,OAAO,EAAE,KAAK;IACd,SAAS,EAAE;QACP,KAAK,EAAE,YAAY;QACnB,SAAS,EAAE,YAAY;QACvB,KAAK,EAAE,YAAY;KACtB;IACD,KAAK,EAAE;QACH,cAAc,EAAE,GAAG;QACnB,UAAU,EAAE,SAAS;QACrB,gBAAgB,EAAE,oBAAoB;QACtC,eAAe,EAAE,IAAI;QACrB,iBAAiB,EAAE,IAAI;QACvB,oBAAoB,EAAE,IAAI;QAC1B,oBAAoB,EAAE,KAAK;QAC3B,UAAU,EAAE,KAAK;QACjB,KAAK,EAAE,KAAK;KACf;CACJ,CAAA","sourcesContent":["import type { FinalConfig } from '../../types.js'\n\nexport const defaultConfig: FinalConfig = {\n testsBase: '.',\n tests: [\n '**/*.sxyt.{js,mjs,jsx}',\n '**/*.test.{js,mjs,jsx}',\n '**/*.spec.{js,mjs,jsx}',\n '**/tests?/*.{js,mjs,jsx}',\n '**/__tests?__/*.{js,mjs,jsx}'\n ],\n testsIgnore: ['**/node_modules/**'],\n showErrorTrace: false,\n compact: false,\n execution: {\n files: 'sequential',\n describes: 'sequential',\n tests: 'sequential'\n },\n watch: {\n watchFilesBase: '.',\n watchFiles: '**/*.js',\n watchFilesIgnore: '**/node_modules/**',\n runAllOnStartup: true,\n reRunFailingTests: true,\n dependencyEvaluation: true,\n ttyActionsOnKeypress: false,\n statusFile: false,\n agent: false\n }\n}\n"]}
@@ -5,10 +5,22 @@ import chalk from '../../packages/chalk.js';
5
5
  import { out as mainOut } from '../../output.js';
6
6
  import figures from '../../packages/figures.js';
7
7
  import { indexNumberToLetters } from '../../indexNumberToLetters.js';
8
- import { AssertionError as ChaiAssertionError } from 'chai';
9
- import { AssertionError as NodeAssertionError } from 'node:assert';
10
8
  import { inspect } from 'node:util';
11
9
  const { timeProfileAsync } = createTimeProfiler(showTimeProfiling);
10
+ // Assertion failures are recognised by shape, not by where they came from. Importing an
11
+ // assertion library to test `instanceof` against cannot work here: the runner would need it
12
+ // as a dependency, and the copy a test file throws from is a separate ESM instance anyway,
13
+ // so the check fails for the very errors it is meant to catch.
14
+ function isAssertionLike(error) {
15
+ return 'actual' in error || 'expected' in error;
16
+ }
17
+ // Node's assertion messages run to several lines. Later lines are indented to the message
18
+ // column and blank ones dropped; a single line message passes through untouched.
19
+ function alignMessage(message, spacer) {
20
+ return message.split('\n').reduce((previous, line) => (previous.length === 0)
21
+ ? [line]
22
+ : (line.trim()) ? [...previous, spacer + line] : previous, []).join('\n');
23
+ }
12
24
  export async function showTestResult(config, testResult, customOut) {
13
25
  const out = customOut ?? mainOut;
14
26
  await timeProfileAsync('show test result', () => {
@@ -76,38 +88,15 @@ export async function showTestResult(config, testResult, customOut) {
76
88
  const spacer = `${indent}${' '.repeat(letters.length)} `;
77
89
  const err = itResult.error;
78
90
  if (err) {
79
- if (err instanceof ChaiAssertionError) {
80
- out(chalk.mediumred(`${spacer}Chai Assertion Failed: ${err.message}`));
81
- const diffOutput = _chalk.yellow `${spacer}Actual ${inspect(err.actual, { depth: 5 })}\n`
82
- + _chalk.blueBright `${spacer}Expected ${inspect(err.expected, { depth: 5 })}`;
83
- out(diffOutput);
84
- }
85
- else if (err instanceof NodeAssertionError) {
86
- /// Node asserts seem to put a message on the 3rd lline, at the start of the line
87
- out(chalk.mediumred(`${spacer}Node Assertion Failed: ${err.message.split('\n')
88
- // this version would collapse it onto one line - but I'm scared of breaking more
89
- // complex displays from more complex types / assertions
90
- // .reduce<string[]>(
91
- // (prev, curr) => prev.length === 0
92
- // ? [curr]
93
- // : (curr.trim()) ? [...prev, ' ' + curr] : prev,
94
- // []
95
- // ).join('')}`
96
- .reduce((prev, curr) => prev.length === 0
97
- ? [curr]
98
- : (curr.trim()) ? [...prev, spacer + curr] : prev, []).join('\n')}`));
99
- const diffOutput = _chalk.yellow `${spacer}Actual ${inspect(err.actual, { depth: 5 })}\n`
100
- + _chalk.blueBright `${spacer}Expected ${inspect(err.expected, { depth: 5 })}`;
101
- out(diffOutput);
102
- }
103
- else if (err.actual && err.expected) {
104
- out(chalk.mediumred(`${spacer}Assertion Failed: ${err.message}`));
105
- const diffOutput = _chalk.yellow `${spacer}Actual ${inspect(err.actual, { depth: 5 })}\n`
106
- + _chalk.blueBright `${spacer}Expected ${inspect(err.expected, { depth: 5 })}`;
107
- out(diffOutput);
91
+ if (isAssertionLike(err)) {
92
+ out(chalk.mediumred(`${spacer}Assertion Failed: ${alignMessage(err.message, spacer)}`));
93
+ // shown whenever the error carries them, so a falsy actual or
94
+ // expected - 0, '', false, null - still gets its diff
95
+ out(_chalk.yellow `${spacer}Actual ${inspect(err.actual, { depth: 5 })}\n`
96
+ + _chalk.blueBright `${spacer}Expected ${inspect(err.expected, { depth: 5 })}`);
108
97
  }
109
98
  else {
110
- out(chalk.mediumred(`${spacer}${err.name}: ${err.message}`));
99
+ out(chalk.mediumred(`${spacer}${err.name}: ${alignMessage(err.message, spacer)}`));
111
100
  }
112
101
  // stack trace
113
102
  if (config.showErrorTrace) {
@@ -1 +1 @@
1
- {"version":3,"file":"showTestResult.js","sourceRoot":"","sources":["../../../src/cli/lib/showTestResult.ts"],"names":[],"mappings":"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","sourcesContent":["import { createTimeProfiler } from '../../packages/timeProfiler.js'\nimport { showTimeProfiling } from '../../config.js'\nimport _chalk from 'chalk'\nimport chalk from '../../packages/chalk.js'\nimport { out as mainOut } from '../../output.js'\nimport figures from '../../packages/figures.js'\nimport { indexNumberToLetters } from '../../indexNumberToLetters.js'\n\nimport type { FinalConfig, OutFn, TestResult } from '../../types.js'\nimport { AssertionError as ChaiAssertionError } from 'chai'\nimport { AssertionError as NodeAssertionError } from 'node:assert'\nimport { AssertionError as NodeStrictAssertionError } from 'node:assert/strict'\nimport { inspect } from 'node:util'\n\n\nconst { timeProfileAsync } = createTimeProfiler(showTimeProfiling)\n\nexport async function showTestResult(config: FinalConfig, testResult: TestResult, customOut?: OutFn): Promise<void> {\n const out = customOut ?? mainOut\n\n await timeProfileAsync('show test result', () => {\n out()\n out(chalk.grey`File ${testResult.file}`)\n\n const indent = ' '\n\n if (testResult.logs.length > 0) {\n out()\n out(chalk.grey`console.logs:`)\n testResult.logs.forEach(log => {\n out(...log)\n })\n out()\n }\n\n let first = true\n\n for (const describeResult of testResult.describeResults) {\n if (!first) out()\n first = false\n\n out(chalk.lightgrey`${describeResult.counter}) describing ` + chalk.brightblue(describeResult.thing)\n + chalk.grey` ${describeResult.time.toLocaleString()}ms`)\n out()\n\n if (describeResult.logs && describeResult.logs.length > 0) {\n out(chalk.grey`console.logs:`)\n describeResult.logs.forEach(log => {\n out(...log)\n })\n out()\n }\n\n if (describeResult.error !== undefined) {\n const describeError = describeResult.error\n const describeErrorText = (\n typeof describeError === 'object'\n && describeError !== null\n && 'name' in describeError\n && 'message' in describeError\n && typeof describeError.name === 'string'\n && typeof describeError.message === 'string'\n )\n ? `${describeError.name}: ${describeError.message}`\n : String(describeError) // eslint-disable-line @typescript-eslint/no-base-to-string -- only a fallback, if it gives poor results, change it\n\n out(chalk.mediumred(`${indent}Threw:`))\n out(chalk.mediumred(`${indent}${describeErrorText}`))\n if (config.showErrorTrace) {\n const describeErrorStack = (\n typeof describeError === 'object'\n && describeError !== null\n && 'stack' in describeError\n && typeof describeError.stack === 'string'\n )\n ? describeError.stack\n : ''\n out()\n out(chalk.grey(describeErrorStack))\n }\n out()\n }\n\n for (const itResult of describeResult.itResults) {\n const letters = indexNumberToLetters(itResult.counter) ?? ''\n const itTime = chalk.grey` ${itResult.time.toLocaleString()}ms`\n if (itResult.success === true) {\n out(chalk.lightgrey`${indent}${letters})`\n + chalk.mediumgreen` ${figures.tick} ${itResult.should}` + itTime)\n } else {\n out(chalk.lightgrey`${indent}${letters})`\n + chalk.mediumred` ${figures.cross} ${itResult.should}` + itTime)\n out()\n const spacer = `${indent}${' '.repeat(letters.length)} `\n const err = itResult.error\n if (err) {\n if (err instanceof ChaiAssertionError) {\n out(chalk.mediumred(`${spacer}Chai Assertion Failed: ${err.message}`))\n const diffOutput\n = _chalk.yellow`${spacer}Actual ${inspect(err.actual, { depth: 5 })}\\n`\n + _chalk.blueBright`${spacer}Expected ${inspect(err.expected, { depth: 5 })}`\n out(diffOutput)\n } else if (err instanceof NodeAssertionError) {\n /// Node asserts seem to put a message on the 3rd lline, at the start of the line\n out(chalk.mediumred(\n `${spacer}Node Assertion Failed: ${err.message.split('\\n')\n // this version would collapse it onto one line - but I'm scared of breaking more\n // complex displays from more complex types / assertions\n // .reduce<string[]>(\n // (prev, curr) => prev.length === 0\n // ? [curr]\n // : (curr.trim()) ? [...prev, ' ' + curr] : prev,\n // []\n // ).join('')}`\n .reduce<string[]>(\n (prev, curr) => prev.length === 0\n ? [curr]\n : (curr.trim()) ? [...prev, spacer + curr] : prev,\n []\n ).join('\\n')}`\n ))\n const diffOutput\n = _chalk.yellow`${spacer}Actual ${inspect(err.actual, { depth: 5 })}\\n`\n + _chalk.blueBright`${spacer}Expected ${inspect(err.expected, { depth: 5 })}`\n out(diffOutput)\n } else\n if (err.actual && err.expected) {\n out(chalk.mediumred(`${spacer}Assertion Failed: ${err.message}`))\n const diffOutput\n = _chalk.yellow`${spacer}Actual ${inspect(err.actual, { depth: 5 })}\\n`\n + _chalk.blueBright`${spacer}Expected ${inspect(err.expected, { depth: 5 })}`\n out(diffOutput)\n } else {\n out(chalk.mediumred(`${spacer}${err.name}: ${err.message}`))\n }\n // stack trace\n if (config.showErrorTrace) {\n out()\n out(chalk.grey(err.stack ?? ''))\n }\n }\n }\n\n out()\n if (itResult.logs.length > 0) {\n out(chalk.grey`console.logs:`)\n itResult.logs.forEach(log => {\n out(...log)\n })\n out()\n }\n }\n }\n })\n}\n"]}
1
+ {"version":3,"file":"showTestResult.js","sourceRoot":"","sources":["../../../src/cli/lib/showTestResult.ts"],"names":[],"mappings":"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","sourcesContent":["import { createTimeProfiler } from '../../packages/timeProfiler.js'\nimport { showTimeProfiling } from '../../config.js'\nimport _chalk from 'chalk'\nimport chalk from '../../packages/chalk.js'\nimport { out as mainOut } from '../../output.js'\nimport figures from '../../packages/figures.js'\nimport { indexNumberToLetters } from '../../indexNumberToLetters.js'\n\nimport type { FinalConfig, OutFn, TestError, TestResult } from '../../types.js'\nimport { inspect } from 'node:util'\n\n\nconst { timeProfileAsync } = createTimeProfiler(showTimeProfiling)\n\n// Assertion failures are recognised by shape, not by where they came from. Importing an\n// assertion library to test `instanceof` against cannot work here: the runner would need it\n// as a dependency, and the copy a test file throws from is a separate ESM instance anyway,\n// so the check fails for the very errors it is meant to catch.\nfunction isAssertionLike(error: TestError): boolean {\n return 'actual' in error || 'expected' in error\n}\n\n// Node's assertion messages run to several lines. Later lines are indented to the message\n// column and blank ones dropped; a single line message passes through untouched.\nfunction alignMessage(message: string, spacer: string): string {\n return message.split('\\n').reduce<string[]>(\n (previous, line) => (previous.length === 0)\n ? [line]\n : (line.trim()) ? [...previous, spacer + line] : previous,\n []\n ).join('\\n')\n}\n\nexport async function showTestResult(config: FinalConfig, testResult: TestResult, customOut?: OutFn): Promise<void> {\n const out = customOut ?? mainOut\n\n await timeProfileAsync('show test result', () => {\n out()\n out(chalk.grey`File ${testResult.file}`)\n\n const indent = ' '\n\n if (testResult.logs.length > 0) {\n out()\n out(chalk.grey`console.logs:`)\n testResult.logs.forEach(log => {\n out(...log)\n })\n out()\n }\n\n let first = true\n\n for (const describeResult of testResult.describeResults) {\n if (!first) out()\n first = false\n\n out(chalk.lightgrey`${describeResult.counter}) describing ` + chalk.brightblue(describeResult.thing)\n + chalk.grey` ${describeResult.time.toLocaleString()}ms`)\n out()\n\n if (describeResult.logs && describeResult.logs.length > 0) {\n out(chalk.grey`console.logs:`)\n describeResult.logs.forEach(log => {\n out(...log)\n })\n out()\n }\n\n if (describeResult.error !== undefined) {\n const describeError = describeResult.error\n const describeErrorText = (\n typeof describeError === 'object'\n && describeError !== null\n && 'name' in describeError\n && 'message' in describeError\n && typeof describeError.name === 'string'\n && typeof describeError.message === 'string'\n )\n ? `${describeError.name}: ${describeError.message}`\n : String(describeError) // eslint-disable-line @typescript-eslint/no-base-to-string -- only a fallback, if it gives poor results, change it\n\n out(chalk.mediumred(`${indent}Threw:`))\n out(chalk.mediumred(`${indent}${describeErrorText}`))\n if (config.showErrorTrace) {\n const describeErrorStack = (\n typeof describeError === 'object'\n && describeError !== null\n && 'stack' in describeError\n && typeof describeError.stack === 'string'\n )\n ? describeError.stack\n : ''\n out()\n out(chalk.grey(describeErrorStack))\n }\n out()\n }\n\n for (const itResult of describeResult.itResults) {\n const letters = indexNumberToLetters(itResult.counter) ?? ''\n const itTime = chalk.grey` ${itResult.time.toLocaleString()}ms`\n if (itResult.success === true) {\n out(chalk.lightgrey`${indent}${letters})`\n + chalk.mediumgreen` ${figures.tick} ${itResult.should}` + itTime)\n } else {\n out(chalk.lightgrey`${indent}${letters})`\n + chalk.mediumred` ${figures.cross} ${itResult.should}` + itTime)\n out()\n const spacer = `${indent}${' '.repeat(letters.length)} `\n const err = itResult.error\n if (err) {\n if (isAssertionLike(err)) {\n out(chalk.mediumred(\n `${spacer}Assertion Failed: ${alignMessage(err.message, spacer)}`\n ))\n // shown whenever the error carries them, so a falsy actual or\n // expected - 0, '', false, null - still gets its diff\n out(\n _chalk.yellow`${spacer}Actual ${inspect(err.actual, { depth: 5 })}\\n`\n + _chalk.blueBright`${spacer}Expected ${inspect(err.expected, { depth: 5 })}`\n )\n } else {\n out(chalk.mediumred(\n `${spacer}${err.name}: ${alignMessage(err.message, spacer)}`\n ))\n }\n // stack trace\n if (config.showErrorTrace) {\n out()\n out(chalk.grey(err.stack ?? ''))\n }\n }\n }\n\n out()\n if (itResult.logs.length > 0) {\n out(chalk.grey`console.logs:`)\n itResult.logs.forEach(log => {\n out(...log)\n })\n out()\n }\n }\n }\n })\n}\n"]}
@@ -27,5 +27,8 @@ export function validateConfig(config, customOut) {
27
27
  if (typeof config.watch.agent !== 'boolean') {
28
28
  doError('Config error, config.watch.agent should be a boolean');
29
29
  }
30
+ if (typeof config.watch.dependencyEvaluation !== 'boolean') {
31
+ doError('Config error, config.watch.dependencyEvaluation should be a boolean');
32
+ }
30
33
  }
31
34
  //# sourceMappingURL=validateConfig.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"validateConfig.js","sourceRoot":"","sources":["../../../src/cli/lib/validateConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,IAAI,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAGhD,MAAM,UAAU,cAAc,CAAC,MAAmB,EAAE,SAAiB;IACjE,MAAM,GAAG,GAAG,SAAS,IAAI,OAAO,CAAA;IAEhC,SAAS,OAAO,CAAC,OAAe;QAC5B,GAAG,CAAC,OAAO,CAAC,CAAA;QACZ,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAA;IAC5B,CAAC;IAED,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO,CAAC,+CAA+C,CAAC,CAAA;IAC5D,CAAC;IAED,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,KAAK,UAAU,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,KAAK,YAAY,EAAE,CAAC;QACnF,OAAO,CAAC,+EAA+E,CAAC,CAAA;IAC5F,CAAC;IAED,IAAI,MAAM,CAAC,SAAS,CAAC,SAAS,KAAK,UAAU,IAAI,MAAM,CAAC,SAAS,CAAC,SAAS,KAAK,YAAY,EAAE,CAAC;QAC3F,OAAO,CAAC,mFAAmF,CAAC,CAAA;IAChG,CAAC;IAED,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,KAAK,UAAU,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,KAAK,YAAY,EAAE,CAAC;QACnF,OAAO,CAAC,+EAA+E,CAAC,CAAA;IAC5F,CAAC;IAED,IAAI,OAAO,MAAM,CAAC,KAAK,CAAC,oBAAoB,KAAK,SAAS,EAAE,CAAC;QACzD,OAAO,CAAC,qEAAqE,CAAC,CAAA;IAClF,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,UAAU,CAAA;IAC1C,IAAI,UAAU,KAAK,KAAK,IAAI,CAAC,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,EAAE,CAAC,EAAE,CAAC;QAChF,OAAO,CAAC,sEAAsE,CAAC,CAAA;IACnF,CAAC;IAED,IAAI,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1C,OAAO,CAAC,sDAAsD,CAAC,CAAA;IACnE,CAAC;AACL,CAAC","sourcesContent":["import { out as mainOut } from '../../output.js'\nimport type { FinalConfig, OutFn } from '../../types.js'\n\nexport function validateConfig(config: FinalConfig, customOut?: OutFn): void {\n const out = customOut ?? mainOut\n\n function doError(message: string): never {\n out(message)\n throw new Error(message)\n }\n\n if (config.execution === undefined) {\n doError('Config error, config.execution is not defined')\n }\n\n if (config.execution.files !== 'parallel' && config.execution.files !== 'sequential') {\n doError('Config error, config.execution.files should be \\'parallel\\' or \\'sequential\\'')\n }\n\n if (config.execution.describes !== 'parallel' && config.execution.describes !== 'sequential') {\n doError('Config error, config.execution.describes should be \\'parallel\\' or \\'sequential\\'')\n }\n\n if (config.execution.tests !== 'parallel' && config.execution.tests !== 'sequential') {\n doError('Config error, config.execution.tests should be \\'parallel\\' or \\'sequential\\'')\n }\n\n if (typeof config.watch.ttyActionsOnKeypress !== 'boolean') {\n doError('Config error, config.watch.ttyActionsOnKeypress should be a boolean')\n }\n\n const statusFile = config.watch.statusFile\n if (statusFile !== false && (typeof statusFile !== 'string' || statusFile === '')) {\n doError('Config error, config.watch.statusFile should be false or a file path')\n }\n\n if (typeof config.watch.agent !== 'boolean') {\n doError('Config error, config.watch.agent should be a boolean')\n }\n}\n"]}
1
+ {"version":3,"file":"validateConfig.js","sourceRoot":"","sources":["../../../src/cli/lib/validateConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,IAAI,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAGhD,MAAM,UAAU,cAAc,CAAC,MAAmB,EAAE,SAAiB;IACjE,MAAM,GAAG,GAAG,SAAS,IAAI,OAAO,CAAA;IAEhC,SAAS,OAAO,CAAC,OAAe;QAC5B,GAAG,CAAC,OAAO,CAAC,CAAA;QACZ,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAA;IAC5B,CAAC;IAED,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO,CAAC,+CAA+C,CAAC,CAAA;IAC5D,CAAC;IAED,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,KAAK,UAAU,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,KAAK,YAAY,EAAE,CAAC;QACnF,OAAO,CAAC,+EAA+E,CAAC,CAAA;IAC5F,CAAC;IAED,IAAI,MAAM,CAAC,SAAS,CAAC,SAAS,KAAK,UAAU,IAAI,MAAM,CAAC,SAAS,CAAC,SAAS,KAAK,YAAY,EAAE,CAAC;QAC3F,OAAO,CAAC,mFAAmF,CAAC,CAAA;IAChG,CAAC;IAED,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,KAAK,UAAU,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,KAAK,YAAY,EAAE,CAAC;QACnF,OAAO,CAAC,+EAA+E,CAAC,CAAA;IAC5F,CAAC;IAED,IAAI,OAAO,MAAM,CAAC,KAAK,CAAC,oBAAoB,KAAK,SAAS,EAAE,CAAC;QACzD,OAAO,CAAC,qEAAqE,CAAC,CAAA;IAClF,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,UAAU,CAAA;IAC1C,IAAI,UAAU,KAAK,KAAK,IAAI,CAAC,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,EAAE,CAAC,EAAE,CAAC;QAChF,OAAO,CAAC,sEAAsE,CAAC,CAAA;IACnF,CAAC;IAED,IAAI,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1C,OAAO,CAAC,sDAAsD,CAAC,CAAA;IACnE,CAAC;IAED,IAAI,OAAO,MAAM,CAAC,KAAK,CAAC,oBAAoB,KAAK,SAAS,EAAE,CAAC;QACzD,OAAO,CAAC,qEAAqE,CAAC,CAAA;IAClF,CAAC;AACL,CAAC","sourcesContent":["import { out as mainOut } from '../../output.js'\nimport type { FinalConfig, OutFn } from '../../types.js'\n\nexport function validateConfig(config: FinalConfig, customOut?: OutFn): void {\n const out = customOut ?? mainOut\n\n function doError(message: string): never {\n out(message)\n throw new Error(message)\n }\n\n if (config.execution === undefined) {\n doError('Config error, config.execution is not defined')\n }\n\n if (config.execution.files !== 'parallel' && config.execution.files !== 'sequential') {\n doError('Config error, config.execution.files should be \\'parallel\\' or \\'sequential\\'')\n }\n\n if (config.execution.describes !== 'parallel' && config.execution.describes !== 'sequential') {\n doError('Config error, config.execution.describes should be \\'parallel\\' or \\'sequential\\'')\n }\n\n if (config.execution.tests !== 'parallel' && config.execution.tests !== 'sequential') {\n doError('Config error, config.execution.tests should be \\'parallel\\' or \\'sequential\\'')\n }\n\n if (typeof config.watch.ttyActionsOnKeypress !== 'boolean') {\n doError('Config error, config.watch.ttyActionsOnKeypress should be a boolean')\n }\n\n const statusFile = config.watch.statusFile\n if (statusFile !== false && (typeof statusFile !== 'string' || statusFile === '')) {\n doError('Config error, config.watch.statusFile should be false or a file path')\n }\n\n if (typeof config.watch.agent !== 'boolean') {\n doError('Config error, config.watch.agent should be a boolean')\n }\n\n if (typeof config.watch.dependencyEvaluation !== 'boolean') {\n doError('Config error, config.watch.dependencyEvaluation should be a boolean')\n }\n}\n"]}
@@ -49,6 +49,10 @@ customOut, executionFilters = {}) {
49
49
  reRunManager.state.allTestFiles.delete(filename);
50
50
  delete dependencyTrees[filename];
51
51
  }
52
+ else if (!config.watch.dependencyEvaluation) {
53
+ // without trees there is nothing to look the file up in
54
+ reRunManager.state.allTestFiles.delete(filename);
55
+ }
52
56
  }
53
57
  // info on the event found
54
58
  out(chalk.grey `change: ${filename} (${event})`);
@@ -74,12 +78,26 @@ customOut, executionFilters = {}) {
74
78
  debug('its a test', file);
75
79
  //tests.push(file)
76
80
  tests.add(file);
77
- if (!(file in dependencyTrees)) { // if its a new test
78
- debug('try to add a new test', file);
79
- addNewTest(file);
81
+ if (config.watch.dependencyEvaluation) {
82
+ if (!(file in dependencyTrees)) { // if its a new test
83
+ debug('try to add a new test', file);
84
+ addNewTest(file);
85
+ }
86
+ }
87
+ else {
88
+ // no trees to record it in, so this is what makes a
89
+ // newly created test part of the run set
90
+ reRunManager.state.allTestFiles.add(file);
80
91
  }
81
92
  }
82
93
  }
94
+ // with evaluation off there is nothing to map the change through:
95
+ // any watched file could affect any test, so run the lot
96
+ if (!config.watch.dependencyEvaluation) {
97
+ for (const f of reRunManager.state.allTestFiles)
98
+ tests.add(f);
99
+ continue;
100
+ }
83
101
  debug('dtrees', dependencyTrees);
84
102
  debug('2 tests', tests);
85
103
  for (const f of Object.getOwnPropertyNames(dependencyTrees)) {
@@ -1 +1 @@
1
- {"version":3,"file":"watchFilesAndRunTestsNodeWatch.js","sourceRoot":"","sources":["../../../src/cli/lib/watchFilesAndRunTestsNodeWatch.ts"],"names":[],"mappings":"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","sourcesContent":["import { createTimeProfiler } from '../../packages/timeProfiler.js'\nimport { showTimeProfiling } from '../../config.js'\nimport chalk from '../../packages/chalk.js'\nimport minimatch from 'minimatch'\nimport slash from '../../packages/slash.js'\nimport { out as mainOut, log, debug } from '../../output.js'\n\nimport { agentChange } from './agentReport.js'\nimport { runTests } from './runTests.js'\nimport { buildDependencyTree } from './buildDependencyTree.js'\nimport { globArgCombine } from './globArgCombine.js'\nimport { addBasePath } from './addBasePath.js'\nimport { watchFilesNodeWatch } from './watchFilesNodeWatch.js'\nimport { filter } from './filter.js'\nimport { remove as arrayRemove } from 'sxy-lib/arrays.js'\n\nimport type { FinalConfig, DependencyTrees, OutFn, TestExecutionFilters } from '../../types.js'\nimport { ReRunManageState } from './makeWatchRunState.js'\nimport { ReRunManager } from './reRunManager.js'\nimport { inspect } from 'util'\n\nconst { timeProfileAsync } = createTimeProfiler(showTimeProfiling)\n\nexport async function watchFilesAndRunTestsNodeWatch(\n config: FinalConfig,\n //testFiles: Set<string>,\n dependencyTrees: DependencyTrees,\n failingTests: string[],\n reRunManager: ReRunManager,\n //watchRunState: WatchRunState,\n customOut?: OutFn,\n executionFilters: TestExecutionFilters = {}\n): Promise<void> {\n const projectDir = process.cwd()\n // agent mode passes a sink here, so its own change lines are the only ones printed\n const out = customOut ?? mainOut\n\n await timeProfileAsync('init watching', async () => {\n debug('failingTests', failingTests)\n\n const testsGlobs = addBasePath(config.testsBase, config.tests)\n const testsIgnoreGlobs = addBasePath(config.testsBase, config.testsIgnore)\n\n // indentify a test file\n const testFilter = (file: string): boolean => {\n return minimatch(file, globArgCombine(testsGlobs))\n && !minimatch(file, globArgCombine(testsIgnoreGlobs))\n && (\n config.testsFilter === undefined\n || config.testsFilter === ''\n || filter(config.testsBase, config.testsFilter, file)\n )\n }\n\n let changedFiles: Array<[string, string]> = []\n let timeout: ReturnType<typeof setTimeout> | null = null\n\n if (config.watch.watchFilesBase === '') {\n out('No config.watch.watchFilesBase provided, defaulting to \\'.\\'')\n config.watch.watchFilesBase = '.'\n }\n\n await watchFilesNodeWatch(config, watchEvent)\n\n function watchEvent(filename: string, event: string): void {\n debug('handle watch event ', filename, event)\n\n filename = slash(filename)\n\n // remove dep tree for any tests that are deleted, avoiding trying to run it later\n if (event === 'remove') {\n debug('removing test', filename)\n if (filename in dependencyTrees) {\n reRunManager.state.allTestFiles.delete(filename)\n delete dependencyTrees[filename]\n }\n }\n\n // info on the event found\n out(chalk.grey`change: ${filename} (${event})`)\n agentChange(config, filename, event)\n\n // add the file to changed files\n changedFiles.push([filename, event])\n\n // wait 100ms after any change before processing, to avoid multiple execution?\n if (timeout) {\n clearTimeout(timeout)\n }\n\n timeout = setTimeout(() => {\n void timeProfileAsync('handle changed files', async () => {\n debug('changedFiles', changedFiles)\n try {\n // build related test list\n //const tests: string[] = []\n const tests = new Set<string>\n for (const [file, fileEvent] of changedFiles) {\n debug('check', file)\n debug('1 tests', tests)\n if (fileEvent !== 'remove') { // only check if it's a test if it exists (has not just been removed)\n if (testFilter(file)) { // it is a test file itself, add to run list\n debug('its a test', file)\n //tests.push(file)\n tests.add(file)\n if (!(file in dependencyTrees)) { // if its a new test\n debug('try to add a new test', file)\n addNewTest(file)\n }\n }\n }\n debug('dtrees', dependencyTrees)\n debug('2 tests', tests)\n for (const f of Object.getOwnPropertyNames(dependencyTrees)) {\n debug('dep tree', f, dependencyTrees[f])\n if (dependencyTrees[f]?.some(dep => dep === file) === true) { // a test depends on this file\n debug('its a dependency', file)\n //tests.push(f)\n tests.add(f)\n }\n }\n }\n\n changedFiles = []\n\n debug('tests', tests)\n\n if (tests.size > 0) {\n await timeProfileAsync('build list of files to test and request a run', async () => {\n debug('tests', tests)\n debug('reRunFailingTests', config.watch.reRunFailingTests)\n\n // changes accumulate here because an 'auto' request made while a\n // run is in flight is coalesced into the queued one - everything\n // edited in the meantime still has to be covered\n reRunManager.state.untestedFiles\n = reRunManager.state.untestedFiles.union(tests)\n\n reRunManager.requestRun(\n 'auto',\n () => {\n // resolved when the run actually starts, not when it is\n // queued, so a coalesced request picks up the later edits\n const toTest = (config.watch.reRunFailingTests)\n ? reRunManager.state.untestedFiles\n .union(reRunManager.state.failedTestFiles)\n : new Set(reRunManager.state.untestedFiles)\n\n // consumed by this run - without this they are retested\n // on every later run for the rest of the session\n reRunManager.state.untestedFiles = new Set()\n\n debug('run tests on change')\n debug('toTest', toTest)\n\n return runTests(\n config,\n toTest,\n reRunManager,\n 'refresh',\n customOut,\n executionFilters\n )\n }\n )\n })\n }\n } catch (e) {\n log('watch handler error', e)\n }\n })\n }, 33)\n } // end of watch event\n\n function addNewTest(testFile: string): void {\n debug('new test', testFile)\n const dependencyTree = buildDependencyTree(config, testFile)\n dependencyTrees[testFile] = dependencyTree\n .map(file => slash(file).slice(projectDir.length + 1))\n .filter(f => f !== testFile)\n }\n })\n\n // NOTE: \"watching...\" is intentionally NOT printed here. watch() already emits it,\n // tied to a real milestone (the initial test run finishing, or no tests found).\n // Printing it again here produced a duplicate \"watching...\" on every startup.\n // out(chalk.brightblue`watching...`)\n}\n"]}
1
+ {"version":3,"file":"watchFilesAndRunTestsNodeWatch.js","sourceRoot":"","sources":["../../../src/cli/lib/watchFilesAndRunTestsNodeWatch.ts"],"names":[],"mappings":"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","sourcesContent":["import { createTimeProfiler } from '../../packages/timeProfiler.js'\nimport { showTimeProfiling } from '../../config.js'\nimport chalk from '../../packages/chalk.js'\nimport minimatch from 'minimatch'\nimport slash from '../../packages/slash.js'\nimport { out as mainOut, log, debug } from '../../output.js'\n\nimport { agentChange } from './agentReport.js'\nimport { runTests } from './runTests.js'\nimport { buildDependencyTree } from './buildDependencyTree.js'\nimport { globArgCombine } from './globArgCombine.js'\nimport { addBasePath } from './addBasePath.js'\nimport { watchFilesNodeWatch } from './watchFilesNodeWatch.js'\nimport { filter } from './filter.js'\nimport { remove as arrayRemove } from 'sxy-lib/arrays.js'\n\nimport type { FinalConfig, DependencyTrees, OutFn, TestExecutionFilters } from '../../types.js'\nimport { ReRunManageState } from './makeWatchRunState.js'\nimport { ReRunManager } from './reRunManager.js'\nimport { inspect } from 'util'\n\nconst { timeProfileAsync } = createTimeProfiler(showTimeProfiling)\n\nexport async function watchFilesAndRunTestsNodeWatch(\n config: FinalConfig,\n //testFiles: Set<string>,\n dependencyTrees: DependencyTrees,\n failingTests: string[],\n reRunManager: ReRunManager,\n //watchRunState: WatchRunState,\n customOut?: OutFn,\n executionFilters: TestExecutionFilters = {}\n): Promise<void> {\n const projectDir = process.cwd()\n // agent mode passes a sink here, so its own change lines are the only ones printed\n const out = customOut ?? mainOut\n\n await timeProfileAsync('init watching', async () => {\n debug('failingTests', failingTests)\n\n const testsGlobs = addBasePath(config.testsBase, config.tests)\n const testsIgnoreGlobs = addBasePath(config.testsBase, config.testsIgnore)\n\n // indentify a test file\n const testFilter = (file: string): boolean => {\n return minimatch(file, globArgCombine(testsGlobs))\n && !minimatch(file, globArgCombine(testsIgnoreGlobs))\n && (\n config.testsFilter === undefined\n || config.testsFilter === ''\n || filter(config.testsBase, config.testsFilter, file)\n )\n }\n\n let changedFiles: Array<[string, string]> = []\n let timeout: ReturnType<typeof setTimeout> | null = null\n\n if (config.watch.watchFilesBase === '') {\n out('No config.watch.watchFilesBase provided, defaulting to \\'.\\'')\n config.watch.watchFilesBase = '.'\n }\n\n await watchFilesNodeWatch(config, watchEvent)\n\n function watchEvent(filename: string, event: string): void {\n debug('handle watch event ', filename, event)\n\n filename = slash(filename)\n\n // remove dep tree for any tests that are deleted, avoiding trying to run it later\n if (event === 'remove') {\n debug('removing test', filename)\n if (filename in dependencyTrees) {\n reRunManager.state.allTestFiles.delete(filename)\n delete dependencyTrees[filename]\n } else if (!config.watch.dependencyEvaluation) {\n // without trees there is nothing to look the file up in\n reRunManager.state.allTestFiles.delete(filename)\n }\n }\n\n // info on the event found\n out(chalk.grey`change: ${filename} (${event})`)\n agentChange(config, filename, event)\n\n // add the file to changed files\n changedFiles.push([filename, event])\n\n // wait 100ms after any change before processing, to avoid multiple execution?\n if (timeout) {\n clearTimeout(timeout)\n }\n\n timeout = setTimeout(() => {\n void timeProfileAsync('handle changed files', async () => {\n debug('changedFiles', changedFiles)\n try {\n // build related test list\n //const tests: string[] = []\n const tests = new Set<string>\n for (const [file, fileEvent] of changedFiles) {\n debug('check', file)\n debug('1 tests', tests)\n if (fileEvent !== 'remove') { // only check if it's a test if it exists (has not just been removed)\n if (testFilter(file)) { // it is a test file itself, add to run list\n debug('its a test', file)\n //tests.push(file)\n tests.add(file)\n if (config.watch.dependencyEvaluation) {\n if (!(file in dependencyTrees)) { // if its a new test\n debug('try to add a new test', file)\n addNewTest(file)\n }\n } else {\n // no trees to record it in, so this is what makes a\n // newly created test part of the run set\n reRunManager.state.allTestFiles.add(file)\n }\n }\n }\n\n // with evaluation off there is nothing to map the change through:\n // any watched file could affect any test, so run the lot\n if (!config.watch.dependencyEvaluation) {\n for (const f of reRunManager.state.allTestFiles) tests.add(f)\n continue\n }\n\n debug('dtrees', dependencyTrees)\n debug('2 tests', tests)\n for (const f of Object.getOwnPropertyNames(dependencyTrees)) {\n debug('dep tree', f, dependencyTrees[f])\n if (dependencyTrees[f]?.some(dep => dep === file) === true) { // a test depends on this file\n debug('its a dependency', file)\n //tests.push(f)\n tests.add(f)\n }\n }\n }\n\n changedFiles = []\n\n debug('tests', tests)\n\n if (tests.size > 0) {\n await timeProfileAsync('build list of files to test and request a run', async () => {\n debug('tests', tests)\n debug('reRunFailingTests', config.watch.reRunFailingTests)\n\n // changes accumulate here because an 'auto' request made while a\n // run is in flight is coalesced into the queued one - everything\n // edited in the meantime still has to be covered\n reRunManager.state.untestedFiles\n = reRunManager.state.untestedFiles.union(tests)\n\n reRunManager.requestRun(\n 'auto',\n () => {\n // resolved when the run actually starts, not when it is\n // queued, so a coalesced request picks up the later edits\n const toTest = (config.watch.reRunFailingTests)\n ? reRunManager.state.untestedFiles\n .union(reRunManager.state.failedTestFiles)\n : new Set(reRunManager.state.untestedFiles)\n\n // consumed by this run - without this they are retested\n // on every later run for the rest of the session\n reRunManager.state.untestedFiles = new Set()\n\n debug('run tests on change')\n debug('toTest', toTest)\n\n return runTests(\n config,\n toTest,\n reRunManager,\n 'refresh',\n customOut,\n executionFilters\n )\n }\n )\n })\n }\n } catch (e) {\n log('watch handler error', e)\n }\n })\n }, 33)\n } // end of watch event\n\n function addNewTest(testFile: string): void {\n debug('new test', testFile)\n const dependencyTree = buildDependencyTree(config, testFile)\n dependencyTrees[testFile] = dependencyTree\n .map(file => slash(file).slice(projectDir.length + 1))\n .filter(f => f !== testFile)\n }\n })\n\n // NOTE: \"watching...\" is intentionally NOT printed here. watch() already emits it,\n // tied to a real milestone (the initial test run finishing, or no tests found).\n // Printing it again here produced a duplicate \"watching...\" on every startup.\n // out(chalk.brightblue`watching...`)\n}\n"]}
package/dist/cli/watch.js CHANGED
@@ -122,9 +122,13 @@ export async function watch() {
122
122
  let initialTestRun = null;
123
123
  if (testFiles.size > 0) {
124
124
  agentOut(chalk.brightblue(foundTestsMessage(testFiles.size)));
125
- const { buildDependencyTrees } = await import('./lib/buildDependencyTrees.js');
126
- agentOut(chalk.brightblue `finding initial dependency trees...`);
127
- dependencyTrees = await buildDependencyTrees(config, testFiles);
125
+ // the trees are only consulted to narrow a run, so with evaluation off building them
126
+ // is pure cost - and it is the slowest part of startup on a large suite
127
+ if (config.watch.dependencyEvaluation) {
128
+ const { buildDependencyTrees } = await import('./lib/buildDependencyTrees.js');
129
+ agentOut(chalk.brightblue `finding initial dependency trees...`);
130
+ dependencyTrees = await buildDependencyTrees(config, testFiles);
131
+ }
128
132
  if (config.watch.runAllOnStartup) {
129
133
  agentOut(chalk.brightblue `running initial tests...`);
130
134
  initialTestRun = runTests(config, testFiles, reRunManager, (isTest) ? 'refresh' : 'cached', runsOut, executionFilters).then(async (testsResult) => {
@@ -1 +1 @@
1
- {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/cli/watch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,sBAAsB,CAAA;AAExC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,cAAc,CAAA;AAGzC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAA;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAExD,MAAM,CAAC,KAAK,UAAU,KAAK;IACvB,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,CAAA;IAEtC,MAAM,EAAE,yBAAyB,EAAE,GAAG,MAAM,MAAM,CAAC,oCAAoC,CAAC,CAAA;IACxF,MAAM,kBAAkB,GAAqB;QACzC,QAAQ,EAAE;YACN,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,IAAI;SACjB;QACD,YAAY,EAAE;YACV,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,IAAI;SACjB;QACD,QAAQ,EAAE;YACN,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,IAAI;SACjB;QACD,WAAW,EAAE;YACT,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,IAAI;SACjB;QACD,iBAAiB,EAAE;YACf,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,IAAI;SACjB;QACD,aAAa,EAAE;YACX,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,IAAI;SACjB;QACD,OAAO,EAAE;YACL,QAAQ,EAAE,KAAK;SAClB;KACJ,CAAA;IACD,MAAM,WAAW,GAAG,yBAAyB,CAAC,kBAAkB,CAAC,CAAA;IACjE,mCAAmC;IAEnC,wFAAwF;IACxF,wFAAwF;IACxF,qDAAqD;IACrD,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,KAAK,IAAI,CAAA;IAC5C,MAAM,EACF,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,cAAc,EACjF,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAA;IACxC,SAAS,CAAC,SAAS,CAAC,CAAA;IACpB,MAAM,QAAQ,GAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAA;IAC1D,MAAM,OAAO,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAA;IAExD,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAA,IAAI,WAAW,MAAM,CAAC,CAAA;IAE/C,MAAM,EAAE,CAAA;IAER,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAA;IAC1D,MAAM,UAAU,GAAG,CAAC,OAAO,WAAW,CAAC,MAAM,KAAK,QAAQ,CAAC;QACvD,CAAC,CAAC,MAAM,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC;QACtC,CAAC,CAAC,MAAM,UAAU,EAAE,CAAA;IAExB,IAAI,YAAY,IAAI,WAAW,EAAE,CAAC;QAC9B,MAAM,gBAAgB,GAAG,WAAW,CAAC,YAAY,CAAC,CAAA;QAClD,IAAI,OAAO,gBAAgB,KAAK,QAAQ,IAAI,gBAAgB,KAAK,EAAE,EAAE,CAAC;YAClE,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAA;QAC3E,CAAC;QACD,UAAU,CAAC,KAAK,GAAG,gBAAgB,CAAA;IACvC,CAAC;IAED,IAAI,QAAQ,IAAI,WAAW,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAA;QACjC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,EAAE,EAAE,CAAC;YAC9C,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAA;QACvE,CAAC;QACD,UAAU,CAAC,WAAW,GAAG,MAAM,CAAA;IACnC,CAAC;IAED,IAAI,aAAa,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,UAAU,GAAG,WAAW,CAAC,aAAa,CAAC,CAAA;QAC7C,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,EAAE,EAAE,CAAC;YACtD,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAA;QAC9E,CAAC;QACD,UAAU,CAAC,KAAK,GAAG,EAAE,GAAG,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,CAAA;IAC1D,CAAC;IAED,MAAM,QAAQ,GAAG,WAAW,CAAC,WAAW,CAAC,CAAA;IACzC,MAAM,cAAc,GAAG,WAAW,CAAC,iBAAiB,CAAC,CAAA;IACrD,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAA;IACnG,IAAI,cAAc,KAAK,IAAI,IAAI,cAAc,KAAK,EAAE,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAA;IACnE,CAAC;IACD,MAAM,gBAAgB,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAA;IAEnE,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM,MAAM,CAAC,8BAA8B,CAAC,CAAA;IAC5E,MAAM,MAAM,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAA;IAC9C,IAAI,SAAS;QAAE,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAA;IAExC,uFAAuF;IACvF,gDAAgD;IAChD,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAA;IAClE,cAAc,CAAC,MAAM,CAAC,CAAA;IAEtB,6EAA6E;IAC7E,MAAM,EAAE,eAAe,EAAE,WAAW,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAA;IAC7F,eAAe,CAAC,MAAM,CAAC,CAAA;IAEvB,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAA;IAC5D,MAAM,WAAW,CAAC,MAAM,CAAC,CAAA;IAEzB,wFAAwF;IACxF,wFAAwF;IACxF,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAA;IAClE,MAAM,EAAE,wBAAwB,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAA;IACtE,wBAAwB,CAAC,MAAM,EAAE;QAC7B,QAAQ,EAAE,cAAc;QACxB,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;KACnC,CAAC,CAAA;IAEF,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IACvD,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAA;IAChE,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAA;IAC7C,KAAK,CAAC,SAAS,CAAC,CAAA;IAChB,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,CAAA;IAElC,4CAA4C;IAC5C,IAAI,eAAe,GAAoB,EAAE,CAAA;IACzC,6CAA6C;IAC7C,MAAM,YAAY,GAAa,EAAE,CAAA;IAEjC,MAAM,YAAY,GAAG,gBAAgB,CACjC,IAAI,EACJ,mBAAmB,CAAC;QAChB,YAAY,EAAE,SAAS;QACvB,aAAa,EAAE,SAAS;KAC3B,CAAC,EACF,OAAO,CACV,CAAA;IAED,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAA;IACtD,IAAI,cAAc,GAAmC,IAAI,CAAA;IAEzD,IAAI,SAAS,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QACrB,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,iBAAiB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAC7D,MAAM,EAAE,oBAAoB,EAAE,GAAG,MAAM,MAAM,CAAC,+BAA+B,CAAC,CAAA;QAC9E,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAA,qCAAqC,CAAC,CAAA;QAC/D,eAAe,GAAG,MAAM,oBAAoB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;QAE/D,IAAI,MAAM,CAAC,KAAK,CAAC,eAAe,EAAE,CAAC;YAC/B,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAA,0BAA0B,CAAC,CAAA;YACpD,cAAc,GAAG,QAAQ,CACrB,MAAM,EAAE,SAAS,EAAE,YAAY,EAC/B,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAC/B,OAAO,EAAE,gBAAgB,CAC5B,CAAC,IAAI,CAAC,KAAK,EAAC,WAAW,EAAC,EAAE;gBACvB,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,SAAS,CAAA;gBAC7C,0DAA0D;gBAC1D,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAA,KAAK,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,CAAA;gBAClD,OAAO,WAAW,CAAA;YACtB,CAAC,CAAC,CAAA;YACF,YAAY,CAAC,KAAK,CAAC,UAAU,GAAG,cAAc,CAAA;YAC9C,wCAAwC;YACxC,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,kCAAkC,GAAG,EAAE,CAAC,CAAA;QACxE,CAAC;IACL,CAAC;SAAM,CAAC;QACJ,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAA,qBAAqB,CAAC,CAAA;QAC3C,eAAe,CAAC,MAAM,EAAE,WAAW,CAAC,WAAW,EAAE,qBAAqB,CAAC,CAAA;QACvE,8EAA8E;QAC9E,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QACpC,SAAS,CACL,MAAM,EAAE,GAAG,EAAE,WAAW,CAAC,WAAW,EAAE,qBAAqB,EAC3D,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,SAAS,EAAE,CAAC,CAC5C,CAAA;IACL,CAAC;IAED,MAAM,EAAE,qBAAqB,EAAE,GAAG,MAAM,MAAM,CAAC,gCAAgC,CAAC,CAAA;IAChF,MAAM,qBAAqB,CACvB,MAAM;IACN,YAAY;IACZ,eAAe,EACf,YAAY,EAAE,qCAAqC;IACnD,YAAY;IACZ,gBAAgB;IAChB,OAAO,EACP,gBAAgB,CACnB,CAAA;IAGD,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAA,aAAa,CAAC,CAAA;IACvC,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,CAAA;IAErC,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAA;IAC9D,YAAY,CACR,YAAY,EACZ,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE;QACV,OAAO,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAA;IACtF,CAAC,EACD,MAAM,CAAC,KAAK,CAAC,oBAAoB,EACjC,cAAc,EACd,OAAO,CAAC,KAAK,EACb,OAAO,CACV,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;IAGzB,0FAA0F;IAC1F,+CAA+C;IAC/C,MAAM,IAAI,OAAO,CAAO,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;AACrC,CAAC","sourcesContent":["import chalk from '../packages/chalk.js'\n\nimport { packageName } from '../config.js'\nimport { out, debug } from '../output.js'\n\nimport type { AllowedArguments, DependencyTrees, OutFn } from '../types.js'\nimport { setEnv } from './lib/setEnv.js'\nimport { findingTestsMessage } from './lib/findingTestsMessage.js'\nimport { foundTestsMessage } from './lib/foundTestsMessage.js'\nimport { isTest } from './lib/isTest.js'\nimport { makeRunManagerState } from './lib/makeWatchRunState.js'\nimport { makeReRunManager } from './lib/reRunManager.js'\n\nexport async function watch(): Promise<void> {\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 },\n 'filter': {\n flag: 'f',\n hasValue: 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 }\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 when the flag is on. Announced before the config loads, so a reader\n // sees the process is alive even if startup is slow.\n const agentMode = clArguments.agent === true\n const {\n agentInit, agentFound, agentRunStart, agentDone, agentWatching, agentSilentOut\n } = await import('./lib/agentReport.js')\n agentInit(agentMode)\n const agentOut: OutFn = (agentMode) ? agentSilentOut : out\n const runsOut = (agentMode) ? agentSilentOut : undefined\n\n agentOut(chalk.brightblue`[${packageName}]...`)\n\n setEnv()\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 (agentMode) config.watch.agent = true\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)\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 registerShutdownHandlers(config, {\n teardown: doUserTeardown,\n exit: code => process.exit(code)\n })\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 // global store of the dependencies of tests\n let dependencyTrees: DependencyTrees = {}\n // store failing tests so we can re-run them.\n const failingTests: string[] = []\n \n const reRunManager = makeReRunManager(\n null,\n makeRunManagerState({\n allTestFiles: testFiles,\n lastTestFiles: testFiles\n }),\n runsOut\n )\n\n const { runTests } = await import('./lib/runTests.js')\n let initialTestRun: Promise<boolean | null> | null = null\n\n if (testFiles.size > 0) {\n agentOut(chalk.brightblue(foundTestsMessage(testFiles.size)))\n const { buildDependencyTrees } = await import('./lib/buildDependencyTrees.js')\n agentOut(chalk.brightblue`finding initial dependency trees...`)\n dependencyTrees = await buildDependencyTrees(config, testFiles)\n\n if (config.watch.runAllOnStartup) {\n agentOut(chalk.brightblue`running initial tests...`)\n initialTestRun = runTests(\n config, testFiles, reRunManager,\n (isTest) ? 'refresh' : 'cached',\n runsOut, executionFilters\n ).then(async 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 // do we need to catch errors like this?\n initialTestRun.catch(err => `Error during initial test run: ${err}`)\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 const { watchFilesAndRunTests } = await import('./lib/watchFilesAndRunTests.js')\n await watchFilesAndRunTests(\n config,\n //testFiles,\n dependencyTrees,\n failingTests, // CHECK this should also be in state\n reRunManager,\n //watchRunState,\n runsOut,\n executionFilters\n )\n\n\n agentOut(chalk.brightblue`watching...`)\n agentWatching(config, testFiles.size)\n\n const { listenToUser } = await import('./lib/listenToUser.js')\n listenToUser(\n reRunManager,\n files => () => {\n return runTests(config, files, reRunManager, 'refresh', runsOut, executionFilters)\n },\n config.watch.ttyActionsOnKeypress,\n initialTestRun,\n process.stdin,\n runsOut\n ).catch(e => { throw e })\n\n\n // park forever - watch mode ends by being signalled, and the shutdown handlers registered\n // above run the user's teardown on the way out\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":["import chalk from '../packages/chalk.js'\n\nimport { packageName } from '../config.js'\nimport { out, debug } from '../output.js'\n\nimport type { AllowedArguments, DependencyTrees, OutFn } from '../types.js'\nimport { setEnv } from './lib/setEnv.js'\nimport { findingTestsMessage } from './lib/findingTestsMessage.js'\nimport { foundTestsMessage } from './lib/foundTestsMessage.js'\nimport { isTest } from './lib/isTest.js'\nimport { makeRunManagerState } from './lib/makeWatchRunState.js'\nimport { makeReRunManager } from './lib/reRunManager.js'\n\nexport async function watch(): Promise<void> {\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 },\n 'filter': {\n flag: 'f',\n hasValue: 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 }\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 when the flag is on. Announced before the config loads, so a reader\n // sees the process is alive even if startup is slow.\n const agentMode = clArguments.agent === true\n const {\n agentInit, agentFound, agentRunStart, agentDone, agentWatching, agentSilentOut\n } = await import('./lib/agentReport.js')\n agentInit(agentMode)\n const agentOut: OutFn = (agentMode) ? agentSilentOut : out\n const runsOut = (agentMode) ? agentSilentOut : undefined\n\n agentOut(chalk.brightblue`[${packageName}]...`)\n\n setEnv()\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 (agentMode) config.watch.agent = true\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)\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 registerShutdownHandlers(config, {\n teardown: doUserTeardown,\n exit: code => process.exit(code)\n })\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 // global store of the dependencies of tests\n let dependencyTrees: DependencyTrees = {}\n // store failing tests so we can re-run them.\n const failingTests: string[] = []\n \n const reRunManager = makeReRunManager(\n null,\n makeRunManagerState({\n allTestFiles: testFiles,\n lastTestFiles: testFiles\n }),\n runsOut\n )\n\n const { runTests } = await import('./lib/runTests.js')\n let initialTestRun: Promise<boolean | null> | null = null\n\n if (testFiles.size > 0) {\n agentOut(chalk.brightblue(foundTestsMessage(testFiles.size)))\n\n // the trees are only consulted to narrow a run, so with evaluation off building them\n // is pure cost - and it is the slowest part of startup on a large suite\n if (config.watch.dependencyEvaluation) {\n const { buildDependencyTrees } = await import('./lib/buildDependencyTrees.js')\n agentOut(chalk.brightblue`finding initial dependency trees...`)\n dependencyTrees = await buildDependencyTrees(config, testFiles)\n }\n\n if (config.watch.runAllOnStartup) {\n agentOut(chalk.brightblue`running initial tests...`)\n initialTestRun = runTests(\n config, testFiles, reRunManager,\n (isTest) ? 'refresh' : 'cached',\n runsOut, executionFilters\n ).then(async 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 // do we need to catch errors like this?\n initialTestRun.catch(err => `Error during initial test run: ${err}`)\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 const { watchFilesAndRunTests } = await import('./lib/watchFilesAndRunTests.js')\n await watchFilesAndRunTests(\n config,\n //testFiles,\n dependencyTrees,\n failingTests, // CHECK this should also be in state\n reRunManager,\n //watchRunState,\n runsOut,\n executionFilters\n )\n\n\n agentOut(chalk.brightblue`watching...`)\n agentWatching(config, testFiles.size)\n\n const { listenToUser } = await import('./lib/listenToUser.js')\n listenToUser(\n reRunManager,\n files => () => {\n return runTests(config, files, reRunManager, 'refresh', runsOut, executionFilters)\n },\n config.watch.ttyActionsOnKeypress,\n initialTestRun,\n process.stdin,\n runsOut\n ).catch(e => { throw e })\n\n\n // park forever - watch mode ends by being signalled, and the shutdown handlers registered\n // above run the user's teardown on the way out\n await new Promise<void>(() => {})\n}\n"]}
package/dist/types.d.ts CHANGED
@@ -14,6 +14,7 @@ export interface WatchConfig {
14
14
  watchFilesIgnore: GlobPattern;
15
15
  runAllOnStartup: boolean;
16
16
  reRunFailingTests: boolean;
17
+ dependencyEvaluation: boolean;
17
18
  ttyActionsOnKeypress: boolean;
18
19
  statusFile: StatusFileConfig;
19
20
  agent: boolean;
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,2EAA2E;AAC3E,2EAA2E;AAC3E,+EAA+E","sourcesContent":["// 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 { DescribeMeta } from './describe.js'\nimport { FileMeta } from './meta.js'\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 ttyActionsOnKeypress: boolean\n statusFile: StatusFileConfig\n // report the session as single agent readable lines instead of the usual output\n agent: boolean\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 execution: ExecutionConfig\n watch: WatchConfig\n}\n\nexport type UserConfig = Partial<Omit<FinalConfig, 'testsFilter' | 'execution' | 'watch'>> & {\n execution?: Partial<ExecutionConfig>\n watch?: Partial<WatchConfig>\n}\n\nexport type UserConfigInternal = UserConfig & Partial<Pick<FinalConfig, 'testsFilter'>>\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\nexport interface Describe {\n counter: number\n thing: string\n meta?: DescribeMeta\n tests: DescribeCallback\n}\n\nexport interface It {\n counter: number\n should: string\n test: (parcel: TestParcel) => void | Promise<void>\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\nexport interface TestError extends Error {\n actual?: unknown\n expected?: unknown\n}\n\nexport interface ItResult {\n counter: number\n should: string\n success: boolean | null\n time: number\n error?: TestError\n logs: unknown[][]\n}\n\nexport interface ItResultsSummary {\n total: number\n passes: number\n}\n\nexport interface DescribeResult {\n counter: number\n thing: string\n success: boolean | null\n // total elapsed for the whole describe, filled in by runDescribe once it has finished\n time: number\n itResults: ItResult[]\n itResultsSummary: ItResultsSummary\n logs?: unknown[][]\n error?: unknown\n}\n\nexport interface DescribeResultsSummary {\n total: number\n passes: number\n invalid: number\n itsTotal: number\n itsPasses: number\n}\n\nexport interface TestFile {\n file: string\n describes?: Describe[]\n meta?: FileMeta\n error?: string | false\n logs?: unknown[][]\n}\n\nexport interface TestResult {\n file: string\n success: boolean | null\n describeResults: DescribeResult[]\n describeResultsSummary: DescribeResultsSummary\n logs: unknown[][]\n}\n\nexport interface TestsResultsSummary {\n total: number\n passes: number\n invalid: number\n describesTotal: number\n describesPasses: number\n describesInvalid: number\n itsTotal: number\n itsPasses: number\n}\n\nexport type DependencyTrees = Record<string, string[]>\n\nexport type OutFn = (...texts: unknown[]) => void\n\n\n\n// -- CLI argument parsing ---------------------------------------------------\n\nexport interface AllowedArgument {\n flag?: string\n hasValue: boolean\n}\n\nexport type AllowedArguments = Record<string, AllowedArgument>\nexport type AllowedFlags = Record<string, string>\nexport type ParsedArguments = Record<string, string | true>\n\nexport interface TestExecutionFilters {\n describe?: string\n it?: string\n}\n\n// -- globals ----------------------------------------------------------------\n\nexport interface SxyTestRunnerGlobal {\n describes: Describe[]\n describeCounter: number\n fileMeta?: FileMeta\n}\ndeclare global {\n // eslint-disable-next-line camelcase\n var __sxy_test_runner__: SxyTestRunnerGlobal | undefined\n // eslint-disable-next-line camelcase\n var __sxyt_commandLineArguments: string[]\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,2EAA2E;AAC3E,2EAA2E;AAC3E,+EAA+E","sourcesContent":["// 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 { DescribeMeta } from './describe.js'\nimport { FileMeta } from './meta.js'\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 // report the session as single agent readable lines instead of the usual output\n agent: boolean\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 execution: ExecutionConfig\n watch: WatchConfig\n}\n\nexport type UserConfig = Partial<Omit<FinalConfig, 'testsFilter' | 'execution' | 'watch'>> & {\n execution?: Partial<ExecutionConfig>\n watch?: Partial<WatchConfig>\n}\n\nexport type UserConfigInternal = UserConfig & Partial<Pick<FinalConfig, 'testsFilter'>>\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\nexport interface Describe {\n counter: number\n thing: string\n meta?: DescribeMeta\n tests: DescribeCallback\n}\n\nexport interface It {\n counter: number\n should: string\n test: (parcel: TestParcel) => void | Promise<void>\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\nexport interface TestError extends Error {\n actual?: unknown\n expected?: unknown\n}\n\nexport interface ItResult {\n counter: number\n should: string\n success: boolean | null\n time: number\n error?: TestError\n logs: unknown[][]\n}\n\nexport interface ItResultsSummary {\n total: number\n passes: number\n}\n\nexport interface DescribeResult {\n counter: number\n thing: string\n success: boolean | null\n // total elapsed for the whole describe, filled in by runDescribe once it has finished\n time: number\n itResults: ItResult[]\n itResultsSummary: ItResultsSummary\n logs?: unknown[][]\n error?: unknown\n}\n\nexport interface DescribeResultsSummary {\n total: number\n passes: number\n invalid: number\n itsTotal: number\n itsPasses: number\n}\n\nexport interface TestFile {\n file: string\n describes?: Describe[]\n meta?: FileMeta\n error?: string | false\n logs?: unknown[][]\n}\n\nexport interface TestResult {\n file: string\n success: boolean | null\n describeResults: DescribeResult[]\n describeResultsSummary: DescribeResultsSummary\n logs: unknown[][]\n}\n\nexport interface TestsResultsSummary {\n total: number\n passes: number\n invalid: number\n describesTotal: number\n describesPasses: number\n describesInvalid: number\n itsTotal: number\n itsPasses: number\n}\n\nexport type DependencyTrees = Record<string, string[]>\n\nexport type OutFn = (...texts: unknown[]) => void\n\n\n\n// -- CLI argument parsing ---------------------------------------------------\n\nexport interface AllowedArgument {\n flag?: string\n hasValue: boolean\n}\n\nexport type AllowedArguments = Record<string, AllowedArgument>\nexport type AllowedFlags = Record<string, string>\nexport type ParsedArguments = Record<string, string | true>\n\nexport interface TestExecutionFilters {\n describe?: string\n it?: string\n}\n\n// -- globals ----------------------------------------------------------------\n\nexport interface SxyTestRunnerGlobal {\n describes: Describe[]\n describeCounter: number\n fileMeta?: FileMeta\n}\ndeclare global {\n // eslint-disable-next-line camelcase\n var __sxy_test_runner__: SxyTestRunnerGlobal | undefined\n // eslint-disable-next-line camelcase\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.4.0",
3
+ "version": "2.4.2",
4
4
  "license": "MIT",
5
5
  "homepage": "https://github.com/RobertSandiford/sxy-test-runner",
6
6
  "repository": {
@@ -39,8 +39,6 @@
39
39
  "readme.md"
40
40
  ],
41
41
  "dependencies": {
42
- "@types/chai": "^5.2.3",
43
- "assertion-error": "^2.0.1",
44
42
  "chalk": "^4.1.2",
45
43
  "chokidar": "^3.6.0",
46
44
  "cross-env": "^7.0.3",
@@ -52,6 +50,7 @@
52
50
  "sxy-lib": "^3.0.5"
53
51
  },
54
52
  "devDependencies": {
53
+ "@types/chai": "^5.2.3",
55
54
  "@types/chai-as-promised": "^7.1.8",
56
55
  "@types/chai-string": "^1.4.5",
57
56
  "@types/minimatch": "^5.1.2",