mocha 6.2.1 → 7.0.0

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.
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- const utils = require('../utils');
3
+ const path = require('path');
4
+ const chokidar = require('chokidar');
4
5
  const Context = require('../context');
5
- const Mocha = require('../mocha');
6
6
  const collectFiles = require('./collect-files');
7
7
 
8
8
  /**
@@ -16,36 +16,88 @@ const collectFiles = require('./collect-files');
16
16
  * Run Mocha in "watch" mode
17
17
  * @param {Mocha} mocha - Mocha instance
18
18
  * @param {Object} opts - Options
19
- * @param {string} opts.ui - User interface
19
+ * @param {string[]} [opts.watchFiles] - List of paths and patterns to
20
+ * watch. If not provided all files with an extension included in
21
+ * `fileColletionParams.extension` are watched. See first argument of
22
+ * `chokidar.watch`.
23
+ * @param {string[]} opts.watchIgnore - List of paths and patterns to
24
+ * exclude from watching. See `ignored` option of `chokidar`.
20
25
  * @param {Object} fileCollectParams - Parameters that control test
21
26
  * file collection. See `lib/cli/collect-files.js`.
22
- * @param {string[]} fileCollectParams.extension - List of extensions to watch
27
+ * @param {string[]} fileCollectParams.extension - List of extensions
28
+ * to watch if `opts.watchFiles` is not given.
23
29
  * @private
24
30
  */
25
- module.exports = (mocha, {ui}, fileCollectParams) => {
26
- let runner;
27
- const files = collectFiles(fileCollectParams);
31
+ module.exports = (mocha, {watchFiles, watchIgnore}, fileCollectParams) => {
32
+ if (!watchFiles) {
33
+ watchFiles = fileCollectParams.extension.map(ext => `**/*.${ext}`);
34
+ }
35
+
36
+ const watcher = chokidar.watch(watchFiles, {
37
+ ignored: watchIgnore,
38
+ ignoreInitial: true
39
+ });
40
+
41
+ const rerunner = createRerunner(mocha, () => {
42
+ getWatchedFiles(watcher).forEach(file => {
43
+ delete require.cache[file];
44
+ });
45
+ mocha.files = collectFiles(fileCollectParams);
46
+ });
47
+
48
+ watcher.on('ready', () => {
49
+ rerunner.run();
50
+ });
51
+
52
+ watcher.on('all', () => {
53
+ rerunner.scheduleRun();
54
+ });
28
55
 
29
56
  console.log();
30
57
  hideCursor();
58
+ process.on('exit', () => {
59
+ showCursor();
60
+ });
31
61
  process.on('SIGINT', () => {
32
62
  showCursor();
33
63
  console.log('\n');
34
- // By UNIX/Posix convention this indicates that the process was
35
- // killed by SIGINT which has portable number 2.
36
64
  process.exit(128 + 2);
37
65
  });
38
66
 
39
- const watchFiles = utils.files(process.cwd(), fileCollectParams.extension);
40
- let runAgain = false;
67
+ // Keyboard shortcut for restarting when "rs\n" is typed (ala Nodemon)
68
+ process.stdin.resume();
69
+ process.stdin.setEncoding('utf8');
70
+ process.stdin.on('data', data => {
71
+ const str = data
72
+ .toString()
73
+ .trim()
74
+ .toLowerCase();
75
+ if (str === 'rs') rerunner.scheduleRun();
76
+ });
77
+ };
78
+
79
+ /**
80
+ * Create an object that allows you to rerun tests on the mocha
81
+ * instance. `beforeRun` is called everytime before `mocha.run()` is
82
+ * called.
83
+ *
84
+ * @param {Mocha} mocha - Mocha instance
85
+ * @param {function} beforeRun - Called just before `mocha.run()`
86
+ */
87
+ const createRerunner = (mocha, beforeRun) => {
88
+ // Set to a `Runner` when mocha is running. Set to `null` when mocha is not
89
+ // running.
90
+ let runner = null;
41
91
 
42
- const loadAndRun = () => {
92
+ let rerunScheduled = false;
93
+
94
+ const run = () => {
43
95
  try {
44
- mocha.files = files;
45
- runAgain = false;
96
+ beforeRun();
97
+ resetMocha(mocha);
46
98
  runner = mocha.run(() => {
47
99
  runner = null;
48
- if (runAgain) {
100
+ if (rerunScheduled) {
49
101
  rerun();
50
102
  }
51
103
  });
@@ -54,29 +106,62 @@ module.exports = (mocha, {ui}, fileCollectParams) => {
54
106
  }
55
107
  };
56
108
 
57
- const purge = () => {
58
- watchFiles.forEach(Mocha.unloadFile);
59
- };
60
-
61
- loadAndRun();
62
-
63
- const rerun = () => {
64
- purge();
65
- eraseLine();
66
- mocha.suite = mocha.suite.clone();
67
- mocha.suite.ctx = new Context();
68
- mocha.ui(ui);
69
- loadAndRun();
70
- };
109
+ const scheduleRun = () => {
110
+ if (rerunScheduled) {
111
+ return;
112
+ }
71
113
 
72
- utils.watch(watchFiles, () => {
73
- runAgain = true;
114
+ rerunScheduled = true;
74
115
  if (runner) {
75
116
  runner.abort();
76
117
  } else {
77
118
  rerun();
78
119
  }
120
+ };
121
+
122
+ const rerun = () => {
123
+ rerunScheduled = false;
124
+ eraseLine();
125
+ run();
126
+ };
127
+
128
+ return {
129
+ scheduleRun,
130
+ run
131
+ };
132
+ };
133
+
134
+ /**
135
+ * Return the list of absolute paths watched by a chokidar watcher.
136
+ *
137
+ * @param watcher - Instance of a chokidar watcher
138
+ * @return {string[]} - List of absolute paths
139
+ */
140
+ const getWatchedFiles = watcher => {
141
+ const watchedDirs = watcher.getWatched();
142
+ let watchedFiles = [];
143
+ Object.keys(watchedDirs).forEach(dir => {
144
+ watchedFiles = watchedFiles.concat(
145
+ watchedDirs[dir].map(file => path.join(dir, file))
146
+ );
79
147
  });
148
+ return watchedFiles;
149
+ };
150
+
151
+ /**
152
+ * Reset the internal state of the mocha instance so that tests can be rerun.
153
+ *
154
+ * @param {Mocha} mocha - Mocha instance
155
+ * @private
156
+ */
157
+ const resetMocha = mocha => {
158
+ mocha.unloadFiles();
159
+ mocha.suite = mocha.suite.clone();
160
+ mocha.suite.ctx = new Context();
161
+ // Registers a callback on `mocha.suite` that wires new context to the DSL
162
+ // (e.g. `describe`) that is exposed as globals when the test files are
163
+ // reloaded.
164
+ mocha.ui(mocha.options.ui);
80
165
  };
81
166
 
82
167
  /**