Skip to content

Commit

Permalink
feat(jest-config): override jest config (#34)
Browse files Browse the repository at this point in the history
Override config options like bail, code coverage and verbosity for performance reasons.
  • Loading branch information
Sander Koenders authored and nicojs committed Jul 8, 2018
1 parent 22802bb commit e783c80
Show file tree
Hide file tree
Showing 12 changed files with 97 additions and 36 deletions.
9 changes: 9 additions & 0 deletions packages/stryker-jest-runner/src/JestConfigEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { Config, ConfigEditor } from 'stryker-api/config';
import JestConfigLoader from './configLoaders/JestConfigLoader';
import DefaultJestConfigLoader from './configLoaders/DefaultJestConfigLoader';
import ReactScriptsJestConfigLoader from './configLoaders/ReactScriptsJestConfigLoader';
import JestConfiguration from './configLoaders/JestConfiguration';
import JEST_OVERRIDE_OPTIONS from './jestOverrideOptions';

const DEFAULT_PROJECT_NAME = 'default';

Expand All @@ -16,6 +18,9 @@ export default class JestConfigEditor implements ConfigEditor {

// When no config property is set load the configuration with the project type
strykerConfig.jest.config = strykerConfig.jest.config || this.getConfigLoader(strykerConfig.jest.project).loadConfig();

// Override some of the config properties to optimise Jest for Stryker
strykerConfig.jest.config = this.overrideProperties(strykerConfig.jest.config);
}

private getConfigLoader(project: string): JestConfigLoader {
Expand All @@ -34,4 +39,8 @@ export default class JestConfigEditor implements ConfigEditor {

return configLoader;
}

private overrideProperties(config: JestConfiguration) {
return Object.assign(config, JEST_OVERRIDE_OPTIONS);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,24 @@ export default class DefaultJestConfigLoader implements JestConfigLoader {
}

public loadConfig(): JestConfiguration {
let jestConfig: JestConfiguration;

try {
jestConfig = this.readConfigFromJestConfigFile();
} catch {
jestConfig = JSON.parse(this.readConfigFromPackageJson()).jest;
}
const jestConfig = this.readConfigFromJestConfigFile() || this.readConfigFromPackageJson();

if (!jestConfig) {
throw new Error('No Jest configuration found in your projectroot, please supply a jest.config.js or a jest config in your package.json');
throw new Error('Could not read Jest configuration, please provide a jest.config.js file or a jest config in your package.json');
}

return jestConfig;
}

private readConfigFromJestConfigFile() {
return this._loader(path.join(this._projectRoot, 'jest.config.js'));
try {
return this._loader(path.join(this._projectRoot, 'jest.config.js'));
} catch { /* Don't return anything (implicitly return undefined) */ }
}

private readConfigFromPackageJson() {
return this._fs.readFileSync(path.join(this._projectRoot, 'package.json'), 'utf8');
try {
return JSON.parse(this._fs.readFileSync(path.join(this._projectRoot, 'package.json'), 'utf8')).jest;
} catch { /* Don't return anything (implicitly return undefined) */ }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@ export interface HasteConfig {
export default interface JestConfiguration {
automock: boolean;
browser: boolean;
cache: boolean;
bail: boolean;
cacheDirectory: Path;
clearMocks: boolean;
collectCoverage: boolean;
collectCoverageFrom: Array<string>;
coverageDirectory: string;
coveragePathIgnorePatterns: string[];
coverageReporters: Array<string>;
forceCoverageMatch: Glob[];
cwd: Path;
detectLeaks: boolean;
displayName: Maybe<string>;
forceCoverageMatch: Glob[];
globals: ConfigGlobals;
haste: HasteConfig;
moduleDirectories: string[];
Expand Down Expand Up @@ -57,4 +60,6 @@ export default interface JestConfiguration {
transformIgnorePatterns: Glob[];
unmockedModulePathPatterns: Maybe<string[]>;
watchPathIgnorePatterns: string[];
}
testResultsProcessor?: string;
verbose: boolean;
}
16 changes: 16 additions & 0 deletions packages/stryker-jest-runner/src/jestOverrideOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const JEST_OVERRIDE_OPTIONS = Object.freeze({
// Prevent the user from using his or her own testResultProcessor because this might
// Mess with the way Stryker gets the results
testResultsProcessor: undefined,

// Disable code coverage, it is not used in Stryker and will only slow down the test runs
collectCoverage: false,

// Disable verbose logging, this will only slow down Stryker test runs
verbose: false,

// Enable bail so the process quits immediately when one of the tests fails
bail: true,
});

export default JEST_OVERRIDE_OPTIONS;
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,11 @@ describe('Integration JestConfigEditor', () => {
'node'
],
rootDir: projectRoot,
setupTestFrameworkScriptFile: undefined
setupTestFrameworkScriptFile: undefined,
testResultsProcessor: undefined,
collectCoverage: false,
verbose: false,
bail: true
};

// Parse the json back to an object in order to match
Expand All @@ -76,12 +80,14 @@ describe('Integration JestConfigEditor', () => {

expect(config.jest.project).to.equal('default');
expect(config.jest.config).to.deep.equal({
collectCoverage: false,
moduleFileExtensions: ['js', 'json', 'jsx', 'node'],
testEnvironment: 'jest-environment-jsdom',
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.jsx?$',
testRunner: 'jest-jasmine2',
verbose: true
testResultsProcessor: undefined,
collectCoverage: false,
verbose: false,
bail: true
});
});

Expand All @@ -92,12 +98,14 @@ describe('Integration JestConfigEditor', () => {

expect(config.jest.project).to.equal('default');
expect(config.jest.config).to.deep.equal({
collectCoverage: false,
moduleFileExtensions: ['js', 'json', 'jsx', 'node'],
testEnvironment: 'jest-environment-jsdom',
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.jsx?$',
testRunner: 'jest-jasmine2',
verbose: true
testResultsProcessor: undefined,
collectCoverage: false,
verbose: false,
bail: true
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ describe('Integration StrykerJestRunner', function () {
expect(result.tests).to.be.an('array').that.is.not.empty;
expect(result.tests[0].name).to.equal('renders without crashing');
expect(result.tests[0].status).to.equal(TestStatus.Success);
expect(result.tests[0].timeSpentMs).to.be.above(0);
expect(result.tests[0].timeSpentMs).to.be.above(-1);
expect(result.tests[0].failureMessages).to.be.an('array').that.is.empty;
expect(result.status).to.equal(RunStatus.Complete);
}).timeout(10000);
});

it('should run tests on the example custom project using package.json', async () => {
processCwdStub.returns(getProjectRoot('exampleProject'));
Expand All @@ -75,7 +75,7 @@ describe('Integration StrykerJestRunner', function () {
const result = await jestTestRunner.run();

expect(result).to.have.property('tests');
expect(result.tests).to.be.an('array').with.length(6);
expect(result.tests).to.be.an('array').with.length(testNames.length);

for (let test of result.tests) {
expect(testNames).to.include(test.name);
Expand All @@ -96,7 +96,7 @@ describe('Integration StrykerJestRunner', function () {
const result = await jestTestRunner.run();

expect(result).to.have.property('tests');
expect(result.tests).to.be.an('array').with.length(6);
expect(result.tests).to.be.an('array').with.length(testNames.length);

for (let test of result.tests) {
expect(testNames).to.include(test.name);
Expand Down
16 changes: 16 additions & 0 deletions packages/stryker-jest-runner/test/unit/JestConfigEditorSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { assert, expect } from 'chai';
import JestConfigEditor from '../../src/JestConfigEditor';
import DefaultJestConfigLoader, * as defaultJestConfigLoader from '../../src/configLoaders/DefaultJestConfigLoader';
import ReactScriptsJestConfigLoader, * as reactScriptsJestConfigLoader from '../../src/configLoaders/ReactScriptsJestConfigLoader';
import JestConfiguration from '../../src/configLoaders/JestConfiguration';

describe('JestConfigEditor', () => {
let jestConfigEditor: JestConfigEditor;
Expand All @@ -22,6 +23,10 @@ describe('JestConfigEditor', () => {
sandbox.stub(defaultJestConfigLoader, 'default').returns(defaultConfigLoaderStub);
sandbox.stub(reactScriptsJestConfigLoader, 'default').returns(reactConfigLoaderStub);

const defaultOptions: Partial<JestConfiguration> = { collectCoverage : true, verbose: true, bail: false, testResultsProcessor: 'someResultProcessor' };
defaultConfigLoaderStub.loadConfig.returns(defaultOptions);
reactConfigLoaderStub.loadConfig.returns(defaultOptions);

jestConfigEditor = new JestConfigEditor();
config = new Config();
});
Expand All @@ -43,6 +48,17 @@ describe('JestConfigEditor', () => {
assert(reactConfigLoaderStub.loadConfig.calledOnce, 'ReactConfigLoader loadConfig not called');
});

it('should override verbose, collectcoverage, testResultsProcessor and bail on all loaded configs', () => {
jestConfigEditor.edit(config);

expect(config.jest.config).to.deep.equal({
testResultsProcessor: undefined,
collectCoverage: false,
verbose: false,
bail: true
});
});

it('should return an error when an invalid project is defined', () => {
const project = 'invalidProject';
config.set({ jest: { project } });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,22 @@ describe('DefaultJestConfigLoader', () => {
});
});

it('should fallback and load the Jest configuration from the package.json when jest.config.js is not present in the project', () => {
it('should return an error when no Jest configuration is present in neither jest.config.js or package.json', () => {
requireStub.throws(Error('ENOENT: no such file or directory, open jest.config.js'));
fsStub.readFileSync.returns('{ "name": "dummy", "version": "0.0.1", "description": "Dummy package.json without jest property"}');

expect(() => defaultConfigLoader.loadConfig()).to.throw(Error, 'Could not read Jest configuration, please provide a jest.config.js file or a jest config in your package.json');
});

it('should fallback and load the Jest configuration from the package.json when jest.config.js is not present in the project', () => {
requireStub.throws(Error('ENOENT: no such file or directory, open package.json'));
const config = defaultConfigLoader.loadConfig();

assert(fsStub.readFileSync.calledWith(path.join(projectRoot, 'package.json'), 'utf8'), `readFileSync not called with ${projectRoot}/package.json`);
expect(config).to.deep.equal({
exampleProperty: 'examplePackageJsonValue'
});
});

it('should return an error when no Jest configuration is present in neither jest.config.js or package.json', () => {
requireStub.throws(Error('ENOENT: no such file or directory, open jest.config.js'));
fsStub.readFileSync.returns('{ "name": "dummy", "version": "0.0.1", "description": "Dummy package.json without jest property"}');

expect(() => defaultConfigLoader.loadConfig()).to.throw(Error, 'No Jest configuration found in your projectroot, please supply a jest.config.js or a jest config in your package.json');
});
});

interface FsStub {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
coverage
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
"version": "0.0.0",
"description": "A testResource for jest-test-runner",
"jest": {
"collectCoverage": false,
"moduleFileExtensions": ["js", "json", "jsx", "node"],
"testEnvironment": "jest-environment-jsdom",
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.jsx?$",
"testRunner": "jest-jasmine2",
"verbose": true
"testResultsProcessor": "my-awesome-testResultProcessor",
"collectCoverage": true,
"verbose": true,
"bail": false
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
module.exports = {
collectCoverage: false,
moduleFileExtensions: ["js", "json", "jsx", "node"],
testEnvironment: "jest-environment-jsdom",
testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.jsx?$",
testRunner: "jest-jasmine2",
verbose: true
testResultsProcessor: "my-awesome-testResultProcessor",
collectCoverage: true,
verbose: true,
bail: false
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
"moduleFileExtensions": [],
"testEnvironment": "some-invalid-test-environment",
"testRegex": "not-a-regular-expression",
"testRunner": "this-testRunner-does-not-exist"
"testRunner": "this-testRunner-does-not-exist",
"testResultProcessor": "an-invalid-testResult-processor",
"collectCoverage": true,
"verbose": true,
"bail": false
}
}

0 comments on commit e783c80

Please sign in to comment.