@reporters/testwatch 1.1.0 → 1.2.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.2.0](https://github.com/MoLow/reporters/compare/testwatch-v1.1.1...testwatch-v1.2.0) (2023-06-19)
4
+
5
+
6
+ ### Features
7
+
8
+ * add test:watch script ([4357fbd](https://github.com/MoLow/reporters/commit/4357fbde5f337cfd39226497f8ce0f6760f8a62c))
9
+ * change default file filter ([5968235](https://github.com/MoLow/reporters/commit/596823529cd9a86e5eeada0523825fa215e49efe))
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * don't exit when no tests on initial run ([66bcc2b](https://github.com/MoLow/reporters/commit/66bcc2bc6436b544900cfbceb4bbfb0d93973490))
15
+
16
+ ## [1.1.1](https://github.com/MoLow/reporters/compare/testwatch-v1.1.0...testwatch-v1.1.1) (2023-06-12)
17
+
18
+
19
+ ### Bug Fixes
20
+
21
+ * increas maximum listeners of event emitters ([b16d2ab](https://github.com/MoLow/reporters/commit/b16d2ab3b55554e1aaa9b9ca2222254bac364803))
22
+ * support partial file name filter ([2b3f0ab](https://github.com/MoLow/reporters/commit/2b3f0abe0be37450c7b9189667ad47d4d39a4252))
23
+
3
24
  ## [1.1.0](https://github.com/MoLow/reporters/compare/testwatch-v1.0.0...testwatch-v1.1.0) (2023-06-08)
4
25
 
5
26
 
package/index.js CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  const { run } = require('node:test');
4
4
  const { pipeline } = require('node:stream/promises');
5
- const { on, once, EventEmitter } = require('node:events');
5
+ const {
6
+ on, once, EventEmitter, setMaxListeners,
7
+ } = require('node:events');
6
8
  const { glob } = require('glob');
7
9
  const chalk = require('chalk');
8
10
  const { isSupported } = require('./nodeVersion');
@@ -28,6 +30,7 @@ const KEY_NAMES = {
28
30
  };
29
31
  const UnknownCommand = Symbol('UnknownKey');
30
32
 
33
+ setMaxListeners(Infinity);
31
34
  process.stdout.setMaxListeners(Infinity);
32
35
  process.setMaxListeners(Infinity);
33
36
  process.stdin.setEncoding('utf8');
@@ -36,7 +39,7 @@ process.stdin.setRawMode?.(true);
36
39
  class REPL {
37
40
  #controller = new AbortController();
38
41
 
39
- #filesFilter = '';
42
+ #filesFilter = process.argv[2] || '';
40
43
 
41
44
  #testsFilter = '';
42
45
 
@@ -56,7 +59,7 @@ class REPL {
56
59
  async #runTests() {
57
60
  this.#controller.abort();
58
61
  this.#controller = new AbortController();
59
- const filter = this.#filesFilter ? `**/${this.#filesFilter}.*` : '**/*.test.js';
62
+ const filter = this.#filesFilter ? `**/${this.#filesFilter}*.*` : '**/?(*.)+(spec|test).[jt]s';
60
63
  const files = await glob(filter, { ignore: 'node_modules/**' });
61
64
 
62
65
  if (!files.length) {
@@ -200,7 +203,7 @@ class REPL {
200
203
  if (this.#filesFilter || this.#testsFilter) {
201
204
  const message = `
202
205
  ${chalk.white.bold('Active Filters:')} \
203
- ${this.#filesFilter ? `file name ${chalk.gray('**/')}${chalk.yellow(this.#filesFilter)}${chalk.gray('.*')}` : ''}\
206
+ ${this.#filesFilter ? `file name ${chalk.gray('**/')}${chalk.yellow(this.#filesFilter)}${chalk.gray('*.*')}` : ''}\
204
207
  ${(this.#testsFilter && this.#filesFilter) ? ', ' : ''}\
205
208
  ${this.#testsFilter ? `test name ${chalk.yellow(`/${this.#testsFilter}/`)}` : ''}
206
209
  `;
@@ -217,8 +220,7 @@ ${Object.entries(this.#currentCommands)
217
220
  }
218
221
 
219
222
  async run() {
220
- await this.#runTests();
221
- await once(this.#emitter, 'drained');
223
+ await Promise.all([once(this.#emitter, 'drained'), this.#runTests()]);
222
224
  this.#emitter.on('drained', () => this.#compactHelp());
223
225
  this.#help();
224
226
  for await (const data of on(process.stdin, 'data')) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reporters/testwatch",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "An interactive repl for `node:test`",
5
5
  "keywords": [
6
6
  "node:test",
@@ -10,7 +10,8 @@
10
10
  ],
11
11
  "bin": "./index.js",
12
12
  "scripts": {
13
- "test": "node --test-reporter=spec --test-reporter-destination=stdout --test-reporter=../github/index.js --test-reporter-destination=stdout --test tests/index.test.js"
13
+ "test": "node --test-reporter=spec --test-reporter-destination=stdout --test-reporter=../github/index.js --test-reporter-destination=stdout --test tests/index.test.js",
14
+ "test:watch": "testwatch tests/index"
14
15
  },
15
16
  "bugs": {
16
17
  "url": "https://github.com/MoLow/reporters/issues"
@@ -0,0 +1,6 @@
1
+ const { test } = require('node:test');
2
+ const assert = require('node:assert');
3
+
4
+ test('should not run', () => {
5
+ assert.strictEqual(1 + 2, 3);
6
+ });
@@ -35,11 +35,11 @@ Filter Test
35
35
  pattern › `;
36
36
  const filterFilesPrompt = filterTestsPrompt.replace('test', 'file').replace('Test', 'File');
37
37
 
38
- async function spawnInteractive(commandSequence = 'q') {
38
+ async function spawnInteractive(commandSequence = 'q', args = []) {
39
39
  let stderr = '';
40
40
  let stdout = '';
41
- const child = spawn(process.execPath, ['../../index.js'], {
42
- env: { }, cwd: path.resolve(__dirname, 'fixtures'),
41
+ const child = spawn(process.execPath, ['../../index.js', ...args], {
42
+ env: {}, cwd: path.resolve(__dirname, 'fixtures'),
43
43
  });
44
44
  child.stdin.setEncoding('utf8');
45
45
  let writing = false;
@@ -62,7 +62,7 @@ async function spawnInteractive(commandSequence = 'q') {
62
62
  child.stdout.setEncoding('utf8');
63
63
  child.stdout.on('data', (data) => {
64
64
  stdout += data;
65
- if (stdout.includes(mainMenu)) {
65
+ if (stdout.includes(mainMenu) || stdout.includes(mainMenuWithFilters)) {
66
66
  writeInput();
67
67
  }
68
68
  });
@@ -103,7 +103,7 @@ describe('testwatch', { concurrency: true, skip: !isSupported ? 'unsupported nod
103
103
  });
104
104
  it('should exit on sigkill', async () => {
105
105
  const child = spawn(process.execPath, ['../../index.js'], {
106
- env: { }, cwd: path.resolve(__dirname, 'fixtures'),
106
+ env: {}, cwd: path.resolve(__dirname, 'fixtures'),
107
107
  });
108
108
  let stderr = '';
109
109
  let stdout = '';
@@ -155,21 +155,57 @@ describe('testwatch', { concurrency: true, skip: !isSupported ? 'unsupported nod
155
155
  ]);
156
156
  });
157
157
 
158
- it('should filter files on "p"', async () => {
159
- const { outputs, stderr } = await spawnInteractive(['p', 'index', '\r', 'w', 'q'].join(''));
160
- const activeFilters = '\nActive Filters: file name **/index.*\n';
161
- assert.strictEqual(stderr, '');
162
- assert.deepStrictEqual(outputs, [
163
- '',
164
- `${tests}\n${mainMenu}`,
165
- `${filterFilesPrompt}index`,
166
- '',
167
- `${testsRun[1]}\n${compactMenu}\n${clearLines}${activeFilters}${mainMenuWithFilters}\n`,
168
- ]);
158
+ describe('files filter', () => {
159
+ it('should not exit if no test found on first run', async () => {
160
+ const { outputs, stderr } = await spawnInteractive('q', ['notexist']);
161
+ const activeFilters = '\nActive Filters: file name **/notexist*.*\n';
162
+ const notFound = '\nNo files found for pattern **/notexist*.*';
163
+ assert.strictEqual(stderr, '');
164
+ assert.deepStrictEqual(outputs, [
165
+ '',
166
+ `${notFound}\n${activeFilters}${mainMenuWithFilters}\n`,
167
+ ]);
168
+ });
169
+
170
+ it('should set first argument as file filter', async () => {
171
+ const { outputs, stderr } = await spawnInteractive('q', ['ind']);
172
+ const activeFilters = '\nActive Filters: file name **/ind*.*\n';
173
+ assert.strictEqual(stderr, '');
174
+ assert.deepStrictEqual(outputs, [
175
+ '',
176
+ `${testsRun[1]}\n${activeFilters}${mainMenuWithFilters}\n`,
177
+ ]);
178
+ });
179
+
180
+ it('should filter files on "p"', async () => {
181
+ const { outputs, stderr } = await spawnInteractive(['p', 'index', '\r', 'w', 'q'].join(''));
182
+ const activeFilters = '\nActive Filters: file name **/index*.*\n';
183
+ assert.strictEqual(stderr, '');
184
+ assert.deepStrictEqual(outputs, [
185
+ '',
186
+ `${tests}\n${mainMenu}`,
187
+ `${filterFilesPrompt}index`,
188
+ '',
189
+ `${testsRun[1]}\n${compactMenu}\n${clearLines}${activeFilters}${mainMenuWithFilters}\n`,
190
+ ]);
191
+ });
192
+
193
+ it('should filter partial file names on "p"', async () => {
194
+ const { outputs, stderr } = await spawnInteractive(['p', 'ind', '\r', 'w', 'q'].join(''));
195
+ const activeFilters = '\nActive Filters: file name **/ind*.*\n';
196
+ assert.strictEqual(stderr, '');
197
+ assert.deepStrictEqual(outputs, [
198
+ '',
199
+ `${tests}\n${mainMenu}`,
200
+ `${filterFilesPrompt}ind`,
201
+ '',
202
+ `${testsRun[1]}\n${compactMenu}\n${clearLines}${activeFilters}${mainMenuWithFilters}\n`,
203
+ ]);
204
+ });
169
205
  });
170
206
  it('should filter tests and files togetheer', async () => {
171
207
  const { outputs, stderr } = await spawnInteractive(['p', 'index', '\r', 't', 'sum', '\r', 'w', 'q'].join(''));
172
- const activeFilters = '\nActive Filters: file name **/index.*, test name /sum/\n';
208
+ const activeFilters = '\nActive Filters: file name **/index*.*, test name /sum/\n';
173
209
  assert.strictEqual(stderr, '');
174
210
  assert.strictEqual(outputs.length, 8);
175
211
  assert.strictEqual(outputs[7], `${testsRun[1].replace('✔ index - subtraction (*ms)', '﹣ index - subtraction (*ms) # SKIP')}\n${compactMenu}\n${clearLines}${activeFilters}${mainMenuWithFilters}\n`);
@@ -177,8 +213,8 @@ describe('testwatch', { concurrency: true, skip: !isSupported ? 'unsupported nod
177
213
 
178
214
  it('should mention when no files found', async () => {
179
215
  const { outputs, stderr } = await spawnInteractive(['p', 'nothing', '\r', 'w', 'q'].join(''));
180
- const activeFilters = '\nActive Filters: file name **/nothing.*\n';
181
- const notFound = '\nNo files found for pattern **/nothing.*';
216
+ const activeFilters = '\nActive Filters: file name **/nothing*.*\n';
217
+ const notFound = '\nNo files found for pattern **/nothing*.*';
182
218
  assert.strictEqual(stderr, '');
183
219
  assert.deepStrictEqual(outputs, [
184
220
  '',
@@ -194,16 +230,16 @@ describe('testwatch', { concurrency: true, skip: !isSupported ? 'unsupported nod
194
230
  assert.strictEqual(stderr, '');
195
231
  assert.strictEqual(outputs.length, 9);
196
232
 
197
- assert.match(outputs[4], /Active Filters: file name \*\*\/index\.\*/);
198
- assert.match(outputs[5], /Active Filters: file name \*\*\/index\.\*/);
199
- assert.match(outputs[7], /Active Filters: file name \*\*\/index\.\*, test name \/sum\//);
233
+ assert.match(outputs[4], /Active Filters: file name \*\*\/index\*\.\*/);
234
+ assert.match(outputs[5], /Active Filters: file name \*\*\/index\*\.\*/);
235
+ assert.match(outputs[7], /Active Filters: file name \*\*\/index\*\.\*, test name \/sum\//);
200
236
  assert.strictEqual(outputs[8], `${tests}\n${compactMenu}\n${clearLines}${mainMenu}\n`);
201
237
  });
202
238
 
203
239
  it('prompt ESC should preserve previous state', async () => {
204
240
  const { outputs } = await spawnInteractive(['p', esc, 'p', 'filter', '\r', 'p', esc, 'q'].join(''));
205
- const notFound = '\nNo files found for pattern **/filter.*';
206
- const activeFilters = '\nActive Filters: file name **/filter.*\n';
241
+ const notFound = '\nNo files found for pattern **/filter*.*';
242
+ const activeFilters = '\nActive Filters: file name **/filter*.*\n';
207
243
  assert.deepStrictEqual(outputs, [
208
244
  '',
209
245
  `${tests}\n${mainMenu}`,
@@ -224,7 +260,7 @@ describe('testwatch', { concurrency: true, skip: !isSupported ? 'unsupported nod
224
260
  const { outputs, stderr } = await spawnInteractive(['p', `noth123${backspace}${backspace}ing`, '\r', 'w', 'q'].join(''));
225
261
  assert.strictEqual(stderr, '');
226
262
  assert.strictEqual(outputs.length, 5);
227
- assert.match(outputs[4], /No files found for pattern \*\*\/noth1ing\.\*/);
263
+ assert.match(outputs[4], /No files found for pattern \*\*\/noth1ing\*\.\*/);
228
264
  });
229
265
  });
230
266
  });
File without changes