subprocess.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. 'use strict';
  2. const currentlyUnhandled = require('currently-unhandled')();
  3. /* eslint-disable unicorn/no-process-exit */
  4. /* eslint-disable import/no-unassigned-import */
  5. require('./ensure-forked');
  6. require('./load-chalk');
  7. require('./consume-argv');
  8. require('./fake-tty');
  9. const nowAndTimers = require('../now-and-timers');
  10. const Runner = require('../runner');
  11. const serializeError = require('../serialize-error');
  12. const dependencyTracking = require('./dependency-tracker');
  13. const ipc = require('./ipc');
  14. const options = require('./options').get();
  15. const precompilerHook = require('./precompiler-hook');
  16. function exit(code) {
  17. if (!process.exitCode) {
  18. process.exitCode = code;
  19. }
  20. dependencyTracking.flush();
  21. return ipc.flush().then(() => process.exit());
  22. }
  23. const runner = new Runner({
  24. failFast: options.failFast,
  25. failWithoutAssertions: options.failWithoutAssertions,
  26. file: options.file,
  27. match: options.match,
  28. projectDir: options.projectDir,
  29. runOnlyExclusive: options.runOnlyExclusive,
  30. serial: options.serial,
  31. snapshotDir: options.snapshotDir,
  32. updateSnapshots: options.updateSnapshots
  33. });
  34. ipc.peerFailed.then(() => {
  35. runner.interrupt();
  36. });
  37. const attributedRejections = new Set();
  38. process.on('unhandledRejection', (reason, promise) => {
  39. if (runner.attributeLeakedError(reason)) {
  40. attributedRejections.add(promise);
  41. }
  42. });
  43. runner.on('dependency', dependencyTracking.track);
  44. runner.on('stateChange', state => ipc.send(state));
  45. runner.on('error', err => {
  46. ipc.send({type: 'internal-error', err: serializeError('Internal runner error', false, err)});
  47. exit(1);
  48. });
  49. runner.on('finish', () => {
  50. try {
  51. const touchedFiles = runner.saveSnapshotState();
  52. if (touchedFiles) {
  53. ipc.send({type: 'touched-files', files: touchedFiles});
  54. }
  55. } catch (err) {
  56. ipc.send({type: 'internal-error', err: serializeError('Internal runner error', false, err)});
  57. exit(1);
  58. return;
  59. }
  60. nowAndTimers.setImmediate(() => {
  61. currentlyUnhandled().filter(rejection => {
  62. return !attributedRejections.has(rejection.promise);
  63. }).forEach(rejection => {
  64. ipc.send({type: 'unhandled-rejection', err: serializeError('Unhandled rejection', true, rejection.reason)});
  65. });
  66. exit(0);
  67. });
  68. });
  69. process.on('uncaughtException', err => {
  70. if (runner.attributeLeakedError(err)) {
  71. return;
  72. }
  73. ipc.send({type: 'uncaught-exception', err: serializeError('Uncaught exception', true, err)});
  74. exit(1);
  75. });
  76. let accessedRunner = false;
  77. exports.getRunner = () => {
  78. accessedRunner = true;
  79. return runner;
  80. };
  81. // Store value in case to prevent required modules from modifying it.
  82. const testPath = options.file;
  83. // Install before processing options.require, so if helpers are added to the
  84. // require configuration the *compiled* helper will be loaded.
  85. dependencyTracking.install(testPath);
  86. precompilerHook.install();
  87. try {
  88. (options.require || []).forEach(x => {
  89. const required = require(x);
  90. try {
  91. if (required[Symbol.for('esm\u200D:package')]) {
  92. require = required(module); // eslint-disable-line no-global-assign
  93. }
  94. } catch (_) {}
  95. });
  96. require(testPath);
  97. if (accessedRunner) {
  98. // Unreference the IPC channel if the test file required AVA. This stops it
  99. // from keeping the event loop busy, which means the `beforeExit` event can be
  100. // used to detect when tests stall.
  101. ipc.unref();
  102. } else {
  103. ipc.send({type: 'missing-ava-import'});
  104. exit(1);
  105. }
  106. } catch (err) {
  107. ipc.send({type: 'uncaught-exception', err: serializeError('Uncaught exception', true, err)});
  108. exit(1);
  109. }