@wdio/local-runner 7.17.0 → 7.18.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/build/constants.d.ts +7 -0
- package/build/constants.d.ts.map +1 -0
- package/build/constants.js +13 -0
- package/build/index.d.ts +29 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +85 -0
- package/build/repl.d.ts +15 -0
- package/build/repl.d.ts.map +1 -0
- package/build/repl.js +48 -0
- package/build/replQueue.d.ts +15 -0
- package/build/replQueue.d.ts.map +1 -0
- package/build/replQueue.js +44 -0
- package/build/run.d.ts +15 -0
- package/build/run.d.ts.map +1 -0
- package/build/run.js +48 -0
- package/build/stdStream.d.ts +8 -0
- package/build/stdStream.d.ts.map +1 -0
- package/build/stdStream.js +27 -0
- package/build/transformStream.d.ts +4 -0
- package/build/transformStream.d.ts.map +1 -0
- package/build/transformStream.js +39 -0
- package/build/utils.d.ts +4 -0
- package/build/utils.d.ts.map +1 -0
- package/build/utils.js +10 -0
- package/build/worker.d.ts +56 -0
- package/build/worker.d.ts.map +1 -0
- package/build/worker.js +158 -0
- package/package.json +6 -6
|
@@ -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
|
+
};
|
package/build/index.d.ts
ADDED
|
@@ -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;
|
package/build/repl.d.ts
ADDED
|
@@ -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 @@
|
|
|
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
|
+
}
|
package/build/utils.d.ts
ADDED
|
@@ -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"}
|
package/build/worker.js
ADDED
|
@@ -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.
|
|
3
|
+
"version": "7.18.0",
|
|
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.
|
|
28
|
-
"@wdio/repl": "7.
|
|
29
|
-
"@wdio/runner": "7.
|
|
30
|
-
"@wdio/types": "7.
|
|
27
|
+
"@wdio/logger": "7.17.3",
|
|
28
|
+
"@wdio/repl": "7.18.0",
|
|
29
|
+
"@wdio/runner": "7.18.0",
|
|
30
|
+
"@wdio/types": "7.18.0",
|
|
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": "
|
|
42
|
+
"gitHead": "44729cdd585af3ad69f2093f32377f297f5ac344"
|
|
43
43
|
}
|