fix: prevent asset conflicts between React and Grid.js versions

Add coexistence checks to all enqueue methods to prevent loading
both React and Grid.js assets simultaneously.

Changes:
- ReactAdmin.php: Only enqueue React assets when ?react=1
- Init.php: Skip Grid.js when React active on admin pages
- Form.php, Coupon.php, Access.php: Restore classic assets when ?react=0
- Customer.php, Product.php, License.php: Add coexistence checks

Now the toggle between Classic and React versions works correctly.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
dwindown
2026-04-18 17:02:14 +07:00
parent bd9cdac02e
commit e8fbfb14c1
74973 changed files with 6658406 additions and 71 deletions

41
node_modules/@wordpress/scripts/utils/block-json.js generated vendored Normal file
View File

@@ -0,0 +1,41 @@
const moduleFields = new Set( [ 'viewScriptModule', 'viewModule' ] );
const scriptFields = new Set( [ 'viewScript', 'script', 'editorScript' ] );
/**
* @param {Object} blockJson
* @return {null|Record<string, unknown>} Fields
*/
function getBlockJsonModuleFields( blockJson ) {
let result = null;
for ( const field of moduleFields ) {
if ( Object.hasOwn( blockJson, field ) ) {
if ( ! result ) {
result = {};
}
result[ field ] = blockJson[ field ];
}
}
return result;
}
/**
* @param {Object} blockJson
* @return {null|Record<string, unknown>} Fields
*/
function getBlockJsonScriptFields( blockJson ) {
let result = null;
for ( const field of scriptFields ) {
if ( Object.hasOwn( blockJson, field ) ) {
if ( ! result ) {
result = {};
}
result[ field ] = blockJson[ field ];
}
}
return result;
}
module.exports = {
getBlockJsonModuleFields,
getBlockJsonScriptFields,
};

99
node_modules/@wordpress/scripts/utils/cli.js generated vendored Normal file
View File

@@ -0,0 +1,99 @@
/**
* External dependencies
*/
const minimist = require( 'minimist' );
const spawn = require( 'cross-spawn' );
/**
* Internal dependencies
*/
const { fromScriptsRoot, hasScriptFile, getScripts } = require( './file' );
const { exit, getArgsFromCLI } = require( './process' );
const getArgFromCLI = ( arg ) => {
for ( const cliArg of getArgsFromCLI() ) {
const [ name, value ] = cliArg.split( '=' );
if ( name === arg ) {
return value || null;
}
}
};
const hasArgInCLI = ( arg ) => getArgFromCLI( arg ) !== undefined;
const getFileArgsFromCLI = () => minimist( getArgsFromCLI() )._;
const getNodeArgsFromCLI = () => {
const args = getArgsFromCLI();
const scripts = getScripts();
const scriptIndex = args.findIndex( ( arg ) => scripts.includes( arg ) );
return {
nodeArgs: args.slice( 0, scriptIndex ),
scriptName: args[ scriptIndex ],
scriptArgs: args.slice( scriptIndex + 1 ),
};
};
const hasFileArgInCLI = () => getFileArgsFromCLI().length > 0;
const handleSignal = ( signal ) => {
if ( signal === 'SIGKILL' ) {
// eslint-disable-next-line no-console
console.log(
'The script failed because the process exited too early. ' +
'This probably means the system ran out of memory or someone called ' +
'`kill -9` on the process.'
);
} else if ( signal === 'SIGTERM' ) {
// eslint-disable-next-line no-console
console.log(
'The script failed because the process exited too early. ' +
'Someone might have called `kill` or `killall`, or the system could ' +
'be shutting down.'
);
}
exit( 1 );
};
const spawnScript = ( scriptName, args = [], nodeArgs = [] ) => {
if ( ! scriptName ) {
// eslint-disable-next-line no-console
console.log( 'Script name is missing.' );
exit( 1 );
}
if ( ! hasScriptFile( scriptName ) ) {
// eslint-disable-next-line no-console
console.log(
'Unknown script "' +
scriptName +
'". ' +
'Perhaps you need to update @wordpress/scripts?'
);
exit( 1 );
}
const { signal, status } = spawn.sync(
'node',
[ ...nodeArgs, fromScriptsRoot( scriptName ), ...args ],
{
stdio: 'inherit',
}
);
if ( signal ) {
handleSignal( signal );
}
exit( status );
};
module.exports = {
getArgFromCLI,
getArgsFromCLI,
getFileArgsFromCLI,
getNodeArgsFromCLI,
hasArgInCLI,
hasFileArgInCLI,
spawnScript,
};

413
node_modules/@wordpress/scripts/utils/config.js generated vendored Normal file
View File

@@ -0,0 +1,413 @@
/**
* External dependencies
*/
const chalk = require( 'chalk' );
const { readFileSync } = require( 'fs' );
const { basename, dirname, extname, join, sep } = require( 'path' );
const { sync: glob } = require( 'fast-glob' );
/**
* Internal dependencies
*/
const {
getArgsFromCLI,
getFileArgsFromCLI,
hasArgInCLI,
hasFileArgInCLI,
} = require( './cli' );
const { fromConfigRoot, fromProjectRoot, hasProjectFile } = require( './file' );
const { hasPackageProp } = require( './package' );
const {
getBlockJsonModuleFields,
getBlockJsonScriptFields,
} = require( './block-json' );
const { log } = console;
// See https://babeljs.io/docs/en/config-files#configuration-file-types.
const hasBabelConfig = () =>
hasProjectFile( '.babelrc.js' ) ||
hasProjectFile( '.babelrc.json' ) ||
hasProjectFile( 'babel.config.js' ) ||
hasProjectFile( 'babel.config.json' ) ||
hasProjectFile( '.babelrc' ) ||
hasPackageProp( 'babel' );
// See https://cssnano.co/docs/config-file.
const hasCssnanoConfig = () =>
hasProjectFile( '.cssnanorc' ) ||
hasProjectFile( '.cssnanorc.js' ) ||
hasProjectFile( '.cssnanorc.json' ) ||
hasProjectFile( '.cssnanorc.yaml' ) ||
hasProjectFile( '.cssnanorc.yml' ) ||
hasProjectFile( 'cssnano.config.js' ) ||
hasPackageProp( 'cssnano' );
/**
* 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= | undefined} 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` );
}
}
// See https://jestjs.io/docs/configuration.
const hasJestConfig = () =>
hasProjectFile( 'jest.config.js' ) ||
hasProjectFile( 'jest.config.json' ) ||
hasProjectFile( 'jest.config.ts' ) ||
hasPackageProp( 'jest' );
// See https://prettier.io/docs/en/configuration.html.
const hasPrettierConfig = () =>
hasProjectFile( '.prettierrc.js' ) ||
hasProjectFile( '.prettierrc.json' ) ||
hasProjectFile( '.prettierrc.toml' ) ||
hasProjectFile( '.prettierrc.yaml' ) ||
hasProjectFile( '.prettierrc.yml' ) ||
hasProjectFile( 'prettier.config.js' ) ||
hasProjectFile( '.prettierrc' ) ||
hasPackageProp( 'prettier' );
const hasWebpackConfig = () =>
hasArgInCLI( '--config' ) ||
hasProjectFile( 'webpack.config.js' ) ||
hasProjectFile( 'webpack.config.babel.js' );
// See https://github.com/michael-ciniawsky/postcss-load-config#usage (used by postcss-loader).
const hasPostCSSConfig = () =>
hasProjectFile( 'postcss.config.js' ) ||
hasProjectFile( '.postcssrc' ) ||
hasProjectFile( '.postcssrc.json' ) ||
hasProjectFile( '.postcssrc.yaml' ) ||
hasProjectFile( '.postcssrc.yml' ) ||
hasProjectFile( '.postcssrc.js' ) ||
hasPackageProp( 'postcss' );
/**
* Converts CLI arguments to the format which webpack understands.
*
* @see https://webpack.js.org/api/cli/#usage-with-config-file
*
* @return {Array} The list of CLI arguments to pass to webpack CLI.
*/
const getWebpackArgs = () => {
// Gets all args from CLI without those prefixed with `--webpack`.
let webpackArgs = getArgsFromCLI( [
'--experimental-modules',
'--webpack',
] );
const hasWebpackOutputOption =
hasArgInCLI( '-o' ) || hasArgInCLI( '--output' );
if (
! hasWebpackOutputOption &&
! hasArgInCLI( '--entry' ) &&
hasFileArgInCLI()
) {
/**
* Converts a legacy path to the entry pair supported by webpack, e.g.:
* `./entry-one.js` -> `[ 'entry-one', './entry-one.js] ]`
* `entry-two.js` -> `[ 'entry-two', './entry-two.js' ]`
*
* @param {string} path The path provided.
*
* @return {string[]} The entry pair of its name and the file path.
*/
const pathToEntry = ( path ) => {
const entryName = basename( path, '.js' );
if ( ! path.startsWith( './' ) ) {
path = './' + path;
}
return [ entryName, path ];
};
const fileArgs = getFileArgsFromCLI();
if ( fileArgs.length > 0 ) {
// Filters out all CLI arguments that are recognized as file paths.
const fileArgsToRemove = new Set( fileArgs );
webpackArgs = webpackArgs.filter( ( cliArg ) => {
if ( fileArgsToRemove.has( cliArg ) ) {
fileArgsToRemove.delete( cliArg );
return false;
}
return true;
} );
// Converts all CLI arguments that are file paths to the `entry` format supported by webpack.
// It is going to be consumed in the config through the WP_ENTRY global variable.
const entry = {};
fileArgs.forEach( ( fileArg ) => {
const [ entryName, path ] = fileArg.includes( '=' )
? fileArg.split( '=' )
: pathToEntry( fileArg );
entry[ entryName ] = path;
} );
process.env.WP_ENTRY = JSON.stringify( entry );
}
}
if ( ! hasWebpackConfig() ) {
webpackArgs.push( '--config', fromConfigRoot( 'webpack.config.js' ) );
}
return webpackArgs;
};
/**
* Returns the WordPress source directory. It defaults to 'src' if the
* `process.env.WP_SRC_DIRECTORY` variable is not set.
*
* @return {string} The WordPress source directory.
*/
function getWordPressSrcDirectory() {
return process.env.WP_SRC_DIRECTORY || 'src';
}
/**
* Detects the list of entry points to use with webpack. There are three ways to do this:
* 1. Use the legacy webpack 4 format passed as CLI arguments.
* 2. Scan `block.json` files for scripts.
* 3. Fallback to `src/index.*` file.
*
* @see https://webpack.js.org/concepts/entry-points/
*
* @param {'script' | 'module'} buildType
*/
function getWebpackEntryPoints( buildType ) {
/**
* @return {Object<string,string>} The list of entry points.
*/
return () => {
// 1. Handles the legacy format for entry points when explicitly provided with the `process.env.WP_ENTRY`.
if ( process.env.WP_ENTRY ) {
return buildType === 'script'
? JSON.parse( process.env.WP_ENTRY )
: {};
}
// Continue only if the source directory exists.
if ( ! hasProjectFile( getWordPressSrcDirectory() ) ) {
log(
chalk.yellow(
`Source directory "${ getWordPressSrcDirectory() }" was not found. Please confirm there is a "src" directory in the root or the value passed to --webpack-src-dir is correct.`
)
);
return {};
}
// 2. Checks whether any block metadata files can be detected in the defined source directory.
// It scans all discovered files looking for JavaScript assets and converts them to entry points.
const blockMetadataFiles = glob( '**/block.json', {
absolute: true,
cwd: fromProjectRoot( getWordPressSrcDirectory() ),
} );
if ( blockMetadataFiles.length > 0 ) {
const srcDirectory = fromProjectRoot(
getWordPressSrcDirectory() + sep
);
const entryPoints = {};
for ( const blockMetadataFile of blockMetadataFiles ) {
const fileContents = readFileSync( blockMetadataFile );
let parsedBlockJson;
// wrapping in try/catch in case the file is malformed
// this happens especially when new block.json files are added
// at which point they are completely empty and therefore not valid JSON
try {
parsedBlockJson = JSON.parse( fileContents );
} catch ( error ) {
chalk.yellow(
`Skipping "${ blockMetadataFile.replace(
fromProjectRoot( sep ),
''
) }" due to malformed JSON.`
);
}
const fields =
buildType === 'script'
? getBlockJsonScriptFields( parsedBlockJson )
: getBlockJsonModuleFields( parsedBlockJson );
if ( ! fields ) {
continue;
}
for ( const value of Object.values( fields ).flat() ) {
if ( ! value.startsWith( 'file:' ) ) {
continue;
}
// Removes the `file:` prefix.
const filepath = join(
dirname( blockMetadataFile ),
value.replace( 'file:', '' )
);
// Takes the path without the file extension, and relative to the defined source directory.
if ( ! filepath.startsWith( srcDirectory ) ) {
log(
chalk.yellow(
`Skipping "${ value.replace(
'file:',
''
) }" listed in "${ blockMetadataFile.replace(
fromProjectRoot( sep ),
''
) }". File is located outside of the "${ getWordPressSrcDirectory() }" directory.`
)
);
return;
}
const entryName = filepath
.replace( extname( filepath ), '' )
.replace( srcDirectory, '' )
.replace( /\\/g, '/' );
// Detects the proper file extension used in the defined source directory.
const [ entryFilepath ] = glob(
`${ entryName }.?(m)[jt]s?(x)`,
{
absolute: true,
cwd: fromProjectRoot( getWordPressSrcDirectory() ),
}
);
if ( ! entryFilepath ) {
log(
chalk.yellow(
`Skipping "${ value.replace(
'file:',
''
) }" listed in "${ blockMetadataFile.replace(
fromProjectRoot( sep ),
''
) }". File does not exist in the "${ getWordPressSrcDirectory() }" directory.`
)
);
return;
}
entryPoints[ entryName ] = entryFilepath;
}
}
if ( Object.keys( entryPoints ).length > 0 ) {
return entryPoints;
}
}
// Don't do any further processing if this is a module build.
// This only respects *module block.json fields.
if ( buildType === 'module' ) {
return {};
}
// 3. Checks whether a standard file name can be detected in the defined source directory,
// and converts the discovered file to entry point.
const [ entryFile ] = glob( 'index.[jt]s?(x)', {
absolute: true,
cwd: fromProjectRoot( getWordPressSrcDirectory() ),
} );
if ( ! entryFile ) {
log(
chalk.yellow(
`No entry file discovered in the "${ getWordPressSrcDirectory() }" directory.`
)
);
return {};
}
return {
index: entryFile,
};
};
}
/**
* Returns the list of paths included in the `render` props by scanning the `block.json` files.
*
* @return {Array} The list of all the `render` prop paths included in `block.json` files.
*/
function getRenderPropPaths() {
// Continue only if the source directory exists.
if ( ! hasProjectFile( getWordPressSrcDirectory() ) ) {
return [];
}
// Checks whether any block metadata files can be detected in the defined source directory.
const blockMetadataFiles = glob( '**/block.json', {
absolute: true,
cwd: fromProjectRoot( getWordPressSrcDirectory() ),
} );
const srcDirectory = fromProjectRoot( getWordPressSrcDirectory() + sep );
const renderPaths = blockMetadataFiles.map( ( blockMetadataFile ) => {
const { render } = JSON.parse( readFileSync( blockMetadataFile ) );
if ( render && render.startsWith( 'file:' ) ) {
// Removes the `file:` prefix.
const filepath = join(
dirname( blockMetadataFile ),
render.replace( 'file:', '' )
);
// Takes the path without the file extension, and relative to the defined source directory.
if ( ! filepath.startsWith( srcDirectory ) ) {
log(
chalk.yellow(
`Skipping "${ render.replace(
'file:',
''
) }" listed in "${ blockMetadataFile.replace(
fromProjectRoot( sep ),
''
) }". File is located outside of the "${ getWordPressSrcDirectory() }" directory.`
)
);
return false;
}
return filepath.replace( /\\/g, '/' );
}
return false;
} );
return renderPaths.filter( ( renderPath ) => renderPath );
}
module.exports = {
getJestOverrideConfigFile,
getWebpackArgs,
getWordPressSrcDirectory,
getWebpackEntryPoints,
getRenderPropPaths,
hasBabelConfig,
hasCssnanoConfig,
hasJestConfig,
hasPostCSSConfig,
hasPrettierConfig,
};

39
node_modules/@wordpress/scripts/utils/file.js generated vendored Normal file
View File

@@ -0,0 +1,39 @@
/**
* External dependencies
*/
const { existsSync, readdirSync } = require( 'fs' );
const path = require( 'path' );
/**
* Internal dependencies
*/
const { getPackagePath } = require( './package' );
const fromProjectRoot = ( fileName ) =>
path.join( path.dirname( getPackagePath() ), fileName );
const hasProjectFile = ( fileName ) =>
existsSync( fromProjectRoot( fileName ) );
const fromConfigRoot = ( fileName ) =>
path.join( path.dirname( __dirname ), 'config', fileName );
const fromScriptsRoot = ( scriptName ) =>
path.join( path.dirname( __dirname ), 'scripts', `${ scriptName }.js` );
const hasScriptFile = ( scriptName ) =>
existsSync( fromScriptsRoot( scriptName ) );
const getScripts = () =>
readdirSync( path.join( path.dirname( __dirname ), 'scripts' ) )
.filter( ( f ) => path.extname( f ) === '.js' )
.map( ( f ) => path.basename( f, '.js' ) );
module.exports = {
fromProjectRoot,
fromConfigRoot,
fromScriptsRoot,
getScripts,
hasProjectFile,
hasScriptFile,
};

59
node_modules/@wordpress/scripts/utils/index.js generated vendored Normal file
View File

@@ -0,0 +1,59 @@
/**
* Internal dependencies
*/
const { getAsBooleanFromENV } = require( './process' );
const {
getArgFromCLI,
getArgsFromCLI,
getFileArgsFromCLI,
getNodeArgsFromCLI,
hasArgInCLI,
hasFileArgInCLI,
spawnScript,
} = require( './cli' );
const {
getJestOverrideConfigFile,
getWebpackArgs,
getWordPressSrcDirectory,
getWebpackEntryPoints,
getRenderPropPaths,
hasBabelConfig,
hasCssnanoConfig,
hasJestConfig,
hasPostCSSConfig,
hasPrettierConfig,
} = require( './config' );
const { fromProjectRoot, fromConfigRoot, hasProjectFile } = require( './file' );
const { getPackageProp, hasPackageProp } = require( './package' );
const {
getBlockJsonModuleFields,
getBlockJsonScriptFields,
} = require( './block-json' );
module.exports = {
fromProjectRoot,
fromConfigRoot,
getAsBooleanFromENV,
getArgFromCLI,
getArgsFromCLI,
getFileArgsFromCLI,
getJestOverrideConfigFile,
getNodeArgsFromCLI,
getPackageProp,
getWebpackArgs,
getWordPressSrcDirectory,
getWebpackEntryPoints,
getRenderPropPaths,
getBlockJsonModuleFields,
getBlockJsonScriptFields,
hasArgInCLI,
hasBabelConfig,
hasCssnanoConfig,
hasFileArgInCLI,
hasJestConfig,
hasPackageProp,
hasPostCSSConfig,
hasPrettierConfig,
hasProjectFile,
spawnScript,
};

27
node_modules/@wordpress/scripts/utils/package.js generated vendored Normal file
View File

@@ -0,0 +1,27 @@
/**
* External dependencies
*/
const { realpathSync } = require( 'fs' );
const { sync: readPkgUp } = require( 'read-pkg-up' );
/**
* Internal dependencies
*/
const { getCurrentWorkingDirectory } = require( './process' );
const { packageJson, path: pkgPath } = readPkgUp( {
cwd: realpathSync( getCurrentWorkingDirectory() ),
} );
const getPackagePath = () => pkgPath;
const getPackageProp = ( prop ) => packageJson && packageJson[ prop ];
const hasPackageProp = ( prop ) =>
packageJson && packageJson.hasOwnProperty( prop );
module.exports = {
getPackagePath,
getPackageProp,
hasPackageProp,
};

23
node_modules/@wordpress/scripts/utils/process.js generated vendored Normal file
View File

@@ -0,0 +1,23 @@
const getAsBooleanFromENV = ( name ) => {
const value = process.env[ name ];
return !! value && value !== 'false' && value !== '0';
};
const getArgsFromCLI = ( excludePrefixes ) => {
const args = process.argv.slice( 2 );
if ( excludePrefixes ) {
return args.filter( ( arg ) => {
return ! excludePrefixes.some( ( prefix ) =>
arg.startsWith( prefix )
);
} );
}
return args;
};
module.exports = {
exit: process.exit,
getAsBooleanFromENV,
getArgsFromCLI,
getCurrentWorkingDirectory: process.cwd,
};

274
node_modules/@wordpress/scripts/utils/test/index.js generated vendored Normal file
View File

@@ -0,0 +1,274 @@
/**
* External dependencies
*/
import crossSpawn from 'cross-spawn';
/**
* Internal dependencies
*/
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;
} );
jest.mock( '../process', () => {
const module = jest.requireActual( '../process' );
jest.spyOn( module, 'exit' );
jest.spyOn( module, 'getArgsFromCLI' );
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' );
describe( 'hasArgInCLI', () => {
beforeAll( () => {
getArgsFromCLIMock.mockReturnValue( [
'-a',
'--b',
'--config=test',
] );
} );
afterAll( () => {
getArgsFromCLIMock.mockReset();
} );
test( 'should return false when no args passed', () => {
getArgsFromCLIMock.mockReturnValueOnce( [] );
expect( hasArgInCLI( '--no-args' ) ).toBe( false );
} );
test( 'should return false when checking for unrecognized arg', () => {
expect( hasArgInCLI( '--non-existent' ) ).toBe( false );
} );
test( 'should return true when CLI arg found', () => {
expect( hasArgInCLI( '-a' ) ).toBe( true );
expect( hasArgInCLI( '--b' ) ).toBe( true );
expect( hasArgInCLI( '--config' ) ).toBe( true );
} );
} );
describe( 'hasProjectFile', () => {
test( 'should return false for the current directory and unknown file', () => {
getPackagePathMock.mockReturnValueOnce( __dirname );
expect( hasProjectFile( 'unknown-file.name' ) ).toBe( false );
} );
test( 'should return true for the current directory and this file', () => {
getPackagePathMock.mockReturnValueOnce( __dirname );
expect( hasProjectFile( 'index.js' ) ).toBe( true );
} );
} );
describe( 'getJestOverrideConfigFile', () => {
beforeEach( () => {
getArgsFromCLIMock.mockReturnValue( [] );
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';
beforeAll( () => {
exitMock.mockImplementation( ( code ) => {
throw new Error( `Exit code: ${ code }.` );
} );
} );
afterAll( () => {
exitMock.mockReset();
} );
test( 'should exit when no script name provided', () => {
expect( () => spawnScript() ).toThrow( 'Exit code: 1.' );
expect( console ).toHaveLoggedWith( 'Script name is missing.' );
} );
test( 'should exit when an unknown script name provided', () => {
expect( () => spawnScript( 'unknown-script' ) ).toThrow(
'Exit code: 1.'
);
expect( console ).toHaveLoggedWith(
'Unknown script "unknown-script". Perhaps you need to update @wordpress/scripts?'
);
} );
test( 'should exit when the script failed because of SIGKILL signal', () => {
crossSpawnMock.mockReturnValueOnce( { signal: 'SIGKILL' } );
expect( () => spawnScript( scriptName ) ).toThrow(
'Exit code: 1.'
);
expect( console ).toHaveLogged();
} );
test( 'should exit when the script failed because of SIGTERM signal', () => {
crossSpawnMock.mockReturnValueOnce( { signal: 'SIGTERM' } );
expect( () => spawnScript( scriptName ) ).toThrow(
'Exit code: 1.'
);
expect( console ).toHaveLogged();
} );
test( 'should pass inspect args to node', () => {
crossSpawnMock.mockReturnValueOnce( { status: 0 } );
expect( () =>
spawnScript( scriptName, [], [ '--inspect-brk' ] )
).toThrow( 'Exit code: 0.' );
expect( crossSpawnMock ).toHaveBeenCalledWith(
'node',
[ '--inspect-brk', expect.stringContaining( scriptName ) ],
{ stdio: 'inherit' }
);
} );
test( 'should pass script args to the script', () => {
crossSpawnMock.mockReturnValueOnce( { status: 0 } );
expect( () =>
spawnScript( scriptName, [ '--runInBand' ] )
).toThrow( 'Exit code: 0.' );
expect( crossSpawnMock ).toHaveBeenCalledWith(
'node',
[ expect.stringContaining( scriptName ), '--runInBand' ],
{ stdio: 'inherit' }
);
} );
test( 'should finish successfully when the script properly executed', () => {
crossSpawnMock.mockReturnValueOnce( { status: 0 } );
expect( () => spawnScript( scriptName ) ).toThrow(
'Exit code: 0.'
);
expect( crossSpawnMock ).toHaveBeenCalledWith(
'node',
[ expect.stringContaining( scriptName ) ],
{ stdio: 'inherit' }
);
} );
test( 'should finish successfully when the script properly executed with args', () => {
crossSpawnMock.mockReturnValueOnce( { status: 0 } );
const args = [ '-a', '--bbb', '-c=ccccc' ];
expect( () => spawnScript( scriptName, args ) ).toThrow(
'Exit code: 0.'
);
expect( crossSpawnMock ).toHaveBeenCalledWith(
'node',
[ expect.stringContaining( scriptName ), ...args ],
{ stdio: 'inherit' }
);
} );
} );
} );