0
# Test Runner
1
2
The Web Component Tester programmatic API provides full control over test execution with event-based progress tracking and comprehensive configuration options.
3
4
## Capabilities
5
6
### Main Test Function
7
8
Runs a suite of web component tests with lifecycle events and comprehensive error handling.
9
10
```typescript { .api }
11
/**
12
* Runs a suite of web component tests
13
* @param options - Configuration object or Context instance
14
* @returns Promise that resolves when all tests complete
15
*/
16
function test(options: Config | Context): Promise<void>;
17
```
18
19
**Usage Examples:**
20
21
```javascript
22
const wct = require('web-component-tester');
23
24
// Basic test run
25
await wct.test({
26
suites: ['test/**/*.html'],
27
verbose: true
28
});
29
30
// Advanced configuration
31
await wct.test({
32
suites: ['test/unit/*.html', 'test/integration/*.js'],
33
root: './app',
34
testTimeout: 30000,
35
persistent: false,
36
plugins: {
37
local: {
38
browsers: ['chrome', 'firefox']
39
}
40
}
41
});
42
43
// Using Context for advanced control
44
const { Context } = wct;
45
const context = new Context({
46
verbose: true,
47
suites: ['test/*.html']
48
});
49
50
context.on('test-end', (browser, test, stats) => {
51
console.log(`Test "${test.title}" ${test.state}`);
52
});
53
54
await wct.test(context);
55
```
56
57
### Configuration Interface
58
59
Main configuration object for controlling test execution behavior.
60
61
```typescript { .api }
62
interface Config {
63
/** Array of test file patterns to run */
64
suites?: string[];
65
/** Output stream for test results */
66
output?: NodeJS.WritableStream;
67
/** Enable TTY-specific output formatting */
68
ttyOutput?: boolean;
69
/** Enable verbose logging */
70
verbose?: boolean;
71
/** Suppress output */
72
quiet?: boolean;
73
/** Show expanded test results */
74
expanded?: boolean;
75
/** Root directory for test files */
76
root?: string;
77
/** Test timeout in milliseconds */
78
testTimeout?: number;
79
/** Keep browsers open after tests complete */
80
persistent?: boolean;
81
/** Additional scripts to load in browser */
82
extraScripts?: string[];
83
/** Package name for client-side WCT code */
84
wctPackageName?: string;
85
/** Browser-side configuration options */
86
clientOptions?: {
87
root?: string;
88
verbose?: boolean;
89
environmentScripts?: string[];
90
};
91
/** Active browser configurations */
92
activeBrowsers?: BrowserDef[];
93
/** Plugin configurations */
94
plugins?: {[key: string]: any};
95
/** Browser-specific options */
96
browserOptions?: any;
97
/** Skip cleanup after tests */
98
skipCleanup?: boolean;
99
}
100
```
101
102
### Browser Definition
103
104
Configuration for individual browser instances.
105
106
```typescript { .api }
107
interface BrowserDef {
108
/** Browser name (chrome, firefox, safari, etc.) */
109
browserName?: string;
110
/** Platform/OS name */
111
platform?: string;
112
/** Browser version */
113
version?: string;
114
/** Unique browser ID (assigned automatically) */
115
id?: number;
116
/** Variant name for dependency testing */
117
variant?: string;
118
/** Additional browser-specific capabilities */
119
[key: string]: any;
120
}
121
122
type Browser = string | BrowserDef;
123
```
124
125
## Test Lifecycle Events
126
127
The test runner emits comprehensive lifecycle events for monitoring test progress:
128
129
### Event Types
130
131
```typescript { .api }
132
// Lifecycle Events
133
interface TestEvents {
134
'run-start': (options: Config) => void;
135
'browser-init': (browser: BrowserDef, stats: TestStats) => void;
136
'browser-start': (browser: BrowserDef, metadata: any, stats: TestStats) => void;
137
'sub-suite-start': (browser: BrowserDef, sharedState: any, stats: TestStats) => void;
138
'test-start': (browser: BrowserDef, test: TestCase, stats: TestStats) => void;
139
'test-end': (browser: BrowserDef, test: TestCase, stats: TestStats) => void;
140
'sub-suite-end': (browser: BrowserDef, sharedState: any, stats: TestStats) => void;
141
'browser-end': (browser: BrowserDef, error: any, stats: TestStats) => void;
142
'run-end': (error: any) => void;
143
144
// Log Events
145
'log:debug': (message: string, ...args: any[]) => void;
146
'log:info': (message: string, ...args: any[]) => void;
147
'log:warn': (message: string, ...args: any[]) => void;
148
'log:error': (message: string, ...args: any[]) => void;
149
}
150
```
151
152
### Event Usage Examples
153
154
```javascript
155
const wct = require('web-component-tester');
156
const { Context } = wct;
157
158
const context = new Context({
159
suites: ['test/*.html'],
160
verbose: true
161
});
162
163
// Track test progress
164
context.on('run-start', (options) => {
165
console.log('Starting test run with', options.activeBrowsers.length, 'browsers');
166
});
167
168
context.on('browser-start', (browser, metadata, stats) => {
169
console.log(`Browser ${browser.browserName} started`);
170
});
171
172
context.on('test-end', (browser, test, stats) => {
173
const status = test.state === 'passed' ? '✓' : '✗';
174
console.log(`${status} ${test.title} (${browser.browserName})`);
175
});
176
177
context.on('browser-end', (browser, error, stats) => {
178
if (error) {
179
console.error(`Browser ${browser.browserName} failed:`, error);
180
} else {
181
console.log(`Browser ${browser.browserName} completed: ${stats.passed}/${stats.total} passed`);
182
}
183
});
184
185
context.on('run-end', (error) => {
186
if (error) {
187
console.error('Test run failed:', error);
188
} else {
189
console.log('All tests completed successfully');
190
}
191
});
192
193
await wct.test(context);
194
```
195
196
## Advanced Usage
197
198
### Custom Reporting
199
200
```javascript
201
const wct = require('web-component-tester');
202
const fs = require('fs');
203
204
class CustomReporter {
205
constructor() {
206
this.results = [];
207
}
208
209
onTestEnd(browser, test, stats) {
210
this.results.push({
211
browser: browser.browserName,
212
test: test.title,
213
state: test.state,
214
duration: test.duration,
215
timestamp: new Date().toISOString()
216
});
217
}
218
219
onRunEnd() {
220
fs.writeFileSync('test-results.json', JSON.stringify(this.results, null, 2));
221
}
222
}
223
224
const context = new wct.Context({ suites: ['test/*.html'] });
225
const reporter = new CustomReporter();
226
227
context.on('test-end', reporter.onTestEnd.bind(reporter));
228
context.on('run-end', reporter.onRunEnd.bind(reporter));
229
230
await wct.test(context);
231
```
232
233
### Error Handling
234
235
```javascript
236
const wct = require('web-component-tester');
237
238
try {
239
await wct.test({
240
suites: ['test/*.html'],
241
testTimeout: 10000
242
});
243
console.log('All tests passed!');
244
} catch (error) {
245
console.error('Test run failed:', error.message);
246
247
// Check if it's a test failure vs system error
248
if (error.message.includes('failed')) {
249
process.exit(1); // Test failures
250
} else {
251
console.error('System error occurred');
252
process.exit(2); // System errors
253
}
254
}
255
```
256
257
### Plugin Integration
258
259
```javascript
260
const wct = require('web-component-tester');
261
262
await wct.test({
263
suites: ['test/*.html'],
264
plugins: {
265
// Local browser testing
266
local: {
267
browsers: ['chrome', 'firefox'],
268
browserOptions: {
269
chrome: ['--headless', '--disable-gpu'],
270
firefox: ['-headless']
271
}
272
},
273
// Sauce Labs testing
274
sauce: {
275
username: process.env.SAUCE_USERNAME,
276
accessKey: process.env.SAUCE_ACCESS_KEY,
277
browsers: [
278
{ browserName: 'chrome', platform: 'Windows 10' },
279
{ browserName: 'firefox', platform: 'macOS 10.15' }
280
]
281
}
282
}
283
});
284
```
285
286
## Types
287
288
```typescript { .api }
289
interface TestCase {
290
title: string;
291
state: 'passed' | 'failed' | 'pending';
292
duration?: number;
293
error?: Error;
294
}
295
296
interface TestStats {
297
passed: number;
298
pending: number;
299
failed: number;
300
total: number;
301
}
302
303
interface Context extends EventEmitter {
304
options: Config;
305
emitHook(name: string): Promise<void>;
306
plugins(): Promise<Plugin[]>;
307
}
308
```