@wdio/cli 9.0.0-alpha.9 → 9.0.1

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.
Files changed (86) hide show
  1. package/build/commands/config.d.ts.map +1 -1
  2. package/build/commands/repl.d.ts.map +1 -1
  3. package/build/commands/run.d.ts +14 -13
  4. package/build/commands/run.d.ts.map +1 -1
  5. package/build/constants.d.ts +83 -10
  6. package/build/constants.d.ts.map +1 -1
  7. package/build/index.cjs +46 -0
  8. package/build/index.d.cts +2 -0
  9. package/build/index.d.cts.map +1 -0
  10. package/build/index.js +3233 -4
  11. package/build/interface.d.ts +0 -1
  12. package/build/interface.d.ts.map +1 -1
  13. package/build/launcher.d.ts.map +1 -1
  14. package/build/run.d.ts.map +1 -1
  15. package/build/types.d.ts +3 -4
  16. package/build/types.d.ts.map +1 -1
  17. package/build/utils.d.ts +7 -11
  18. package/build/utils.d.ts.map +1 -1
  19. package/build/watcher.d.ts.map +1 -1
  20. package/package.json +20 -25
  21. package/build/cjs/index.d.ts +0 -2
  22. package/build/cjs/index.d.ts.map +0 -1
  23. package/build/cjs/index.js +0 -26
  24. package/build/cjs/package.json +0 -5
  25. package/build/commands/config.js +0 -197
  26. package/build/commands/index.js +0 -5
  27. package/build/commands/install.js +0 -109
  28. package/build/commands/repl.js +0 -50
  29. package/build/commands/run.js +0 -262
  30. package/build/constants.js +0 -909
  31. package/build/install.js +0 -38
  32. package/build/interface.js +0 -285
  33. package/build/launcher.js +0 -513
  34. package/build/run.js +0 -75
  35. package/build/templates/EjsHelpers.js +0 -59
  36. package/build/templates/EjsHelpers.ts +0 -84
  37. package/build/templates/exampleFiles/browser/Component.css.ejs +0 -121
  38. package/build/templates/exampleFiles/browser/Component.lit.ejs +0 -154
  39. package/build/templates/exampleFiles/browser/Component.lit.test.ejs +0 -24
  40. package/build/templates/exampleFiles/browser/Component.preact.ejs +0 -28
  41. package/build/templates/exampleFiles/browser/Component.preact.test.ejs +0 -59
  42. package/build/templates/exampleFiles/browser/Component.react.ejs +0 -29
  43. package/build/templates/exampleFiles/browser/Component.react.test.ejs +0 -58
  44. package/build/templates/exampleFiles/browser/Component.solid.ejs +0 -28
  45. package/build/templates/exampleFiles/browser/Component.solid.test.ejs +0 -58
  46. package/build/templates/exampleFiles/browser/Component.stencil.ejs +0 -43
  47. package/build/templates/exampleFiles/browser/Component.stencil.test.ejs +0 -45
  48. package/build/templates/exampleFiles/browser/Component.svelte.ejs +0 -47
  49. package/build/templates/exampleFiles/browser/Component.svelte.test.ejs +0 -58
  50. package/build/templates/exampleFiles/browser/Component.vue.ejs +0 -34
  51. package/build/templates/exampleFiles/browser/Component.vue.test.ejs +0 -62
  52. package/build/templates/exampleFiles/browser/standalone.test.ejs +0 -13
  53. package/build/templates/exampleFiles/cucumber/features/login.feature +0 -12
  54. package/build/templates/exampleFiles/cucumber/step_definitions/steps.js.ejs +0 -55
  55. package/build/templates/exampleFiles/mochaJasmine/test.e2e.js.ejs +0 -11
  56. package/build/templates/exampleFiles/pageobjects/login.page.js.ejs +0 -45
  57. package/build/templates/exampleFiles/pageobjects/page.js.ejs +0 -17
  58. package/build/templates/exampleFiles/pageobjects/secure.page.js.ejs +0 -20
  59. package/build/templates/exampleFiles/serenity-js/common/config/serenity.properties.ejs +0 -1
  60. package/build/templates/exampleFiles/serenity-js/common/serenity/github-api/GitHubStatus.ts.ejs +0 -41
  61. package/build/templates/exampleFiles/serenity-js/common/serenity/todo-list-app/TodoList.ts.ejs +0 -100
  62. package/build/templates/exampleFiles/serenity-js/common/serenity/todo-list-app/TodoListItem.ts.ejs +0 -36
  63. package/build/templates/exampleFiles/serenity-js/cucumber/step-definitions/steps.ts.ejs +0 -37
  64. package/build/templates/exampleFiles/serenity-js/cucumber/support/parameter.config.ts.ejs +0 -18
  65. package/build/templates/exampleFiles/serenity-js/cucumber/todo-list/completing_items.feature.ejs +0 -23
  66. package/build/templates/exampleFiles/serenity-js/cucumber/todo-list/narrative.md.ejs +0 -17
  67. package/build/templates/exampleFiles/serenity-js/jasmine/example.spec.ts.ejs +0 -86
  68. package/build/templates/exampleFiles/serenity-js/mocha/example.spec.ts.ejs +0 -88
  69. package/build/templates/snippets/afterTest.ejs +0 -20
  70. package/build/templates/snippets/capabilities.ejs +0 -57
  71. package/build/templates/snippets/cucumber.ejs +0 -50
  72. package/build/templates/snippets/electronTest.js.ejs +0 -7
  73. package/build/templates/snippets/jasmine.ejs +0 -20
  74. package/build/templates/snippets/macosTest.js.ejs +0 -11
  75. package/build/templates/snippets/mocha.ejs +0 -14
  76. package/build/templates/snippets/reporters.ejs +0 -14
  77. package/build/templates/snippets/serenity.ejs +0 -18
  78. package/build/templates/snippets/services.ejs +0 -18
  79. package/build/templates/snippets/testWithPO.js.ejs +0 -22
  80. package/build/templates/snippets/testWithoutPO.js.ejs +0 -19
  81. package/build/templates/snippets/vscodeTest.js.ejs +0 -9
  82. package/build/templates/wdio.conf.tpl.ejs +0 -422
  83. package/build/types.js +0 -1
  84. package/build/utils.js +0 -930
  85. package/build/watcher.js +0 -156
  86. /package/{LICENSE-MIT → LICENSE} +0 -0
package/build/launcher.js DELETED
@@ -1,513 +0,0 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
- import exitHook from 'async-exit-hook';
4
- import logger from '@wdio/logger';
5
- import { validateConfig } from '@wdio/config';
6
- import { ConfigParser } from '@wdio/config/node';
7
- import { initializePlugin, initializeLauncherService, sleep } from '@wdio/utils';
8
- import { setupDriver, setupBrowser } from '@wdio/utils/node';
9
- import CLInterface from './interface.js';
10
- import { runLauncherHook, runOnCompleteHook, runServiceHook } from './utils.js';
11
- import { TESTRUNNER_DEFAULTS, WORKER_GROUPLOGS_MESSAGES } from './constants.js';
12
- const log = logger('@wdio/cli:launcher');
13
- class Launcher {
14
- _configFilePath;
15
- _args;
16
- _isWatchMode;
17
- configParser;
18
- isMultiremote = false;
19
- isParallelMultiremote = false;
20
- runner;
21
- interface;
22
- _exitCode = 0;
23
- _hasTriggeredExitRoutine = false;
24
- _schedule = [];
25
- _rid = [];
26
- _runnerStarted = 0;
27
- _runnerFailed = 0;
28
- _launcher;
29
- _resolve;
30
- constructor(_configFilePath, _args = {}, _isWatchMode = false) {
31
- this._configFilePath = _configFilePath;
32
- this._args = _args;
33
- this._isWatchMode = _isWatchMode;
34
- this.configParser = new ConfigParser(this._configFilePath, this._args);
35
- }
36
- /**
37
- * run sequence
38
- * @return {Promise} that only gets resolved with either an exitCode or an error
39
- */
40
- async run() {
41
- await this.configParser.initialize(this._args);
42
- const config = this.configParser.getConfig();
43
- /**
44
- * assign parsed autocompile options into args so it can be used within the worker
45
- * without having to read the config again
46
- */
47
- this._args.autoCompileOpts = config.autoCompileOpts;
48
- const capabilities = this.configParser.getCapabilities();
49
- this.isParallelMultiremote = Array.isArray(capabilities) &&
50
- capabilities.every(cap => Object.values(cap).length > 0 && Object.values(cap).every(c => typeof c === 'object' && c.capabilities));
51
- this.isMultiremote = this.isParallelMultiremote || !Array.isArray(capabilities);
52
- validateConfig(TESTRUNNER_DEFAULTS, { ...config, capabilities });
53
- if (config.outputDir) {
54
- await fs.mkdir(path.join(config.outputDir), { recursive: true });
55
- process.env.WDIO_LOG_PATH = path.join(config.outputDir, 'wdio.log');
56
- }
57
- logger.setLogLevelsConfig(config.logLevels, config.logLevel);
58
- /**
59
- * For Parallel-Multiremote, only get the specs and excludes from the first object
60
- */
61
- const totalWorkerCnt = Array.isArray(capabilities)
62
- ? capabilities
63
- .map((c) => {
64
- if (this.isParallelMultiremote) {
65
- const keys = Object.keys(c);
66
- return this.configParser.getSpecs(c[keys[0]].capabilities.specs, c[keys[0]].capabilities.exclude).length;
67
- }
68
- return this.configParser.getSpecs(c.specs, c.exclude).length;
69
- })
70
- .reduce((a, b) => a + b, 0)
71
- : 1;
72
- this.interface = new CLInterface(config, totalWorkerCnt, this._isWatchMode);
73
- config.runnerEnv.FORCE_COLOR = Number(this.interface.hasAnsiSupport);
74
- const [runnerName, runnerOptions] = Array.isArray(config.runner) ? config.runner : [config.runner, {}];
75
- const Runner = (await initializePlugin(runnerName, 'runner')).default;
76
- this.runner = new Runner(runnerOptions, config);
77
- /**
78
- * catches ctrl+c event
79
- */
80
- exitHook(this._exitHandler.bind(this));
81
- let exitCode = 0;
82
- let error = undefined;
83
- try {
84
- const caps = this.configParser.getCapabilities();
85
- const { ignoredWorkerServices, launcherServices } = await initializeLauncherService(config, caps);
86
- this._launcher = launcherServices;
87
- this._args.ignoredWorkerServices = ignoredWorkerServices;
88
- /**
89
- * run pre test tasks for runner plugins
90
- * (e.g. deploy Lambda function to AWS)
91
- */
92
- await this.runner.initialize();
93
- /**
94
- * run onPrepare hook
95
- */
96
- log.info('Run onPrepare hook');
97
- await runLauncherHook(config.onPrepare, config, caps);
98
- await runServiceHook(this._launcher, 'onPrepare', config, caps);
99
- /**
100
- * pre-configure necessary driver for worker threads
101
- */
102
- await Promise.all([
103
- setupDriver(config, caps),
104
- setupBrowser(config, caps)
105
- ]);
106
- exitCode = await this._runMode(config, caps);
107
- /**
108
- * run onComplete hook
109
- * Even if it fails we still want to see result and end logger stream.
110
- * Also ensure that user hooks are run before service hooks so that e.g.
111
- * a user can use plugin service, e.g. shared store service is still
112
- * available running hooks in this order
113
- */
114
- log.info('Run onComplete hook');
115
- const onCompleteResults = await runOnCompleteHook(config.onComplete, config, caps, exitCode, this.interface.result);
116
- await runServiceHook(this._launcher, 'onComplete', exitCode, config, caps);
117
- // if any of the onComplete hooks failed, update the exit code
118
- exitCode = onCompleteResults.includes(1) ? 1 : exitCode;
119
- await logger.waitForBuffer();
120
- this.interface.finalise();
121
- }
122
- catch (err) {
123
- error = err;
124
- }
125
- finally {
126
- if (!this._hasTriggeredExitRoutine) {
127
- this._hasTriggeredExitRoutine = true;
128
- const passesCodeCoverage = await this.runner.shutdown();
129
- if (!passesCodeCoverage) {
130
- exitCode = exitCode || 1;
131
- }
132
- }
133
- }
134
- if (error) {
135
- this.interface.logHookError(error);
136
- throw error;
137
- }
138
- return exitCode;
139
- }
140
- /**
141
- * run without triggering onPrepare/onComplete hooks
142
- */
143
- _runMode(config, caps) {
144
- /**
145
- * fail if no caps were found
146
- */
147
- if (!caps) {
148
- return new Promise((resolve) => {
149
- log.error('Missing capabilities, exiting with failure');
150
- return resolve(1);
151
- });
152
- }
153
- /**
154
- * avoid retries in watch mode
155
- */
156
- const specFileRetries = this._isWatchMode ? 0 : config.specFileRetries;
157
- /**
158
- * schedule test runs
159
- */
160
- let cid = 0;
161
- if (this.isMultiremote && !this.isParallelMultiremote) {
162
- /**
163
- * Multiremote mode
164
- */
165
- this._schedule.push({
166
- cid: cid++,
167
- caps: caps,
168
- specs: this._formatSpecs(caps, specFileRetries),
169
- availableInstances: config.maxInstances || 1,
170
- runningInstances: 0
171
- });
172
- }
173
- else {
174
- /**
175
- * Regular mode & Parallel Multiremote
176
- */
177
- for (const capabilities of caps) {
178
- /**
179
- * when using browser runner we only allow one session per browser
180
- */
181
- const availableInstances = this.isParallelMultiremote ? config.maxInstances || 1 : config.runner === 'browser'
182
- ? 1
183
- : capabilities.maxInstances || capabilities['wdio:maxInstances'] || config.maxInstancesPerCapability;
184
- this._schedule.push({
185
- cid: cid++,
186
- caps: capabilities,
187
- specs: this._formatSpecs(capabilities, specFileRetries),
188
- availableInstances,
189
- runningInstances: 0
190
- });
191
- }
192
- }
193
- return new Promise((resolve) => {
194
- this._resolve = resolve;
195
- /**
196
- * fail if no specs were found or specified
197
- */
198
- if (Object.values(this._schedule).reduce((specCnt, schedule) => specCnt + schedule.specs.length, 0) === 0) {
199
- const { total, current } = config.shard;
200
- if (total > 1) {
201
- log.info(`No specs to execute in shard ${current}/${total}, exiting!`);
202
- return resolve(0);
203
- }
204
- log.error('No specs found to run, exiting with failure');
205
- return resolve(1);
206
- }
207
- /**
208
- * return immediately if no spec was run
209
- */
210
- if (this._runSpecs()) {
211
- resolve(0);
212
- }
213
- });
214
- }
215
- /**
216
- * Format the specs into an array of objects with files and retries
217
- */
218
- _formatSpecs(capabilities, specFileRetries) {
219
- let caps;
220
- if ('alwaysMatch' in capabilities) {
221
- caps = capabilities.alwaysMatch;
222
- }
223
- else if (typeof Object.keys(capabilities)[0] === 'object' && 'capabilities' in capabilities[Object.keys(capabilities)[0]]) {
224
- caps = {};
225
- }
226
- else {
227
- caps = capabilities;
228
- }
229
- const specs = caps.specs || caps['wdio:specs'];
230
- const excludes = caps.exclude || caps['wdio:exclude'];
231
- const files = this.configParser.getSpecs(specs, excludes);
232
- return files.map((file) => {
233
- if (typeof file === 'string') {
234
- return { files: [file], retries: specFileRetries };
235
- }
236
- else if (Array.isArray(file)) {
237
- return { files: file, retries: specFileRetries };
238
- }
239
- log.warn('Unexpected entry in specs that is neither string nor array: ', file);
240
- // Returning an empty structure to avoid undefined
241
- return { files: [], retries: specFileRetries };
242
- });
243
- }
244
- /**
245
- * run multiple single remote tests
246
- * @return {Boolean} true if all specs have been run and all instances have finished
247
- */
248
- _runSpecs() {
249
- /**
250
- * stop spawning new processes when CTRL+C was triggered
251
- */
252
- if (this._hasTriggeredExitRoutine) {
253
- return true;
254
- }
255
- const config = this.configParser.getConfig();
256
- while (this._getNumberOfRunningInstances() < config.maxInstances) {
257
- const schedulableCaps = this._schedule
258
- /**
259
- * bail if number of errors exceeds allowed
260
- */
261
- .filter(() => {
262
- const filter = typeof config.bail !== 'number' || config.bail < 1 ||
263
- config.bail > this._runnerFailed;
264
- /**
265
- * clear number of specs when filter is false
266
- */
267
- if (!filter) {
268
- this._schedule.forEach((t) => { t.specs = []; });
269
- }
270
- return filter;
271
- })
272
- /**
273
- * make sure complete number of running instances is not higher than general maxInstances number
274
- */
275
- .filter(() => this._getNumberOfRunningInstances() < config.maxInstances)
276
- /**
277
- * make sure the capability has available capacities
278
- */
279
- .filter((a) => a.availableInstances > 0)
280
- /**
281
- * make sure capability has still caps to run
282
- */
283
- .filter((a) => a.specs.length > 0)
284
- /**
285
- * make sure we are running caps with less running instances first
286
- */
287
- .sort((a, b) => a.runningInstances - b.runningInstances);
288
- /**
289
- * continue if no capability were schedulable
290
- */
291
- if (schedulableCaps.length === 0) {
292
- break;
293
- }
294
- const specs = schedulableCaps[0].specs.shift();
295
- this._startInstance(specs.files, schedulableCaps[0].caps, schedulableCaps[0].cid, specs.rid, specs.retries);
296
- schedulableCaps[0].availableInstances--;
297
- schedulableCaps[0].runningInstances++;
298
- }
299
- return this._getNumberOfRunningInstances() === 0 && this._getNumberOfSpecsLeft() === 0;
300
- }
301
- /**
302
- * gets number of all running instances
303
- * @return {number} number of running instances
304
- */
305
- _getNumberOfRunningInstances() {
306
- return this._schedule.map((a) => a.runningInstances).reduce((a, b) => a + b);
307
- }
308
- /**
309
- * get number of total specs left to complete whole suites
310
- * @return {number} specs left to complete suite
311
- */
312
- _getNumberOfSpecsLeft() {
313
- return this._schedule.map((a) => a.specs.length).reduce((a, b) => a + b);
314
- }
315
- /**
316
- * Start instance in a child process.
317
- * @param {Array} specs Specs to run
318
- * @param {number} cid Capabilities ID
319
- * @param {string} rid Runner ID override
320
- * @param {number} retries Number of retries remaining
321
- */
322
- async _startInstance(specs, caps, cid, rid, retries) {
323
- if (!this.runner || !this.interface) {
324
- throw new Error('Internal Error: no runner initialized, call run() first');
325
- }
326
- const config = this.configParser.getConfig();
327
- // wait before retrying the spec file
328
- if (typeof config.specFileRetriesDelay === 'number' && config.specFileRetries > 0 && config.specFileRetries !== retries) {
329
- await sleep(config.specFileRetriesDelay * 1000);
330
- }
331
- // Retried tests receive the cid of the failing test as rid
332
- // so they can run with the same cid of the failing test.
333
- const runnerId = rid || this._getRunnerId(cid);
334
- const processNumber = this._runnerStarted + 1;
335
- // process.debugPort defaults to 5858 and is set even when process
336
- // is not being debugged.
337
- const debugArgs = [];
338
- let debugType;
339
- let debugHost = '';
340
- const debugPort = process.debugPort;
341
- for (const i in process.execArgv) {
342
- const debugArgs = process.execArgv[i].match('--(debug|inspect)(?:-brk)?(?:=(.*):)?');
343
- if (debugArgs) {
344
- const [, type, host] = debugArgs;
345
- if (type) {
346
- debugType = type;
347
- }
348
- if (host) {
349
- debugHost = `${host}:`;
350
- }
351
- }
352
- }
353
- if (debugType) {
354
- debugArgs.push(`--${debugType}=${debugHost}${(debugPort + processNumber)}`);
355
- }
356
- // if you would like to add --debug-brk, use a different port, etc...
357
- const capExecArgs = [...(config.execArgv || [])];
358
- // The default value for child.fork execArgs is process.execArgs,
359
- // so continue to use this unless another value is specified in config.
360
- const defaultArgs = (capExecArgs.length) ? process.execArgv : [];
361
- // If an arg appears multiple times the last occurrence is used
362
- const execArgv = [...defaultArgs, ...debugArgs, ...capExecArgs];
363
- // bump up worker count
364
- this._runnerStarted++;
365
- // run worker hook to allow modify runtime and capabilities of a specific worker
366
- log.info('Run onWorkerStart hook');
367
- await runLauncherHook(config.onWorkerStart, runnerId, caps, specs, this._args, execArgv)
368
- .catch((error) => this._workerHookError(error));
369
- await runServiceHook(this._launcher, 'onWorkerStart', runnerId, caps, specs, this._args, execArgv)
370
- .catch((error) => this._workerHookError(error));
371
- // prefer launcher settings in capabilities over general launcher
372
- const worker = await this.runner.run({
373
- cid: runnerId,
374
- command: 'run',
375
- configFile: this._configFilePath,
376
- args: {
377
- ...this._args,
378
- ...(config?.autoCompileOpts
379
- ? { autoCompileOpts: config.autoCompileOpts }
380
- : {}),
381
- /**
382
- * Pass on user and key values to ensure they are available in the worker process when using
383
- * environment variables that were locally exported but not part of the environment.
384
- */
385
- user: config.user,
386
- key: config.key
387
- },
388
- caps,
389
- specs,
390
- execArgv,
391
- retries
392
- });
393
- worker.on('message', this.interface.onMessage.bind(this.interface));
394
- worker.on('error', this.interface.onMessage.bind(this.interface));
395
- worker.on('exit', (code) => {
396
- if (!this.configParser.getConfig().groupLogsByTestSpec) {
397
- return;
398
- }
399
- if (code.exitCode === 0) {
400
- console.log(WORKER_GROUPLOGS_MESSAGES.normalExit(code.cid));
401
- }
402
- else {
403
- console.log(WORKER_GROUPLOGS_MESSAGES.exitWithError(code.cid));
404
- }
405
- worker.logsAggregator.forEach((logLine) => {
406
- console.log(logLine.replace(new RegExp('\\n$'), ''));
407
- });
408
- });
409
- worker.on('exit', this._endHandler.bind(this));
410
- }
411
- _workerHookError(error) {
412
- if (!this.interface) {
413
- throw new Error('Internal Error: no interface initialized, call run() first');
414
- }
415
- this.interface.logHookError(error);
416
- if (this._resolve) {
417
- this._resolve(1);
418
- }
419
- }
420
- /**
421
- * generates a runner id
422
- * @param {number} cid capability id (unique identifier for a capability)
423
- * @return {String} runner id (combination of cid and test id e.g. 0a, 0b, 1a, 1b ...)
424
- */
425
- _getRunnerId(cid) {
426
- if (!this._rid[cid]) {
427
- this._rid[cid] = 0;
428
- }
429
- return `${cid}-${this._rid[cid]++}`;
430
- }
431
- /**
432
- * Close test runner process once all child processes have exited
433
- * @param {number} cid Capabilities ID
434
- * @param {number} exitCode exit code of child process
435
- * @param {Array} specs Specs that were run
436
- * @param {number} retries Number or retries remaining
437
- */
438
- async _endHandler({ cid: rid, exitCode, specs, retries }) {
439
- const passed = this._isWatchModeHalted() || exitCode === 0;
440
- if (!passed && retries > 0) {
441
- // Default is true, so test for false explicitly
442
- const requeue = this.configParser.getConfig().specFileRetriesDeferred !== false ? 'push' : 'unshift';
443
- this._schedule[parseInt(rid, 10)].specs[requeue]({ files: specs, retries: retries - 1, rid });
444
- }
445
- else {
446
- this._exitCode = this._isWatchModeHalted() ? 0 : this._exitCode || exitCode;
447
- this._runnerFailed += !passed ? 1 : 0;
448
- }
449
- /**
450
- * avoid emitting job:end if watch mode has been stopped by user
451
- */
452
- if (!this._isWatchModeHalted() && this.interface) {
453
- this.interface.emit('job:end', { cid: rid, passed, retries });
454
- }
455
- /**
456
- * Update schedule now this process has ended
457
- * get cid (capability id) from rid (runner id)
458
- */
459
- const cid = parseInt(rid, 10);
460
- this._schedule[cid].availableInstances++;
461
- this._schedule[cid].runningInstances--;
462
- log.info('Run onWorkerEnd hook');
463
- const config = this.configParser.getConfig();
464
- await runLauncherHook(config.onWorkerEnd, rid, exitCode, specs, retries)
465
- .catch((error) => this._workerHookError(error));
466
- await runServiceHook(this._launcher, 'onWorkerEnd', rid, exitCode, specs, retries)
467
- .catch((error) => this._workerHookError(error));
468
- /**
469
- * do nothing if
470
- * - there are specs to be executed
471
- * - we are running watch mode
472
- */
473
- const shouldRunSpecs = this._runSpecs();
474
- const inWatchMode = this._isWatchMode && !this._hasTriggeredExitRoutine;
475
- if (!shouldRunSpecs || inWatchMode) {
476
- /**
477
- * print reporter results when in watch mode
478
- */
479
- if (inWatchMode) {
480
- this.interface?.finalise();
481
- }
482
- return;
483
- }
484
- if (this._resolve) {
485
- this._resolve(passed ? this._exitCode : 1);
486
- }
487
- }
488
- /**
489
- * We need exitHandler to catch SIGINT / SIGTERM events.
490
- * Make sure all started selenium sessions get closed properly and prevent
491
- * having dead driver processes. To do so let the runner end its Selenium
492
- * session first before killing
493
- */
494
- _exitHandler(callback) {
495
- if (!callback || !this.runner || !this.interface) {
496
- return;
497
- }
498
- if (this._hasTriggeredExitRoutine) {
499
- return callback(true);
500
- }
501
- this._hasTriggeredExitRoutine = true;
502
- this.interface.sigintTrigger();
503
- return this.runner.shutdown().then(callback);
504
- }
505
- /**
506
- * returns true if user stopped watch mode, ex with ctrl+c
507
- * @returns {boolean}
508
- */
509
- _isWatchModeHalted() {
510
- return this._isWatchMode && this._hasTriggeredExitRoutine;
511
- }
512
- }
513
- export default Launcher;
package/build/run.js DELETED
@@ -1,75 +0,0 @@
1
- import fs from 'node:fs';
2
- import url from 'node:url';
3
- import path from 'node:path';
4
- import yargs from 'yargs';
5
- import { hideBin } from 'yargs/helpers';
6
- import { commands } from './commands/index.js';
7
- import { handler, cmdArgs } from './commands/run.js';
8
- import { CLI_EPILOGUE, pkg } from './constants.js';
9
- const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
10
- const DEFAULT_CONFIG_FILENAME = 'wdio.conf.js';
11
- const DESCRIPTION = [
12
- 'The `wdio` command allows you run and manage your WebdriverIO test suite.',
13
- 'If no command is provided it calls the `run` command by default, so:',
14
- '',
15
- '$ wdio wdio.conf.js',
16
- '',
17
- 'is the same as:',
18
- '$ wdio run wdio.conf.js',
19
- '',
20
- 'For more information, visit: https://webdriver.io/docs/clioptions'
21
- ];
22
- export default async function run() {
23
- const commandDir = path.join(__dirname, 'commands');
24
- const argv = yargs(hideBin(process.argv))
25
- .command(commands)
26
- .example('wdio run wdio.conf.js --suite foobar', 'Run suite on testsuite "foobar"')
27
- .example('wdio run wdio.conf.js --spec ./tests/e2e/a.js --spec ./tests/e2e/b.js', 'Run suite on specific specs')
28
- .example('wdio run wdio.conf.js --spec ./tests/e2e/a.feature:5', 'Run scenario by line number')
29
- .example('wdio run wdio.conf.js --spec ./tests/e2e/a.feature:5:10', 'Run scenarios by line number')
30
- .example('wdio run wdio.conf.js --spec ./tests/e2e/a.feature:5:10 --spec ./test/e2e/b.feature', 'Run scenarios by line number in single feature and another complete feature')
31
- .example('wdio install reporter spec', 'Install @wdio/spec-reporter')
32
- .example('wdio repl chrome -u <SAUCE_USERNAME> -k <SAUCE_ACCESS_KEY>', 'Run repl in Sauce Labs cloud')
33
- .updateStrings({ 'Commands:': `${DESCRIPTION.join('\n')}\n\nCommands:` })
34
- .version(pkg.version)
35
- .epilogue(CLI_EPILOGUE);
36
- /**
37
- * parse CLI arguments according to what run expects, without this adding
38
- * `--spec ./test.js` results in propagating the spec parameter as a
39
- * string while in reality is should be parsed into a array of strings
40
- */
41
- if (!process.argv.find((arg) => arg === '--help')) {
42
- argv.options(cmdArgs);
43
- }
44
- /**
45
- * The only way we reach this point is if the user runs the binary without a command (i.e. wdio wdio.conf.js)
46
- * We can safely assume that if this is the case, the user is trying to execute the `run` command as it
47
- * was previous to https://github.com/webdriverio/webdriverio/pull/4402
48
- *
49
- * Since the `run` command verifies if the configuration file exists before executing
50
- * we don't have to check that again here.
51
- */
52
- const params = await argv.parse();
53
- const supportedCommands = fs
54
- .readdirSync(commandDir)
55
- .map((file) => file.slice(0, -3));
56
- if (!params._ || params._.find((param) => supportedCommands.includes(param))) {
57
- return;
58
- }
59
- const args = {
60
- ...params,
61
- configPath: path.resolve(process.cwd(), params._[0] && params._[0].toString() || DEFAULT_CONFIG_FILENAME)
62
- };
63
- try {
64
- const cp = await handler(args);
65
- return cp;
66
- }
67
- catch (err) {
68
- const output = await new Promise((resolve) => (yargs(hideBin(process.argv)).parse('--help', (err, argv, output) => resolve(output))));
69
- console.error(`${output}\n\n${err.stack}`);
70
- /* istanbul ignore if */
71
- if (!process.env.VITEST_WORKER_ID) {
72
- process.exit(1);
73
- }
74
- }
75
- }
@@ -1,59 +0,0 @@
1
- export class EjsHelpers {
2
- useTypeScript;
3
- useEsm;
4
- constructor(config) {
5
- this.useTypeScript = config.useTypeScript ?? false;
6
- this.useEsm = config.useEsm ?? false;
7
- }
8
- if(condition, trueValue, falseValue = '') {
9
- return condition
10
- ? trueValue
11
- : falseValue;
12
- }
13
- ifTs = (trueValue, falseValue = '') => this.if(this.useTypeScript, trueValue, falseValue);
14
- ifEsm = (trueValue, falseValue = '') => this.if(this.useEsm, trueValue, falseValue);
15
- param(name, type) {
16
- return this.useTypeScript
17
- ? `${name}: ${type}`
18
- : name;
19
- }
20
- returns(type) {
21
- return this.useTypeScript
22
- ? `: ${type}`
23
- : '';
24
- }
25
- import(exports, moduleId) {
26
- const individualExports = exports.split(',').map(id => id.trim());
27
- const imports = this.useTypeScript
28
- ? individualExports
29
- : individualExports.filter(id => !id.startsWith('type '));
30
- if (!imports.length) {
31
- return '';
32
- }
33
- const modulePath = this.modulePathFrom(moduleId);
34
- return this.useEsm || this.useTypeScript
35
- ? `import { ${imports.join(', ')} } from '${modulePath}'`
36
- : `const { ${imports.join(', ')} } = require('${modulePath}')`;
37
- }
38
- modulePathFrom(moduleId) {
39
- if (!(moduleId.startsWith('.') && this.useEsm)) {
40
- return moduleId;
41
- }
42
- if (moduleId.endsWith('/') && this.useEsm) {
43
- return moduleId + 'index.js';
44
- }
45
- return moduleId + '.js';
46
- }
47
- export(keyword, name) {
48
- if (this.useTypeScript) {
49
- return `export ${keyword} ${name}`;
50
- }
51
- if (this.useEsm) {
52
- return `export ${keyword} ${name}`;
53
- }
54
- if (['class', 'function'].includes(keyword)) {
55
- return `module.exports.${name} = ${keyword} ${name}`;
56
- }
57
- return `module.exports.${name}`;
58
- }
59
- }