@wordpress/env
Version:
A zero-config, self contained local WordPress environment for development and testing.
459 lines (409 loc) • 11.8 kB
JavaScript
'use strict';
/**
* Internal dependencies
*/
const { parseConfig } = require( '../parse-config' );
const readRawConfigFile = require( '../read-raw-config-file' );
const { getLatestWordPressVersion } = require( '../../wordpress' );
const { ValidationError } = require( '../validate-config' );
const detectDirectoryType = require( '../detect-directory-type' );
jest.mock( 'got', () => jest.fn() );
jest.mock( '../read-raw-config-file', () => jest.fn() );
jest.mock( '../detect-directory-type', () => jest.fn() );
jest.mock( '../../wordpress', () => ( {
getLatestWordPressVersion: jest.fn(),
} ) );
/**
* Since our configurations are merged, we will want to refer to the parsed default config frequently.
*/
const DEFAULT_CONFIG = {
port: 8888,
testsPort: 8889,
mysqlPort: null,
phpmyadminPort: null,
multisite: false,
phpVersion: null,
coreSource: {
type: 'git',
url: 'https://github.com/WordPress/WordPress.git',
ref: '100.0.0',
path: '/cache/WordPress',
clonePath: '/cache/WordPress',
basename: 'WordPress',
testsPath: '/cache/tests-WordPress',
},
pluginSources: [],
themeSources: [],
config: {
FS_METHOD: 'direct',
WP_DEBUG: true,
SCRIPT_DEBUG: true,
WP_ENVIRONMENT_TYPE: 'local',
WP_PHP_BINARY: 'php',
WP_TESTS_EMAIL: 'admin@example.org',
WP_TESTS_TITLE: 'Test Blog',
WP_TESTS_DOMAIN: 'localhost',
WP_SITEURL: 'http://localhost',
WP_HOME: 'http://localhost',
},
mappings: {},
lifecycleScripts: {
afterStart: null,
afterClean: null,
afterDestroy: null,
},
env: {
development: {},
tests: {
config: {
WP_DEBUG: false,
SCRIPT_DEBUG: false,
},
},
},
};
describe( 'parseConfig', () => {
beforeEach( () => {
readRawConfigFile.mockResolvedValue( null );
detectDirectoryType.mockResolvedValue( null );
getLatestWordPressVersion.mockResolvedValue( '100.0.0' );
} );
afterEach( () => {
jest.clearAllMocks();
delete process.env.WP_ENV_PORT;
delete process.env.WP_ENV_TESTS_PORT;
delete process.env.WP_ENV_CORE;
delete process.env.WP_ENV_PHP_VERSION;
delete process.env.WP_ENV_LIFECYCLE_SCRIPT_AFTER_START;
} );
it( 'should return default config', async () => {
const parsed = await parseConfig( '/test/gutenberg', '/cache' );
expect( parsed ).toEqual( DEFAULT_CONFIG );
} );
it( 'should infer a core mounting default when ran from a WordPress directory', async () => {
detectDirectoryType.mockResolvedValue( 'core' );
const parsed = await parseConfig( '/test/gutenberg', '/cache' );
expect( parsed.pluginSources ).toHaveLength( 0 );
expect( parsed.themeSources ).toHaveLength( 0 );
expect( parsed.coreSource ).toMatchObject( { type: 'local' } );
} );
it( 'should infer a plugin mounting default when ran from a plugin directory', async () => {
detectDirectoryType.mockResolvedValue( 'plugin' );
const parsed = await parseConfig( '/test/gutenberg', '/cache' );
expect( parsed.coreSource ).toMatchObject( { type: 'git' } );
expect( parsed.themeSources ).toHaveLength( 0 );
expect( parsed.pluginSources ).toHaveLength( 1 );
expect( parsed.pluginSources[ 0 ] ).toMatchObject( { type: 'local' } );
} );
it( 'should infer a theme mounting default when ran from a theme directory', async () => {
detectDirectoryType.mockResolvedValue( 'theme' );
const parsed = await parseConfig( '/test/gutenberg', '/cache' );
expect( parsed.coreSource ).toMatchObject( { type: 'git' } );
expect( parsed.pluginSources ).toHaveLength( 0 );
expect( parsed.themeSources ).toHaveLength( 1 );
expect( parsed.themeSources[ 0 ] ).toMatchObject( { type: 'local' } );
} );
it( 'should merge configs with precedence', async () => {
readRawConfigFile.mockImplementation( async ( configFile ) => {
if ( configFile === '/test/gutenberg/.wp-env.json' ) {
return {
core: 'WordPress/WordPress#Test',
phpVersion: '1.0',
lifecycleScripts: {
afterStart: 'test',
},
env: {
development: {
port: 1234,
},
tests: {
port: 5678,
},
},
};
}
if ( configFile === '/test/gutenberg/.wp-env.override.json' ) {
return {
phpVersion: '2.0',
lifecycleScripts: {
afterDestroy: 'test',
},
env: {
tests: {
port: 1011,
},
},
};
}
throw new Error( 'Invalid File: ' + configFile );
} );
const parsed = await parseConfig( '/test/gutenberg', '/cache' );
const expected = {
...DEFAULT_CONFIG,
coreSource: {
basename: 'WordPress',
path: '/cache/WordPress',
clonePath: '/cache/WordPress',
ref: 'Test',
testsPath: '/cache/tests-WordPress',
url: 'https://github.com/WordPress/WordPress.git',
type: 'git',
},
phpVersion: '2.0',
lifecycleScripts: {
...DEFAULT_CONFIG.lifecycleScripts,
afterStart: 'test',
afterDestroy: 'test',
},
env: {
development: {
...DEFAULT_CONFIG.env.development,
port: 1234,
},
tests: {
...DEFAULT_CONFIG.env.tests,
port: 1011,
},
},
};
expect( parsed ).toEqual( expected );
} );
it( 'should parse core, plugin, theme, and mapping sources', async () => {
readRawConfigFile.mockImplementation( async ( configFile ) => {
if ( configFile === '/test/gutenberg/.wp-env.json' ) {
return {
core: 'WordPress/WordPress#Test',
plugins: [ 'WordPress/TestPlugin#Test' ],
themes: [ 'WordPress/TestTheme#Test' ],
mappings: {
'/var/www/html/wp-content/plugins/test-mapping':
'WordPress/TestMapping#Test',
},
};
}
if ( configFile === '/test/gutenberg/.wp-env.override.json' ) {
return {};
}
throw new Error( 'Invalid File: ' + configFile );
} );
const parsed = await parseConfig( '/test/gutenberg', '/cache' );
expect( parsed ).toEqual( {
...DEFAULT_CONFIG,
coreSource: {
basename: 'WordPress',
path: '/cache/WordPress',
clonePath: '/cache/WordPress',
ref: 'Test',
testsPath: '/cache/tests-WordPress',
url: 'https://github.com/WordPress/WordPress.git',
type: 'git',
},
pluginSources: [
{
basename: 'TestPlugin',
path: '/cache/TestPlugin',
clonePath: '/cache/TestPlugin',
ref: 'Test',
url: 'https://github.com/WordPress/TestPlugin.git',
type: 'git',
},
],
themeSources: [
{
basename: 'TestTheme',
path: '/cache/TestTheme',
clonePath: '/cache/TestTheme',
ref: 'Test',
url: 'https://github.com/WordPress/TestTheme.git',
type: 'git',
},
],
mappings: {
'/var/www/html/wp-content/plugins/test-mapping': {
basename: 'TestMapping',
path: '/cache/TestMapping',
clonePath: '/cache/TestMapping',
ref: 'Test',
url: 'https://github.com/WordPress/TestMapping.git',
type: 'git',
},
},
} );
} );
it( 'should ignore `$schema` key', async () => {
readRawConfigFile.mockImplementation( async ( configFile ) => {
if ( configFile === '/test/gutenberg/.wp-env.json' ) {
return {
$schema: 'test',
};
}
if ( configFile === '/test/gutenberg/.wp-env.override.json' ) {
return {};
}
throw new Error( 'Invalid File: ' + configFile );
} );
const parsed = await parseConfig( '/test/gutenberg', '/cache' );
expect( parsed ).toEqual( DEFAULT_CONFIG );
} );
it( 'should override with environment variables', async () => {
process.env.WP_ENV_PORT = 123;
process.env.WP_ENV_TESTS_PORT = 456;
process.env.WP_ENV_CORE = 'WordPress/WordPress#test';
process.env.WP_ENV_PHP_VERSION = '3.0';
process.env.WP_ENV_LIFECYCLE_SCRIPT_AFTER_START = 'test after';
const parsed = await parseConfig( '/test/gutenberg', '/cache' );
expect( parsed ).toEqual( {
...DEFAULT_CONFIG,
port: 123,
testsPort: 456,
coreSource: {
basename: 'WordPress',
path: '/cache/WordPress',
clonePath: '/cache/WordPress',
ref: 'test',
testsPath: '/cache/tests-WordPress',
url: 'https://github.com/WordPress/WordPress.git',
type: 'git',
},
phpVersion: '3.0',
lifecycleScripts: {
...DEFAULT_CONFIG.lifecycleScripts,
afterStart: 'test after',
},
env: {
development: {
port: 123,
phpVersion: '3.0',
coreSource: {
basename: 'WordPress',
path: '/cache/WordPress',
clonePath: '/cache/WordPress',
ref: 'test',
testsPath: '/cache/tests-WordPress',
url: 'https://github.com/WordPress/WordPress.git',
type: 'git',
},
},
tests: {
port: 456,
phpVersion: '3.0',
coreSource: {
basename: 'WordPress',
path: '/cache/WordPress',
clonePath: '/cache/WordPress',
ref: 'test',
testsPath: '/cache/tests-WordPress',
url: 'https://github.com/WordPress/WordPress.git',
type: 'git',
},
config: {
WP_DEBUG: false,
SCRIPT_DEBUG: false,
},
},
},
} );
} );
it( 'throws when latest WordPress version needed but not found', async () => {
getLatestWordPressVersion.mockResolvedValue( null );
await expect(
parseConfig( '/test/gutenberg', '/cache' )
).rejects.toEqual(
new ValidationError(
'Could not find the latest WordPress version. There may be a network issue.'
)
);
} );
it( 'throws for unknown config options', async () => {
readRawConfigFile.mockImplementation( async ( configFile ) => {
if ( configFile === '/test/gutenberg/.wp-env.json' ) {
return {
test: 'test',
};
}
if ( configFile === '/test/gutenberg/.wp-env.override.json' ) {
return {};
}
throw new Error( 'Invalid File: ' + configFile );
} );
await expect(
parseConfig( '/test/gutenberg', '/cache' )
).rejects.toEqual(
new ValidationError(
`Invalid /test/gutenberg/.wp-env.json: "test" is not a configuration option.`
)
);
} );
it( 'throws for root-only config options', async () => {
readRawConfigFile.mockImplementation( async ( configFile ) => {
if ( configFile === '/test/gutenberg/.wp-env.json' ) {
return {
env: {
development: {
// Only the root can have environment-specific configurations.
env: {},
},
},
};
}
if ( configFile === '/test/gutenberg/.wp-env.override.json' ) {
return {};
}
throw new Error( 'Invalid File: ' + configFile );
} );
await expect(
parseConfig( '/test/gutenberg', '/cache' )
).rejects.toEqual(
new ValidationError(
`Invalid /test/gutenberg/.wp-env.json: "development.env" is not a configuration option.`
)
);
} );
it( 'should parse phpmyadmin configuration for a given environment', async () => {
readRawConfigFile.mockImplementation( async ( configFile ) => {
if ( configFile === '/test/gutenberg/.wp-env.json' ) {
return {
core: 'WordPress/WordPress#Test',
phpVersion: '1.0',
lifecycleScripts: {
afterStart: 'test',
},
env: {
development: {
phpmyadminPort: 9001,
},
},
};
}
} );
const parsed = await parseConfig( '/test/gutenberg', '/cache' );
const expected = {
development: {
...DEFAULT_CONFIG.env.development,
phpmyadminPort: 9001,
},
tests: DEFAULT_CONFIG.env.tests,
};
expect( parsed.env ).toEqual( expected );
} );
it( 'should ignore root-level configuration for phpmyadmin', async () => {
readRawConfigFile.mockImplementation( async ( configFile ) => {
if ( configFile === '/test/gutenberg/.wp-env.json' ) {
return {
core: 'WordPress/WordPress#Test',
phpVersion: '1.0',
lifecycleScripts: {
afterStart: 'test',
},
phpmyadminPort: 9001,
};
}
} );
const parsed = await parseConfig( '/test/gutenberg', '/cache' );
const expected = {
development: DEFAULT_CONFIG.env.development,
tests: DEFAULT_CONFIG.env.tests,
};
expect( parsed.env ).toEqual( expected );
} );
} );