0
# Programmatic API
1
2
TestCafe's programmatic API enables you to create, configure, and run tests through JavaScript code rather than the command line, providing fine-grained control over test execution and integration with other tools.
3
4
## Capabilities
5
6
### TestCafe Instance Creation
7
8
Create and configure TestCafe instances programmatically.
9
10
```javascript { .api }
11
/**
12
* Creates a TestCafe instance for programmatic test execution
13
* @param hostname - Hostname for TestCafe servers (default: 'localhost')
14
* @param port1 - Port for main TestCafe server (default: auto-assigned)
15
* @param port2 - Port for file server (default: auto-assigned)
16
* @param sslOptions - SSL configuration for HTTPS
17
* @param developmentMode - Enable development mode features
18
* @param retryTestPages - Retry test pages on failure
19
* @param cache - Enable caching
20
* @param configFile - Path to configuration file
21
* @returns Promise resolving to TestCafe instance
22
*/
23
function createTestCafe(
24
hostname?: string,
25
port1?: number,
26
port2?: number,
27
sslOptions?: SSLOptions,
28
developmentMode?: boolean,
29
retryTestPages?: boolean,
30
cache?: boolean,
31
configFile?: string
32
): Promise<TestCafe>;
33
34
// Alternative: Configuration object approach
35
function createTestCafe(config?: TestCafeConfiguration): Promise<TestCafe>;
36
37
interface TestCafe {
38
/** Create a test runner instance */
39
createRunner(): Runner;
40
41
/** Create browser connection for remote browsers */
42
createBrowserConnection(): Promise<BrowserConnection>;
43
44
/** Create live mode runner */
45
createLiveModeRunner(): LiveModeRunner;
46
47
/** Close TestCafe instance and cleanup resources */
48
close(): Promise<void>;
49
}
50
51
interface SSLOptions {
52
key?: string;
53
cert?: string;
54
pfx?: string;
55
passphrase?: string;
56
}
57
58
interface TestCafeConfiguration {
59
hostname?: string;
60
port1?: number;
61
port2?: number;
62
ssl?: SSLOptions;
63
developmentMode?: boolean;
64
retryTestPages?: boolean;
65
cache?: boolean;
66
configFile?: string;
67
}
68
```
69
70
**Usage Examples:**
71
72
```javascript
73
import createTestCafe from 'testcafe';
74
75
// Basic TestCafe instance
76
async function runBasicTests() {
77
const testcafe = await createTestCafe('localhost', 1337, 1338);
78
79
try {
80
const runner = testcafe.createRunner();
81
82
const failedCount = await runner
83
.src(['tests/fixture1.js', 'tests/fixture2.js'])
84
.browsers(['chrome', 'firefox'])
85
.run();
86
87
console.log(`Tests failed: ${failedCount}`);
88
} finally {
89
await testcafe.close();
90
}
91
}
92
93
// Configuration object approach
94
async function runConfiguredTests() {
95
const testcafe = await createTestCafe({
96
hostname: 'localhost',
97
port1: 1337,
98
port2: 1338,
99
ssl: {
100
key: './ssl/private-key.pem',
101
cert: './ssl/certificate.pem'
102
},
103
developmentMode: true
104
});
105
106
try {
107
// Test execution code
108
} finally {
109
await testcafe.close();
110
}
111
}
112
113
// Auto-port assignment
114
async function runAutoPortTests() {
115
const testcafe = await createTestCafe(); // Uses default localhost and auto-assigned ports
116
117
try {
118
const runner = testcafe.createRunner();
119
await runner.src('tests/**/*.js').browsers('chrome').run();
120
} finally {
121
await testcafe.close();
122
}
123
}
124
```
125
126
### Test Runner Configuration
127
128
Configure test execution through the Runner interface.
129
130
```javascript { .api }
131
interface Runner {
132
/** Set test source files or globs */
133
src(source: string | string[]): Runner;
134
135
/** Set target browsers */
136
browsers(browsers: string | string[]): Runner;
137
138
/** Set test execution concurrency */
139
concurrency(concurrency: number): Runner;
140
141
/** Set test reporter */
142
reporter(reporter: string | ReporterPlugin, output?: string): Runner;
143
144
/** Set test filter */
145
filter(filter: (testName: string, fixtureName: string, fixturePath: string, testMeta: object, fixtureMeta: object) => boolean): Runner;
146
147
/** Run tests and return number of failed tests */
148
run(options?: RunOptions): Promise<number>;
149
150
/** Stop test execution */
151
stop(): Promise<void>;
152
}
153
154
interface RunOptions {
155
/** Skip JS errors in tests */
156
skipJsErrors?: boolean;
157
158
/** Disable page reloads */
159
disablePageReloads?: boolean;
160
161
/** Quarantine mode for unstable tests */
162
quarantineMode?: boolean | QuarantineOptions;
163
164
/** Debug mode */
165
debugMode?: boolean;
166
167
/** Debug on fail */
168
debugOnFail?: boolean;
169
170
/** Skip uncaught errors */
171
skipUncaughtErrors?: boolean;
172
173
/** Selector timeout */
174
selectorTimeout?: number;
175
176
/** Assertion timeout */
177
assertionTimeout?: number;
178
179
/** Page load timeout */
180
pageLoadTimeout?: number;
181
182
/** Test execution speed */
183
speed?: number;
184
185
/** Stop on first test failure */
186
stopOnFirstFail?: boolean;
187
}
188
189
interface QuarantineOptions {
190
/** Number of attempts to run failing tests */
191
attemptLimit?: number;
192
193
/** Number of successful runs required to pass */
194
successThreshold?: number;
195
}
196
```
197
198
**Usage Examples:**
199
200
```javascript
201
async function configureRunner() {
202
const testcafe = await createTestCafe();
203
204
try {
205
const runner = testcafe.createRunner();
206
207
const failedCount = await runner
208
.src(['tests/login.js', 'tests/checkout.js'])
209
.browsers(['chrome:headless', 'firefox:headless'])
210
.concurrency(3)
211
.reporter('spec')
212
.filter((testName, fixtureName) => {
213
return testName.includes('critical') || fixtureName.includes('smoke');
214
})
215
.run({
216
skipJsErrors: true,
217
quarantineMode: true,
218
speed: 0.8,
219
stopOnFirstFail: false,
220
selectorTimeout: 10000,
221
assertionTimeout: 5000
222
});
223
224
if (failedCount > 0) {
225
console.error(`${failedCount} tests failed`);
226
process.exit(1);
227
}
228
} finally {
229
await testcafe.close();
230
}
231
}
232
233
// Multiple reporter configuration
234
async function runWithMultipleReporters() {
235
const testcafe = await createTestCafe();
236
237
try {
238
const runner = testcafe.createRunner();
239
240
await runner
241
.src('tests/**/*.js')
242
.browsers('chrome')
243
.reporter([
244
{
245
name: 'spec',
246
output: process.stdout
247
},
248
{
249
name: 'json',
250
output: 'reports/test-results.json'
251
},
252
{
253
name: 'xunit',
254
output: 'reports/test-results.xml'
255
}
256
])
257
.run();
258
} finally {
259
await testcafe.close();
260
}
261
}
262
```
263
264
### Browser Management
265
266
Manage browser connections and configurations.
267
268
```javascript { .api }
269
interface BrowserConnection {
270
/** Browser connection URL for remote browsers */
271
url: string;
272
273
/** Unique identifier for the connection */
274
id: string;
275
276
/** Connection ready promise */
277
ready: Promise<void>;
278
279
/** Establish browser connection */
280
establish(userAgent: string): Promise<void>;
281
282
/** Close browser connection */
283
close(): Promise<void>;
284
}
285
286
interface LiveModeRunner extends Runner {
287
/** Watch files for changes */
288
watchFiles(files: string | string[]): LiveModeRunner;
289
290
/** Start live mode */
291
run(): Promise<void>;
292
293
/** Stop live mode */
294
stop(): Promise<void>;
295
}
296
```
297
298
**Usage Examples:**
299
300
```javascript
301
// Remote browser connection
302
async function setupRemoteBrowser() {
303
const testcafe = await createTestCafe();
304
305
try {
306
const connection = await testcafe.createBrowserConnection();
307
308
console.log(`Connect remote browser to: ${connection.url}`);
309
310
// Wait for browser to connect
311
await connection.ready;
312
console.log('Remote browser connected');
313
314
const runner = testcafe.createRunner();
315
316
await runner
317
.src('tests/remote-tests.js')
318
.browsers(connection)
319
.run();
320
321
} finally {
322
await testcafe.close();
323
}
324
}
325
326
// Live mode testing
327
async function runLiveMode() {
328
const testcafe = await createTestCafe();
329
330
try {
331
const liveRunner = testcafe.createLiveModeRunner();
332
333
await liveRunner
334
.src('tests/live-tests.js')
335
.browsers('chrome')
336
.watchFiles(['tests/**/*.js', 'src/**/*.js'])
337
.run();
338
339
} finally {
340
await testcafe.close();
341
}
342
}
343
344
// Multiple browser connections
345
async function runMultipleBrowsers() {
346
const testcafe = await createTestCafe();
347
348
try {
349
const connection1 = await testcafe.createBrowserConnection();
350
const connection2 = await testcafe.createBrowserConnection();
351
352
console.log(`Browser 1: ${connection1.url}`);
353
console.log(`Browser 2: ${connection2.url}`);
354
355
await Promise.all([connection1.ready, connection2.ready]);
356
357
const runner = testcafe.createRunner();
358
359
await runner
360
.src('tests/cross-browser.js')
361
.browsers([connection1, connection2, 'chrome:headless'])
362
.concurrency(3)
363
.run();
364
365
} finally {
366
await testcafe.close();
367
}
368
}
369
```
370
371
### Advanced Configuration
372
373
Advanced TestCafe configuration and customization options.
374
375
```javascript { .api }
376
// Custom reporter integration
377
interface ReporterPlugin {
378
reportTaskStart(startTime: Date, userAgents: string[], testCount: number): void;
379
reportFixtureStart(name: string, path: string, meta: object): void;
380
reportTestStart(name: string, meta: object): void;
381
reportTestDone(name: string, testRunInfo: TestRunInfo): void;
382
reportTaskDone(endTime: Date, passed: number, warnings: string[], result: object): void;
383
}
384
385
interface TestRunInfo {
386
errs: TestError[];
387
durationMs: number;
388
unstable: boolean;
389
screenshotPath: string;
390
screenshots: Screenshot[];
391
videos: Video[];
392
quarantine: object;
393
skipped: boolean;
394
}
395
396
// Custom browser provider
397
interface BrowserProvider {
398
openBrowser(id: string, pageUrl: string, browserName: string): Promise<void>;
399
closeBrowser(id: string): Promise<void>;
400
resizeWindow(id: string, width: number, height: number): Promise<void>;
401
takeScreenshot(id: string, screenshotPath: string, pageWidth: number, pageHeight: number): Promise<void>;
402
}
403
```
404
405
**Usage Examples:**
406
407
```javascript
408
// Custom reporter
409
class CustomReporter {
410
reportTaskStart(startTime, userAgents, testCount) {
411
console.log(`Starting ${testCount} tests at ${startTime}`);
412
console.log(`User agents: ${userAgents.join(', ')}`);
413
}
414
415
reportFixtureStart(name, path, meta) {
416
console.log(`\n=== Fixture: ${name} ===`);
417
console.log(`Path: ${path}`);
418
}
419
420
reportTestStart(name, meta) {
421
console.log(`\n► Running: ${name}`);
422
}
423
424
reportTestDone(name, testRunInfo) {
425
const status = testRunInfo.errs.length > 0 ? 'FAILED' : 'PASSED';
426
const duration = testRunInfo.durationMs;
427
428
console.log(`◄ ${status}: ${name} (${duration}ms)`);
429
430
if (testRunInfo.errs.length > 0) {
431
testRunInfo.errs.forEach(err => {
432
console.error(` Error: ${err.errMsg}`);
433
});
434
}
435
436
if (testRunInfo.screenshots.length > 0) {
437
console.log(` Screenshots: ${testRunInfo.screenshots.length}`);
438
}
439
}
440
441
reportTaskDone(endTime, passed, warnings, result) {
442
console.log(`\n=== Test Results ===`);
443
console.log(`Passed: ${passed}`);
444
console.log(`Failed: ${result.failedCount}`);
445
console.log(`Total: ${result.passedCount + result.failedCount}`);
446
console.log(`Duration: ${endTime - result.startTime}ms`);
447
448
if (warnings.length > 0) {
449
console.log(`Warnings: ${warnings.length}`);
450
}
451
}
452
}
453
454
async function runWithCustomReporter() {
455
const testcafe = await createTestCafe();
456
457
try {
458
const runner = testcafe.createRunner();
459
460
await runner
461
.src('tests/**/*.js')
462
.browsers('chrome')
463
.reporter(new CustomReporter())
464
.run();
465
466
} finally {
467
await testcafe.close();
468
}
469
}
470
471
// Configuration with environment variables
472
async function runEnvironmentSpecificTests() {
473
const config = {
474
hostname: process.env.TESTCAFE_HOSTNAME || 'localhost',
475
port1: parseInt(process.env.TESTCAFE_PORT1) || undefined,
476
port2: parseInt(process.env.TESTCAFE_PORT2) || undefined,
477
developmentMode: process.env.NODE_ENV === 'development'
478
};
479
480
const testcafe = await createTestCafe(config);
481
482
try {
483
const runner = testcafe.createRunner();
484
485
const browsers = process.env.BROWSERS
486
? process.env.BROWSERS.split(',')
487
: ['chrome:headless'];
488
489
const sources = process.env.TEST_FILES
490
? process.env.TEST_FILES.split(',')
491
: ['tests/**/*.js'];
492
493
await runner
494
.src(sources)
495
.browsers(browsers)
496
.concurrency(parseInt(process.env.CONCURRENCY) || 1)
497
.run({
498
speed: parseFloat(process.env.TEST_SPEED) || 1,
499
skipJsErrors: process.env.SKIP_JS_ERRORS === 'true',
500
quarantineMode: process.env.QUARANTINE_MODE === 'true'
501
});
502
503
} finally {
504
await testcafe.close();
505
}
506
}
507
```
508
509
### Integration Examples
510
511
Real-world integration examples with build systems and CI/CD.
512
513
```javascript { .api }
514
// Integration with build systems
515
async function integrationWithBuildSystem() {
516
// Pre-test setup
517
console.log('Building application...');
518
await buildApplication();
519
520
console.log('Starting test server...');
521
const server = await startTestServer();
522
523
const testcafe = await createTestCafe();
524
525
try {
526
const runner = testcafe.createRunner();
527
528
const failedCount = await runner
529
.src('tests/integration/**/*.js')
530
.browsers(['chrome:headless'])
531
.run({
532
pageLoadTimeout: 30000,
533
assertionTimeout: 10000
534
});
535
536
// Post-test cleanup
537
console.log('Stopping test server...');
538
await server.close();
539
540
if (failedCount > 0) {
541
throw new Error(`${failedCount} tests failed`);
542
}
543
544
} finally {
545
await testcafe.close();
546
}
547
}
548
549
// Parallel test execution
550
async function runParallelTests() {
551
const testGroups = [
552
'tests/unit/**/*.js',
553
'tests/integration/**/*.js',
554
'tests/e2e/**/*.js'
555
];
556
557
const results = await Promise.all(
558
testGroups.map(async (group) => {
559
const testcafe = await createTestCafe();
560
561
try {
562
const runner = testcafe.createRunner();
563
564
const failedCount = await runner
565
.src(group)
566
.browsers('chrome:headless')
567
.run();
568
569
return { group, failedCount };
570
} finally {
571
await testcafe.close();
572
}
573
})
574
);
575
576
const totalFailed = results.reduce((sum, result) => sum + result.failedCount, 0);
577
578
results.forEach(result => {
579
console.log(`${result.group}: ${result.failedCount} failed`);
580
});
581
582
if (totalFailed > 0) {
583
process.exit(1);
584
}
585
}
586
587
// Conditional test execution
588
async function runConditionalTests() {
589
const testcafe = await createTestCafe();
590
591
try {
592
const runner = testcafe.createRunner();
593
594
// Filter tests based on environment or conditions
595
const testFilter = (testName, fixtureName, fixturePath, testMeta, fixtureMeta) => {
596
// Skip slow tests in CI
597
if (process.env.CI && testMeta.slow) {
598
return false;
599
}
600
601
// Run only smoke tests in staging
602
if (process.env.ENVIRONMENT === 'staging' && !testMeta.smoke) {
603
return false;
604
}
605
606
// Skip browser-specific tests
607
if (testMeta.browserSpecific && !testMeta.browserSpecific.includes(process.env.BROWSER)) {
608
return false;
609
}
610
611
return true;
612
};
613
614
await runner
615
.src('tests/**/*.js')
616
.browsers(process.env.BROWSER || 'chrome:headless')
617
.filter(testFilter)
618
.run();
619
620
} finally {
621
await testcafe.close();
622
}
623
}
624
```