UNPKG

@stryker-mutator/karma-runner

Version:

A plugin to use the karma test runner in Stryker, the JavaScript mutation testing framework

129 lines (113 loc) 4.48 kB
import path from 'path'; import url, { fileURLToPath } from 'url'; import { RequestHandler } from 'express'; import { CoverageAnalysis, INSTRUMENTER_CONSTANTS } from '@stryker-mutator/api/core'; import { MutantRunOptions } from '@stryker-mutator/api/test-runner'; import { escapeRegExpLiteral } from '@stryker-mutator/util'; export const TEST_HOOKS_FILE_NAME = path.resolve( path.dirname(fileURLToPath(import.meta.url)), 'test-hooks-middleware-21f23d35-a4c9-4b01-aeff-da9c99c3ffc0.js', ); const TEST_HOOKS_FILE_BASE_NAME = path.basename(TEST_HOOKS_FILE_NAME); const SUPPORTED_FRAMEWORKS = Object.freeze(['mocha', 'jasmine'] as const); type SupportedFramework = 'jasmine' | 'mocha'; function isSupportedFramework(framework: string): framework is SupportedFramework { return (SUPPORTED_FRAMEWORKS as readonly string[]).includes(framework); } /** * Keep in sync with StrykerMutantCoverageAdapter.ts */ const SHOULD_REPORT_COVERAGE_FLAG = '__strykerShouldReportCoverage__'; const { ACTIVE_MUTANT, NAMESPACE, CURRENT_TEST_ID, HIT_COUNT, HIT_LIMIT } = INSTRUMENTER_CONSTANTS; export class TestHooksMiddleware { private static _instance?: TestHooksMiddleware; private testFramework: 'jasmine' | 'mocha' | undefined; public currentTestHooks = ''; public static get instance(): TestHooksMiddleware { if (!this._instance) { this._instance = new TestHooksMiddleware(); } return this._instance; } public configureTestFramework(frameworks?: string[]): void { this.testFramework = frameworks?.find(isSupportedFramework); } public configureCoverageAnalysis(coverageAnalysis: CoverageAnalysis): void { switch (coverageAnalysis) { case 'perTest': this.configurePerTestCoverageAnalysis(); break; case 'all': this.currentTestHooks = `window.${SHOULD_REPORT_COVERAGE_FLAG} = true;`; break; case 'off': this.currentTestHooks = `window.${SHOULD_REPORT_COVERAGE_FLAG} = false;`; break; } } public configureMutantRun({ activeMutant, testFilter, hitLimit }: MutantRunOptions): void { this.configureCoverageAnalysis('off'); this.currentTestHooks += `window.${NAMESPACE} = window.${NAMESPACE} || {};`; this.currentTestHooks += this.configureHitLimit(hitLimit); this.currentTestHooks += `window.${NAMESPACE}.${ACTIVE_MUTANT} = "${activeMutant.id}";`; if (testFilter) { switch (this.testFramework) { case 'jasmine': this.currentTestHooks += `jasmine.getEnv().configure({ specFilter: function(spec) { return ${JSON.stringify(testFilter)}.indexOf(spec.id) !== -1; }})`; break; case 'mocha': { const metaRegExp = testFilter.map((testId) => `(${escapeRegExpLiteral(testId)})`).join('|'); this.currentTestHooks += `mocha.grep(/${metaRegExp}/)`; break; } default: } } } private configureHitLimit(hitLimit: number | undefined) { return `window.${NAMESPACE}.${HIT_COUNT} = ${hitLimit === undefined ? undefined : 0}; window.${NAMESPACE}.${HIT_LIMIT} = ${hitLimit};`; } private configurePerTestCoverageAnalysis() { this.currentTestHooks = ` window.${SHOULD_REPORT_COVERAGE_FLAG} = true; window.${NAMESPACE} = window.${NAMESPACE} || {};`; switch (this.testFramework) { case 'jasmine': this.currentTestHooks += ` jasmine.getEnv().addReporter({ specStarted: function (spec) { window.${NAMESPACE}.${CURRENT_TEST_ID} = spec.id; } });`; break; case 'mocha': this.currentTestHooks += ` beforeEach(function() { window.${NAMESPACE}.${CURRENT_TEST_ID} = this.currentTest && this.currentTest.fullTitle(); }); `; break; case undefined: throw new Error( `Could not configure coverageAnalysis "perTest". Your test framework is not supported by the \`@stryker-mutator/karma-runner\`. Supported test frameworks: ${SUPPORTED_FRAMEWORKS.join( ', ', )}.`, ); } } public handler: RequestHandler = (request, response, next) => { const pathName = url.parse(request.url).pathname; if (pathName?.endsWith(TEST_HOOKS_FILE_BASE_NAME)) { response.writeHead(200, { 'Cache-Control': 'no-cache', 'Content-Type': 'application/javascript', }); response.end(this.currentTestHooks); } else { next(); } }; }