@wdio/local-runner 7.17.0 → 7.17.3

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.
@@ -0,0 +1,7 @@
1
+ export declare const SHUTDOWN_TIMEOUT = 5000;
2
+ export declare const DEBUGGER_MESSAGES: string[];
3
+ export declare const BUFFER_OPTIONS: {
4
+ initialSize: number;
5
+ incrementAmount: number;
6
+ };
7
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,OAAO,CAAA;AAEpC,eAAO,MAAM,iBAAiB,UAI7B,CAAA;AAED,eAAO,MAAM,cAAc;;;CAG1B,CAAA"}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BUFFER_OPTIONS = exports.DEBUGGER_MESSAGES = exports.SHUTDOWN_TIMEOUT = void 0;
4
+ exports.SHUTDOWN_TIMEOUT = 5000;
5
+ exports.DEBUGGER_MESSAGES = [
6
+ 'Debugger listening on',
7
+ 'Debugger attached',
8
+ 'Waiting for the debugger'
9
+ ];
10
+ exports.BUFFER_OPTIONS = {
11
+ initialSize: (1000 * 1024),
12
+ incrementAmount: (100 * 1024) // grow by 10 kilobytes each time buffer overflows.
13
+ };
@@ -0,0 +1,29 @@
1
+ import { WritableStreamBuffer } from 'stream-buffers';
2
+ import type { Options, Workers } from '@wdio/types';
3
+ import WorkerInstance from './worker';
4
+ interface RunArgs extends Workers.WorkerRunPayload {
5
+ command: string;
6
+ args: any;
7
+ }
8
+ export default class LocalRunner {
9
+ private _config;
10
+ workerPool: Record<string, WorkerInstance>;
11
+ stdout: WritableStreamBuffer;
12
+ stderr: WritableStreamBuffer;
13
+ constructor(configFile: unknown, _config: Options.Testrunner);
14
+ /**
15
+ * nothing to initialise when running locally
16
+ */
17
+ initialise(): void;
18
+ getWorkerCount(): number;
19
+ run({ command, args, ...workerOptions }: RunArgs): WorkerInstance;
20
+ /**
21
+ * shutdown all worker processes
22
+ *
23
+ * @return {Promise} resolves when all worker have been shutdown or
24
+ * a timeout was reached
25
+ */
26
+ shutdown(): Promise<void>;
27
+ }
28
+ export {};
29
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AACrD,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAEnD,OAAO,cAAc,MAAM,UAAU,CAAA;AAKrC,UAAU,OAAQ,SAAQ,OAAO,CAAC,gBAAgB;IAC9C,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,GAAG,CAAA;CACZ;AAED,MAAM,CAAC,OAAO,OAAO,WAAW;IAQxB,OAAO,CAAC,OAAO;IAPnB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAK;IAE/C,MAAM,uBAA2C;IACjD,MAAM,uBAA2C;gBAG7C,UAAU,EAAE,OAAO,EACX,OAAO,EAAE,OAAO,CAAC,UAAU;IAGvC;;OAEG;IACH,UAAU;IAEV,cAAc;IAId,GAAG,CAAE,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,aAAa,EAAE,EAAE,OAAO;IAiBjD;;;;;OAKG;IACH,QAAQ;CA2CX"}
package/build/index.js ADDED
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const logger_1 = __importDefault(require("@wdio/logger"));
7
+ const stream_buffers_1 = require("stream-buffers");
8
+ const worker_1 = __importDefault(require("./worker"));
9
+ const constants_1 = require("./constants");
10
+ const log = (0, logger_1.default)('@wdio/local-runner');
11
+ class LocalRunner {
12
+ constructor(configFile, _config) {
13
+ this._config = _config;
14
+ this.workerPool = {};
15
+ this.stdout = new stream_buffers_1.WritableStreamBuffer(constants_1.BUFFER_OPTIONS);
16
+ this.stderr = new stream_buffers_1.WritableStreamBuffer(constants_1.BUFFER_OPTIONS);
17
+ }
18
+ /**
19
+ * nothing to initialise when running locally
20
+ */
21
+ initialise() { }
22
+ getWorkerCount() {
23
+ return Object.keys(this.workerPool).length;
24
+ }
25
+ run({ command, args, ...workerOptions }) {
26
+ /**
27
+ * adjust max listeners on stdout/stderr when creating listeners
28
+ */
29
+ const workerCnt = this.getWorkerCount();
30
+ if (workerCnt >= process.stdout.getMaxListeners() - 2) {
31
+ process.stdout.setMaxListeners(workerCnt + 2);
32
+ process.stderr.setMaxListeners(workerCnt + 2);
33
+ }
34
+ const worker = new worker_1.default(this._config, workerOptions, this.stdout, this.stderr);
35
+ this.workerPool[workerOptions.cid] = worker;
36
+ worker.postMessage(command, args);
37
+ return worker;
38
+ }
39
+ /**
40
+ * shutdown all worker processes
41
+ *
42
+ * @return {Promise} resolves when all worker have been shutdown or
43
+ * a timeout was reached
44
+ */
45
+ shutdown() {
46
+ log.info('Shutting down spawned worker');
47
+ for (const [cid, worker] of Object.entries(this.workerPool)) {
48
+ const { caps, server, sessionId, config, isMultiremote, instances } = worker;
49
+ let payload = {};
50
+ /**
51
+ * put connection information to payload if in watch mode
52
+ * in order to attach to browser session and kill it
53
+ */
54
+ if (config && config.watch && (sessionId || isMultiremote)) {
55
+ payload = {
56
+ config: { ...server, sessionId },
57
+ caps,
58
+ watch: true,
59
+ isMultiremote,
60
+ instances
61
+ };
62
+ }
63
+ else if (!worker.isBusy) {
64
+ delete this.workerPool[cid];
65
+ continue;
66
+ }
67
+ worker.postMessage('endSession', payload);
68
+ }
69
+ return new Promise((resolve) => {
70
+ const timeout = setTimeout(resolve, constants_1.SHUTDOWN_TIMEOUT);
71
+ const interval = setInterval(() => {
72
+ const busyWorker = Object.entries(this.workerPool)
73
+ .filter(([, worker]) => worker.isBusy).length;
74
+ log.info(`Waiting for ${busyWorker} to shut down gracefully`);
75
+ if (busyWorker === 0) {
76
+ clearTimeout(timeout);
77
+ clearInterval(interval);
78
+ log.info('shutting down');
79
+ return resolve();
80
+ }
81
+ }, 250);
82
+ });
83
+ }
84
+ }
85
+ exports.default = LocalRunner;
@@ -0,0 +1,15 @@
1
+ /// <reference types="node" />
2
+ import vm from 'vm';
3
+ import WDIORepl, { ReplConfig, ReplCallback } from '@wdio/repl';
4
+ import type { ChildProcess } from 'child_process';
5
+ export default class WDIORunnerRepl extends WDIORepl {
6
+ childProcess: ChildProcess;
7
+ callback?: ReplCallback;
8
+ commandIsRunning: boolean;
9
+ constructor(childProcess: ChildProcess, options: ReplConfig);
10
+ private _getError;
11
+ eval(cmd: string, context: vm.Context, filename: string, callback: ReplCallback): void;
12
+ onResult(params: any): void;
13
+ start(context?: vm.Context): Promise<unknown>;
14
+ }
15
+ //# sourceMappingURL=repl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../src/repl.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AAEnB,OAAO,QAAQ,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAEjD,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,QAAQ;IAChD,YAAY,EAAE,YAAY,CAAA;IAC1B,QAAQ,CAAC,EAAE,YAAY,CAAA;IACvB,gBAAgB,UAAQ;gBAEX,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU;IAK5D,OAAO,CAAC,SAAS;IAUjB,IAAI,CAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY;IAehF,QAAQ,CAAE,MAAM,EAAE,GAAG;IAUrB,KAAK,CAAE,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO;CAQ9B"}
package/build/repl.js ADDED
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const repl_1 = __importDefault(require("@wdio/repl"));
7
+ class WDIORunnerRepl extends repl_1.default {
8
+ constructor(childProcess, options) {
9
+ super(options);
10
+ this.commandIsRunning = false;
11
+ this.childProcess = childProcess;
12
+ }
13
+ _getError(params) {
14
+ if (!params.error) {
15
+ return null;
16
+ }
17
+ const err = new Error(params.message);
18
+ err.stack = params.stack;
19
+ return err;
20
+ }
21
+ eval(cmd, context, filename, callback) {
22
+ if (this.commandIsRunning) {
23
+ return;
24
+ }
25
+ this.commandIsRunning = true;
26
+ this.childProcess.send({
27
+ origin: 'debugger',
28
+ name: 'eval',
29
+ content: { cmd }
30
+ });
31
+ this.callback = callback;
32
+ }
33
+ onResult(params) {
34
+ const error = this._getError(params);
35
+ if (this.callback) {
36
+ this.callback(error, params.result);
37
+ }
38
+ this.commandIsRunning = false;
39
+ }
40
+ start(context) {
41
+ this.childProcess.send({
42
+ origin: 'debugger',
43
+ name: 'start'
44
+ });
45
+ return super.start(context);
46
+ }
47
+ }
48
+ exports.default = WDIORunnerRepl;
@@ -0,0 +1,15 @@
1
+ /// <reference types="node" />
2
+ import type { ChildProcess } from 'child_process';
3
+ import WDIORepl from './repl';
4
+ /**
5
+ * repl queue class
6
+ * allows to run debug commands in mutliple workers one after another
7
+ */
8
+ export default class ReplQueue {
9
+ private _repls;
10
+ runningRepl?: WDIORepl;
11
+ add(childProcess: ChildProcess, options: any, onStart: Function, onEnd: Function): void;
12
+ next(): void;
13
+ get isRunning(): boolean;
14
+ }
15
+ //# sourceMappingURL=replQueue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replQueue.d.ts","sourceRoot":"","sources":["../src/replQueue.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAEjD,OAAO,QAAQ,MAAM,QAAQ,CAAA;AAS7B;;;GAGG;AACH,MAAM,CAAC,OAAO,OAAO,SAAS;IAC1B,OAAO,CAAC,MAAM,CAAa;IAC3B,WAAW,CAAC,EAAE,QAAQ,CAAA;IAEtB,GAAG,CAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ;IAIjF,IAAI;IA2BJ,IAAI,SAAS,YAEZ;CACJ"}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const repl_1 = __importDefault(require("./repl"));
7
+ /**
8
+ * repl queue class
9
+ * allows to run debug commands in mutliple workers one after another
10
+ */
11
+ class ReplQueue {
12
+ constructor() {
13
+ this._repls = [];
14
+ }
15
+ add(childProcess, options, onStart, onEnd) {
16
+ this._repls.push({ childProcess, options, onStart, onEnd });
17
+ }
18
+ next() {
19
+ if (this.isRunning || this._repls.length === 0) {
20
+ return;
21
+ }
22
+ const nextRepl = this._repls.shift();
23
+ if (!nextRepl) {
24
+ return;
25
+ }
26
+ const { childProcess, options, onStart, onEnd } = nextRepl;
27
+ const runningRepl = this.runningRepl = new repl_1.default(childProcess, options);
28
+ onStart();
29
+ runningRepl.start().then(() => {
30
+ const ev = {
31
+ origin: 'debugger',
32
+ name: 'stop'
33
+ };
34
+ runningRepl.childProcess.send(ev);
35
+ onEnd(ev);
36
+ delete this.runningRepl;
37
+ this.next();
38
+ });
39
+ }
40
+ get isRunning() {
41
+ return Boolean(this.runningRepl);
42
+ }
43
+ }
44
+ exports.default = ReplQueue;
package/build/run.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ /// <reference types="node" />
2
+ /**
3
+ * ToDo(Christian): remove when @wdio/runner got typed
4
+ */
5
+ interface RunnerInterface extends NodeJS.EventEmitter {
6
+ sigintWasCalled: boolean;
7
+ [key: string]: any;
8
+ }
9
+ export declare const runner: RunnerInterface;
10
+ /**
11
+ * catch sigint messages as they are handled by main process
12
+ */
13
+ export declare const exitHookFn: (callback: () => void) => void;
14
+ export {};
15
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":";AAUA;;GAEG;AACH,UAAU,eAAgB,SAAQ,MAAM,CAAC,YAAY;IACjD,eAAe,EAAE,OAAO,CAAA;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACrB;AAED,eAAO,MAAM,MAAM,iBAA6C,CAAA;AA8BhE;;GAEG;AACH,eAAO,MAAM,UAAU,aAAc,MAAM,IAAI,SAQ9C,CAAA"}
package/build/run.js ADDED
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.exitHookFn = exports.runner = void 0;
7
+ const async_exit_hook_1 = __importDefault(require("async-exit-hook"));
8
+ const runner_1 = __importDefault(require("@wdio/runner"));
9
+ const logger_1 = __importDefault(require("@wdio/logger"));
10
+ const constants_1 = require("./constants");
11
+ const log = (0, logger_1.default)('@wdio/local-runner');
12
+ exports.runner = new runner_1.default();
13
+ exports.runner.on('exit', process.exit.bind(process));
14
+ exports.runner.on('error', ({ name, message, stack }) => process.send({
15
+ origin: 'worker',
16
+ name: 'error',
17
+ content: { name, message, stack }
18
+ }));
19
+ process.on('message', (m) => {
20
+ if (!m || !m.command) {
21
+ return;
22
+ }
23
+ log.info(`Run worker command: ${m.command}`);
24
+ exports.runner[m.command](m).then((result) => process.send({
25
+ origin: 'worker',
26
+ name: 'finisedCommand',
27
+ content: {
28
+ command: m.command,
29
+ result
30
+ }
31
+ }), (e) => {
32
+ log.error(`Failed launching test session: ${e.stack}`);
33
+ setTimeout(() => process.exit(1), 10);
34
+ });
35
+ });
36
+ /**
37
+ * catch sigint messages as they are handled by main process
38
+ */
39
+ const exitHookFn = (callback) => {
40
+ if (!callback) {
41
+ return;
42
+ }
43
+ exports.runner.sigintWasCalled = true;
44
+ log.info(`Received SIGINT, giving process ${constants_1.SHUTDOWN_TIMEOUT}ms to shutdown gracefully`);
45
+ setTimeout(callback, constants_1.SHUTDOWN_TIMEOUT);
46
+ };
47
+ exports.exitHookFn = exitHookFn;
48
+ (0, async_exit_hook_1.default)(exports.exitHookFn);
@@ -0,0 +1,8 @@
1
+ /// <reference types="node" />
2
+ import { Transform, TransformCallback } from 'stream';
3
+ export default class RunnerStream extends Transform {
4
+ constructor();
5
+ _transform(chunk: any, encoding: BufferEncoding, callback: TransformCallback): void;
6
+ _final(callback: (error?: Error | undefined) => void): void;
7
+ }
8
+ //# sourceMappingURL=stdStream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdStream.d.ts","sourceRoot":"","sources":["../src/stdStream.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAA;AAGrD,MAAM,CAAC,OAAO,OAAO,YAAa,SAAQ,SAAS;;IAgB/C,UAAU,CAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAIpF,MAAM,CAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,KAAK,IAAI,GAAG,IAAI;CAI/D"}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const stream_1 = require("stream");
4
+ const utils_1 = require("./utils");
5
+ class RunnerStream extends stream_1.Transform {
6
+ constructor() {
7
+ super();
8
+ /**
9
+ * Remove events that are automatically created by Writable stream
10
+ */
11
+ this.on('pipe', () => {
12
+ (0, utils_1.removeLastListener)(this, 'close');
13
+ (0, utils_1.removeLastListener)(this, 'drain');
14
+ (0, utils_1.removeLastListener)(this, 'error');
15
+ (0, utils_1.removeLastListener)(this, 'finish');
16
+ (0, utils_1.removeLastListener)(this, 'unpipe');
17
+ });
18
+ }
19
+ _transform(chunk, encoding, callback) {
20
+ callback(undefined, chunk);
21
+ }
22
+ _final(callback) {
23
+ this.unpipe();
24
+ callback();
25
+ }
26
+ }
27
+ exports.default = RunnerStream;
@@ -0,0 +1,4 @@
1
+ /// <reference types="node" />
2
+ import { Readable } from 'stream';
3
+ export default function runnerTransformStream(cid: string, inputStream: Readable): Readable;
4
+ //# sourceMappingURL=transformStream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transformStream.d.ts","sourceRoot":"","sources":["../src/transformStream.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,QAAQ,EAAgC,MAAM,QAAQ,CAAA;AAG/D,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,GAAG,QAAQ,CAK1F"}
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const split = require("split2");
4
+ const stream_1 = require("stream");
5
+ const constants_1 = require("./constants");
6
+ function runnerTransformStream(cid, inputStream) {
7
+ return inputStream
8
+ .pipe(split(/\r?\n/, line => `${line}\n`))
9
+ .pipe(ignore(constants_1.DEBUGGER_MESSAGES))
10
+ .pipe(map(line => `[${cid}] ${line}`));
11
+ }
12
+ exports.default = runnerTransformStream;
13
+ function ignore(patternsToIgnore) {
14
+ return new stream_1.Transform({
15
+ decodeStrings: false,
16
+ transform(chunk, encoding, next) {
17
+ if (patternsToIgnore.some(m => chunk.startsWith(m))) {
18
+ return next();
19
+ }
20
+ return next(null, chunk);
21
+ },
22
+ final(next) {
23
+ this.unpipe();
24
+ next();
25
+ },
26
+ });
27
+ }
28
+ function map(mapper) {
29
+ return new stream_1.Transform({
30
+ decodeStrings: false,
31
+ transform(chunk, encoding, next) {
32
+ return next(null, mapper(chunk));
33
+ },
34
+ final(next) {
35
+ this.unpipe();
36
+ next();
37
+ },
38
+ });
39
+ }
@@ -0,0 +1,4 @@
1
+ /// <reference types="node" />
2
+ import type { Transform } from 'stream';
3
+ export declare function removeLastListener(target: Transform, eventName: string): void;
4
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAEvC,wBAAgB,kBAAkB,CAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAK9E"}
package/build/utils.js ADDED
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.removeLastListener = void 0;
4
+ function removeLastListener(target, eventName) {
5
+ const listener = target.listeners(eventName).reverse()[0];
6
+ if (listener) {
7
+ target.removeListener(eventName, listener);
8
+ }
9
+ }
10
+ exports.removeLastListener = removeLastListener;
@@ -0,0 +1,56 @@
1
+ /// <reference types="node" />
2
+ import child from 'child_process';
3
+ import { EventEmitter } from 'events';
4
+ import type { WritableStreamBuffer } from 'stream-buffers';
5
+ import type { ChildProcess } from 'child_process';
6
+ import type { Capabilities, Options, Workers } from '@wdio/types';
7
+ /**
8
+ * WorkerInstance
9
+ * responsible for spawning a sub process to run the framework in and handle its
10
+ * session lifetime.
11
+ */
12
+ export default class WorkerInstance extends EventEmitter implements Workers.Worker {
13
+ cid: string;
14
+ config: Options.Testrunner;
15
+ configFile: string;
16
+ caps: Capabilities.RemoteCapability;
17
+ capabilities: Capabilities.RemoteCapability;
18
+ specs: string[];
19
+ execArgv: string[];
20
+ retries: number;
21
+ stdout: WritableStreamBuffer;
22
+ stderr: WritableStreamBuffer;
23
+ childProcess?: ChildProcess;
24
+ sessionId?: string;
25
+ server?: Record<string, any>;
26
+ instances?: Record<string, {
27
+ sessionId: string;
28
+ }>;
29
+ isMultiremote?: boolean;
30
+ isBusy: boolean;
31
+ /**
32
+ * assigns paramters to scope of instance
33
+ * @param {object} config parsed configuration object
34
+ * @param {string} cid capability id (e.g. 0-1)
35
+ * @param {string} configFile path to config file (for sub process to parse)
36
+ * @param {object} caps capability object
37
+ * @param {string[]} specs list of paths to test files to run in this worker
38
+ * @param {number} retries number of retries remaining
39
+ * @param {object} execArgv execution arguments for the test run
40
+ */
41
+ constructor(config: Options.Testrunner, { cid, configFile, caps, specs, execArgv, retries }: Workers.WorkerRunPayload, stdout: WritableStreamBuffer, stderr: WritableStreamBuffer);
42
+ /**
43
+ * spawns process to kick of wdio-runner
44
+ */
45
+ startProcess(): child.ChildProcess;
46
+ private _handleMessage;
47
+ private _handleError;
48
+ private _handleExit;
49
+ /**
50
+ * sends message to sub process to execute functions in wdio-runner
51
+ * @param command method to run in wdio-runner
52
+ * @param args arguments for functions to call
53
+ */
54
+ postMessage(command: string, args: Workers.WorkerMessageArgs): void;
55
+ }
56
+ //# sourceMappingURL=worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":";AACA,OAAO,KAAK,MAAM,eAAe,CAAA;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAA;AACrC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAgBjE;;;;GAIG;AACH,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,YAAa,YAAW,OAAO,CAAC,MAAM;IAC9E,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,OAAO,CAAC,UAAU,CAAA;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,YAAY,CAAC,gBAAgB,CAAA;IACnC,YAAY,EAAE,YAAY,CAAC,gBAAgB,CAAA;IAC3C,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,oBAAoB,CAAA;IAC5B,MAAM,EAAE,oBAAoB,CAAA;IAC5B,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAE5B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACjD,aAAa,CAAC,EAAE,OAAO,CAAA;IAEvB,MAAM,UAAQ;IAEd;;;;;;;;;OASG;gBAEC,MAAM,EAAE,OAAO,CAAC,UAAU,EAC1B,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,gBAAgB,EAC7E,MAAM,EAAE,oBAAoB,EAC5B,MAAM,EAAE,oBAAoB;IAehC;;OAEG;IACH,YAAY;IAsCZ,OAAO,CAAC,cAAc;IA8CtB,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,WAAW;IAiBnB;;;;OAIG;IACH,WAAW,CAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,iBAAiB,GAAG,IAAI;CAmBvE"}
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const path_1 = __importDefault(require("path"));
7
+ const child_process_1 = __importDefault(require("child_process"));
8
+ const events_1 = require("events");
9
+ const logger_1 = __importDefault(require("@wdio/logger"));
10
+ const transformStream_1 = __importDefault(require("./transformStream"));
11
+ const replQueue_1 = __importDefault(require("./replQueue"));
12
+ const stdStream_1 = __importDefault(require("./stdStream"));
13
+ const log = (0, logger_1.default)('@wdio/local-runner');
14
+ const replQueue = new replQueue_1.default();
15
+ const stdOutStream = new stdStream_1.default();
16
+ const stdErrStream = new stdStream_1.default();
17
+ stdOutStream.pipe(process.stdout);
18
+ stdErrStream.pipe(process.stderr);
19
+ /**
20
+ * WorkerInstance
21
+ * responsible for spawning a sub process to run the framework in and handle its
22
+ * session lifetime.
23
+ */
24
+ class WorkerInstance extends events_1.EventEmitter {
25
+ /**
26
+ * assigns paramters to scope of instance
27
+ * @param {object} config parsed configuration object
28
+ * @param {string} cid capability id (e.g. 0-1)
29
+ * @param {string} configFile path to config file (for sub process to parse)
30
+ * @param {object} caps capability object
31
+ * @param {string[]} specs list of paths to test files to run in this worker
32
+ * @param {number} retries number of retries remaining
33
+ * @param {object} execArgv execution arguments for the test run
34
+ */
35
+ constructor(config, { cid, configFile, caps, specs, execArgv, retries }, stdout, stderr) {
36
+ super();
37
+ this.isBusy = false;
38
+ this.cid = cid;
39
+ this.config = config;
40
+ this.configFile = configFile;
41
+ this.caps = caps;
42
+ this.capabilities = caps;
43
+ this.specs = specs;
44
+ this.execArgv = execArgv;
45
+ this.retries = retries;
46
+ this.stdout = stdout;
47
+ this.stderr = stderr;
48
+ }
49
+ /**
50
+ * spawns process to kick of wdio-runner
51
+ */
52
+ startProcess() {
53
+ const { cid, execArgv } = this;
54
+ const argv = process.argv.slice(2);
55
+ const runnerEnv = Object.assign({}, process.env, this.config.runnerEnv, {
56
+ WDIO_WORKER: true
57
+ });
58
+ if (this.config.outputDir) {
59
+ runnerEnv.WDIO_LOG_PATH = path_1.default.join(this.config.outputDir, `wdio-${cid}.log`);
60
+ }
61
+ log.info(`Start worker ${cid} with arg: ${argv}`);
62
+ const childProcess = this.childProcess = child_process_1.default.fork(path_1.default.join(__dirname, 'run.js'), argv, {
63
+ cwd: process.cwd(),
64
+ env: runnerEnv,
65
+ execArgv,
66
+ stdio: ['inherit', 'pipe', 'pipe', 'ipc']
67
+ });
68
+ childProcess.on('message', this._handleMessage.bind(this));
69
+ childProcess.on('error', this._handleError.bind(this));
70
+ childProcess.on('exit', this._handleExit.bind(this));
71
+ /* istanbul ignore if */
72
+ if (!process.env.JEST_WORKER_ID) {
73
+ if (childProcess.stdout !== null) {
74
+ (0, transformStream_1.default)(cid, childProcess.stdout).pipe(stdOutStream);
75
+ }
76
+ if (childProcess.stderr !== null) {
77
+ (0, transformStream_1.default)(cid, childProcess.stderr).pipe(stdErrStream);
78
+ }
79
+ }
80
+ return childProcess;
81
+ }
82
+ _handleMessage(payload) {
83
+ var _a;
84
+ const { cid, childProcess } = this;
85
+ /**
86
+ * resolve pending commands
87
+ */
88
+ if (payload.name === 'finisedCommand') {
89
+ this.isBusy = false;
90
+ }
91
+ /**
92
+ * store sessionId and connection data to worker instance
93
+ */
94
+ if (payload.name === 'sessionStarted') {
95
+ if (payload.content.isMultiremote) {
96
+ Object.assign(this, payload.content);
97
+ }
98
+ else {
99
+ this.sessionId = payload.content.sessionId;
100
+ delete payload.content.sessionId;
101
+ }
102
+ return;
103
+ }
104
+ /**
105
+ * handle debug command called within worker process
106
+ */
107
+ if (childProcess && payload.origin === 'debugger' && payload.name === 'start') {
108
+ replQueue.add(childProcess, { prompt: `[${cid}] \u203A `, ...payload.params }, () => this.emit('message', Object.assign(payload, { cid })), (ev) => this.emit('message', ev));
109
+ return replQueue.next();
110
+ }
111
+ /**
112
+ * handle debugger results
113
+ */
114
+ if (replQueue.isRunning && payload.origin === 'debugger' && payload.name === 'result') {
115
+ (_a = replQueue.runningRepl) === null || _a === void 0 ? void 0 : _a.onResult(payload.params);
116
+ }
117
+ this.emit('message', Object.assign(payload, { cid }));
118
+ }
119
+ _handleError(payload) {
120
+ const { cid } = this;
121
+ this.emit('error', Object.assign(payload, { cid }));
122
+ }
123
+ _handleExit(exitCode) {
124
+ const { cid, childProcess, specs, retries } = this;
125
+ /**
126
+ * delete process of worker
127
+ */
128
+ delete this.childProcess;
129
+ this.isBusy = false;
130
+ log.debug(`Runner ${cid} finished with exit code ${exitCode}`);
131
+ this.emit('exit', { cid, exitCode, specs, retries });
132
+ if (childProcess) {
133
+ childProcess.kill('SIGTERM');
134
+ }
135
+ }
136
+ /**
137
+ * sends message to sub process to execute functions in wdio-runner
138
+ * @param command method to run in wdio-runner
139
+ * @param args arguments for functions to call
140
+ */
141
+ postMessage(command, args) {
142
+ const { cid, configFile, caps, specs, retries, isBusy } = this;
143
+ if (isBusy && command !== 'endSession') {
144
+ return log.info(`worker with cid ${cid} already busy and can't take new commands`);
145
+ }
146
+ /**
147
+ * start up process if worker hasn't done yet or if child process
148
+ * closes after running its job
149
+ */
150
+ if (!this.childProcess) {
151
+ this.childProcess = this.startProcess();
152
+ }
153
+ const cmd = { cid, command, configFile, args, caps, specs, retries };
154
+ this.childProcess.send(cmd);
155
+ this.isBusy = true;
156
+ }
157
+ }
158
+ exports.default = WorkerInstance;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wdio/local-runner",
3
- "version": "7.17.0",
3
+ "version": "7.17.3",
4
4
  "description": "A WebdriverIO runner to run tests locally",
5
5
  "author": "Christian Bromann <christian@saucelabs.com>",
6
6
  "homepage": "https://github.com/webdriverio/webdriverio/tree/main/packages/wdio-local-runner",
@@ -24,10 +24,10 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "@types/stream-buffers": "^3.0.3",
27
- "@wdio/logger": "7.16.0",
28
- "@wdio/repl": "7.17.0",
29
- "@wdio/runner": "7.17.0",
30
- "@wdio/types": "7.16.14",
27
+ "@wdio/logger": "7.17.3",
28
+ "@wdio/repl": "7.17.3",
29
+ "@wdio/runner": "7.17.3",
30
+ "@wdio/types": "7.17.3",
31
31
  "async-exit-hook": "^2.0.1",
32
32
  "split2": "^4.0.0",
33
33
  "stream-buffers": "^3.0.2"
@@ -39,5 +39,5 @@
39
39
  "access": "public"
40
40
  },
41
41
  "types": "./build/index.d.ts",
42
- "gitHead": "e18d2cde6ff979758830bdff4c3bc82ca9818b24"
42
+ "gitHead": "2bcb589dbdd10ca181f301a269b4dd158faab257"
43
43
  }