diff --git a/packages/jest-runner/src/jest-test-adapters/jest-greater-than-25-adapter.ts b/packages/jest-runner/src/jest-test-adapters/jest-greater-than-25-adapter.ts index 9a5fc1503b..b264f347da 100644 --- a/packages/jest-runner/src/jest-test-adapters/jest-greater-than-25-adapter.ts +++ b/packages/jest-runner/src/jest-test-adapters/jest-greater-than-25-adapter.ts @@ -1,11 +1,14 @@ +import { join } from 'path'; + import { jestWrapper } from '../utils'; import { JestRunResult } from '../jest-run-result'; import { JestTestAdapter, RunSettings } from './jest-test-adapter'; export class JestGreaterThan25TestAdapter implements JestTestAdapter { - public async run({ jestConfig, projectRoot, fileNameUnderTest, testNamePattern }: RunSettings): Promise { - const config = JSON.stringify(jestConfig); + public async run({ jestConfig, projectRoot, fileNameUnderTest, testNamePattern, jestConfigPath }: RunSettings): Promise { + const config = jestConfigPath ? join(projectRoot, jestConfigPath) : JSON.stringify(jestConfig); + const result = await jestWrapper.runCLI( { $0: 'stryker', diff --git a/packages/jest-runner/src/jest-test-adapters/jest-less-than-25-adapter.ts b/packages/jest-runner/src/jest-test-adapters/jest-less-than-25-adapter.ts index 72a4820022..b93fb1bd46 100644 --- a/packages/jest-runner/src/jest-test-adapters/jest-less-than-25-adapter.ts +++ b/packages/jest-runner/src/jest-test-adapters/jest-less-than-25-adapter.ts @@ -1,3 +1,4 @@ +import { join } from 'path'; import jest from 'jest'; import { JestRunResult } from '../jest-run-result'; @@ -9,8 +10,8 @@ import { RunSettings, JestTestAdapter } from './jest-test-adapter'; * It has a lot of `any` typings here, since the installed typings are not in sync. */ export class JestLessThan25TestAdapter implements JestTestAdapter { - public run({ jestConfig, projectRoot, fileNameUnderTest, testNamePattern }: RunSettings): Promise { - const config = JSON.stringify(jestConfig); + public run({ jestConfig, projectRoot, fileNameUnderTest, testNamePattern, jestConfigPath }: RunSettings): Promise { + const config = jestConfigPath ? join(projectRoot, jestConfigPath) : JSON.stringify(jestConfig); return jest.runCLI( { ...(fileNameUnderTest && { _: [fileNameUnderTest], findRelatedTests: true }), diff --git a/packages/jest-runner/src/jest-test-adapters/jest-test-adapter.ts b/packages/jest-runner/src/jest-test-adapters/jest-test-adapter.ts index 73970ee65f..cf3a6034ae 100644 --- a/packages/jest-runner/src/jest-test-adapters/jest-test-adapter.ts +++ b/packages/jest-runner/src/jest-test-adapters/jest-test-adapter.ts @@ -5,6 +5,7 @@ import { JestRunResult } from '../jest-run-result'; export interface RunSettings { jestConfig: Config.InitialOptions; projectRoot: string; + jestConfigPath?: string; testNamePattern?: string; fileNameUnderTest?: string; } diff --git a/packages/jest-runner/src/jest-test-runner.ts b/packages/jest-runner/src/jest-test-runner.ts index a713063cd4..7e174dbd44 100644 --- a/packages/jest-runner/src/jest-test-runner.ts +++ b/packages/jest-runner/src/jest-test-runner.ts @@ -60,6 +60,7 @@ export const jestTestRunnerFactory = createJestTestRunnerFactory(); export class JestTestRunner implements TestRunner { private readonly jestConfig: jest.Config.InitialOptions; private readonly enableFindRelatedTests: boolean; + private readonly jestRunnerOptions: JestRunnerOptionsWithStrykerOptions; public static inject = tokens( commonTokens.logger, @@ -78,13 +79,13 @@ export class JestTestRunner implements TestRunner { configLoader: JestConfigLoader, private readonly globalNamespace: typeof INSTRUMENTER_CONSTANTS.NAMESPACE | '__stryker2__' ) { - const jestOptions = options as JestRunnerOptionsWithStrykerOptions; + this.jestRunnerOptions = options as JestRunnerOptionsWithStrykerOptions; // Get jest configuration from stryker options and assign it to jestConfig const configFromFile = configLoader.loadConfig(); - this.jestConfig = this.mergeConfigSettings(configFromFile, jestOptions.jest || {}); + this.jestConfig = this.mergeConfigSettings(configFromFile, this.jestRunnerOptions.jest || {}); // Get enableFindRelatedTests from stryker jest options or default to true - this.enableFindRelatedTests = jestOptions.jest.enableFindRelatedTests; + this.enableFindRelatedTests = this.jestRunnerOptions.jest.enableFindRelatedTests; if (this.enableFindRelatedTests) { this.log.debug('Running jest with --findRelatedTests flag. Set jest.enableFindRelatedTests to false to run all tests on every mutant.'); @@ -109,6 +110,7 @@ export class JestTestRunner implements TestRunner { const { dryRunResult, jestResult } = await this.run({ jestConfig: withCoverageAnalysis(this.jestConfig, coverageAnalysis), projectRoot: process.cwd(), + jestConfigPath: this.jestRunnerOptions.jest?.configFile, }); if (dryRunResult.status === DryRunStatus.Complete && coverageAnalysis !== 'off') { const errorMessage = verifyAllTestFilesHaveCoverage(jestResult, fileNamesWithMutantCoverage); @@ -132,11 +134,17 @@ export class JestTestRunner implements TestRunner { state.coverageAnalysis = 'off'; let testNamePattern: string | undefined; if (testFilter) { - testNamePattern = testFilter.map((testId) => `(${escapeRegExp(testId)})`).join('|'); + testNamePattern = testFilter.map(testId => `(${escapeRegExp(testId)})`).join('|'); } process.env[INSTRUMENTER_CONSTANTS.ACTIVE_MUTANT_ENV_VARIABLE] = activeMutant.id.toString(); try { - const { dryRunResult } = await this.run({ fileNameUnderTest, jestConfig: this.jestConfig, projectRoot: process.cwd(), testNamePattern }); + const { dryRunResult } = await this.run({ + fileNameUnderTest, + jestConfig: this.jestConfig, + projectRoot: process.cwd(), + testNamePattern, + jestConfigPath: this.jestRunnerOptions.jest?.configFile, + }); return toMutantRunResult(dryRunResult); } finally { delete process.env[INSTRUMENTER_CONSTANTS.ACTIVE_MUTANT_ENV_VARIABLE]; @@ -155,7 +163,7 @@ export class JestTestRunner implements TestRunner { private collectRunResult(results: jestTestResult.AggregatedResult): DryRunResult { if (results.numRuntimeErrorTestSuites) { const errorMessage = results.testResults - .map((testSuite) => this.collectSerializableErrorText(testSuite.testExecError)) + .map(testSuite => this.collectSerializableErrorText(testSuite.testExecError)) .filter(notEmpty) .join(', '); return { diff --git a/packages/jest-runner/test/unit/jest-test-adapters/jest-greater-than-25-adapter.spec.ts b/packages/jest-runner/test/unit/jest-test-adapters/jest-greater-than-25-adapter.spec.ts index 3f1a0e5828..7acc294d88 100644 --- a/packages/jest-runner/test/unit/jest-test-adapters/jest-greater-than-25-adapter.spec.ts +++ b/packages/jest-runner/test/unit/jest-test-adapters/jest-greater-than-25-adapter.spec.ts @@ -13,6 +13,7 @@ describe(JestGreaterThan25TestAdapter.name, () => { const projectRoot = '/path/to/project'; const fileNameUnderTest = '/path/to/file'; + const jestConfigPath = 'jest.config.js'; const jestConfig: Config.InitialOptions = { rootDir: projectRoot }; beforeEach(() => { @@ -30,6 +31,42 @@ describe(JestGreaterThan25TestAdapter.name, () => { expect(runCLIStub).calledWith(sinon.match.object, [projectRoot]); }); + describe('when jestConfigPath not provided', () => { + it('should call the runCLI method with the stringified jest config flag', async () => { + await sut.run({ jestConfig, projectRoot, fileNameUnderTest }); + + expect(runCLIStub).calledWith( + { + $0: 'stryker', + _: [fileNameUnderTest], + config: JSON.stringify({ rootDir: projectRoot }), + findRelatedTests: true, + runInBand: true, + silent: true, + testNamePattern: undefined, + }, + [projectRoot] + ); + }); + }); + describe('when jestConfigPath provided', () => { + it('should pass the config path instead jest config flag', async () => { + await sut.run({ jestConfig, projectRoot, fileNameUnderTest, jestConfigPath }); + + expect(runCLIStub).calledWith( + { + $0: 'stryker', + _: [fileNameUnderTest], + config: `${projectRoot}/${jestConfigPath}`, + findRelatedTests: true, + runInBand: true, + silent: true, + testNamePattern: undefined, + }, + [projectRoot] + ); + }); + }); it('should call the runCLI method with the --findRelatedTests flag', async () => { await sut.run({ jestConfig, projectRoot, fileNameUnderTest });