poku 1.9.3 → 1.10.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/README.md CHANGED
@@ -111,8 +111,8 @@ bun add -d poku
111
111
  </td>
112
112
  <td width="400">
113
113
 
114
- ```ts
115
- import { poku } from 'npm:poku';
114
+ ```bash
115
+ deno add npm:poku
116
116
  ```
117
117
 
118
118
  </td>
@@ -124,7 +124,7 @@ import { poku } from 'npm:poku';
124
124
  <table>
125
125
  <tr>
126
126
  <td>
127
- <em><code>test/file.test.js</code></em>
127
+ <em><code>test/file.test.mjs</code></em>
128
128
  </td>
129
129
  </tr>
130
130
  <tr>
@@ -140,7 +140,8 @@ assert(true, 'Poku will describe it 🐷');
140
140
  </tr>
141
141
  </table>
142
142
 
143
- > Note that these examples use [**ESM**](https://poku.io/docs/examples/cjs-esm), but you can use [**CJS**](https://poku.io/docs/examples/cjs-esm) as well.
143
+ - Change from `.mjs` to `.js` by defining `"type": "module"` in your _package.json_.
144
+ - Note that these examples use [**ESM**](https://poku.io/docs/examples/cjs-esm), but you can use [**CJS**](https://poku.io/docs/examples/cjs-esm) as well.
144
145
 
145
146
  ### Run it 🚀
146
147
 
@@ -50,6 +50,12 @@ export type Configs = {
50
50
  * @default 'node'
51
51
  */
52
52
  platform?: 'node' | 'bun' | 'deno';
53
+ /**
54
+ * Stops the tests at the first failure.
55
+ *
56
+ * @default false
57
+ */
58
+ failFast?: boolean;
53
59
  /**
54
60
  * You can use this option to run a **callback** or a **file** before each test file on your suite.
55
61
  *
package/lib/bin/index.js CHANGED
@@ -2,12 +2,12 @@
2
2
  "use strict";
3
3
  var _a, _b;
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
+ /* c8 ignore start */
5
6
  const list_files_js_1 = require("../modules/list-files.js");
6
7
  const get_arg_js_1 = require("../helpers/get-arg.js");
7
8
  const index_js_1 = require("../index.js");
8
9
  const get_runtime_js_1 = require("../helpers/get-runtime.js");
9
10
  const format_js_1 = require("../helpers/format.js");
10
- /* c8 ignore start */
11
11
  const dirs = ((0, get_arg_js_1.hasArg)('include')
12
12
  ? (_a = (0, get_arg_js_1.getArg)('include')) === null || _a === void 0 ? void 0 : _a.split(',')
13
13
  : (_b = (0, get_arg_js_1.getLastParam)()) === null || _b === void 0 ? void 0 : _b.split(',')) || [];
@@ -17,9 +17,9 @@ const exclude = (0, get_arg_js_1.getArg)('exclude');
17
17
  const parallel = (0, get_arg_js_1.hasArg)('parallel');
18
18
  const quiet = (0, get_arg_js_1.hasArg)('quiet');
19
19
  const debug = (0, get_arg_js_1.hasArg)('debug');
20
+ const failFast = (0, get_arg_js_1.hasArg)('fail-fast');
20
21
  if ((0, get_arg_js_1.hasArg)('log-success'))
21
22
  console.log(`The flag ${format_js_1.format.bold('--log-success')} is deprecated. Use ${format_js_1.format.bold('--debug')} instead.`);
22
- /* c8 ignore end */
23
23
  (0, index_js_1.poku)(dirs, {
24
24
  platform: (0, get_runtime_js_1.platformIsValid)(platform) ? platform : undefined,
25
25
  filter: filter ? new RegExp((0, list_files_js_1.escapeRegExp)(filter)) : undefined,
@@ -27,4 +27,6 @@ if ((0, get_arg_js_1.hasArg)('log-success'))
27
27
  parallel,
28
28
  quiet,
29
29
  debug,
30
+ failFast,
30
31
  });
32
+ /* c8 ignore stop */
@@ -26,4 +26,4 @@ const findFile = (error) => {
26
26
  return file;
27
27
  };
28
28
  exports.findFile = findFile;
29
- /* c8 ignore end */
29
+ /* c8 ignore stop */
@@ -15,4 +15,4 @@ const padStart = (str, targetLength, padString) => {
15
15
  return fullPadString + str;
16
16
  };
17
17
  exports.padStart = padStart;
18
- /* c8 ignore end */
18
+ /* c8 ignore stop */
@@ -178,12 +178,11 @@ function doesNotReject(block, errorOrMessage, message) {
178
178
  });
179
179
  });
180
180
  }
181
+ /* c8 ignore start */
181
182
  const match = (value, regExp, message) => __awaiter(void 0, void 0, void 0, function* () {
182
- /* c8 ignore start */
183
183
  if (typeof get_runtime_js_1.nodeVersion === 'number' && get_runtime_js_1.nodeVersion < 12) {
184
184
  throw new Error('match is available from Node.js 12 or higher');
185
185
  }
186
- /* c8 ignore stop */
187
186
  yield (0, parseAsssetion_js_1.parseAssertion)(() => nodeAssert === null || nodeAssert === void 0 ? void 0 : nodeAssert.match(value, regExp), {
188
187
  message,
189
188
  actual: 'Value',
@@ -191,12 +190,12 @@ const match = (value, regExp, message) => __awaiter(void 0, void 0, void 0, func
191
190
  defaultMessage: 'Value should match regExp',
192
191
  });
193
192
  });
193
+ /* c8 ignore stop */
194
+ /* c8 ignore start */
194
195
  const doesNotMatch = (value, regExp, message) => __awaiter(void 0, void 0, void 0, function* () {
195
- /* c8 ignore start */
196
196
  if (typeof get_runtime_js_1.nodeVersion === 'number' && get_runtime_js_1.nodeVersion < 12) {
197
197
  throw new Error('doesNotMatch is available from Node.js 12 or higher');
198
198
  }
199
- /* c8 ignore stop */
200
199
  yield (0, parseAsssetion_js_1.parseAssertion)(() => nodeAssert.doesNotMatch(value, regExp), {
201
200
  message,
202
201
  actual: 'Value',
@@ -204,6 +203,7 @@ const doesNotMatch = (value, regExp, message) => __awaiter(void 0, void 0, void
204
203
  defaultMessage: 'Value should not match regExp',
205
204
  });
206
205
  });
206
+ /* c8 ignore stop */
207
207
  exports.assertPromise = Object.assign((value, message) => ok(value, message), {
208
208
  ok,
209
209
  equal,
@@ -168,12 +168,11 @@ function doesNotReject(block, errorOrMessage, message) {
168
168
  });
169
169
  });
170
170
  }
171
+ /* c8 ignore start */
171
172
  const match = (value, regExp, message) => {
172
- /* c8 ignore start */
173
173
  if (typeof get_runtime_js_1.nodeVersion === 'number' && get_runtime_js_1.nodeVersion < 12) {
174
174
  throw new Error('match is available from Node.js 12 or higher');
175
175
  }
176
- /* c8 ignore stop */
177
176
  (0, parseAsssetion_js_1.parseAssertion)(() => nodeAssert === null || nodeAssert === void 0 ? void 0 : nodeAssert.match(value, regExp), {
178
177
  message,
179
178
  actual: 'Value',
@@ -181,12 +180,12 @@ const match = (value, regExp, message) => {
181
180
  defaultMessage: 'Value should match regExp',
182
181
  });
183
182
  };
183
+ /* c8 ignore stop */
184
+ /* c8 ignore start */
184
185
  const doesNotMatch = (value, regExp, message) => {
185
- /* c8 ignore start */
186
186
  if (typeof get_runtime_js_1.nodeVersion === 'number' && get_runtime_js_1.nodeVersion < 12) {
187
187
  throw new Error('doesNotMatch is available from Node.js 12 or higher');
188
188
  }
189
- /* c8 ignore stop */
190
189
  (0, parseAsssetion_js_1.parseAssertion)(() => nodeAssert.doesNotMatch(value, regExp), {
191
190
  message,
192
191
  actual: 'Value',
@@ -194,6 +193,7 @@ const doesNotMatch = (value, regExp, message) => {
194
193
  defaultMessage: 'Value should not match regExp',
195
194
  });
196
195
  };
196
+ /* c8 ignore stop */
197
197
  exports.assert = Object.assign((value, message) => ok(value, message), {
198
198
  ok,
199
199
  equal,
@@ -27,15 +27,18 @@ const killWindowsProcess = (PID) => (0, node_child_process_1.spawn)('taskkill',
27
27
  node_process_1.default.once('SIGINT', () => {
28
28
  secureEnds();
29
29
  });
30
- /* c8 ignore end */
30
+ /* c8 ignore stop */
31
31
  const backgroundProcess = (runtime, args, file, options) => new Promise((resolve, reject) => {
32
32
  let isResolved = false;
33
33
  const service = (0, node_child_process_1.spawn)(runtime, args, {
34
34
  stdio: ['inherit', 'pipe', 'pipe'],
35
- shell: false,
35
+ /* c8 ignore next */
36
+ shell: runner_js_1.isWindows,
36
37
  cwd: (options === null || options === void 0 ? void 0 : options.cwd) ? (0, list_files_js_1.sanitizePath)(node_path_1.default.normalize(options.cwd)) : undefined,
37
38
  env: node_process_1.default.env,
39
+ /* c8 ignore next */
38
40
  detached: !runner_js_1.isWindows,
41
+ /* c8 ignore next */
39
42
  windowsHide: runner_js_1.isWindows,
40
43
  timeout: options === null || options === void 0 ? void 0 : options.timeout,
41
44
  });
@@ -56,7 +59,7 @@ const backgroundProcess = (runtime, args, file, options) => new Promise((resolve
56
59
  return;
57
60
  };
58
61
  runningProcesses[PID] = end;
59
- /* c8 ignore end */
62
+ /* c8 ignore stop */
60
63
  service.stdout.on('data', (data) => {
61
64
  if (!isResolved && typeof (options === null || options === void 0 ? void 0 : options.startAfter) !== 'number') {
62
65
  const stringData = JSON.stringify(String(data));
@@ -142,7 +145,7 @@ const startScript = (script, options) => __awaiter(void 0, void 0, void 0, funct
142
145
  /* c8 ignore start */
143
146
  if (['bun', 'deno'].includes(runner))
144
147
  throw new Error(`${format_js_1.format.bold('startScript')} currently doesn't works for Bun and Deno.${node_os_1.EOL}See: https://github.com/wellwelwel/poku/issues/143`);
145
- /* c8 ignore end */
148
+ /* c8 ignore stop */
146
149
  return yield backgroundProcess(runtime, runtimeArgs, script, Object.assign(Object.assign({}, options), { isScript: true, runner }));
147
150
  });
148
151
  exports.startScript = startScript;
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
+ /* c8 ignore start */
2
3
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
5
  };
@@ -12,15 +13,14 @@ const exit = (code, quiet) => {
12
13
  const isPoku = run_tests_js_1.results.success > 0 || run_tests_js_1.results.fail > 0;
13
14
  !quiet &&
14
15
  node_process_1.default.on('exit', (code) => {
15
- isPoku &&
16
+ if (isPoku) {
17
+ (0, hr_js_1.hr)();
16
18
  console.log(format_js_1.format.bg(42, `PASS › ${run_tests_js_1.results.success}`), format_js_1.format.bg(run_tests_js_1.results.fail === 0 ? 100 : 41, `FAIL › ${run_tests_js_1.results.fail}`));
17
- isPoku && (0, hr_js_1.hr)();
19
+ (0, hr_js_1.hr)();
20
+ }
18
21
  console.log(`${format_js_1.format.dim('Exited with code')} ${format_js_1.format.bold(format_js_1.format === null || format_js_1.format === void 0 ? void 0 : format_js_1.format[code === 0 ? 'success' : 'fail'](String(code)))}`);
19
22
  });
20
- isPoku && !quiet && (0, hr_js_1.hr)();
21
- if (code !== 0)
22
- node_process_1.default.exit(1);
23
- node_process_1.default.exit(0);
23
+ node_process_1.default.exit(code === 0 ? 0 : 1);
24
24
  };
25
25
  exports.exit = exit;
26
26
  node_process_1.default.on('unhandledRejection', (reason) => {
@@ -31,3 +31,4 @@ node_process_1.default.on('uncaughtException', (err) => {
31
31
  console.log('uncaughtException', err);
32
32
  node_process_1.default.exit(1);
33
33
  });
34
+ /* c8 ignore stop */
@@ -29,33 +29,47 @@ function poku(targetPaths, configs) {
29
29
  const prepareDirs = (0, force_array_js_1.forceArray)(targetPaths);
30
30
  const dirs = prepareDirs.length > 0 ? prepareDirs : ['./'];
31
31
  const showLogs = !(0, logs_js_1.isQuiet)(configs);
32
- if (configs === null || configs === void 0 ? void 0 : configs.parallel) {
33
- if (showLogs) {
34
- (0, hr_js_1.hr)();
35
- console.log(`${format_js_1.format.bold('Running the Test Suite in Parallel')}${node_os_1.EOL}`);
32
+ // Sequential
33
+ if (!(configs === null || configs === void 0 ? void 0 : configs.parallel)) {
34
+ for (const dir of dirs) {
35
+ const result = yield (0, run_tests_js_1.runTests)(dir, configs);
36
+ if (!result) {
37
+ code = 1;
38
+ if (configs === null || configs === void 0 ? void 0 : configs.failFast)
39
+ break;
40
+ }
36
41
  }
37
- const concurrency = yield Promise.all(dirs.map((dir) => (0, run_tests_js_1.runTestsParallel)(dir, configs)));
38
- if (concurrency.some((result) => !result))
39
- code = 1;
40
- showLogs && (0, hr_js_1.hr)();
41
- if (showLogs && run_test_file_js_1.fileResults.success.length > 0)
42
- console.log(run_test_file_js_1.fileResults.success
43
- .map((current) => `${indentation_js_1.indentation.test}${format_js_1.format.success('✔')} ${format_js_1.format.dim(current)}`)
44
- .join(node_os_1.EOL));
45
- if (showLogs && run_test_file_js_1.fileResults.fail.length > 0)
46
- console.log(run_test_file_js_1.fileResults.fail
47
- .map((current) => `${indentation_js_1.indentation.test}${format_js_1.format.fail('✘')} ${current}`)
48
- .join(node_os_1.EOL));
49
42
  if (configs === null || configs === void 0 ? void 0 : configs.noExit)
50
43
  return code;
51
44
  (0, exit_js_1.exit)(code, configs === null || configs === void 0 ? void 0 : configs.quiet);
52
45
  return;
53
46
  }
54
- for (const dir of dirs) {
55
- const result = yield (0, run_tests_js_1.runTests)(dir, configs);
56
- if (!result)
47
+ // Parallel
48
+ if (showLogs) {
49
+ (0, hr_js_1.hr)();
50
+ console.log(`${format_js_1.format.bold('Running the Test Suite in Parallel')}${node_os_1.EOL}`);
51
+ }
52
+ try {
53
+ const promises = dirs.map((dir) => __awaiter(this, void 0, void 0, function* () {
54
+ const result = yield (0, run_tests_js_1.runTestsParallel)(dir, configs);
55
+ if (!result && (configs === null || configs === void 0 ? void 0 : configs.failFast))
56
+ throw '';
57
+ return result;
58
+ }));
59
+ const concurrency = yield Promise.all(promises);
60
+ if (concurrency.some((result) => !result))
57
61
  code = 1;
58
62
  }
63
+ catch (_a) { }
64
+ showLogs && (0, hr_js_1.hr)();
65
+ if (showLogs && run_test_file_js_1.fileResults.success.length > 0)
66
+ console.log(run_test_file_js_1.fileResults.success
67
+ .map((current) => `${indentation_js_1.indentation.test}${format_js_1.format.success('✔')} ${format_js_1.format.dim(current)}`)
68
+ .join(node_os_1.EOL));
69
+ if (showLogs && run_test_file_js_1.fileResults.fail.length > 0)
70
+ console.log(run_test_file_js_1.fileResults.fail
71
+ .map((current) => `${indentation_js_1.indentation.test}${format_js_1.format.fail('✘')} ${current}`)
72
+ .join(node_os_1.EOL));
59
73
  if (configs === null || configs === void 0 ? void 0 : configs.noExit)
60
74
  return code;
61
75
  (0, exit_js_1.exit)(code, configs === null || configs === void 0 ? void 0 : configs.quiet);
@@ -23,10 +23,13 @@ const format_js_1 = require("../helpers/format.js");
23
23
  const logs_js_1 = require("../helpers/logs.js");
24
24
  const remove_repeats_js_1 = require("../helpers/remove-repeats.js");
25
25
  const each_js_1 = require("./each.js");
26
+ /* c8 ignore stop */
27
+ /* c8 ignore start */
26
28
  exports.fileResults = {
27
29
  success: [],
28
30
  fail: [],
29
31
  };
32
+ /* c8 ignore stop */
30
33
  const runTestFile = (filePath, configs) => new Promise((resolve) => __awaiter(void 0, void 0, void 0, function* () {
31
34
  const runtimeOptions = (0, runner_js_1.runner)(filePath, configs);
32
35
  const runtime = runtimeOptions.shift();
@@ -75,7 +78,8 @@ const runTestFile = (filePath, configs) => new Promise((resolve) => __awaiter(vo
75
78
  // Export spawn helper is not an option
76
79
  const child = (0, node_child_process_1.spawn)(runtime, runtimeArguments, {
77
80
  stdio: ['inherit', 'pipe', 'pipe'],
78
- shell: false,
81
+ /* c8 ignore next */
82
+ shell: runner_js_1.isWindows,
79
83
  env: Object.assign(Object.assign({}, node_process_1.default.env), { FILE: (configs === null || configs === void 0 ? void 0 : configs.parallel) ? fileRelative : '' }),
80
84
  });
81
85
  child.stdout.on('data', stdOut);
@@ -59,6 +59,11 @@ const runTests = (dir, configs) => __awaiter(void 0, void 0, void 0, function* (
59
59
  showLogs &&
60
60
  console.log(`${indentation_js_1.indentation.test}${format_js_1.format.fail('✘')} ${log}`, nextLine);
61
61
  passed = false;
62
+ if (configs === null || configs === void 0 ? void 0 : configs.failFast) {
63
+ (0, hr_js_1.hr)();
64
+ console.log(` ${format_js_1.format.fail('ℹ')} ${format_js_1.format.bold('fail-fast')} is enabled`);
65
+ break;
66
+ }
62
67
  }
63
68
  }
64
69
  return passed;
@@ -68,16 +73,27 @@ const runTestsParallel = (dir, configs) => __awaiter(void 0, void 0, void 0, fun
68
73
  const cwd = node_process_1.default.cwd();
69
74
  const testDir = node_path_1.default.join(cwd, dir);
70
75
  const files = (0, list_files_js_1.isFile)(dir) ? [dir] : (0, list_files_js_1.listFiles)(testDir, undefined, configs);
71
- const promises = files.map((filePath) => __awaiter(void 0, void 0, void 0, function* () {
72
- const testPassed = yield (0, run_test_file_js_1.runTestFile)(filePath, configs);
73
- if (!testPassed) {
74
- ++exports.results.fail;
75
- return false;
76
- }
77
- ++exports.results.success;
78
- return true;
79
- }));
80
- const concurrency = yield Promise.all(promises);
81
- return concurrency.every((result) => result);
76
+ try {
77
+ const promises = files.map((filePath) => __awaiter(void 0, void 0, void 0, function* () {
78
+ if ((configs === null || configs === void 0 ? void 0 : configs.failFast) && exports.results.fail > 0)
79
+ return;
80
+ const testPassed = yield (0, run_test_file_js_1.runTestFile)(filePath, configs);
81
+ if (!testPassed) {
82
+ ++exports.results.fail;
83
+ if (configs === null || configs === void 0 ? void 0 : configs.failFast)
84
+ throw ` ${format_js_1.format.fail('ℹ')} ${format_js_1.format.bold('fail-fast')} is enabled`;
85
+ return false;
86
+ }
87
+ ++exports.results.success;
88
+ return true;
89
+ }));
90
+ const concurrency = yield Promise.all(promises);
91
+ return concurrency.every((result) => result);
92
+ }
93
+ catch (error) {
94
+ (0, hr_js_1.hr)();
95
+ console.log(error);
96
+ return false;
97
+ }
82
98
  });
83
99
  exports.runTestsParallel = runTestsParallel;
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "poku",
3
- "version": "1.9.3",
3
+ "version": "1.10.0",
4
4
  "description": "🐷 Poku makes testing easy for Node.js, Bun & Deno at the same time.",
5
5
  "main": "./lib/index.js",
6
6
  "scripts": {
7
- "test": "npx poku --parallel --debug test/unit,test/integration,test/e2e",
8
- "pretest:c8": "npm run build",
7
+ "test": "tsx src/bin/index.ts --parallel --debug --include=\"test/unit,test/integration,test/e2e\"",
9
8
  "test:c8": "c8 npm run test",
10
9
  "test:ci": "tsx ./test/ci.test.ts",
11
10
  "test:node": "FILTER='node-' npm run test:ci",
@@ -23,7 +22,7 @@
23
22
  "lint:fix": "npm run eslint:fix && npm run prettier:fix",
24
23
  "prettier:checker": "prettier --check .",
25
24
  "prettier:fix": "prettier --write .github/workflows/*.yml .",
26
- "update": "npu && npm i && npm run lint:fix && npm audit"
25
+ "update": "npu --minor && npm i && npm run lint:fix && npm audit"
27
26
  },
28
27
  "license": "MIT",
29
28
  "repository": {
@@ -103,9 +102,9 @@
103
102
  ],
104
103
  "type": "commonjs",
105
104
  "devDependencies": {
106
- "@types/node": "^20.11.27",
107
- "@typescript-eslint/eslint-plugin": "^7.2.0",
108
- "@typescript-eslint/parser": "^7.2.0",
105
+ "@types/node": "^20.12.11",
106
+ "@typescript-eslint/eslint-plugin": "^7.8.0",
107
+ "@typescript-eslint/parser": "^7.8.0",
109
108
  "c8": "^9.1.0",
110
109
  "eslint": "^8.57.0",
111
110
  "eslint-config-prettier": "^9.1.0",
@@ -116,6 +115,6 @@
116
115
  "prettier": "^3.2.5",
117
116
  "shx": "^0.3.4",
118
117
  "tsx": "4.2.1",
119
- "typescript": "^5.4.2"
118
+ "typescript": "^5.4.5"
120
119
  }
121
120
  }