Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): change react to create-react-app #1978

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/core/src/initializer/presets/ReactPreset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ const handbookUrl = 'https://github.com/stryker-mutator/stryker-handbook/blob/ma
* https://github.com/stryker-mutator/stryker-handbook/blob/master/stryker/guides/react.md#react
*/
export class ReactPreset implements Preset {
public readonly name = 'react';
public readonly name = 'create-react-app';
private readonly generalDependencies = ['@stryker-mutator/core', '@stryker-mutator/jest-runner', '@stryker-mutator/html-reporter'];

private readonly sharedConfig = `testRunner: 'jest',
reporters: ['progress', 'clear-text', 'html'],
coverageAnalysis: 'off',
jest: {
projectType: 'react'
projectType: 'create-react-app'
}
`;

Expand Down
4 changes: 2 additions & 2 deletions packages/core/test/unit/initializer/Presets.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ describe('Presets', () => {
reactPreset = new ReactPreset();
});

it('should have the name "react"', () => {
expect(reactPreset.name).to.eq('react');
it('should have the name "create-react-app"', () => {
expect(reactPreset.name).to.eq('create-react-app');
});

it('should mutate typescript when TSX is chosen', async () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/jest-runner/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ The @stryker-mutator/jest-runner also provides a couple of configurable options
| option | description | default value | alternative values |
|----|----|----|---|
| projectType (optional) | The type of project you are working on. | `custom` | `custom` uses the `config` option (see below)|
| | | | `react` when you are using [create-react-app](https://github.com/facebook/create-react-app) |
| | | | `react-ts` when you are using [create-react-app-typescript](https://github.com/wmonk/create-react-app-typescript) |
| | | | `create-react-app` when you are using [create-react-app](https://github.com/facebook/create-react-app) |
| | | | `create-react-app-ts` when you are using [create-react-app-typescript](https://github.com/wmonk/create-react-app-typescript) |
| config (optional) | A custom Jest configuration object. You could also use `require` to load it here) | undefined | |
| enableFindRelatedTests (optional) | Whether to run jest with the `--findRelatedTests` flag. When `true`, Jest will only run tests related to the mutated file per test. (See [_--findRelatedTests_](https://jestjs.io/docs/en/cli.html#findrelatedtests-spaceseparatedlistofsourcefiles)) | true | false |

Expand Down
16 changes: 16 additions & 0 deletions packages/jest-runner/src/JestConfigEditor.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Config, ConfigEditor } from '@stryker-mutator/api/config';
import { Logger } from '@stryker-mutator/api/logging';
import jest from 'jest';
import { commonTokens, tokens } from '@stryker-mutator/api/plugin';

import CustomJestConfigLoader from './configLoaders/CustomJestConfigLoader';
import JestConfigLoader from './configLoaders/JestConfigLoader';
Expand All @@ -10,6 +12,10 @@ import JEST_OVERRIDE_OPTIONS from './jestOverrideOptions';
const DEFAULT_PROJECT_NAME = 'custom';

export default class JestConfigEditor implements ConfigEditor {
public static inject = tokens(commonTokens.logger);

constructor(private readonly log: Logger) {}

public edit(strykerConfig: Config): void {
// If there is no Jest property on the Stryker config create it
strykerConfig.jest = strykerConfig.jest || {};
Expand All @@ -28,9 +34,19 @@ export default class JestConfigEditor implements ConfigEditor {
switch (projectType.toLowerCase()) {
case DEFAULT_PROJECT_NAME:
return new CustomJestConfigLoader(process.cwd());
case 'create-react-app':
return new ReactScriptsJestConfigLoader(process.cwd());
case 'create-react-app-ts':
return new ReactScriptsTSJestConfigLoader(process.cwd());
case 'react':
this.log.warn(
mthmulders marked this conversation as resolved.
Show resolved Hide resolved
'DEPRECATED: The projectType "react" is deprecated. Use projectType "create-react-app" for react projects created by "create-react-app" or use "custom" for other react projects.'
);
return new ReactScriptsJestConfigLoader(process.cwd());
case 'react-ts':
this.log.warn(
'DEPRECATED: The projectType "react-ts" is deprecated. Use projectType "create-react-app-ts" for react projects created by "create-react-app" or use "custom" for other react projects.'
);
return new ReactScriptsTSJestConfigLoader(process.cwd());
default:
throw new Error(`No configLoader available for ${projectType}`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default class ReactScriptsJestConfigLoader implements JestConfigLoader {
return jestConfiguration;
} catch (e) {
if (this.isNodeErrnoException(e) && e.code === 'MODULE_NOT_FOUND') {
throw Error('Unable to locate package react-scripts. This package is required when projectType is set to "react".');
throw Error('Unable to locate package react-scripts. This package is required when projectType is set to "create-react-app".');
}
throw e;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default class ReactScriptsTSJestConfigLoader implements JestConfigLoader
return jestConfiguration;
} catch (e) {
if (this.isNodeErrnoException(e) && e.code === 'MODULE_NOT_FOUND') {
throw Error('Unable to locate package react-scripts-ts. ' + 'This package is required when projectType is set to "react-ts".');
throw Error('Unable to locate package react-scripts-ts. ' + 'This package is required when projectType is set to "create-react-app-ts".');
}
throw e;
}
Expand Down
92 changes: 92 additions & 0 deletions packages/jest-runner/test/integration/JestConfigEditor.it.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,39 @@ describe('Integration test for Jest ConfigEditor', () => {
config = new Config();
});

it('should create a Jest configuration for a create-react-app project', () => {
config.set({ jest: { projectType: 'create-react-app' } });

jestConfigEditor.edit(config);

const expectedResult = {
bail: false,
collectCoverage: false,
collectCoverageFrom: ['!src/**/*.d.ts', 'src/**/*.{js,jsx,ts,tsx}'],
moduleFileExtensions: ['js', 'json', 'jsx', 'node', 'ts', 'tsx', 'web.js', 'web.jsx', 'web.ts', 'web.tsx'],
moduleNameMapper: {
'^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
'^react-native$': 'react-native-web'
},
notify: false,
rootDir: projectRoot,
setupFiles: [path.join(projectRoot, 'node_modules', 'react-app-polyfill', 'jsdom.js')],
setupTestFrameworkScriptFile: undefined,
testEnvironment: 'jsdom',
testMatch: ['<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}', '<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}'],
testResultsProcessor: undefined,
transform: {
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': path.join(projectRoot, 'node_modules', 'react-scripts', 'config', 'jest', 'fileTransform.js'),
'^.+\\.(js|jsx|ts|tsx)$': path.join(projectRoot, 'node_modules', 'react-scripts', 'config', 'jest', 'babelTransform.js'),
'^.+\\.css$': path.join(projectRoot, 'node_modules', 'react-scripts', 'config', 'jest', 'cssTransform.js')
},
transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\].+\\.(js|jsx|ts|tsx)$', '^.+\\.module\\.(css|sass|scss)$'],
verbose: false
};

assertJestConfig(expectedResult, config.jest.config);
});

it('should create a Jest configuration for a React project', () => {
config.set({ jest: { projectType: 'react' } });

Expand Down Expand Up @@ -56,6 +89,55 @@ describe('Integration test for Jest ConfigEditor', () => {
assertJestConfig(expectedResult, config.jest.config);
});

it('should log a deprecation warning when projectType is "react"', () => {
config.set({ jest: { projectType: 'react' } });

jestConfigEditor.edit(config);

expect(testInjector.logger.warn).calledWith(
'DEPRECATED: The projectType "react" is deprecated. Use projectType "create-react-app" for react projects created by "create-react-app" or use "custom" for other react projects.'
);
});

it('should create a Jest configuration for a create-react-app + TypeScript project', () => {
config.set({ jest: { projectType: 'create-react-app-ts' } });

jestConfigEditor.edit(config);

const expectedResult = {
bail: false,
collectCoverage: false,
collectCoverageFrom: ['!**/*.d.ts', 'src/**/*.{js,jsx,ts,tsx}'],
globals: {
'ts-jest': {
tsConfigFile: path.join(projectRoot, 'testResources', 'reactTsProject', 'tsconfig.test.json')
}
},
moduleFileExtensions: ['web.ts', 'ts', 'web.tsx', 'tsx', 'web.js', 'js', 'web.jsx', 'jsx', 'json', 'node', 'mjs'],
moduleNameMapper: {
'^react-native$': 'react-native-web'
},
notify: false,
rootDir: projectRoot,
setupFiles: [path.join(projectRoot, 'node_modules', 'react-scripts-ts', 'config', 'polyfills.js')],
setupTestFrameworkScriptFile: undefined,
testEnvironment: 'jsdom',
testMatch: ['<rootDir>/src/**/__tests__/**/*.(j|t)s?(x)', '<rootDir>/src/**/?(*.)(spec|test).(j|t)s?(x)'],
testResultsProcessor: undefined,
testURL: 'http://localhost',
transform: {
'^(?!.*\\.(js|jsx|mjs|css|json)$)': path.join(projectRoot, 'node_modules', 'react-scripts-ts', 'config', 'jest', 'fileTransform.js'),
'^.+\\.(js|jsx|mjs)$': path.join(projectRoot, 'node_modules', 'react-scripts-ts', 'config', 'jest', 'babelTransform.js'),
'^.+\\.css$': path.join(projectRoot, 'node_modules', 'react-scripts-ts', 'config', 'jest', 'cssTransform.js'),
'^.+\\.tsx?$': path.join(projectRoot, 'node_modules', 'react-scripts-ts', 'config', 'jest', 'typescriptTransform.js')
},
transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|ts|tsx)$'],
verbose: false
};

assertJestConfig(expectedResult, config.jest.config);
});

it('should create a Jest configuration for a React + TypeScript project', () => {
config.set({ jest: { projectType: 'react-ts' } });

Expand Down Expand Up @@ -95,6 +177,16 @@ describe('Integration test for Jest ConfigEditor', () => {
assertJestConfig(expectedResult, config.jest.config);
});

it('should log a deprecation warning when projectType is "react-ts"', () => {
config.set({ jest: { projectType: 'react-ts' } });

jestConfigEditor.edit(config);

expect(testInjector.logger.warn).calledWith(
'DEPRECATED: The projectType "react-ts" is deprecated. Use projectType "create-react-app-ts" for react projects created by "create-react-app" or use "custom" for other react projects.'
);
});

it('should load the Jest configuration from the jest.config.js', () => {
getProjectRootStub.returns(path.join(process.cwd(), 'testResources', 'exampleProjectWithExplicitJestConfig'));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ describe(ReactScriptsJestConfigLoader.name, () => {
requireResolveStub.throws(error);

// Act & Assert
expect(() => sut.loadConfig()).throws('Unable to locate package react-scripts. This package is required when projectType is set to "react".');
expect(() => sut.loadConfig()).throws(
'Unable to locate package react-scripts. This package is required when projectType is set to "create-react-app".'
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ describe(ReactScriptsTSJestConfigLoader.name, () => {

// Act & Assert
expect(() => sut.loadConfig()).throws(
'Unable to locate package react-scripts-ts. This package is required when projectType is set to "react-ts".'
'Unable to locate package react-scripts-ts. This package is required when projectType is set to "create-react-app-ts".'
);
});
});