apiveritas
Version:
Lightweight CLI tool for consumer-driven API contract testing via JSON schema and payload comparisons.
113 lines (95 loc) • 4.01 kB
text/typescript
/**
* @file TestSuiteLoader.ts
* @author Mario Galea
* @description
* Responsible for loading API test suites from disk and preparing them for execution by enriching them with metadata.
* Supports both real and mock test modes depending on configuration.
*/
import fs from 'fs';
import path from 'path';
import { IApiRequest } from '../../interfaces/IApiRequest';
import { Logger } from '../utils/Logger';
import { IComparerOptions } from '../../interfaces/IComparerOptions';
/**
* Handles loading of test suite files (JSON), enriching each test with metadata like baseUrl and testSuite name.
* Also supports mock server mode for isolated contract test runs.
*/
export class TestSuiteLoader {
private static logger = new Logger({ level: 'info' });
/**
* Loads and parses a test suite JSON file, returning a list of API requests enriched with suite-specific metadata.
*
* - Validates file presence and schema integrity.
* - Supports switching to mock test mode via `config.enableMockServer`.
* - Injects `testSuite` and `baseUrl` fields into each request.
*
* @param testFileName - The name of the test suite JSON file (e.g., `bookings.json`).
* @param config - Optional comparer configuration, including mock mode and base URL overrides.
* @returns An array of enriched `ApiRequest` objects ready to be called.
*
* @throws Will throw if:
* - The file doesn't exist.
* - The file doesn't contain an array.
* - Any test entry is missing required fields (`name`, `url`).
* - JSON parse fails.
*/
static loadSuite(testFileName: string, config?: IComparerOptions): IApiRequest[] {
const useMock = config?.enableMockServer;
const actualFile = useMock ? 'mock.json' : testFileName;
const baseUrl = useMock
? 'http://localhost:3000'
: config?.baseUrl || 'http://localhost:8080';
if (useMock) {
this.logger.info(
'\n> Mock server mode enabled\n> Mock Test Suite: mock.json\n> Mock BaseUrl: http://localhost:3000\n'
);
}
const testFolder = useMock ? 'mock' : 'real';
const testFilePath = path.resolve(process.cwd(), 'apiveritas', 'tests', testFolder, actualFile);
console.log(testFolder);
// Check file existence
if (!fs.existsSync(testFilePath)) {
this.logger.error(`Test file not found: ${testFilePath}`);
throw new Error(`Test file not found: ${testFilePath}`);
}
try {
// Read and parse the test suite JSON
const rawData = fs.readFileSync(testFilePath, 'utf-8');
const parsed = JSON.parse(rawData);
if (!Array.isArray(parsed)) {
throw new Error('Test suite JSON must be an array of API definitions');
}
const suiteName = path.basename(actualFile, '.json');
// Validate and enrich each test case
const enrichedRequests = parsed.map((entry, i) => {
if (!entry.name || !entry.url) {
throw new Error(`Test case at index ${i} is missing required fields (name, url)`);
}
return {
...entry,
testSuite: suiteName,
baseUrl, // inject resolved base URL
};
});
return enrichedRequests as IApiRequest[];
} catch (err: any) {
this.logger.error(`Failed to parse or validate test suite file: ${err.message}`);
throw err;
}
}
/**
* Lists all available test suite JSON files in the `tests/` directory.
*
* Useful for CLI commands like `apiveritas list-tests` or for UI tools.
*
* @returns A list of file names ending in `.json` from the `tests/` folder.
*/
static listAvailableSuites(): string[] {
const testsDir = path.resolve(process.cwd(), 'apiveritas', 'tests', 'real');
// If folder doesn't exist, return empty list
if (!fs.existsSync(testsDir)) return [];
return fs
.readdirSync(testsDir)
.filter((file) => file.endsWith('.json'));
}
}