Skip to content
This repository was archived by the owner on Jul 9, 2018. It is now read-only.

Commit

Permalink
Scripts: Add tests for utils to ensure they work properly
Browse files Browse the repository at this point in the history
  • Loading branch information
gziolo committed Feb 15, 2018
1 parent 33f0d3b commit cf7900c
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 35 deletions.
39 changes: 20 additions & 19 deletions packages/scripts/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,55 @@
* External dependencies
*/
const spawn = require( 'cross-spawn' );
const { existsSync, realpathSync } = require( 'fs' );
const { existsSync } = require( 'fs' );
const path = require( 'path' );
const readPkgUp = require( 'read-pkg-up' );

/**
* Internal dependencies
*/
const { exit, getCliArgs, getCurrentWorkingDirectory } = require( './process' );
const { getPackagePath, hasPackageProp } = require( './package' );
const { exit, getCliArgs } = require( './process' );

const first = list => list[ 0 ];

const hasCliArg = ( arg ) => getCliArgs()
.some( ( value ) => first( value.split( '=' ) ) === arg );

const { pkg, path: pkgPath } = readPkgUp.sync( {
cwd: realpathSync( getCurrentWorkingDirectory() ),
} );
const fromProjectRoot = ( fileName ) =>
path.join( path.dirname( getPackagePath() ), fileName );

const appDirectory = path.dirname( pkgPath );
const hasProjectFile = ( fileName ) =>
existsSync( fromProjectRoot( fileName ) );

const fromProjectRoot = ( fileName ) => path.join( appDirectory, fileName );
const fromScriptsRoot = ( scriptName ) =>
path.join( path.dirname( __dirname ), 'scripts', `${ scriptName }.js` );

const hasProjectFile = ( fileName ) => existsSync( fromProjectRoot( fileName ) );

const fromScriptsRoot = ( scriptName ) => path.join( path.dirname( __dirname ), 'scripts', `${ scriptName }.js` );

const hasScriptFile = ( scriptName ) => existsSync( fromScriptsRoot( scriptName ) );

const hasPackageProp = ( prop ) => pkg && pkg.hasOwnProperty( prop );
const hasScriptFile = ( scriptName ) =>
existsSync( fromScriptsRoot( scriptName ) );

const handleSignal = ( signal ) => {
if ( signal === 'SIGKILL' ) {
console.log(
'The build failed because the process exited too early. ' +
'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' ) {
console.log(
'The build failed because the process exited too early. ' +
'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 ) => {
const spawnScript = ( scriptName, args = [] ) => {
if ( ! scriptName ) {
console.log( 'Script name is missing.' );
exit( 1 );
}

if ( ! hasScriptFile( scriptName ) ) {
console.log( 'Unknown script "' + scriptName + '".' );
console.log( 'Perhaps you need to update @wordpress/scripts?' );
Expand All @@ -62,7 +63,7 @@ const spawnScript = ( scriptName, args ) => {
fromScriptsRoot( scriptName ),
...args
],
{ stdio: 'inherit' }
{ stdio: 'inherit' },
);

if ( signal ) {
Expand Down
23 changes: 23 additions & 0 deletions packages/scripts/utils/package.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* External dependencies
*/
const { realpathSync } = require( 'fs' );
const readPkgUp = require( 'read-pkg-up' );

/**
* Internal dependencies
*/
const { getCurrentWorkingDirectory } = require( './process' );

const { pkg, path: pkgPath } = readPkgUp.sync( {
cwd: realpathSync( getCurrentWorkingDirectory() ),
} );

const getPackagePath = () => pkgPath;

const hasPackageProp = ( prop ) => pkg && pkg.hasOwnProperty( prop );

module.exports = {
getPackagePath,
hasPackageProp,
};
107 changes: 91 additions & 16 deletions packages/scripts/utils/test/index.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,38 @@
jest.mock( '../process', () => {
const process = require.requireActual( '../process' );

return Object.keys( process ).reduce(
( accumulator, methodName ) => ( {
...accumulator,
[ methodName ]: jest.spyOn( process, methodName ),
} ),
{},
);
jest.mock( '../package', () => {
const module = require.requireActual( '../package' );

jest.spyOn( module, 'getPackagePath' );

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

jest.spyOn( module, 'exit' );
jest.spyOn( module, 'getCliArgs' );

return module;
} );
/**
* Internal dependencies
*/
import crossSpawn from 'cross-spawn';
import {
getCliArgs,
hasCliArg,
hasProjectFile,
spawnScript,
} from '../';
import { getCliArgs as getCliArgsMock } from '../process';
import {
getPackagePath as getPackagePathMock,
} from '../package';
import {
exit as exitMock,
getCliArgs as getCliArgsMock,
} from '../process';

describe( 'utils', () => {
describe( 'getCliArgs', () => {
test( 'should have function defined', () => {
expect( getCliArgs() ).toBeDefined();
} );
} );
const crossSpawnMock = jest.spyOn( crossSpawn, 'sync' );

describe( 'hasCliArg', () => {
beforeAll( () => {
Expand All @@ -51,4 +59,71 @@ describe( 'utils', () => {
expect( hasCliArg( '--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( 'spawnScript', () => {
const scriptName = 'test-unit';

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.' );
} );

test( 'should exit when an unknown script name provided', () => {
expect( () => spawnScript( 'unknown-script' ) ).toThrow( 'Exit code: 1.' );
} );

test( 'should exit when the script failed because of SIGKILL signal', () => {
crossSpawnMock.mockReturnValueOnce( { signal: 'SIGKILL' } );

expect( () => spawnScript( scriptName ) ).toThrow( 'Exit code: 1.' );
} );

test( 'should exit when the script failed because of SIGTERM signal', () => {
crossSpawnMock.mockReturnValueOnce( { signal: 'SIGTERM' } );

expect( () => spawnScript( scriptName ) ).toThrow( 'Exit code: 1.' );
} );

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' }
);
} );
} );
} );

0 comments on commit cf7900c

Please sign in to comment.