0
# WebdriverIO Local Runner
1
2
WebdriverIO Local Runner executes test files locally within isolated worker processes to achieve maximum concurrency and test isolation. It spawns a separate worker process per capability, with each worker maintaining its own browser session for complete test isolation.
3
4
## Package Information
5
6
- **Package Name**: @wdio/local-runner
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install --save-dev @wdio/local-runner`
10
11
## Core Imports
12
13
```typescript
14
import LocalRunner from "@wdio/local-runner";
15
import type { WorkerInstance, RunArgs } from "@wdio/local-runner";
16
17
// Worker process runner (separate entry point)
18
import { runner } from "@wdio/local-runner/run";
19
```
20
21
For CommonJS:
22
23
```javascript
24
const LocalRunner = require("@wdio/local-runner");
25
const { runner } = require("@wdio/local-runner/run");
26
```
27
28
## Basic Usage
29
30
```typescript
31
import LocalRunner from "@wdio/local-runner";
32
33
// Initialize the runner with WebdriverIO config
34
const runner = new LocalRunner({} as never, {
35
autoXvfb: true,
36
outputDir: "./logs",
37
runnerEnv: { NODE_ENV: "test" }
38
} as WebdriverIO.Config);
39
40
// Initialize the runner
41
await runner.initialize();
42
43
// Run a test worker
44
const worker = await runner.run({
45
cid: "0-0",
46
command: "run",
47
configFile: "/path/to/wdio.conf.js",
48
args: {},
49
caps: { browserName: "chrome" },
50
specs: ["./test/example.spec.js"],
51
execArgv: [],
52
retries: 0
53
});
54
55
// Shutdown all workers when done
56
await runner.shutdown();
57
```
58
59
## Architecture
60
61
WebdriverIO Local Runner is built around several key components:
62
63
- **LocalRunner**: Main class that manages the worker pool and coordinates test execution
64
- **WorkerInstance**: Individual worker process manager that handles test execution in isolation
65
- **Runner Process**: Worker child process executor that runs the actual test framework
66
- **Process Management**: Each worker runs as a separate Node.js child process for complete isolation
67
- **IPC Message System**: Inter-process communication using Node.js child_process messaging
68
- **Xvfb Integration**: Automatic virtual display setup for headless browser testing with lazy initialization
69
- **Stream Management**: Aggregated output handling with capability ID prefixing and transformation
70
- **REPL Integration**: Interactive debugging support with queue management for multiple workers
71
- **Buffer Management**: Stream buffering for stdout/stderr aggregation with configurable options
72
73
## Capabilities
74
75
### Runner Management
76
77
Core runner functionality for managing worker processes and coordinating test execution across multiple isolated environments.
78
79
```typescript { .api }
80
class LocalRunner {
81
workerPool: Record<string, WorkerInstance>;
82
stdout: WritableStreamBuffer;
83
stderr: WritableStreamBuffer;
84
85
constructor(options: never, config: WebdriverIO.Config);
86
initialize(): Promise<void>;
87
getWorkerCount(): number;
88
run(args: RunArgs): Promise<WorkerInstance>;
89
shutdown(): Promise<boolean>;
90
}
91
92
interface RunArgs extends Workers.WorkerRunPayload {
93
command: string;
94
args: Workers.WorkerMessageArgs;
95
cid: string;
96
}
97
```
98
99
[Runner Management](./runner-management.md)
100
101
### Worker Process Management
102
103
Individual worker process management with lifecycle control, message passing, and browser session handling.
104
105
```typescript { .api }
106
class WorkerInstance extends EventEmitter implements Workers.Worker {
107
cid: string;
108
config: WebdriverIO.Config;
109
configFile: string;
110
caps: WebdriverIO.Capabilities;
111
capabilities: WebdriverIO.Capabilities;
112
specs: string[];
113
execArgv: string[];
114
retries: number;
115
stdout: WritableStreamBuffer;
116
stderr: WritableStreamBuffer;
117
childProcess?: ChildProcess;
118
sessionId?: string;
119
server?: Record<string, string>;
120
instances?: Record<string, { sessionId: string }>;
121
isMultiremote?: boolean;
122
isBusy: boolean;
123
isKilled: boolean;
124
isReady: Promise<boolean>;
125
isSetup: Promise<boolean>;
126
127
constructor(
128
config: WebdriverIO.Config,
129
payload: Workers.WorkerRunPayload,
130
stdout: WritableStreamBuffer,
131
stderr: WritableStreamBuffer,
132
xvfbManager: XvfbManager
133
);
134
135
startProcess(): Promise<ChildProcess>;
136
postMessage(
137
command: string,
138
args: Workers.WorkerMessageArgs,
139
requiresSetup?: boolean
140
): Promise<void>;
141
}
142
```
143
144
[Worker Process Management](./worker-management.md)
145
146
### Worker Process Execution
147
148
Worker child process executor that runs the actual test framework in isolated processes.
149
150
```typescript { .api }
151
// Exported from './run' entry point
152
interface RunnerInterface extends NodeJS.EventEmitter {
153
sigintWasCalled: boolean;
154
[key: string]: unknown;
155
}
156
157
const runner: RunnerInterface;
158
```
159
160
[Worker Process Execution](./worker-process-execution.md)
161
162
### Stream Management and Debugging
163
164
Advanced stream handling, output transformation, and interactive debugging capabilities.
165
166
```typescript { .api }
167
function runnerTransformStream(
168
cid: string,
169
inputStream: Readable,
170
aggregator?: string[]
171
): Readable;
172
173
class ReplQueue {
174
isRunning: boolean;
175
add(childProcess: ChildProcess, config: ReplConfig, onStart: () => void, onResult: (ev: unknown) => void): void;
176
next(): void;
177
}
178
179
const SHUTDOWN_TIMEOUT: 5000;
180
const DEBUGGER_MESSAGES: string[];
181
const BUFFER_OPTIONS: { initialSize: number; incrementAmount: number; };
182
```
183
184
[Stream Management and Debugging](./stream-debugging.md)
185
186
## Types
187
188
```typescript { .api }
189
interface Workers.WorkerRunPayload {
190
cid: string;
191
configFile: string;
192
caps: WebdriverIO.Capabilities;
193
specs: string[];
194
execArgv: string[];
195
retries: number;
196
}
197
198
interface Workers.WorkerMessageArgs {
199
[key: string]: any;
200
}
201
202
interface Workers.WorkerMessage {
203
name: string;
204
origin: string;
205
content?: any;
206
params?: any;
207
}
208
209
interface Workers.WorkerCommand {
210
cid: string;
211
command: string;
212
configFile: string;
213
args: Workers.WorkerMessageArgs;
214
caps: WebdriverIO.Capabilities;
215
specs: string[];
216
retries: number;
217
}
218
219
interface Workers.Worker {
220
cid: string;
221
isBusy: boolean;
222
// Additional worker interface properties
223
}
224
225
interface WebdriverIO.Config {
226
autoXvfb?: boolean;
227
xvfbAutoInstall?: string | boolean | object;
228
xvfbAutoInstallMode?: string;
229
xvfbAutoInstallCommand?: string;
230
xvfbMaxRetries?: number;
231
xvfbRetryDelay?: number;
232
outputDir?: string;
233
runnerEnv?: Record<string, any>;
234
watch?: boolean;
235
groupLogsByTestSpec?: boolean;
236
}
237
238
interface WebdriverIO.Capabilities {
239
browserName?: string;
240
[key: string]: any;
241
}
242
243
// External dependency types
244
interface WritableStreamBuffer {
245
// From 'stream-buffers' package
246
getContents(): Buffer;
247
}
248
249
interface XvfbManager {
250
// From '@wdio/xvfb' package
251
init(capabilities: WebdriverIO.Capabilities): Promise<boolean>;
252
shouldRun(): boolean;
253
}
254
255
interface ProcessFactory {
256
// From '@wdio/xvfb' package
257
createWorkerProcess(
258
scriptPath: string,
259
args: string[],
260
options: {
261
cwd: string;
262
env: Record<string, string>;
263
execArgv: string[];
264
stdio: any[];
265
}
266
): Promise<ChildProcess>;
267
}
268
269
interface ReplConfig {
270
// From '@wdio/repl' package
271
prompt?: string;
272
[key: string]: any;
273
}
274
275
interface ChildProcess {
276
// From Node.js 'child_process' module
277
pid?: number;
278
stdout: Readable | null;
279
stderr: Readable | null;
280
send(message: any): boolean;
281
kill(signal?: string): boolean;
282
on(event: string, listener: Function): this;
283
}
284
285
interface Readable {
286
// From Node.js 'stream' module
287
pipe(destination: any): any;
288
on(event: string, listener: Function): this;
289
}
290
291
interface Transform extends Readable {
292
// From Node.js 'stream' module
293
}
294
295
class EventEmitter {
296
// From Node.js 'events' module
297
on(event: string, listener: Function): this;
298
emit(event: string, ...args: any[]): boolean;
299
}
300
```