Implementation:DevExpress Testcafe Compiler GetTests
| Knowledge Sources | |
|---|---|
| Domains | Testing, Web_Automation |
| Last Updated | 2026-02-12 04:00 GMT |
Overview
Concrete test file compilation system for TestCafe that transforms source files in multiple formats into executable Test objects.
Description
The Compiler class orchestrates multi-format test file compilation through a plugin-based compiler system. The getTests() method processes all source files by chunking them into batches (1000 files per chunk to avoid filesystem limits), detecting appropriate compilers based on file extension and content, optionally precompiling batches for performance, and executing each file to extract Test objects through the TestCafe API registration mechanism.
Supported file extensions include .js, .ts, .jsx, .tsx, .coffee, .cjs, and .mjs. The compiler uses strip-bom to handle Unicode byte-order marks, lodash for array operations, and delegates to specialized compilers initialized via initTestFileCompilers(). The system supports both CommonJS and ESM modes, with conditional ESM loader usage based on Node.js version.
The createTestFileInfo() static method reads file contents, strips BOM, and matches against registered compilers. Files that don't match any compiler are skipped. Precompilation is used for TypeScript batch transpilation, while individual compilation handles runtime test registration.
Usage
Use the Compiler when initializing a test run to transform source file paths into executable Test objects that can be scheduled and executed.
Code Reference
Source Location
- Repository: testcafe
- File: src/compiler/index.js
- Lines: L17-128
Signature
class Compiler {
constructor(sources: string[], compilerOptions: object, { baseUrl?, esm? })
async getTests(): Promise<Test[]>
static getSupportedTestFileExtensions(): string[]
static async createTestFileInfo(filename: string, esm?: boolean): Promise<TestFileInfo>
static cleanUp(): void
}
Import
import Compiler from './compiler';
// Initialize compiler
const compiler = new Compiler(
['tests/**/*.js', 'tests/**/*.ts'],
{ typescript: { configPath: './tsconfig.json' } },
{ baseUrl: '/project/root', esm: false }
);
// Get all tests
const tests = await compiler.getTests();
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| sources | string[] | Yes | Array of file paths to compile |
| compilerOptions | object | No | Compiler-specific options (TypeScript config, Babel presets, etc.) |
| baseUrl | string | No | Base URL for resolving relative imports |
| esm | boolean | No | Enable ES module mode (default: false) |
Outputs
| Name | Type | Description |
|---|---|---|
| tests | Test[] | Array of Test objects with fixture and metadata |
| Test.name | string | Test name from test() call |
| Test.fixture | Fixture | Parent fixture object |
| Test.fn | Function | Test implementation function |
| Test.meta | object | Metadata tags from .meta() |
Usage Examples
Basic Compilation
import Compiler from './compiler/index';
// Compile JavaScript and TypeScript tests
const compiler = new Compiler(
[
'tests/auth.test.js',
'tests/checkout.test.ts'
],
{},
{ esm: false }
);
const tests = await compiler.getTests();
console.log(`Compiled ${tests.length} tests`);
// Clean up compiler resources
Compiler.cleanUp();
TypeScript with Custom Config
const compiler = new Compiler(
['tests/**/*.ts'],
{
typescript: {
configPath: './tsconfig.test.json',
customCompilerModulePath: 'typescript'
}
},
{ baseUrl: process.cwd() }
);
const tests = await compiler.getTests();
ESM Mode
// Compile ES modules (.mjs files)
const compiler = new Compiler(
['tests/**/*.mjs'],
{},
{ esm: true }
);
const tests = await compiler.getTests();
Get Supported Extensions
const extensions = Compiler.getSupportedTestFileExtensions();
// Returns: ['.js', '.ts', '.jsx', '.tsx', '.coffee', '.cjs', '.mjs']
console.log(`Supported extensions: ${extensions.join(', ')}`);
Compilation Pipeline Implementation
// Internal compilation flow from index.js
async getTests() {
// Split into chunks to avoid file handle limits
const sourceChunks = chunk(this.sources, 1000);
let tests = [];
while (sourceChunks.length) {
const chunkTests = await this._compileTestFiles(sourceChunks.shift());
tests = tests.concat(chunkTests);
}
Compiler.cleanUp();
return flattenDeep(tests).filter(test => !!test);
}
async _compileTestFiles(filenames) {
// Create file info objects
const testFilesInfo = await this._createTestFilesInfo(filenames);
// Group by compiler
const compilerTasks = this._getCompilerTasks(testFilesInfo);
// Precompile batches (e.g., TypeScript)
await Promise.all(compilerTasks.map(({ compiler, compilerTestFilesInfo }) =>
this._precompileFiles(compiler, compilerTestFilesInfo)
));
// Execute each file to extract tests
const tests = [];
for (const info of testFilesInfo) {
tests.push(await this._getTests(info));
}
return tests;
}
File Info Creation
static async createTestFileInfo(filename, esm = false) {
// Read file
let code = await readFile(filename);
code = stripBom(code).toString();
// Find matching compiler
const compiler = find(
getTestFileCompilers(esm),
someCompiler => someCompiler.canCompile(code, filename)
);
if (!compiler) return null;
return {
filename,
code,
compiler,
compiledCode: null
};
}