sxy-test-runner 2.3.19 → 2.3.22

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.
Files changed (45) hide show
  1. package/AGENTS.md +147 -6
  2. package/LICENSE +21 -0
  3. package/dist/cli/help.js +3 -1
  4. package/dist/cli/help.js.map +1 -1
  5. package/dist/cli/init.js +6 -0
  6. package/dist/cli/init.js.map +1 -1
  7. package/dist/cli/lib/agentReport.d.ts +16 -0
  8. package/dist/cli/lib/agentReport.js +117 -0
  9. package/dist/cli/lib/agentReport.js.map +1 -0
  10. package/dist/cli/lib/defaultConfig.js +3 -1
  11. package/dist/cli/lib/defaultConfig.js.map +1 -1
  12. package/dist/cli/lib/doUserSetup.js +4 -0
  13. package/dist/cli/lib/doUserSetup.js.map +1 -1
  14. package/dist/cli/lib/failureEntries.d.ts +9 -0
  15. package/dist/cli/lib/failureEntries.js +42 -0
  16. package/dist/cli/lib/failureEntries.js.map +1 -0
  17. package/dist/cli/lib/failureLines.d.ts +3 -0
  18. package/dist/cli/lib/failureLines.js +33 -0
  19. package/dist/cli/lib/failureLines.js.map +1 -0
  20. package/dist/cli/lib/listenToUser.d.ts +2 -1
  21. package/dist/cli/lib/listenToUser.js +6 -3
  22. package/dist/cli/lib/listenToUser.js.map +1 -1
  23. package/dist/cli/lib/reRunManager.d.ts +2 -1
  24. package/dist/cli/lib/reRunManager.js +9 -2
  25. package/dist/cli/lib/reRunManager.js.map +1 -1
  26. package/dist/cli/lib/runTests.js +65 -14
  27. package/dist/cli/lib/runTests.js.map +1 -1
  28. package/dist/cli/lib/statusFile.d.ts +12 -0
  29. package/dist/cli/lib/statusFile.js +60 -0
  30. package/dist/cli/lib/statusFile.js.map +1 -0
  31. package/dist/cli/lib/validateConfig.js +7 -0
  32. package/dist/cli/lib/validateConfig.js.map +1 -1
  33. package/dist/cli/lib/watchFilesAndRunTestsNodeWatch.js +24 -23
  34. package/dist/cli/lib/watchFilesAndRunTestsNodeWatch.js.map +1 -1
  35. package/dist/cli/once.js +3 -0
  36. package/dist/cli/once.js.map +1 -1
  37. package/dist/cli/watch.js +48 -13
  38. package/dist/cli/watch.js.map +1 -1
  39. package/dist/config.d.ts +1 -1
  40. package/dist/config.js +1 -1
  41. package/dist/config.js.map +1 -1
  42. package/dist/types.d.ts +3 -0
  43. package/dist/types.js.map +1 -1
  44. package/package.json +1 -1
  45. package/readme.md +47 -1
@@ -1,5 +1,6 @@
1
1
  import { ReRunManager } from './reRunManager.js';
2
2
  import { RunTestsPromise } from './runTests.js';
3
+ import type { OutFn } from '../../types.js';
3
4
  export type RerunTestsFactory = (testFiles: Set<string>) => () => RunTestsPromise;
4
- export declare function listenToUser(rerunManager: ReRunManager, rerunTestsCallback: RerunTestsFactory, ttyActionsOnKeypress: boolean | undefined, initialTestRun: Promise<boolean | null> | null, input?: NodeJS.ReadStream): Promise<void>;
5
+ export declare function listenToUser(rerunManager: ReRunManager, rerunTestsCallback: RerunTestsFactory, ttyActionsOnKeypress: boolean | undefined, initialTestRun: Promise<boolean | null> | null, input?: NodeJS.ReadStream, customOut?: OutFn): Promise<void>;
5
6
  //# sourceMappingURL=listenToUser.d.ts.map
@@ -1,11 +1,14 @@
1
1
  import { createInterface, emitKeypressEvents } from 'node:readline';
2
2
  import { showTtyHelp } from './showTtyHelp.js';
3
3
  import { handleUserInput } from './handleUserInput.js';
4
- import { out } from '../../output.js';
4
+ import { out as mainOut } from '../../output.js';
5
5
  export async function listenToUser(
6
6
  //allTestFiles: Set<string>,
7
7
  //failingTests: Set<string>,
8
- rerunManager, rerunTestsCallback, ttyActionsOnKeypress = false, initialTestRun, input = process.stdin) {
8
+ rerunManager, rerunTestsCallback, ttyActionsOnKeypress = false, initialTestRun, input = process.stdin, customOut) {
9
+ // an agent spawned session has no TTY, so these notices would otherwise be the only
10
+ // lines in agent mode that are not agent events
11
+ const out = customOut ?? mainOut;
9
12
  //console.log('initia test run', initialTestRun)
10
13
  //console.log('listen to user')
11
14
  //setInterval(() => console.log('active runs: ', rerunManager.state.activeRuns), 10_000)
@@ -58,7 +61,7 @@ rerunManager, rerunTestsCallback, ttyActionsOnKeypress = false, initialTestRun,
58
61
  }
59
62
  //console.log('initialTestRun 2', initialTestRun)
60
63
  await initialTestRun;
61
- showTtyHelp();
64
+ showTtyHelp(input.isTTY, out);
62
65
  return;
63
66
  }
64
67
  //# sourceMappingURL=listenToUser.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"listenToUser.js","sourceRoot":"","sources":["../../../src/cli/lib/listenToUser.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAY,MAAM,eAAe,CAAA;AAC7E,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAGtD,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAA;AAKrC,MAAM,CAAC,KAAK,UAAU,YAAY;AAC9B,4BAA4B;AAC5B,4BAA4B;AAC5B,YAA0B,EAC1B,kBAAqC,EACrC,oBAAoB,GAAG,KAAK,EAC5B,cAA8C,EAC9C,QAA2B,OAAO,CAAC,KAAK;IAGxC,gDAAgD;IAChD,+BAA+B;IAE/B,wFAAwF;IAExF,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,2CAA2C,CAAC,CAAA;QAChD,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;IAC5B,CAAC;IAED,IAAI,oBAAoB,EAAE,CAAC;QAEvB,qCAAqC;QAErC,kBAAkB,CAAC,KAAK,CAAC,CAAA;QAEzB,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAA;QAC1B,MAAM,cAAc,GAAG,GAAS,EAAE;YAC9B,+BAA+B;YAC/B,IAAI,KAAK,CAAC,KAAK,KAAK,MAAM;gBAAE,OAAM;YAClC,IAAI,CAAC;gBACD,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;YAC5B,CAAC;YAAC,MAAM,CAAC;gBACL,qEAAqE;YACzE,CAAC;QACL,CAAC,CAAA;QAED,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;QACtB,KAAK,CAAC,MAAM,EAAE,CAAA;QACd,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAA;QACnC,IAAI,KAAK,KAAK,OAAO,CAAC,KAAK;YAAE,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;QAEjE,KAAK,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,aAAqB,EAAE,GAAQ,EAAE,EAAE;YACrD,wCAAwC;YACxC,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,EAAE,CAAC;gBACxC,cAAc,EAAE,CAAA;gBAChB,4EAA4E;gBAC5E,0EAA0E;gBAC1E,sEAAsE;gBACtE,kEAAkE;gBAClE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC;oBAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;gBACxD,OAAM;YACV,CAAC;YAED,eAAe,CAAC,aAAa,EAAE,YAAY,EAAE,kBAAkB,CAAC,CAAA;QACpE,CAAC,CAAC,CAAA;IACN,CAAC;SAAM,CAAC;QACJ,wCAAwC;QAExC,MAAM,SAAS,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;QAE5C,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE;YACzB,kCAAkC;YAClC,eAAe,CAAC,KAAK,EAAE,YAAY,EAAE,kBAAkB,CAAC,CAAA;QAC5D,CAAC,CAAC,CAAA;IACN,CAAC;IAED,iDAAiD;IACjD,MAAM,cAAc,CAAA;IACpB,WAAW,EAAE,CAAA;IAEb,OAAM;AACV,CAAC","sourcesContent":["\nimport { createInterface, emitKeypressEvents, type Key } from 'node:readline'\nimport { showTtyHelp } from './showTtyHelp.js'\nimport { handleUserInput } from './handleUserInput.js'\nimport { ReRunManager } from './reRunManager.js'\nimport { RunTestsPromise } from './runTests.js'\nimport { out } from '../../output.js'\n\nexport type RerunTestsFactory = (testFiles: Set<string>) => () => RunTestsPromise\n\n\nexport async function listenToUser(\n //allTestFiles: Set<string>,\n //failingTests: Set<string>,\n rerunManager: ReRunManager,\n rerunTestsCallback: RerunTestsFactory,\n ttyActionsOnKeypress = false,\n initialTestRun: Promise<boolean | null> | null,\n input: NodeJS.ReadStream = process.stdin\n): Promise<void> {\n \n //console.log('initia test run', initialTestRun)\n //console.log('listen to user')\n\n //setInterval(() => console.log('active runs: ', rerunManager.state.activeRuns), 10_000)\n\n if (!input.isTTY) {\n out('No TTY available, not receiving cli input')\n return Promise.resolve()\n }\n\n if (ttyActionsOnKeypress) {\n \n //console.log('ttyActionsOnKeypress')\n\n emitKeypressEvents(input)\n\n const wasRaw = input.isRaw\n const restoreRawMode = (): void => {\n //console.log('restoreRawMode')\n if (input.isRaw === wasRaw) return\n try {\n input.setRawMode(wasRaw)\n } catch {\n // The terminal stream may already be closed during process shutdown.\n }\n }\n\n input.setRawMode(true)\n input.resume()\n input.once('close', restoreRawMode)\n if (input === process.stdin) process.once('exit', restoreRawMode)\n\n input.on('keypress', (keypressInput: string, key: Key) => {\n //console.log('keypress', keypressInput)\n if (key.ctrl === true && key.name === 'c') {\n restoreRawMode()\n // process.kill(process.pid, 'SIGINT') terminates unconditionally on Windows\n // rather than raising the event, which skips the shutdown handlers and so\n // skips the user's teardown. Emitting reaches them on every platform.\n // Nothing listening means nobody will exit for us, so do it here.\n if (!process.emit('SIGINT', 'SIGINT')) process.exit(130)\n return\n }\n\n handleUserInput(keypressInput, rerunManager, rerunTestsCallback)\n })\n } else {\n //console.log('no ttyActionsOnKeypress')\n\n const userInput = createInterface({ input })\n\n userInput.on('line', input => {\n //console.log('line input', input)\n handleUserInput(input, rerunManager, rerunTestsCallback)\n })\n }\n\n //console.log('initialTestRun 2', initialTestRun)\n await initialTestRun\n showTtyHelp()\n\n return\n}\n"]}
1
+ {"version":3,"file":"listenToUser.js","sourceRoot":"","sources":["../../../src/cli/lib/listenToUser.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAY,MAAM,eAAe,CAAA;AAC7E,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAGtD,OAAO,EAAE,GAAG,IAAI,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAMhD,MAAM,CAAC,KAAK,UAAU,YAAY;AAC9B,4BAA4B;AAC5B,4BAA4B;AAC5B,YAA0B,EAC1B,kBAAqC,EACrC,oBAAoB,GAAG,KAAK,EAC5B,cAA8C,EAC9C,QAA2B,OAAO,CAAC,KAAK,EACxC,SAAiB;IAEjB,oFAAoF;IACpF,gDAAgD;IAChD,MAAM,GAAG,GAAG,SAAS,IAAI,OAAO,CAAA;IAEhC,gDAAgD;IAChD,+BAA+B;IAE/B,wFAAwF;IAExF,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,2CAA2C,CAAC,CAAA;QAChD,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;IAC5B,CAAC;IAED,IAAI,oBAAoB,EAAE,CAAC;QAEvB,qCAAqC;QAErC,kBAAkB,CAAC,KAAK,CAAC,CAAA;QAEzB,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAA;QAC1B,MAAM,cAAc,GAAG,GAAS,EAAE;YAC9B,+BAA+B;YAC/B,IAAI,KAAK,CAAC,KAAK,KAAK,MAAM;gBAAE,OAAM;YAClC,IAAI,CAAC;gBACD,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;YAC5B,CAAC;YAAC,MAAM,CAAC;gBACL,qEAAqE;YACzE,CAAC;QACL,CAAC,CAAA;QAED,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;QACtB,KAAK,CAAC,MAAM,EAAE,CAAA;QACd,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAA;QACnC,IAAI,KAAK,KAAK,OAAO,CAAC,KAAK;YAAE,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;QAEjE,KAAK,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,aAAqB,EAAE,GAAQ,EAAE,EAAE;YACrD,wCAAwC;YACxC,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,EAAE,CAAC;gBACxC,cAAc,EAAE,CAAA;gBAChB,4EAA4E;gBAC5E,0EAA0E;gBAC1E,sEAAsE;gBACtE,kEAAkE;gBAClE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC;oBAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;gBACxD,OAAM;YACV,CAAC;YAED,eAAe,CAAC,aAAa,EAAE,YAAY,EAAE,kBAAkB,CAAC,CAAA;QACpE,CAAC,CAAC,CAAA;IACN,CAAC;SAAM,CAAC;QACJ,wCAAwC;QAExC,MAAM,SAAS,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;QAE5C,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE;YACzB,kCAAkC;YAClC,eAAe,CAAC,KAAK,EAAE,YAAY,EAAE,kBAAkB,CAAC,CAAA;QAC5D,CAAC,CAAC,CAAA;IACN,CAAC;IAED,iDAAiD;IACjD,MAAM,cAAc,CAAA;IACpB,WAAW,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IAE7B,OAAM;AACV,CAAC","sourcesContent":["\nimport { createInterface, emitKeypressEvents, type Key } from 'node:readline'\nimport { showTtyHelp } from './showTtyHelp.js'\nimport { handleUserInput } from './handleUserInput.js'\nimport { ReRunManager } from './reRunManager.js'\nimport { RunTestsPromise } from './runTests.js'\nimport { out as mainOut } from '../../output.js'\nimport type { OutFn } from '../../types.js'\n\nexport type RerunTestsFactory = (testFiles: Set<string>) => () => RunTestsPromise\n\n\nexport async function listenToUser(\n //allTestFiles: Set<string>,\n //failingTests: Set<string>,\n rerunManager: ReRunManager,\n rerunTestsCallback: RerunTestsFactory,\n ttyActionsOnKeypress = false,\n initialTestRun: Promise<boolean | null> | null,\n input: NodeJS.ReadStream = process.stdin,\n customOut?: OutFn\n): Promise<void> {\n // an agent spawned session has no TTY, so these notices would otherwise be the only\n // lines in agent mode that are not agent events\n const out = customOut ?? mainOut\n\n //console.log('initia test run', initialTestRun)\n //console.log('listen to user')\n\n //setInterval(() => console.log('active runs: ', rerunManager.state.activeRuns), 10_000)\n\n if (!input.isTTY) {\n out('No TTY available, not receiving cli input')\n return Promise.resolve()\n }\n\n if (ttyActionsOnKeypress) {\n \n //console.log('ttyActionsOnKeypress')\n\n emitKeypressEvents(input)\n\n const wasRaw = input.isRaw\n const restoreRawMode = (): void => {\n //console.log('restoreRawMode')\n if (input.isRaw === wasRaw) return\n try {\n input.setRawMode(wasRaw)\n } catch {\n // The terminal stream may already be closed during process shutdown.\n }\n }\n\n input.setRawMode(true)\n input.resume()\n input.once('close', restoreRawMode)\n if (input === process.stdin) process.once('exit', restoreRawMode)\n\n input.on('keypress', (keypressInput: string, key: Key) => {\n //console.log('keypress', keypressInput)\n if (key.ctrl === true && key.name === 'c') {\n restoreRawMode()\n // process.kill(process.pid, 'SIGINT') terminates unconditionally on Windows\n // rather than raising the event, which skips the shutdown handlers and so\n // skips the user's teardown. Emitting reaches them on every platform.\n // Nothing listening means nobody will exit for us, so do it here.\n if (!process.emit('SIGINT', 'SIGINT')) process.exit(130)\n return\n }\n\n handleUserInput(keypressInput, rerunManager, rerunTestsCallback)\n })\n } else {\n //console.log('no ttyActionsOnKeypress')\n\n const userInput = createInterface({ input })\n\n userInput.on('line', input => {\n //console.log('line input', input)\n handleUserInput(input, rerunManager, rerunTestsCallback)\n })\n }\n\n //console.log('initialTestRun 2', initialTestRun)\n await initialTestRun\n showTtyHelp(input.isTTY, out)\n\n return\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import { ReRunManageState } from './makeWatchRunState.js';
2
2
  import type { RunTestsPromise } from './runTests.js';
3
+ import type { OutFn } from '../../types.js';
3
4
  export type RunType = 'auto' | 'all' | 'last' | 'failed';
4
5
  type RunReqest = {
5
6
  type: RunType;
@@ -13,6 +14,6 @@ export type ReRunManager = {
13
14
  queue: RunReqest[];
14
15
  };
15
16
  };
16
- export declare function makeReRunManager(currentRun: RunTestsPromise | null, state: ReRunManageState): ReRunManager;
17
+ export declare function makeReRunManager(currentRun: RunTestsPromise | null, state: ReRunManageState, customOut?: OutFn): ReRunManager;
17
18
  export {};
18
19
  //# sourceMappingURL=reRunManager.d.ts.map
@@ -1,7 +1,12 @@
1
1
  import { inspect } from 'util';
2
- import { debug, log, out } from '../../output.js';
2
+ import { debug, log, out as mainOut } from '../../output.js';
3
+ import { agentSetRunReason } from './agentReport.js';
3
4
  import chalk from '../../packages/chalk.js';
4
- export function makeReRunManager(currentRun, state) {
5
+ export function makeReRunManager(currentRun, state,
6
+ //callback: () => RunTestsPromise
7
+ customOut) {
8
+ // agent mode passes a sink - runTests reports the run instead
9
+ const out = customOut ?? mainOut;
5
10
  let queue = [];
6
11
  let waiting = false;
7
12
  const __test = {
@@ -22,6 +27,8 @@ export function makeReRunManager(currentRun, state) {
22
27
  debug('runReqest', runReqest);
23
28
  if (runReqest === undefined)
24
29
  return;
30
+ // tells the run about to start why it is running, for the agent `why=` field
31
+ agentSetRunReason(runReqest.type);
25
32
  switch (runReqest.type) {
26
33
  case 'all': {
27
34
  out(chalk.brightblue `re-running all tests...`);
@@ -1 +1 @@
1
- {"version":3,"file":"reRunManager.js","sourceRoot":"","sources":["../../../src/cli/lib/reRunManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAC9B,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAA;AAGjD,OAAO,KAAK,MAAM,yBAAyB,CAAA;AAsB3C,MAAM,UAAU,gBAAgB,CAC5B,UAAkC,EAClC,KAAuB;IAGvB,IAAI,KAAK,GAAgB,EAAE,CAAA;IAC3B,IAAI,OAAO,GAAG,KAAK,CAAA;IAEnB,MAAM,MAAM,GAAG;QACX,OAAO;QACP,KAAK;KACR,CAAA;IAED,KAAK,UAAU,YAAY;QAEvB,KAAK,CAAC,kBAAkB,CAAC,CAAA;QAEzB,IAAI,OAAO;YAAE,OAAM,CAAC,wDAAwD;QAC5E,MAAM,CAAC,OAAO,GAAG,OAAO,GAAG,IAAI,CAAA,CAAC,2BAA2B;QAC3D,MAAM,UAAU,CAAA,CAAC,uBAAuB;QACxC,MAAM,CAAC,OAAO,GAAG,OAAO,GAAG,KAAK,CAAA;QAEhC,KAAK,CAAC,eAAe,CAAC,CAAA;QAEtB,oCAAoC;QACpC,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;QAClC,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,EAAE,CAAA;QAC/B,KAAK,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;QAC7B,IAAI,SAAS,KAAK,SAAS;YAAE,OAAM;QAEnC,QAAQ,SAAS,CAAC,IAAI,EAAE,CAAC;YACrB,KAAK,KAAK,CAAC,CAAC,CAAC;gBACT,GAAG,CAAC,KAAK,CAAC,UAAU,CAAA,yBAAyB,CAAC,CAAA;gBAC9C,MAAK;YACT,CAAC;YACD,KAAK,MAAM,CAAC,CAAC,CAAC;gBACV,GAAG,CAAC,KAAK,CAAC,UAAU,CAAA,0BAA0B,CAAC,CAAA;gBAC/C,MAAK;YACT,CAAC;YACD,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACZ,GAAG,CAAC,KAAK,CAAC,UAAU,CAAA,4BAA4B,CAAC,CAAA;gBACjD,MAAK;YACT,CAAC;YACD,KAAK,MAAM,CAAC,CAAC,CAAC;gBACV,GAAG,CAAC,KAAK,CAAC,UAAU,CAAA,mCAAmC,CAAC,CAAA;gBACxD,MAAK;YACT,CAAC;YACD,OAAO,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAA;QACrD,CAAC;QAED,qBAAqB;QACrB,KAAK,CAAC,SAAS,EAAE,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAA;QAC/C,UAAU,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAA;QACjC,KAAK,CAAC,UAAU,GAAG,UAAU,CAAA;QAC7B,qDAAqD;QACrD,MAAM,UAAU,CAAA;QAChB,mDAAmD;QACnD,mDAAmD;QACnD,mCAAmC;QACnC,YAAY,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,gCAAgC,GAAG,EAAE,CAAC,CAAC,CAAA;IAC3E,CAAC;IAED,OAAO;QACH,KAAK;QACL,UAAU,CAAC,IAAa,EAAE,QAA+B;YAErD,mDAAmD;YACnD,wDAAwD;YAExD,sDAAsD;YACtD,kDAAkD;YAClD,sDAAsD;YACtD,YAAY;YAEZ,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;gBAClB,MAAM,CAAC,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAA;gBAC3D,KAAK,CAAC,IAAI,CAAC;oBACP,IAAI;oBACJ,QAAQ;oBACR,QAAQ;iBACX,CAAC,CAAA;YACN,CAAC;iBAAM,CAAC;gBACJ,MAAM,CAAC,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAA;gBAC3D,MAAM,CAAC,KAAK,GAAG,KAAK,GAAG,CAAC;wBACpB,IAAI;wBACJ,QAAQ;wBACR,QAAQ;qBACX,CAAC,CAAA;YACN,CAAC;YACD,KAAK,CAAC,gBAAgB,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;YACvC,uBAAuB;YACvB,OAAO,YAAY,EAAE,CAAA,CAAC,2DAA2D;QACrF,CAAC;QACD,MAAM;KACT,CAAA;AACL,CAAC","sourcesContent":["import { inspect } from 'util'\r\nimport { debug, log, out } from '../../output.js'\r\nimport { ReRunManageState } from './makeWatchRunState.js'\r\nimport type { RunTestsPromise } from './runTests.js'\r\nimport chalk from '../../packages/chalk.js'\r\n\r\nexport type RunType = 'auto' | 'all' | 'last' | 'failed'\r\n\r\ntype RunReqest = {\r\n type: RunType\r\n //tests: string[] | Set<string>\r\n callback: () => RunTestsPromise\r\n}\r\n\r\n//export type ReRunManager = ReturnType<typeof makeReRunManager>\r\n\r\nexport type ReRunManager = {\r\n state: ReRunManageState\r\n requestRun: (type: RunType, callback: () => RunTestsPromise) => void\r\n __test: {\r\n waiting: boolean\r\n queue: RunReqest[]\r\n }\r\n}\r\n\r\n\r\nexport function makeReRunManager(\r\n currentRun: RunTestsPromise | null,\r\n state: ReRunManageState,\r\n //callback: () => RunTestsPromise\r\n): ReRunManager {\r\n let queue: RunReqest[] = []\r\n let waiting = false\r\n\r\n const __test = {\r\n waiting,\r\n queue\r\n }\r\n\r\n async function processQueue() {\r\n \r\n debug('processing queue')\r\n\r\n if (waiting) return // do nothing if another processQueue is already waiting\r\n __test.waiting = waiting = true // mark that we are waiting\r\n await currentRun // wait for current run\r\n __test.waiting = waiting = false\r\n\r\n debug('done waitinng')\r\n\r\n // see if there is a request waiting\r\n debug('the queue', inspect(queue))\r\n const runReqest = queue.shift()\r\n debug('runReqest', runReqest)\r\n if (runReqest === undefined) return\r\n\r\n switch (runReqest.type) {\r\n case 'all': {\r\n out(chalk.brightblue`re-running all tests...`)\r\n break\r\n }\r\n case 'last': {\r\n out(chalk.brightblue`re-running last tests...`)\r\n break\r\n }\r\n case 'failed': {\r\n out(chalk.brightblue`re-running failed tests...`)\r\n break\r\n }\r\n case 'auto': {\r\n out(chalk.brightblue`running tests due to file changes`)\r\n break\r\n }\r\n default: throw new Error('Unrecognised run type')\r\n }\r\n\r\n // run it and save it\r\n debug('calling', runReqest.callback.toString())\r\n currentRun = runReqest.callback()\r\n state.currentRun = currentRun\r\n // wait for the run then trigger another processQueue\r\n await currentRun\r\n // if one has already been started by a run request\r\n // then this won't start a new one. This is used to\r\n // clear a queue if it has built it\r\n processQueue().catch(err => log(`processQueue threw an error: ${err}`))\r\n }\r\n\r\n return {\r\n state,\r\n requestRun(type: RunType, callback: () => RunTestsPromise) {\r\n\r\n // if it's type auto, we only want to keep one, but\r\n // we want it to include all relevant tests when it runs\r\n\r\n // if it's a human triggered type, we'll replace other\r\n // human requests, but leave the auto, so the user\r\n // can see update to changed code that would be hidden\r\n // otherwise\r\n \r\n if (type === 'auto') {\r\n __test.queue = queue = queue.filter(x => x.type !== 'auto')\r\n queue.push({\r\n type,\r\n //tests,\r\n callback\r\n })\r\n } else {\r\n __test.queue = queue = queue.filter(x => x.type === 'auto')\r\n __test.queue = queue = [{\r\n type,\r\n //tests,\r\n callback\r\n }]\r\n }\r\n debug('added to queue', inspect(queue))\r\n // see if we can run it\r\n return processQueue() //.catch(err => log(`processQueue threw an error: ${err}`))\r\n },\r\n __test\r\n }\r\n}\r\n\r\n\r\n"]}
1
+ {"version":3,"file":"reRunManager.js","sourceRoot":"","sources":["../../../src/cli/lib/reRunManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { inspect } from 'util'\nimport { debug, log, out as mainOut } from '../../output.js'\nimport { ReRunManageState } from './makeWatchRunState.js'\nimport type { RunTestsPromise } from './runTests.js'\nimport type { OutFn } from '../../types.js'\nimport { agentSetRunReason } from './agentReport.js'\nimport chalk from '../../packages/chalk.js'\n\nexport type RunType = 'auto' | 'all' | 'last' | 'failed'\n\ntype RunReqest = {\n type: RunType\n //tests: string[] | Set<string>\n callback: () => RunTestsPromise\n}\n\n//export type ReRunManager = ReturnType<typeof makeReRunManager>\n\nexport type ReRunManager = {\n state: ReRunManageState\n requestRun: (type: RunType, callback: () => RunTestsPromise) => void\n __test: {\n waiting: boolean\n queue: RunReqest[]\n }\n}\n\n\nexport function makeReRunManager(\n currentRun: RunTestsPromise | null,\n state: ReRunManageState,\n //callback: () => RunTestsPromise\n customOut?: OutFn\n): ReRunManager {\n // agent mode passes a sink - runTests reports the run instead\n const out = customOut ?? mainOut\n let queue: RunReqest[] = []\n let waiting = false\n\n const __test = {\n waiting,\n queue\n }\n\n async function processQueue() {\n \n debug('processing queue')\n\n if (waiting) return // do nothing if another processQueue is already waiting\n __test.waiting = waiting = true // mark that we are waiting\n await currentRun // wait for current run\n __test.waiting = waiting = false\n\n debug('done waitinng')\n\n // see if there is a request waiting\n debug('the queue', inspect(queue))\n const runReqest = queue.shift()\n debug('runReqest', runReqest)\n if (runReqest === undefined) return\n\n // tells the run about to start why it is running, for the agent `why=` field\n agentSetRunReason(runReqest.type)\n\n switch (runReqest.type) {\n case 'all': {\n out(chalk.brightblue`re-running all tests...`)\n break\n }\n case 'last': {\n out(chalk.brightblue`re-running last tests...`)\n break\n }\n case 'failed': {\n out(chalk.brightblue`re-running failed tests...`)\n break\n }\n case 'auto': {\n out(chalk.brightblue`running tests due to file changes`)\n break\n }\n default: throw new Error('Unrecognised run type')\n }\n\n // run it and save it\n debug('calling', runReqest.callback.toString())\n currentRun = runReqest.callback()\n state.currentRun = currentRun\n // wait for the run then trigger another processQueue\n await currentRun\n // if one has already been started by a run request\n // then this won't start a new one. This is used to\n // clear a queue if it has built it\n processQueue().catch(err => log(`processQueue threw an error: ${err}`))\n }\n\n return {\n state,\n requestRun(type: RunType, callback: () => RunTestsPromise) {\n\n // if it's type auto, we only want to keep one, but\n // we want it to include all relevant tests when it runs\n\n // if it's a human triggered type, we'll replace other\n // human requests, but leave the auto, so the user\n // can see update to changed code that would be hidden\n // otherwise\n \n if (type === 'auto') {\n __test.queue = queue = queue.filter(x => x.type !== 'auto')\n queue.push({\n type,\n //tests,\n callback\n })\n } else {\n __test.queue = queue = queue.filter(x => x.type === 'auto')\n __test.queue = queue = [{\n type,\n //tests,\n callback\n }]\n }\n debug('added to queue', inspect(queue))\n // see if we can run it\n return processQueue() //.catch(err => log(`processQueue threw an error: ${err}`))\n },\n __test\n }\n}\n\n\n"]}
@@ -9,14 +9,29 @@ import { loadTestFile } from './loadTestFile.js';
9
9
  import { runTest } from './runTest.js';
10
10
  import { showTestLoadingError } from './showTestLoadingError.js';
11
11
  import { showTestResult } from './showTestResult.js';
12
+ import { failureLines } from './failureLines.js';
13
+ import { failureEntries } from './failureEntries.js';
14
+ import { agentDone, agentFailure, agentRunStart } from './agentReport.js';
15
+ import { statusCodes, writeStatusFile } from './statusFile.js';
12
16
  import { makeRunManagerState } from './makeWatchRunState.js';
13
17
  const { timeProfileAsync } = createTimeProfiler(showTimeProfiling);
18
+ // the summary lines, minus the colouring, for the status file
19
+ function joinPlain(...parts) {
20
+ return parts.filter(part => part !== '').join(' ');
21
+ }
22
+ function plural(count, noun, verb) {
23
+ if (count < 1)
24
+ return '';
25
+ return `${count} ${noun}${count === 1 ? '' : 's'} ${verb}`;
26
+ }
14
27
  export async function runTests(config, testFiles, reRunManager, refresh = 'refresh', customOut, filters = {}) {
15
28
  if (reRunManager !== undefined) {
16
29
  reRunManager.state.lastTestFiles = new Set(testFiles);
17
30
  reRunManager.state.activeRuns++; // whatever, obsolete. Can use it to check on things
18
31
  }
19
32
  const state = reRunManager?.state || makeRunManagerState();
33
+ const runStartTime = new Date().getTime();
34
+ const agentRun = agentRunStart(config, testFiles.size);
20
35
  //console.log('new runTests:', watchRunState?.activeRuns)
21
36
  //console.log(inspect(testFiles))
22
37
  try {
@@ -99,6 +114,9 @@ export async function runTests(config, testFiles, reRunManager, refresh = 'refre
99
114
  && failedToLoadCount === 0
100
115
  && describesThrownCount === 0) {
101
116
  out(chalk.orange('No tests matched the describe/test filters.'));
117
+ const durationMs = new Date().getTime() - runStartTime;
118
+ writeStatusFile(config, statusCodes.couldNotRun, 'no tests matched the describe/test filters', [], durationMs);
119
+ agentDone(config, agentRun, statusCodes.couldNotRun, 'no tests matched the describe/test filters', testsResultsSummary, durationMs, state.failedTestFiles.size);
102
120
  return null;
103
121
  }
104
122
  out('\n');
@@ -121,17 +139,19 @@ export async function runTests(config, testFiles, reRunManager, refresh = 'refre
121
139
  }
122
140
  // number of items successful
123
141
  const describesText = `Items: ${testsResultsSummary.describesPasses}/${testsResultsSummary.describesTotal}`;
124
- const invalidDescribesText = (testsResultsSummary.describesInvalid >= 1)
142
+ const invalidDescribesPlain = (testsResultsSummary.describesInvalid >= 1)
125
143
  ? (testsResultsSummary.describesInvalid === 1)
126
- ? chalk.grey('(+1 describe without tests)')
127
- : chalk.grey(`(+${testsResultsSummary.describesInvalid} describes without tests)`)
144
+ ? '(+1 describe without tests)'
145
+ : `(+${testsResultsSummary.describesInvalid} describes without tests)`
128
146
  : '';
129
- const describesThrownText = (describesThrownCount >= 1)
147
+ const describesThrownPlain = (describesThrownCount >= 1)
130
148
  ? (describesThrownCount === 1)
131
- ? chalk.mediumred('(1 describe errored)')
132
- : chalk.mediumred(`(${describesThrownCount} describes errored)`)
149
+ ? '(1 describe errored)'
150
+ : `(${describesThrownCount} describes errored)`
133
151
  : '';
134
- const describesDetailsText = [invalidDescribesText, describesThrownText]
152
+ const describesDetailsText = [
153
+ chalk.grey(invalidDescribesPlain), chalk.mediumred(describesThrownPlain)
154
+ ]
135
155
  .filter(text => text !== '')
136
156
  .join(' ');
137
157
  const describesDetailsSuffix = describesDetailsText === '' ? '' : ` ${describesDetailsText}`;
@@ -143,17 +163,19 @@ export async function runTests(config, testFiles, reRunManager, refresh = 'refre
143
163
  }
144
164
  // number of test files successful
145
165
  const testFilesText = `Test Files: ${testsResultsSummary.passes}/${testsResultsSummary.total}`;
146
- const invalidTestFilesText = (testsResultsSummary.invalid >= 1)
166
+ const invalidTestFilesPlain = (testsResultsSummary.invalid >= 1)
147
167
  ? (testsResultsSummary.invalid === 1)
148
- ? chalk.grey('(+1 file without tests)')
149
- : chalk.grey(`(+${testsResultsSummary.invalid} files without tests)`)
168
+ ? '(+1 file without tests)'
169
+ : `(+${testsResultsSummary.invalid} files without tests)`
150
170
  : '';
151
- const failedToLoadText = (failedToLoadCount >= 1)
171
+ const failedToLoadPlain = (failedToLoadCount >= 1)
152
172
  ? (failedToLoadCount === 1)
153
- ? chalk.mediumred('(1 file failed to load, or errored)')
154
- : chalk.mediumred(`(${failedToLoadCount} files failed to load, or errored)`)
173
+ ? '(1 file failed to load, or errored)'
174
+ : `(${failedToLoadCount} files failed to load, or errored)`
155
175
  : '';
156
- const testFilesDetailsText = [invalidTestFilesText, failedToLoadText]
176
+ const testFilesDetailsText = [
177
+ chalk.grey(invalidTestFilesPlain), chalk.mediumred(failedToLoadPlain)
178
+ ]
157
179
  .filter(text => text !== '')
158
180
  .join(' ');
159
181
  const testFilesDetailsSuffix = testFilesDetailsText === '' ? '' : ` ${testFilesDetailsText}`;
@@ -163,6 +185,35 @@ export async function runTests(config, testFiles, reRunManager, refresh = 'refre
163
185
  else {
164
186
  out(chalk.mediumred(`${testFilesText}`) + testFilesDetailsSuffix);
165
187
  }
188
+ const summaryLines = [
189
+ testsText,
190
+ joinPlain(describesText, invalidDescribesPlain, describesThrownPlain),
191
+ joinPlain(testFilesText, invalidTestFilesPlain, failedToLoadPlain)
192
+ ];
193
+ const durationMs = new Date().getTime() - runStartTime;
194
+ if (allPassed) {
195
+ writeStatusFile(config, statusCodes.passed, 'all tests passed', summaryLines, durationMs);
196
+ agentDone(config, agentRun, statusCodes.passed, 'all tests passed', testsResultsSummary, durationMs, state.failedTestFiles.size);
197
+ }
198
+ else {
199
+ const abortedFiles = Object.keys(erroringTests);
200
+ // a file that would not load, or a describe that threw, means the run died
201
+ // partway - a different problem from tests that ran and failed
202
+ const aborted = abortedFiles.length > 0 || describesThrownCount > 0;
203
+ const failedTestsCount = testsResultsSummary.itsTotal - testsResultsSummary.itsPasses;
204
+ const description = [
205
+ plural(abortedFiles.length, 'test file', 'failed to load or errored'),
206
+ plural(describesThrownCount, 'describe', 'errored'),
207
+ plural(failedTestsCount, 'test', 'failed')
208
+ ].filter(part => part !== '').join(', ') || 'test run failed';
209
+ const code = (aborted) ? statusCodes.aborted : statusCodes.failed;
210
+ const failures = failureEntries(Object.values(runTestResults), erroringTests);
211
+ writeStatusFile(config, code, description, [...summaryLines, ...failureLines(Object.values(runTestResults), erroringTests)], durationMs);
212
+ // failures first, so the done line is a complete end of run marker
213
+ for (const failure of failures)
214
+ agentFailure(config, agentRun, failure);
215
+ agentDone(config, agentRun, code, description, testsResultsSummary, durationMs, state.failedTestFiles.size);
216
+ }
166
217
  // full success?
167
218
  // true/false gets returned to the caller of runTests()
168
219
  return allPassed;
@@ -1 +1 @@
1
- {"version":3,"file":"runTests.js","sourceRoot":"","sources":["../../../src/cli/lib/runTests.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 { out as mainOut } from '../../output.js'\nimport figures from '../../packages/figures.js'\nimport { count } from 'sxy-lib/objects.js'\nimport { remove as arrayRemove } from 'sxy-lib/arrays.js'\nimport { allObj as promiseAllObj } from 'sxy-lib/promises.js'\n\nimport { loadTestFile } from './loadTestFile.js'\nimport { runTest } from './runTest.js'\nimport { showTestLoadingError } from './showTestLoadingError.js'\nimport { showTestResult } from './showTestResult.js'\n\nimport type {\n FinalConfig, OutFn, TestExecutionFilters, TestFile, TestResult, TestsResultsSummary\n} from '../../types.js'\nimport { makeRunManagerState, ReRunManageState } from './makeWatchRunState.js'\nimport { ReRunManager } from './reRunManager.js'\n\nconst { timeProfileAsync } = createTimeProfiler(showTimeProfiling)\n\nexport type RunTestsPromise = Promise<boolean | null>\n\nexport async function runTests(\n config: FinalConfig,\n testFiles: Set<string>,\n reRunManager: ReRunManager | undefined,\n refresh: 'refresh' | 'cached' = 'refresh',\n customOut?: OutFn,\n filters: TestExecutionFilters = {}\n): RunTestsPromise {\n if (reRunManager !== undefined) {\n reRunManager.state.lastTestFiles = new Set(testFiles)\n reRunManager.state.activeRuns++ // whatever, obsolete. Can use it to check on things\n }\n\n const state = reRunManager?.state || makeRunManagerState()\n //console.log('new runTests:', watchRunState?.activeRuns)\n //console.log(inspect(testFiles))\n\n try {\n const testRunPromises: Record<string, Promise<TestResult>> = {}\n const erroringTests: Record<string, TestFile> = {}\n const testRunOutPromises: Record<string, Promise<void>> = {}\n\n await timeProfileAsync('run tests', async () => {\n if (Array.isArray(testFiles) ? testFiles.length > 0 : testFiles.size > 0) {\n for (const testFile of testFiles) {\n //console.log('testFiles', testFiles)\n //console.log('testFile', testFile)\n const test = await loadTestFile(config, testFile, refresh)\n\n if (test.error !== undefined && test.error !== false) {\n erroringTests[testFile] = test\n state.failedTestFiles.add(testFile)\n showTestLoadingError(config, test, customOut)\n } else {\n const testRunPromise = runTest(config, test, filters)\n testRunPromises[testFile] = testRunPromise\n\n testRunOutPromises[testFile] = testRunPromise.then(async testResult => {\n if (testResult.success === true || testResult.success === null) {\n state.failedTestFiles.delete(testResult.file)\n } else {\n state.failedTestFiles.add(testFile)\n }\n const executionFilterActive = filters.describe !== undefined || filters.it !== undefined\n if (!executionFilterActive || testResult.describeResultsSummary.itsTotal > 0) {\n await showTestResult(config, testResult, customOut)\n }\n })\n\n // wait for the test to complete before proceeding if we are in 'sequential' mode\n if (config.execution.files === 'sequential') await testRunOutPromises[testFile]\n }\n }\n }\n })\n\n let runTestResults: Record<string, TestResult> = {}\n\n await timeProfileAsync('wait for tests to finish', async () => {\n runTestResults = await promiseAllObj(testRunPromises)\n\n // wait for the output to complete\n await promiseAllObj(testRunOutPromises)\n })\n\n return await timeProfileAsync('show initial test run results', () => {\n \n const out = customOut ?? mainOut\n\n const testsResultsSummary: TestsResultsSummary = {\n total: 0,\n passes: 0,\n invalid: 0,\n describesTotal: 0,\n describesPasses: 0,\n describesInvalid: 0,\n itsTotal: 0,\n itsPasses: 0\n // itsInvalid: 0 // we don't check whether tests run any asserts (we don't control the assertion lib)\n }\n let describesThrownCount = 0\n\n for (const testFile in runTestResults) {\n const runTestResult = runTestResults[testFile]\n if (!runTestResult) continue\n\n testsResultsSummary.total += +(runTestResult.success !== null)\n testsResultsSummary.passes += +(runTestResult.success ?? false)\n testsResultsSummary.invalid += +(runTestResult.success === null)\n testsResultsSummary.describesTotal += runTestResult.describeResultsSummary.total\n testsResultsSummary.describesPasses += runTestResult.describeResultsSummary.passes\n testsResultsSummary.describesInvalid += runTestResult.describeResultsSummary.invalid\n testsResultsSummary.itsTotal += runTestResult.describeResultsSummary.itsTotal\n testsResultsSummary.itsPasses += runTestResult.describeResultsSummary.itsPasses\n describesThrownCount += runTestResult.describeResults\n .filter(describeResult => describeResult.error !== undefined)\n .length\n }\n\n const failedToLoadCount = count(erroringTests)\n testsResultsSummary.total += failedToLoadCount\n\n if (\n (filters.describe !== undefined || filters.it !== undefined)\n && testsResultsSummary.itsTotal === 0\n && failedToLoadCount === 0\n && describesThrownCount === 0\n ) {\n out(chalk.orange('No tests matched the describe/test filters.'))\n return null\n }\n\n out('\\n')\n\n const allPassed = (\n testsResultsSummary.passes === testsResultsSummary.total\n && testsResultsSummary.describesPasses === testsResultsSummary.describesTotal\n && testsResultsSummary.itsPasses === testsResultsSummary.itsTotal\n )\n\n if (allPassed) {\n out(chalk.mediumgreen(`${figures.tick}`))\n } else {\n out(chalk.mediumred(`${figures.cross}`))\n }\n\n // number of tests successful\n const testsText = `Tests: ${testsResultsSummary.itsPasses}/${testsResultsSummary.itsTotal}`\n if (testsResultsSummary.itsPasses === testsResultsSummary.itsTotal) {\n out(chalk.mediumgreen(`${testsText}`))\n } else {\n out(chalk.mediumred(`${testsText}`))\n }\n\n // number of items successful\n const describesText = `Items: ${testsResultsSummary.describesPasses}/${testsResultsSummary.describesTotal}`\n const invalidDescribesText = (testsResultsSummary.describesInvalid >= 1)\n ? (testsResultsSummary.describesInvalid === 1)\n ? chalk.grey('(+1 describe without tests)')\n : chalk.grey(`(+${testsResultsSummary.describesInvalid} describes without tests)`)\n : ''\n const describesThrownText = (describesThrownCount >= 1)\n ? (describesThrownCount === 1)\n ? chalk.mediumred('(1 describe errored)')\n : chalk.mediumred(`(${describesThrownCount} describes errored)`)\n : ''\n const describesDetailsText = [invalidDescribesText, describesThrownText]\n .filter(text => text !== '')\n .join(' ')\n const describesDetailsSuffix = describesDetailsText === '' ? '' : ` ${describesDetailsText}`\n if (testsResultsSummary.describesPasses === testsResultsSummary.describesTotal) {\n out(chalk.mediumgreen(`${describesText}`) + describesDetailsSuffix)\n } else {\n out(chalk.mediumred(`${describesText}`) + describesDetailsSuffix)\n }\n\n // number of test files successful\n const testFilesText = `Test Files: ${testsResultsSummary.passes}/${testsResultsSummary.total}`\n const invalidTestFilesText = (testsResultsSummary.invalid >= 1)\n ? (testsResultsSummary.invalid === 1)\n ? chalk.grey('(+1 file without tests)')\n : chalk.grey(`(+${testsResultsSummary.invalid} files without tests)`)\n : ''\n const failedToLoadText = (failedToLoadCount >= 1)\n ? (failedToLoadCount === 1)\n ? chalk.mediumred('(1 file failed to load, or errored)')\n : chalk.mediumred(`(${failedToLoadCount} files failed to load, or errored)`)\n : ''\n const testFilesDetailsText = [invalidTestFilesText, failedToLoadText]\n .filter(text => text !== '')\n .join(' ')\n const testFilesDetailsSuffix = testFilesDetailsText === '' ? '' : ` ${testFilesDetailsText}`\n if (testsResultsSummary.passes === testsResultsSummary.total) {\n out(chalk.mediumgreen(`${testFilesText}`) + testFilesDetailsSuffix)\n } else {\n out(chalk.mediumred(`${testFilesText}`) + testFilesDetailsSuffix)\n }\n\n // full success?\n // true/false gets returned to the caller of runTests()\n return allPassed\n })\n } finally {\n if (reRunManager !== undefined) reRunManager.state.activeRuns--\n }\n}\n\n"]}
1
+ {"version":3,"file":"runTests.js","sourceRoot":"","sources":["../../../src/cli/lib/runTests.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 { out as mainOut } from '../../output.js'\nimport figures from '../../packages/figures.js'\nimport { count } from 'sxy-lib/objects.js'\nimport { remove as arrayRemove } from 'sxy-lib/arrays.js'\nimport { allObj as promiseAllObj } from 'sxy-lib/promises.js'\n\nimport { loadTestFile } from './loadTestFile.js'\nimport { runTest } from './runTest.js'\nimport { showTestLoadingError } from './showTestLoadingError.js'\nimport { showTestResult } from './showTestResult.js'\nimport { failureLines } from './failureLines.js'\nimport { failureEntries } from './failureEntries.js'\nimport { agentDone, agentFailure, agentRunStart } from './agentReport.js'\nimport { statusCodes, writeStatusFile } from './statusFile.js'\n\nimport type {\n FinalConfig, OutFn, TestExecutionFilters, TestFile, TestResult, TestsResultsSummary\n} from '../../types.js'\nimport { makeRunManagerState, ReRunManageState } from './makeWatchRunState.js'\nimport { ReRunManager } from './reRunManager.js'\n\nconst { timeProfileAsync } = createTimeProfiler(showTimeProfiling)\n\nexport type RunTestsPromise = Promise<boolean | null>\n\n// the summary lines, minus the colouring, for the status file\nfunction joinPlain(...parts: string[]): string {\n return parts.filter(part => part !== '').join(' ')\n}\n\nfunction plural(count: number, noun: string, verb: string): string {\n if (count < 1) return ''\n return `${count} ${noun}${count === 1 ? '' : 's'} ${verb}`\n}\n\n\nexport async function runTests(\n config: FinalConfig,\n testFiles: Set<string>,\n reRunManager: ReRunManager | undefined,\n refresh: 'refresh' | 'cached' = 'refresh',\n customOut?: OutFn,\n filters: TestExecutionFilters = {}\n): RunTestsPromise {\n if (reRunManager !== undefined) {\n reRunManager.state.lastTestFiles = new Set(testFiles)\n reRunManager.state.activeRuns++ // whatever, obsolete. Can use it to check on things\n }\n\n const state = reRunManager?.state || makeRunManagerState()\n const runStartTime = new Date().getTime()\n const agentRun = agentRunStart(config, testFiles.size)\n //console.log('new runTests:', watchRunState?.activeRuns)\n //console.log(inspect(testFiles))\n\n try {\n const testRunPromises: Record<string, Promise<TestResult>> = {}\n const erroringTests: Record<string, TestFile> = {}\n const testRunOutPromises: Record<string, Promise<void>> = {}\n\n await timeProfileAsync('run tests', async () => {\n if (Array.isArray(testFiles) ? testFiles.length > 0 : testFiles.size > 0) {\n for (const testFile of testFiles) {\n //console.log('testFiles', testFiles)\n //console.log('testFile', testFile)\n const test = await loadTestFile(config, testFile, refresh)\n\n if (test.error !== undefined && test.error !== false) {\n erroringTests[testFile] = test\n state.failedTestFiles.add(testFile)\n showTestLoadingError(config, test, customOut)\n } else {\n const testRunPromise = runTest(config, test, filters)\n testRunPromises[testFile] = testRunPromise\n\n testRunOutPromises[testFile] = testRunPromise.then(async testResult => {\n if (testResult.success === true || testResult.success === null) {\n state.failedTestFiles.delete(testResult.file)\n } else {\n state.failedTestFiles.add(testFile)\n }\n const executionFilterActive = filters.describe !== undefined || filters.it !== undefined\n if (!executionFilterActive || testResult.describeResultsSummary.itsTotal > 0) {\n await showTestResult(config, testResult, customOut)\n }\n })\n\n // wait for the test to complete before proceeding if we are in 'sequential' mode\n if (config.execution.files === 'sequential') await testRunOutPromises[testFile]\n }\n }\n }\n })\n\n let runTestResults: Record<string, TestResult> = {}\n\n await timeProfileAsync('wait for tests to finish', async () => {\n runTestResults = await promiseAllObj(testRunPromises)\n\n // wait for the output to complete\n await promiseAllObj(testRunOutPromises)\n })\n\n return await timeProfileAsync('show initial test run results', () => {\n \n const out = customOut ?? mainOut\n\n const testsResultsSummary: TestsResultsSummary = {\n total: 0,\n passes: 0,\n invalid: 0,\n describesTotal: 0,\n describesPasses: 0,\n describesInvalid: 0,\n itsTotal: 0,\n itsPasses: 0\n // itsInvalid: 0 // we don't check whether tests run any asserts (we don't control the assertion lib)\n }\n let describesThrownCount = 0\n\n for (const testFile in runTestResults) {\n const runTestResult = runTestResults[testFile]\n if (!runTestResult) continue\n\n testsResultsSummary.total += +(runTestResult.success !== null)\n testsResultsSummary.passes += +(runTestResult.success ?? false)\n testsResultsSummary.invalid += +(runTestResult.success === null)\n testsResultsSummary.describesTotal += runTestResult.describeResultsSummary.total\n testsResultsSummary.describesPasses += runTestResult.describeResultsSummary.passes\n testsResultsSummary.describesInvalid += runTestResult.describeResultsSummary.invalid\n testsResultsSummary.itsTotal += runTestResult.describeResultsSummary.itsTotal\n testsResultsSummary.itsPasses += runTestResult.describeResultsSummary.itsPasses\n describesThrownCount += runTestResult.describeResults\n .filter(describeResult => describeResult.error !== undefined)\n .length\n }\n\n const failedToLoadCount = count(erroringTests)\n testsResultsSummary.total += failedToLoadCount\n\n if (\n (filters.describe !== undefined || filters.it !== undefined)\n && testsResultsSummary.itsTotal === 0\n && failedToLoadCount === 0\n && describesThrownCount === 0\n ) {\n out(chalk.orange('No tests matched the describe/test filters.'))\n const durationMs = new Date().getTime() - runStartTime\n writeStatusFile(\n config,\n statusCodes.couldNotRun,\n 'no tests matched the describe/test filters',\n [],\n durationMs\n )\n agentDone(\n config, agentRun, statusCodes.couldNotRun,\n 'no tests matched the describe/test filters', testsResultsSummary, durationMs,\n state.failedTestFiles.size\n )\n return null\n }\n\n out('\\n')\n\n const allPassed = (\n testsResultsSummary.passes === testsResultsSummary.total\n && testsResultsSummary.describesPasses === testsResultsSummary.describesTotal\n && testsResultsSummary.itsPasses === testsResultsSummary.itsTotal\n )\n\n if (allPassed) {\n out(chalk.mediumgreen(`${figures.tick}`))\n } else {\n out(chalk.mediumred(`${figures.cross}`))\n }\n\n // number of tests successful\n const testsText = `Tests: ${testsResultsSummary.itsPasses}/${testsResultsSummary.itsTotal}`\n if (testsResultsSummary.itsPasses === testsResultsSummary.itsTotal) {\n out(chalk.mediumgreen(`${testsText}`))\n } else {\n out(chalk.mediumred(`${testsText}`))\n }\n\n // number of items successful\n const describesText = `Items: ${testsResultsSummary.describesPasses}/${testsResultsSummary.describesTotal}`\n const invalidDescribesPlain = (testsResultsSummary.describesInvalid >= 1)\n ? (testsResultsSummary.describesInvalid === 1)\n ? '(+1 describe without tests)'\n : `(+${testsResultsSummary.describesInvalid} describes without tests)`\n : ''\n const describesThrownPlain = (describesThrownCount >= 1)\n ? (describesThrownCount === 1)\n ? '(1 describe errored)'\n : `(${describesThrownCount} describes errored)`\n : ''\n const describesDetailsText = [\n chalk.grey(invalidDescribesPlain), chalk.mediumred(describesThrownPlain)\n ]\n .filter(text => text !== '')\n .join(' ')\n const describesDetailsSuffix = describesDetailsText === '' ? '' : ` ${describesDetailsText}`\n if (testsResultsSummary.describesPasses === testsResultsSummary.describesTotal) {\n out(chalk.mediumgreen(`${describesText}`) + describesDetailsSuffix)\n } else {\n out(chalk.mediumred(`${describesText}`) + describesDetailsSuffix)\n }\n\n // number of test files successful\n const testFilesText = `Test Files: ${testsResultsSummary.passes}/${testsResultsSummary.total}`\n const invalidTestFilesPlain = (testsResultsSummary.invalid >= 1)\n ? (testsResultsSummary.invalid === 1)\n ? '(+1 file without tests)'\n : `(+${testsResultsSummary.invalid} files without tests)`\n : ''\n const failedToLoadPlain = (failedToLoadCount >= 1)\n ? (failedToLoadCount === 1)\n ? '(1 file failed to load, or errored)'\n : `(${failedToLoadCount} files failed to load, or errored)`\n : ''\n const testFilesDetailsText = [\n chalk.grey(invalidTestFilesPlain), chalk.mediumred(failedToLoadPlain)\n ]\n .filter(text => text !== '')\n .join(' ')\n const testFilesDetailsSuffix = testFilesDetailsText === '' ? '' : ` ${testFilesDetailsText}`\n if (testsResultsSummary.passes === testsResultsSummary.total) {\n out(chalk.mediumgreen(`${testFilesText}`) + testFilesDetailsSuffix)\n } else {\n out(chalk.mediumred(`${testFilesText}`) + testFilesDetailsSuffix)\n }\n\n const summaryLines = [\n testsText,\n joinPlain(describesText, invalidDescribesPlain, describesThrownPlain),\n joinPlain(testFilesText, invalidTestFilesPlain, failedToLoadPlain)\n ]\n\n const durationMs = new Date().getTime() - runStartTime\n\n if (allPassed) {\n writeStatusFile(\n config, statusCodes.passed, 'all tests passed', summaryLines, durationMs\n )\n agentDone(\n config, agentRun, statusCodes.passed, 'all tests passed',\n testsResultsSummary, durationMs, state.failedTestFiles.size\n )\n } else {\n const abortedFiles = Object.keys(erroringTests)\n\n // a file that would not load, or a describe that threw, means the run died\n // partway - a different problem from tests that ran and failed\n const aborted = abortedFiles.length > 0 || describesThrownCount > 0\n const failedTestsCount = testsResultsSummary.itsTotal - testsResultsSummary.itsPasses\n\n const description = [\n plural(abortedFiles.length, 'test file', 'failed to load or errored'),\n plural(describesThrownCount, 'describe', 'errored'),\n plural(failedTestsCount, 'test', 'failed')\n ].filter(part => part !== '').join(', ') || 'test run failed'\n\n const code = (aborted) ? statusCodes.aborted : statusCodes.failed\n const failures = failureEntries(Object.values(runTestResults), erroringTests)\n\n writeStatusFile(\n config,\n code,\n description,\n [...summaryLines, ...failureLines(Object.values(runTestResults), erroringTests)],\n durationMs\n )\n\n // failures first, so the done line is a complete end of run marker\n for (const failure of failures) agentFailure(config, agentRun, failure)\n agentDone(\n config, agentRun, code, description, testsResultsSummary, durationMs,\n state.failedTestFiles.size\n )\n }\n\n // full success?\n // true/false gets returned to the caller of runTests()\n return allPassed\n })\n } finally {\n if (reRunManager !== undefined) reRunManager.state.activeRuns--\n }\n}\n\n"]}
@@ -0,0 +1,12 @@
1
+ import type { FinalConfig } from '../../types.js';
2
+ export declare const statusCodes: {
3
+ readonly notRunYet: -1;
4
+ readonly passed: 0;
5
+ readonly failed: 1;
6
+ readonly aborted: 2;
7
+ readonly couldNotRun: 3;
8
+ };
9
+ export type StatusCode = typeof statusCodes[keyof typeof statusCodes];
10
+ export declare function resetStatusFile(config: FinalConfig): void;
11
+ export declare function writeStatusFile(config: FinalConfig, code: StatusCode, description: string, details?: string[], durationMs?: number): void;
12
+ //# sourceMappingURL=statusFile.d.ts.map
@@ -0,0 +1,60 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import chalk from '../../packages/chalk.js';
4
+ import { packageName } from '../../config.js';
5
+ import { log } from '../../output.js';
6
+ // The status file holds the result of the latest run: `<code> - <description>` on the first
7
+ // line, then any detail. Watch mode resets it to -1 on startup so a stale result is never
8
+ // mistaken for the current one.
9
+ export const statusCodes = {
10
+ notRunYet: -1, // watch mode has started, but no run has finished
11
+ passed: 0,
12
+ failed: 1, // tests ran and failed
13
+ aborted: 2, // the run died partway - a test file failed to load, or a describe threw
14
+ couldNotRun: 3 // nothing ran at all - no test files, or no match for the filters
15
+ };
16
+ export function resetStatusFile(config) {
17
+ writeStatusFile(config, statusCodes.notRunYet, 'no run has finished yet');
18
+ }
19
+ export function writeStatusFile(config, code, description, details = [], durationMs) {
20
+ write(config, [
21
+ `${code} - ${description}`,
22
+ localTime(new Date()),
23
+ ...details,
24
+ ...(durationMs === undefined) ? [] : [`${durationMs.toLocaleString()}ms`]
25
+ ].join('\n') + '\n');
26
+ }
27
+ // local time, so the file reads the way the terminal beside it does, with the offset so a
28
+ // reader elsewhere can still place it
29
+ function localTime(date) {
30
+ const pad = (value) => String(value).padStart(2, '0');
31
+ // getTimezoneOffset() counts minutes behind UTC, so the sign is the other way round
32
+ const offsetMinutes = -date.getTimezoneOffset();
33
+ const offset = `${(offsetMinutes < 0) ? '-' : '+'}`
34
+ + `${pad(Math.floor(Math.abs(offsetMinutes) / 60))}:${pad(Math.abs(offsetMinutes) % 60)}`;
35
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`
36
+ + ` ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
37
+ + ` ${offset}`;
38
+ }
39
+ function write(config, contents) {
40
+ const statusFile = config.watch.statusFile;
41
+ if (typeof statusFile !== 'string' || statusFile === '')
42
+ return;
43
+ const location = path.resolve(process.cwd(), statusFile);
44
+ // written via a temp file and renamed, so a poller never reads a half written status
45
+ const tempLocation = `${location}.${process.pid}.tmp`;
46
+ try {
47
+ fs.mkdirSync(path.dirname(location), { recursive: true });
48
+ fs.writeFileSync(tempLocation, contents);
49
+ fs.renameSync(tempLocation, location);
50
+ }
51
+ catch (error) {
52
+ // never let the status file take the run down with it
53
+ log(chalk.mediumred(`[${packageName}] Could not write status file ${location}: ${String(error)}`));
54
+ try {
55
+ fs.rmSync(tempLocation, { force: true });
56
+ }
57
+ catch { /* nothing more to do */ }
58
+ }
59
+ }
60
+ //# sourceMappingURL=statusFile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"statusFile.js","sourceRoot":"","sources":["../../../src/cli/lib/statusFile.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs'\nimport path from 'path'\n\nimport chalk from '../../packages/chalk.js'\nimport { packageName } from '../../config.js'\nimport { log } from '../../output.js'\n\nimport type { FinalConfig } from '../../types.js'\n\n// The status file holds the result of the latest run: `<code> - <description>` on the first\n// line, then any detail. Watch mode resets it to -1 on startup so a stale result is never\n// mistaken for the current one.\nexport const statusCodes = {\n notRunYet: -1, // watch mode has started, but no run has finished\n passed: 0,\n failed: 1, // tests ran and failed\n aborted: 2, // the run died partway - a test file failed to load, or a describe threw\n couldNotRun: 3 // nothing ran at all - no test files, or no match for the filters\n} as const\n\nexport type StatusCode = typeof statusCodes[keyof typeof statusCodes]\n\nexport function resetStatusFile(config: FinalConfig): void {\n writeStatusFile(config, statusCodes.notRunYet, 'no run has finished yet')\n}\n\nexport function writeStatusFile(\n config: FinalConfig,\n code: StatusCode,\n description: string,\n details: string[] = [],\n durationMs?: number\n): void {\n write(config, [\n `${code} - ${description}`,\n localTime(new Date()),\n ...details,\n ...(durationMs === undefined) ? [] : [`${durationMs.toLocaleString()}ms`]\n ].join('\\n') + '\\n')\n}\n\n// local time, so the file reads the way the terminal beside it does, with the offset so a\n// reader elsewhere can still place it\nfunction localTime(date: Date): string {\n const pad = (value: number): string => String(value).padStart(2, '0')\n // getTimezoneOffset() counts minutes behind UTC, so the sign is the other way round\n const offsetMinutes = -date.getTimezoneOffset()\n const offset = `${(offsetMinutes < 0) ? '-' : '+'}`\n + `${pad(Math.floor(Math.abs(offsetMinutes) / 60))}:${pad(Math.abs(offsetMinutes) % 60)}`\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`\n + ` ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`\n + ` ${offset}`\n}\n\nfunction write(config: FinalConfig, contents: string): void {\n const statusFile = config.watch.statusFile\n if (typeof statusFile !== 'string' || statusFile === '') return\n\n const location = path.resolve(process.cwd(), statusFile)\n // written via a temp file and renamed, so a poller never reads a half written status\n const tempLocation = `${location}.${process.pid}.tmp`\n try {\n fs.mkdirSync(path.dirname(location), { recursive: true })\n fs.writeFileSync(tempLocation, contents)\n fs.renameSync(tempLocation, location)\n } catch (error) {\n // never let the status file take the run down with it\n log(chalk.mediumred(\n `[${packageName}] Could not write status file ${location}: ${String(error)}`\n ))\n try { fs.rmSync(tempLocation, { force: true }) } catch { /* nothing more to do */ }\n }\n}\n"]}
@@ -20,5 +20,12 @@ export function validateConfig(config, customOut) {
20
20
  if (typeof config.watch.ttyActionsOnKeypress !== 'boolean') {
21
21
  doError('Config error, config.watch.ttyActionsOnKeypress should be a boolean');
22
22
  }
23
+ const statusFile = config.watch.statusFile;
24
+ if (statusFile !== false && (typeof statusFile !== 'string' || statusFile === '')) {
25
+ doError('Config error, config.watch.statusFile should be false or a file path');
26
+ }
27
+ if (typeof config.watch.agent !== 'boolean') {
28
+ doError('Config error, config.watch.agent should be a boolean');
29
+ }
23
30
  }
24
31
  //# 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;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"]}
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"]}
@@ -3,7 +3,8 @@ import { showTimeProfiling } from '../../config.js';
3
3
  import chalk from '../../packages/chalk.js';
4
4
  import minimatch from 'minimatch';
5
5
  import slash from '../../packages/slash.js';
6
- import { out, log, debug } from '../../output.js';
6
+ import { out as mainOut, log, debug } from '../../output.js';
7
+ import { agentChange } from './agentReport.js';
7
8
  import { runTests } from './runTests.js';
8
9
  import { buildDependencyTree } from './buildDependencyTree.js';
9
10
  import { globArgCombine } from './globArgCombine.js';
@@ -17,6 +18,8 @@ dependencyTrees, failingTests, reRunManager,
17
18
  //watchRunState: WatchRunState,
18
19
  customOut, executionFilters = {}) {
19
20
  const projectDir = process.cwd();
21
+ // agent mode passes a sink here, so its own change lines are the only ones printed
22
+ const out = customOut ?? mainOut;
20
23
  await timeProfileAsync('init watching', async () => {
21
24
  debug('failingTests', failingTests);
22
25
  const testsGlobs = addBasePath(config.testsBase, config.tests);
@@ -49,6 +52,7 @@ customOut, executionFilters = {}) {
49
52
  }
50
53
  // info on the event found
51
54
  out(chalk.grey `change: ${filename} (${event})`);
55
+ agentChange(config, filename, event);
52
56
  // add the file to changed files
53
57
  changedFiles.push([filename, event]);
54
58
  // wait 100ms after any change before processing, to avoid multiple execution?
@@ -92,29 +96,26 @@ customOut, executionFilters = {}) {
92
96
  if (tests.size > 0) {
93
97
  await timeProfileAsync('build list of files to test and request a run', async () => {
94
98
  debug('tests', tests);
95
- // NOTE: the original guarded this cleanup with `config.reRunFailingTests`
96
- // (missing the `.watch.` prefix every other reference here uses), which is
97
- // always undefined - so this block never ran. Preserved as dead code rather
98
- // than newly activating it as part of a TS conversion.
99
- debug('tests', tests);
100
- debug('failingTests', failingTests);
101
99
  debug('reRunFailingTests', config.watch.reRunFailingTests);
102
- const toTest = config.watch.reRunFailingTests
103
- ? [...new Set([...tests, ...failingTests])].reverse()
104
- : [...tests].reverse();
105
- //console.log('toTest', inspect(toTest))
106
- debug('run tests on change');
107
- debug('toTest', toTest);
108
- //console.log('reRunManager.state.untestedFiles', inspect(reRunManager.state.untestedFiles))
109
- //console.log('tests', inspect(tests))
110
- reRunManager.state.untestedFiles = reRunManager.state.untestedFiles.union(tests);
111
- //console.log('unioned', inspect(reRunManager.state.untestedFiles))
112
- reRunManager.requestRun('auto', () => runTests(config, reRunManager.state.untestedFiles, reRunManager,
113
- //failingTests,
114
- 'refresh',
115
- //reRunManager.state,
116
- customOut, executionFilters));
117
- //await watchRunState.currentRun
100
+ // changes accumulate here because an 'auto' request made while a
101
+ // run is in flight is coalesced into the queued one - everything
102
+ // edited in the meantime still has to be covered
103
+ reRunManager.state.untestedFiles
104
+ = reRunManager.state.untestedFiles.union(tests);
105
+ reRunManager.requestRun('auto', () => {
106
+ // resolved when the run actually starts, not when it is
107
+ // queued, so a coalesced request picks up the later edits
108
+ const toTest = (config.watch.reRunFailingTests)
109
+ ? reRunManager.state.untestedFiles
110
+ .union(reRunManager.state.failedTestFiles)
111
+ : new Set(reRunManager.state.untestedFiles);
112
+ // consumed by this run - without this they are retested
113
+ // on every later run for the rest of the session
114
+ reRunManager.state.untestedFiles = new Set();
115
+ debug('run tests on change');
116
+ debug('toTest', toTest);
117
+ return runTests(config, toTest, reRunManager, 'refresh', customOut, executionFilters);
118
+ });
118
119
  });
119
120
  }
120
121
  }