0
# Programmatic API
1
2
Testem provides a JavaScript API for integrating into build tools, custom workflows, and automated systems.
3
4
## Capabilities
5
6
### Api Class
7
8
Main programmatic interface for controlling testem execution modes.
9
10
```javascript { .api }
11
/**
12
* Main API class for programmatic testem control
13
*/
14
class Api {
15
/**
16
* Start development mode with file watching and interactive UI
17
* @param options - Configuration options for development mode
18
* @param finalizer - Optional callback when development session ends
19
*/
20
startDev(options: TestemOptions, finalizer?: (exitCode: number, error?: Error) => void): void;
21
22
/**
23
* Start CI mode for automated test execution
24
* @param options - Configuration options for CI mode
25
* @param finalizer - Callback when tests complete with exit code and error
26
*/
27
startCI(options: TestemOptions, finalizer?: (exitCode: number, error?: Error) => void): void;
28
29
/**
30
* Start server-only mode without launching browsers
31
* @param options - Configuration options for server mode
32
*/
33
startServer(options: TestemOptions): void;
34
35
/**
36
* Restart the current test run (development mode only)
37
*/
38
restart(): void;
39
40
/**
41
* Set default options that will be merged with runtime options
42
* @param defaultOptions - Default configuration options
43
*/
44
setDefaultOptions(defaultOptions: TestemOptions): void;
45
}
46
```
47
48
**Usage Examples:**
49
50
```javascript
51
const Api = require('testem/lib/api');
52
53
// Development mode
54
const api = new Api();
55
api.startDev({
56
port: 7357,
57
launch: ['Chrome', 'Firefox'],
58
src_files: ['src/**/*.js', 'test/**/*.js']
59
});
60
61
// CI mode with callback
62
api.startCI({
63
reporter: 'tap',
64
parallel: 3,
65
launch_in_ci: ['Chrome', 'Firefox']
66
}, (exitCode, error) => {
67
if (exitCode === 0) {
68
console.log('All tests passed!');
69
} else {
70
console.error('Tests failed:', error);
71
}
72
process.exit(exitCode);
73
});
74
75
// Server-only mode
76
api.startServer({
77
port: 8080,
78
serve_files: ['dist/bundle.js']
79
});
80
```
81
82
### Config Class
83
84
Configuration management with file parsing and option merging.
85
86
```javascript { .api }
87
/**
88
* Configuration management class
89
*/
90
class Config {
91
/**
92
* Create a new configuration instance
93
* @param appMode - Application mode (dev, ci, server)
94
* @param progOptions - Programmatic options
95
* @param config - Direct configuration object
96
*/
97
constructor(appMode: 'dev' | 'ci' | 'server', progOptions?: TestemOptions, config?: ConfigOptions);
98
99
/**
100
* Read configuration from file system
101
* @param callback - Called when configuration is loaded
102
*/
103
read(callback: () => void): void;
104
105
/**
106
* Get a configuration value
107
* @param key - Configuration key
108
* @returns Configuration value
109
*/
110
get(key: string): any;
111
112
/**
113
* Set a configuration value
114
* @param key - Configuration key
115
* @param value - Value to set
116
*/
117
set(key: string, value: any): void;
118
119
/**
120
* Resolve a file path relative to working directory
121
* @param filepath - File path to resolve
122
* @returns Absolute file path
123
*/
124
resolvePath(filepath: string): string;
125
126
/**
127
* Get client-side configuration
128
* @returns Configuration object for browser clients
129
*/
130
client(): object;
131
132
/**
133
* Print information about available launchers
134
*/
135
printLauncherInfo(): void;
136
137
/**
138
* Set default configuration options
139
* @param defaultOptions - Default options to merge
140
*/
141
setDefaultOptions(defaultOptions: TestemOptions): void;
142
}
143
```
144
145
**Usage Examples:**
146
147
```javascript
148
const Config = require('testem/lib/config');
149
150
// Create configuration
151
const config = new Config('ci', {
152
port: 7357,
153
reporter: 'tap'
154
});
155
156
// Read from file
157
config.read(() => {
158
console.log('Framework:', config.get('framework'));
159
console.log('Source files:', config.get('src_files'));
160
161
// Modify configuration
162
config.set('parallel', 5);
163
164
// Resolve paths
165
const testFile = config.resolvePath('test/runner.js');
166
});
167
```
168
169
### Server Class
170
171
Express-based server for serving test files and managing client connections.
172
173
```javascript { .api }
174
/**
175
* Web server for serving tests and managing browser connections
176
*/
177
class Server extends EventEmitter {
178
/**
179
* Create a new server instance
180
* @param config - Configuration instance
181
*/
182
constructor(config: Config);
183
184
/**
185
* Start the server
186
* @param callback - Optional callback when server starts
187
* @returns Promise that resolves when server is listening
188
*/
189
start(callback?: () => void): Promise<void>;
190
191
/**
192
* Stop the server and close all connections
193
* @param callback - Optional callback when server stops
194
* @returns Promise that resolves when server is closed
195
*/
196
stop(callback?: () => void): Promise<void>;
197
198
// Events emitted:
199
// 'server-start' - Server has started listening
200
// 'server-error' - Server encountered an error
201
}
202
```
203
204
**Usage Examples:**
205
206
```javascript
207
const Server = require('testem/lib/server');
208
const Config = require('testem/lib/config');
209
210
// Create and start server
211
const config = new Config('server', { port: 8080 });
212
config.read(() => {
213
const server = new Server(config);
214
215
server.on('server-start', () => {
216
console.log('Server started on port', config.get('port'));
217
});
218
219
server.on('server-error', (error) => {
220
console.error('Server error:', error);
221
});
222
223
server.start().then(() => {
224
console.log('Server is ready');
225
});
226
});
227
```
228
229
### App Class
230
231
Main application orchestrator that coordinates all testem components.
232
233
```javascript { .api }
234
/**
235
* Main application class that orchestrates test execution
236
*/
237
class App extends EventEmitter {
238
/**
239
* Create a new application instance
240
* @param config - Configuration instance
241
* @param finalizer - Function called when app exits
242
*/
243
constructor(config: Config, finalizer?: (exitCode: number, error?: Error) => void);
244
245
/**
246
* Start the application
247
* @param callback - Optional callback when app starts
248
* @returns Promise that resolves when app is running
249
*/
250
start(callback?: () => void): Promise<void>;
251
252
/**
253
* Exit the application
254
* @param error - Optional error that caused exit
255
*/
256
exit(error?: Error): void;
257
258
/**
259
* Trigger a new test run (development mode)
260
* @param reason - Reason for triggering run
261
*/
262
triggerRun(reason: string): void;
263
264
// Events emitted:
265
// 'tests-finish' - All tests completed successfully
266
// 'tests-error' - Tests completed with errors
267
}
268
```
269
270
**Usage Examples:**
271
272
```javascript
273
const App = require('testem/lib/app');
274
const Config = require('testem/lib/config');
275
276
// Create application
277
const config = new Config('dev', { port: 7357 });
278
config.read(() => {
279
const app = new App(config, (exitCode, error) => {
280
console.log('App exited with code:', exitCode);
281
if (error) console.error('Error:', error);
282
});
283
284
app.on('tests-finish', () => {
285
console.log('Tests completed successfully');
286
});
287
288
app.on('tests-error', () => {
289
console.log('Tests completed with errors');
290
});
291
292
app.start();
293
});
294
```
295
296
## Integration Examples
297
298
### Build Tool Integration
299
300
```javascript
301
// Example: Gulp integration
302
const gulp = require('gulp');
303
const Api = require('testem/lib/api');
304
305
gulp.task('test', (done) => {
306
const api = new Api();
307
api.startCI({
308
launch_in_ci: ['Chrome', 'Firefox'],
309
reporter: 'tap'
310
}, (exitCode, error) => {
311
if (exitCode !== 0) {
312
done(new Error('Tests failed'));
313
} else {
314
done();
315
}
316
});
317
});
318
319
// Example: Webpack plugin
320
class TestemPlugin {
321
apply(compiler) {
322
compiler.hooks.afterEmit.tapAsync('TestemPlugin', (compilation, callback) => {
323
const api = new Api();
324
api.startCI({
325
src_files: ['dist/bundle.js', 'test/**/*.js']
326
}, (exitCode) => {
327
callback();
328
});
329
});
330
}
331
}
332
```
333
334
### Custom Test Runner
335
336
```javascript
337
// Custom test runner with programmatic control
338
const Api = require('testem/lib/api');
339
const Config = require('testem/lib/config');
340
341
class CustomTestRunner {
342
constructor(options) {
343
this.api = new Api();
344
this.config = new Config('ci', options);
345
}
346
347
async run() {
348
return new Promise((resolve, reject) => {
349
this.config.read(() => {
350
this.api.startCI(this.config, (exitCode, error) => {
351
if (exitCode === 0) {
352
resolve({ success: true, exitCode });
353
} else {
354
reject({ success: false, exitCode, error });
355
}
356
});
357
});
358
});
359
}
360
}
361
362
// Usage
363
const runner = new CustomTestRunner({
364
framework: 'jasmine',
365
src_files: ['src/**/*.js', 'test/**/*.js'],
366
launch_in_ci: ['Chrome', 'Firefox']
367
});
368
369
runner.run()
370
.then(result => console.log('Tests passed'))
371
.catch(result => console.error('Tests failed:', result.error));
372
```
373
374
### Development Server Integration
375
376
```javascript
377
// Example: Express middleware integration
378
const express = require('express');
379
const Server = require('testem/lib/server');
380
const Config = require('testem/lib/config');
381
382
const app = express();
383
384
// Regular routes
385
app.get('/api/*', handleApiRequests);
386
387
// Testem integration for testing
388
const config = new Config('server', {
389
port: 0, // Use random port for testem
390
src_files: ['public/js/**/*.js', 'test/**/*.js']
391
});
392
393
config.read(() => {
394
const testemServer = new Server(config);
395
testemServer.start().then(() => {
396
const testemPort = config.get('port');
397
398
// Proxy test requests to testem
399
app.use('/testem', proxy(`http://localhost:${testemPort}`));
400
401
app.listen(3000, () => {
402
console.log('Development server with testem integration ready');
403
});
404
});
405
});
406
```