@japa/runner 1.1.1 → 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/README.md CHANGED
@@ -3,7 +3,9 @@
3
3
 
4
4
  [![github-actions-image]][github-actions-url] [![npm-image]][npm-url] [![license-image]][license-url] [![typescript-image]][typescript-url]
5
5
 
6
- Japa is an API-first testing framework. It focuses only on testing Node.js (backend) applications, thus resulting in a fast, small, and simple tests runner.
6
+ Japa is an API first testing framework. It focuses only on testing Node.js (backend) applications, thus resulting in a fast, small, and a simple tests runner.
7
+
8
+ #### 💁 Please visit https://japa.dev for documentation
7
9
 
8
10
  [github-actions-image]: https://img.shields.io/github/workflow/status/japa/runner/test?style=for-the-badge "github-actions"
9
11
 
package/build/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { TestExecutor } from '@japa/core';
1
+ import { TestExecutor, ReporterContract } from '@japa/core';
2
2
  import { Test, TestContext, Group } from './src/Core';
3
3
  import { PluginFn, ConfigureOptions, RunnerHooksHandler, RunnerHooksCleanupHandler } from './src/Contracts';
4
- export { Test, TestContext, Group, PluginFn, RunnerHooksCleanupHandler, RunnerHooksHandler };
4
+ export { Test, TestContext, Group, PluginFn, RunnerHooksCleanupHandler, RunnerHooksHandler, ReporterContract, };
5
5
  /**
6
6
  * Configure the tests runner
7
7
  */
package/build/index.js CHANGED
@@ -32,6 +32,11 @@ const refinerFilteringLayers = ['tests', 'groups', 'tags'];
32
32
  * test and the group both
33
33
  */
34
34
  let recentlyImportedFile;
35
+ /**
36
+ * Global timeout for tests. Fetched from runner options or suites
37
+ * options
38
+ */
39
+ let globalTimeout;
35
40
  /**
36
41
  * Function to create the test context for the test
37
42
  */
@@ -41,9 +46,9 @@ const getContext = (testInstance) => new Core_1.TestContext(testInstance);
41
46
  */
42
47
  const emitter = new core_1.Emitter();
43
48
  /**
44
- * The default suite for registering tests
49
+ * Active suite for tests
45
50
  */
46
- const suite = new core_1.Suite('default', emitter);
51
+ let activeSuite = new core_1.Suite('default', emitter);
47
52
  /**
48
53
  * Currently active group
49
54
  */
@@ -100,12 +105,23 @@ function isFileAllowed(filePath, filters) {
100
105
  return filePath.replace((0, path_1.extname)(filePath), '').endsWith(matcher);
101
106
  });
102
107
  }
108
+ /**
109
+ * Returns "true" when no filters are applied or the name is part
110
+ * of the applied filter
111
+ */
112
+ function isSuiteAllowed(name, filters) {
113
+ if (!filters || !filters.length) {
114
+ return true;
115
+ }
116
+ return filters.includes(name);
117
+ }
103
118
  /**
104
119
  * Configure the tests runner
105
120
  */
106
121
  function configure(options) {
107
122
  const defaultOptions = {
108
123
  files: [],
124
+ suites: [],
109
125
  plugins: [],
110
126
  reporters: [],
111
127
  timeout: 2000,
@@ -115,6 +131,7 @@ function configure(options) {
115
131
  importer: (filePath) => (0, inclusion_1.default)(filePath),
116
132
  refiner: new core_1.Refiner({}),
117
133
  forceExit: false,
134
+ configureSuite: () => { },
118
135
  };
119
136
  runnerOptions = Object.assign(defaultOptions, options);
120
137
  }
@@ -132,8 +149,8 @@ function test(title, callback) {
132
149
  /**
133
150
  * Define timeout on the test when exists globally
134
151
  */
135
- if (runnerOptions.timeout !== undefined) {
136
- testInstance.timeout(runnerOptions.timeout);
152
+ if (globalTimeout !== undefined) {
153
+ testInstance.timeout(globalTimeout);
137
154
  }
138
155
  /**
139
156
  * Define test executor function
@@ -148,7 +165,7 @@ function test(title, callback) {
148
165
  activeGroup.add(testInstance);
149
166
  }
150
167
  else {
151
- suite.add(testInstance);
168
+ activeSuite.add(testInstance);
152
169
  }
153
170
  return testInstance;
154
171
  }
@@ -173,15 +190,46 @@ test.group = function (title, callback) {
173
190
  /**
174
191
  * Add group to the default suite
175
192
  */
176
- suite.add(activeGroup);
193
+ activeSuite.add(activeGroup);
177
194
  activeGroup = undefined;
178
195
  };
196
+ /**
197
+ * Collect files using the files collector function or by processing
198
+ * the glob pattern
199
+ */
200
+ async function collectFiles(files) {
201
+ if (Array.isArray(files) || typeof files === 'string') {
202
+ return await (0, fast_glob_1.default)(files, { absolute: true, onlyFiles: true });
203
+ }
204
+ else if (typeof files === 'function') {
205
+ return await files();
206
+ }
207
+ throw new Error('Invalid value for "files" property. Expected a string, array or a function');
208
+ }
209
+ /**
210
+ * Import test files using the configured importer. Also
211
+ * filter files using the file filter. (if mentioned).
212
+ */
213
+ async function importFiles(files) {
214
+ for (let file of files) {
215
+ recentlyImportedFile = file;
216
+ if (runnerOptions.filters.files && runnerOptions.filters.files.length) {
217
+ if (isFileAllowed(file, runnerOptions.filters.files)) {
218
+ await runnerOptions.importer(file);
219
+ }
220
+ }
221
+ else {
222
+ await runnerOptions.importer(file);
223
+ }
224
+ }
225
+ }
179
226
  /**
180
227
  * Run japa tests
181
228
  */
182
229
  async function run() {
183
230
  const runner = new core_1.Runner(emitter);
184
- runner.add(suite).manageUnHandledExceptions();
231
+ runner.manageUnHandledExceptions();
232
+ runner.onSuite(runnerOptions.configureSuite);
185
233
  const hooks = new hooks_1.Hooks();
186
234
  let setupRunner;
187
235
  let teardownRunner;
@@ -216,28 +264,34 @@ async function run() {
216
264
  */
217
265
  await setupRunner.run(runner);
218
266
  /**
219
- * Step 4: Collect all test files
267
+ * Step 4: Entertain files property and import test files
268
+ * as part of the default suite
220
269
  */
221
- let files = [];
222
- if (Array.isArray(runnerOptions.files)) {
223
- files = await (0, fast_glob_1.default)(runnerOptions.files, { absolute: true, onlyFiles: true });
224
- }
225
- else if (typeof runnerOptions.files === 'function') {
226
- files = await runnerOptions.files();
270
+ if ('files' in runnerOptions && runnerOptions.files.length) {
271
+ const files = await collectFiles(runnerOptions.files);
272
+ globalTimeout = runnerOptions.timeout;
273
+ runner.add(activeSuite);
274
+ await importFiles(files);
227
275
  }
228
276
  /**
229
- * Step 5: Import files
277
+ * Step 5: Entertain suites property and import test files
278
+ * for the filtered suites.
230
279
  */
231
- for (let file of files) {
232
- recentlyImportedFile = file;
233
- if (runnerOptions.filters.files && runnerOptions.filters.files.length) {
234
- if (isFileAllowed(file, runnerOptions.filters.files)) {
235
- await runnerOptions.importer(file);
280
+ if ('suites' in runnerOptions) {
281
+ for (let suite of runnerOptions.suites) {
282
+ if (isSuiteAllowed(suite.name, runnerOptions.filters.suites)) {
283
+ if (suite.timeout !== undefined) {
284
+ globalTimeout = suite.timeout;
285
+ }
286
+ else {
287
+ globalTimeout = runnerOptions.timeout;
288
+ }
289
+ activeSuite = new core_1.Suite(suite.name, emitter);
290
+ const files = await collectFiles(suite.files);
291
+ runner.add(activeSuite);
292
+ await importFiles(files);
236
293
  }
237
294
  }
238
- else {
239
- await runnerOptions.importer(file);
240
- }
241
295
  }
242
296
  /**
243
297
  * Step 6: Add filters to the refiner
@@ -305,7 +359,7 @@ exports.run = run;
305
359
  */
306
360
  function processCliArgs(argv) {
307
361
  const parsed = (0, getopts_1.default)(argv, {
308
- string: ['tests', 'tags', 'groups', 'ignoreTags', 'files', 'timeout'],
362
+ string: ['tests', 'tags', 'groups', 'ignoreTags', 'files', 'timeout', 'suites'],
309
363
  boolean: ['forceExit'],
310
364
  alias: {
311
365
  ignoreTags: 'ignore-tags',
@@ -322,6 +376,7 @@ function processCliArgs(argv) {
322
376
  processAsString(parsed, 'groups', (groups) => (config.filters.groups = groups));
323
377
  processAsString(parsed, 'tests', (tests) => (config.filters.tests = tests));
324
378
  processAsString(parsed, 'files', (files) => (config.filters.files = files));
379
+ processAsString(parsed, 'suites', (suites) => (config.filters.suites = suites));
325
380
  if (parsed.timeout) {
326
381
  const value = Number(parsed.timeout);
327
382
  if (!isNaN(value)) {
@@ -1,4 +1,4 @@
1
- import { Runner, Refiner, FilteringOptions, ReporterContract } from '@japa/core';
1
+ import { Runner, Refiner, FilteringOptions, ReporterContract, Suite } from '@japa/core';
2
2
  import { Test, Group, TestContext } from '../Core';
3
3
  /**
4
4
  * The cleanup function for runner hooks
@@ -13,6 +13,7 @@ export declare type RunnerHooksHandler = (runner: Runner<TestContext>) => Promis
13
13
  */
14
14
  export declare type Filters = FilteringOptions & {
15
15
  files?: string[];
16
+ suites?: string[];
16
17
  };
17
18
  /**
18
19
  * Shape of the plugin function
@@ -23,13 +24,13 @@ export declare type PluginFn = (config: Required<ConfigureOptions>, runner: Runn
23
24
  Group: typeof Group;
24
25
  }) => void | Promise<void>;
25
26
  /**
26
- * Configuration options
27
+ * Base configuration options
27
28
  */
28
- export declare type ConfigureOptions = {
29
- files: string[] | (() => string[] | Promise<string[]>);
29
+ export declare type BaseConfigureOptions = {
30
30
  timeout?: number;
31
31
  plugins?: PluginFn[];
32
32
  filters?: Filters;
33
+ configureSuite?: (suite: Suite<TestContext>) => void;
33
34
  setup?: RunnerHooksHandler[];
34
35
  teardown?: RunnerHooksHandler[];
35
36
  reporters?: ReporterContract[];
@@ -37,3 +38,15 @@ export declare type ConfigureOptions = {
37
38
  refiner?: Refiner;
38
39
  forceExit?: boolean;
39
40
  };
41
+ /**
42
+ * Configuration options
43
+ */
44
+ export declare type ConfigureOptions = BaseConfigureOptions & ({
45
+ files: string[] | (() => string[] | Promise<string[]>);
46
+ } | {
47
+ suites: {
48
+ name: string;
49
+ files: string | string[] | (() => string[] | Promise<string[]>);
50
+ timeout?: number;
51
+ }[];
52
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@japa/runner",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "Runner for Japa testing framework",
5
5
  "main": "build/index.js",
6
6
  "files": [
@@ -35,13 +35,13 @@
35
35
  "license": "MIT",
36
36
  "devDependencies": {
37
37
  "@adonisjs/mrm-preset": "^5.0.2",
38
- "@adonisjs/require-ts": "^2.0.9",
39
- "@types/node": "^17.0.17",
38
+ "@adonisjs/require-ts": "^2.0.10",
39
+ "@types/node": "^17.0.21",
40
40
  "commitizen": "^4.2.4",
41
41
  "cz-conventional-changelog": "^3.3.0",
42
42
  "del-cli": "^4.0.1",
43
- "eslint": "^8.8.0",
44
- "eslint-config-prettier": "^8.3.0",
43
+ "eslint": "^8.10.0",
44
+ "eslint-config-prettier": "^8.4.0",
45
45
  "eslint-plugin-adonis": "^2.1.0",
46
46
  "eslint-plugin-prettier": "^4.0.0",
47
47
  "github-label-sync": "^2.0.2",
@@ -105,9 +105,9 @@
105
105
  "anyBranch": false
106
106
  },
107
107
  "dependencies": {
108
- "@japa/core": "^5.1.0",
109
- "@japa/errors-printer": "^1.3.1",
110
- "@poppinss/hooks": "^6.0.1-0",
108
+ "@japa/core": "^5.1.1",
109
+ "@japa/errors-printer": "^1.3.3",
110
+ "@poppinss/hooks": "^6.0.2-0",
111
111
  "fast-glob": "^3.2.11",
112
112
  "getopts": "^2.3.0",
113
113
  "inclusion": "^1.0.1"
@@ -116,7 +116,6 @@
116
116
  "access": "public",
117
117
  "tag": "latest"
118
118
  },
119
- "types": "./build/index.d.ts",
120
119
  "directories": {
121
120
  "test": "test"
122
121
  },