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

Scripts: Support split Jest configuration for test commands #22477

Merged
merged 4 commits into from
May 25, 2020
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
1 change: 1 addition & 0 deletions packages/scripts/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- New `--webpack-no-externals` flag added to `build` and `start` scripts. It disables scripts' assets generation, and omits the list of default externals ([#22310](https://github.com/WordPress/gutenberg/pull/22310)).
- New `--webpack-bundle-analyzer` flag added to `build` and `start` scripts. It enables visualization for the size of webpack output files with an interactive zoomable treemap ([#22310](https://github.com/WordPress/gutenberg/pull/22310)).
- New `--webpack--devtool` flag added to `start` script. It controls how source maps are generated. See options at https://webpack.js.org/configuration/devtool/#devtool ([#22310](https://github.com/WordPress/gutenberg/pull/22310)).
- The `test-e2e` and `test-unit` scripts will now disambiguate custom configurations, preferring a `jest-e2e.config.js`, `jest-e2e.config.json`, `jest-unit.config.js`, or `jest-unit.config.json` Jest configuration file if present, falling back to `jest.config.js` or `jest.config.json`. This allows for configurations which should only apply to one or the other test variant.

### Breaking Changes

Expand Down
12 changes: 12 additions & 0 deletions packages/scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,12 @@ We enforce that all tests run serially in the current process using [--runInBand

It uses [Jest](https://jestjs.io/) behind the scenes and you are able to use all of its [CLI options](https://jestjs.io/docs/en/cli.html). You can also run `./node_modules/.bin/wp-scripts test:e2e --help` or `npm run test:e2e:help` (as mentioned above) to view all of the available options. Learn more in the [Advanced Usage](#advanced-usage) section.

Should there be any situation where you want to provide your own Jest config, you can do so.

* the command receives a `--config` argument. Example: `wp-scripts test-e2e --config my-jest-config.js`.
* there is a file called `jest-e2e.config.js`, `jest-e2e.config.json`, `jest.config.js`, or `jest.config.json` in the top-level directory of your package (at the same level than your `package.json`).
* a `jest` object can be provided in the `package.json` file with the test configuration.

### `test-unit-js`

_Alias_: `test-unit-jest`
Expand Down Expand Up @@ -461,6 +467,12 @@ Jest will look for test files with any of the following popular naming conventio

It uses [Jest](https://jestjs.io/) behind the scenes and you are able to use all of its [CLI options](https://jestjs.io/docs/en/cli.html). You can also run `./node_modules/.bin/wp-scripts test:unit --help` or `npm run test:unit:help` (as mentioned above) to view all of the available options. By default, it uses the set of recommended options defined in [@wordpress/jest-preset-default](https://www.npmjs.com/package/@wordpress/jest-preset-default) npm package. You can override them with your own options as described in [Jest documentation](https://jestjs.io/docs/en/configuration). Learn more in the [Advanced Usage](#advanced-usage) section.

Should there be any situation where you want to provide your own Jest config, you can do so.

* the command receives a `--config` argument. Example: `wp-scripts test-unit --config my-jest-config.js`.
* there is a file called `jest-unit.config.js`, `jest-unit.config.json`, `jest.config.js`, or `jest.config.json` in the top-level directory of your package (at the same level than your `package.json`).
* a `jest` object can be provided in the `package.json` file with the test configuration.

## Passing Node.js options

`wp-scripts` supports the full array of [Node.js CLI options](https://nodejs.org/api/cli.html). They can be passed after the `wp-scripts` command and before the script name.
Expand Down
11 changes: 5 additions & 6 deletions packages/scripts/scripts/test-e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ const { sync: spawn } = require( 'cross-spawn' );
* Internal dependencies
*/
const {
getJestOverrideConfigFile,
fromConfigRoot,
getArgFromCLI,
getArgsFromCLI,
hasArgInCLI,
hasProjectFile,
hasJestConfig,
} = require( '../utils' );

const result = spawn( 'node', [ require.resolve( 'puppeteer/install' ) ], {
Expand All @@ -46,11 +46,10 @@ if (
process.env.JEST_PUPPETEER_CONFIG = fromConfigRoot( 'puppeteer.config.js' );
}

const config = ! hasJestConfig()
? [
'--config',
JSON.stringify( require( fromConfigRoot( 'jest-e2e.config.js' ) ) ),
]
const configFile = getJestOverrideConfigFile( 'e2e' );

const config = configFile
? [ '--config', JSON.stringify( require( configFile ) ) ]
: [];

const hasRunInBand = hasArgInCLI( '--runInBand' ) || hasArgInCLI( '-i' );
Expand Down
13 changes: 5 additions & 8 deletions packages/scripts/scripts/test-unit-jest.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,12 @@ const jest = require( 'jest' );
/**
* Internal dependencies
*/
const { fromConfigRoot, getArgsFromCLI, hasJestConfig } = require( '../utils' );
const { getJestOverrideConfigFile, getArgsFromCLI } = require( '../utils' );

const config = ! hasJestConfig()
? [
'--config',
JSON.stringify(
require( fromConfigRoot( 'jest-unit.config.js' ) )
),
]
const configFile = getJestOverrideConfigFile( 'unit' );

const config = configFile
? [ '--config', JSON.stringify( require( configFile ) ) ]
: [];

jest.run( [ ...config, ...getArgsFromCLI() ] );
33 changes: 30 additions & 3 deletions packages/scripts/utils/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const {
hasArgInCLI,
hasFileArgInCLI,
} = require( './cli' );
const { fromConfigRoot, hasProjectFile } = require( './file' );
const { fromConfigRoot, fromProjectRoot, hasProjectFile } = require( './file' );
const { hasPackageProp } = require( './package' );

// See https://babeljs.io/docs/en/config-files#configuration-file-types
Expand All @@ -24,9 +24,35 @@ const hasBabelConfig = () =>
hasProjectFile( '.babelrc' ) ||
hasPackageProp( 'babel' );

/**
* Returns path to a Jest configuration which should be provided as the explicit
* configuration when there is none available for discovery by Jest in the
* project environment. Returns undefined if Jest should be allowed to discover
* an available configuration.
*
* This can be used in cases where multiple possible configurations are
* supported. Since Jest will only discover `jest.config.js`, or `jest` package
* directive, such custom configurations must be specified explicitly.
*
* @param {"e2e"|"unit"} suffix Suffix of configuration file to accept.
*
* @return {string=} Override or fallback configuration file path.
*/
function getJestOverrideConfigFile( suffix ) {
if ( hasArgInCLI( '-c' ) || hasArgInCLI( '--config' ) ) {
return;
}

if ( hasProjectFile( `jest-${ suffix }.config.js` ) ) {
return fromProjectRoot( `jest-${ suffix }.config.js` );
}

if ( ! hasJestConfig() ) {
return fromConfigRoot( `jest-${ suffix }.config.js` );
}
}

const hasJestConfig = () =>
hasArgInCLI( '-c' ) ||
hasArgInCLI( '--config' ) ||
hasProjectFile( 'jest.config.js' ) ||
hasProjectFile( 'jest.config.json' ) ||
hasPackageProp( 'jest' );
Expand Down Expand Up @@ -103,6 +129,7 @@ const getWebpackArgs = () => {
module.exports = {
getWebpackArgs,
hasBabelConfig,
getJestOverrideConfigFile,
hasJestConfig,
hasPrettierConfig,
};
2 changes: 2 additions & 0 deletions packages/scripts/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const {
const {
getWebpackArgs,
hasBabelConfig,
getJestOverrideConfigFile,
hasJestConfig,
hasPrettierConfig,
} = require( './config' );
Expand All @@ -36,6 +37,7 @@ module.exports = {
hasBabelConfig,
hasArgInCLI,
hasFileArgInCLI,
getJestOverrideConfigFile,
hasJestConfig,
hasPackageProp,
hasPrettierConfig,
Expand Down
101 changes: 99 additions & 2 deletions packages/scripts/utils/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,31 @@ import crossSpawn from 'cross-spawn';
/**
* Internal dependencies
*/
import { hasArgInCLI, hasProjectFile, spawnScript } from '../';
import { getPackagePath as getPackagePathMock } from '../package';
import {
hasArgInCLI,
hasProjectFile,
getJestOverrideConfigFile,
spawnScript,
} from '../';
import {
getPackagePath as getPackagePathMock,
hasPackageProp as hasPackagePropMock,
} from '../package';
import {
exit as exitMock,
getArgsFromCLI as getArgsFromCLIMock,
} from '../process';
import {
hasProjectFile as hasProjectFileMock,
fromProjectRoot as fromProjectRootMock,
fromConfigRoot as fromConfigRootMock,
} from '../file';

jest.mock( '../package', () => {
const module = jest.requireActual( '../package' );

jest.spyOn( module, 'getPackagePath' );
jest.spyOn( module, 'hasPackageProp' );

return module;
} );
Expand All @@ -28,6 +42,15 @@ jest.mock( '../process', () => {

return module;
} );
jest.mock( '../file', () => {
const module = jest.requireActual( '../file' );

jest.spyOn( module, 'hasProjectFile' );
jest.spyOn( module, 'fromProjectRoot' );
jest.spyOn( module, 'fromConfigRoot' );

return module;
} );

describe( 'utils', () => {
const crossSpawnMock = jest.spyOn( crossSpawn, 'sync' );
Expand Down Expand Up @@ -76,6 +99,80 @@ describe( 'utils', () => {
} );
} );

describe( 'getJestOverrideConfigFile', () => {
beforeEach( () => {
getArgsFromCLIMock.mockReturnValue( [] );
aduth marked this conversation as resolved.
Show resolved Hide resolved
hasPackagePropMock.mockReturnValue( false );
hasProjectFileMock.mockReturnValue( false );
fromProjectRootMock.mockImplementation( ( path ) => '/p/' + path );
fromConfigRootMock.mockImplementation( ( path ) => '/c/' + path );
} );

afterEach( () => {
getArgsFromCLIMock.mockReset();
hasPackagePropMock.mockReset();
hasProjectFileMock.mockReset();
fromProjectRootMock.mockReset();
fromConfigRootMock.mockReset();
} );

it( 'should return undefined if --config flag is present', () => {
getArgsFromCLIMock.mockReturnValue( [ '--config=test' ] );

expect( getJestOverrideConfigFile( 'e2e' ) ).toBe( undefined );
} );

it( 'should return undefined if -c flag is present', () => {
getArgsFromCLIMock.mockReturnValue( [ '-c=test' ] );

expect( getJestOverrideConfigFile( 'e2e' ) ).toBe( undefined );
} );

it( 'should return variant project configuration if present', () => {
hasProjectFileMock.mockImplementation(
( file ) => file === 'jest-e2e.config.js'
);

expect( getJestOverrideConfigFile( 'e2e' ) ).toBe(
'/p/jest-e2e.config.js'
);
} );

it( 'should return undefined if jest.config.js available', () => {
hasProjectFileMock.mockImplementation(
( file ) => file === 'jest.config.js'
);

expect( getJestOverrideConfigFile( 'e2e' ) ).toBe( undefined );
} );

it( 'should return undefined if jest.config.json available', () => {
hasProjectFileMock.mockImplementation(
( file ) => file === 'jest.config.json'
);

expect( getJestOverrideConfigFile( 'e2e' ) ).toBe( undefined );
} );

it( 'should return undefined if jest package directive specified', () => {
hasPackagePropMock.mockImplementation(
( prop ) => prop === 'jest'
);

expect( getJestOverrideConfigFile( 'e2e' ) ).toBe( undefined );
} );

it( 'should return default configuration if nothing available', () => {
expect( getJestOverrideConfigFile( 'e2e' ) ).toBe(
'/c/jest-e2e.config.js'
);

expect( getJestOverrideConfigFile( 'unit' ) ).toBe(
'/c/jest-unit.config.js'
);
} );
} );

describe( 'spawnScript', () => {
const scriptName = 'test-unit-js';

Expand Down