UNPKG

@wordpress/env

Version:

A zero-config, self contained local WordPress environment for development and testing.

328 lines (297 loc) 10.2 kB
'use strict'; /** * Internal dependencies */ const buildDockerComposeConfig = require( '../runtime/docker/build-docker-compose-config' ); const { wordpressDockerFileContents, getLoopbackPortConfig, } = require( '../runtime/docker/docker-config' ); const getHostUser = require( '../runtime/docker/get-host-user' ); // The basic config keys which build docker compose config requires. const CONFIG = { mappings: {}, pluginSources: [], themeSources: [], port: 8888, configDirectoryPath: '/path/to/config', }; jest.mock( '../runtime/docker/get-host-user', () => jest.fn() ); getHostUser.mockImplementation( () => { return { name: 'test', uid: 1, gid: 2, fullUser: '1:2', }; } ); describe( 'buildDockerComposeConfig', () => { it( 'should map directories before individual sources', () => { const envConfig = { ...CONFIG, mappings: { 'wp-content/plugins': { path: '/path/to/wp-plugins', }, }, pluginSources: [ { path: '/path/to/local/plugin', basename: 'test-name' }, ], }; const dockerConfig = buildDockerComposeConfig( { workDirectoryPath: '/path', env: { development: envConfig, tests: envConfig }, } ); const { volumes } = dockerConfig.services.wordpress; expect( volumes ).toEqual( [ 'wordpress:/var/www/html', // WordPress root. '/path/WordPress-PHPUnit/tests/phpunit:/wordpress-phpunit', // WordPress test library, 'user-home:/home/test', '/path/to/wp-plugins:/var/www/html/wp-content/plugins', // Mapped plugins root. '/path/to/local/plugin:/var/www/html/wp-content/plugins/test-name', // Mapped plugin. ] ); } ); it( 'should add all specified sources to tests, dev, and cli services', () => { const envConfig = { ...CONFIG, mappings: { 'wp-content/plugins': { path: '/path/to/wp-plugins', }, }, pluginSources: [ { path: '/path/to/local/plugin', basename: 'test-name' }, ], themeSources: [ { path: '/path/to/local/theme', basename: 'test-theme' }, ], }; const dockerConfig = buildDockerComposeConfig( { workDirectoryPath: '/path', env: { development: envConfig, tests: envConfig }, } ); const devVolumes = dockerConfig.services.wordpress.volumes; const cliVolumes = dockerConfig.services.cli.volumes; expect( devVolumes ).toEqual( cliVolumes ); const testsVolumes = dockerConfig.services[ 'tests-wordpress' ].volumes; const testsCliVolumes = dockerConfig.services[ 'tests-cli' ].volumes; expect( testsVolumes ).toEqual( testsCliVolumes ); let localSources = [ '/path/to/wp-plugins:/var/www/html/wp-content/plugins', '/path/WordPress-PHPUnit/tests/phpunit:/wordpress-phpunit', 'user-home:/home/test', '/path/to/local/plugin:/var/www/html/wp-content/plugins/test-name', '/path/to/local/theme:/var/www/html/wp-content/themes/test-theme', ]; expect( devVolumes ).toEqual( expect.arrayContaining( localSources ) ); localSources = [ '/path/to/wp-plugins:/var/www/html/wp-content/plugins', '/path/tests-WordPress-PHPUnit/tests/phpunit:/wordpress-phpunit', 'tests-user-home:/home/test', '/path/to/local/plugin:/var/www/html/wp-content/plugins/test-name', '/path/to/local/theme:/var/www/html/wp-content/themes/test-theme', ]; expect( testsVolumes ).toEqual( expect.arrayContaining( localSources ) ); } ); it( 'should create "wordpress" and "tests-wordpress" volumes if they are needed by containers', () => { // CONFIG has no coreSource entry, so there are no core sources on the // local filesystem, so a volume should be created to contain core // sources. const dockerConfig = buildDockerComposeConfig( { workDirectoryPath: '/path', env: { development: CONFIG, tests: CONFIG }, } ); expect( dockerConfig.volumes.wordpress ).not.toBe( undefined ); expect( dockerConfig.volumes[ 'tests-wordpress' ] ).not.toBe( undefined ); } ); it( 'should NOT create "wordpress" and "tests-wordpress" volumes if they are not needed by containers', () => { const envConfig = { ...CONFIG, coreSource: { path: '/some/random/path', local: true, }, }; const dockerConfig = buildDockerComposeConfig( { workDirectoryPath: '/path', env: { development: envConfig, tests: envConfig }, } ); expect( dockerConfig.volumes.wordpress ).toBe( undefined ); expect( dockerConfig.volumes[ 'tests-wordpress' ] ).toBe( undefined ); } ); it( 'should add healthcheck to mysql services', () => { const config = buildDockerComposeConfig( { workDirectoryPath: '/some/path', env: { development: { port: 8888, mysqlPort: 3306, coreSource: null, pluginSources: [], themeSources: [], mappings: {}, }, tests: { port: 8889, mysqlPort: 3307, coreSource: null, pluginSources: [], themeSources: [], mappings: {}, }, }, } ); expect( config.services.mysql.healthcheck ).toBeDefined(); expect( config.services.mysql.healthcheck.test ).toEqual( [ 'CMD', 'healthcheck.sh', '--connect', '--innodb_initialized', ] ); expect( config.services.mysql.healthcheck.interval ).toBe( '5s' ); expect( config.services.mysql.healthcheck.timeout ).toBe( '10s' ); expect( config.services.mysql.healthcheck.retries ).toBe( 12 ); expect( config.services.mysql.healthcheck.start_period ).toBe( '60s' ); // Verify MARIADB_AUTO_UPGRADE is set for existing installations expect( config.services.mysql.environment.MARIADB_AUTO_UPGRADE ).toBe( '1' ); expect( config.services[ 'tests-mysql' ].healthcheck ).toBeDefined(); expect( config.services[ 'tests-mysql' ].healthcheck.test ).toEqual( [ 'CMD', 'healthcheck.sh', '--connect', '--innodb_initialized', ] ); expect( config.services[ 'tests-mysql' ].environment.MARIADB_AUTO_UPGRADE ).toBe( '1' ); } ); it( 'should use service_healthy condition for WordPress depends_on', () => { const config = buildDockerComposeConfig( { workDirectoryPath: '/some/path', env: { development: { port: 8888, mysqlPort: 3306, coreSource: null, pluginSources: [], themeSources: [], mappings: {}, }, tests: { port: 8889, mysqlPort: 3307, coreSource: null, pluginSources: [], themeSources: [], mappings: {}, }, }, } ); expect( config.services.wordpress.depends_on ).toEqual( { mysql: { condition: 'service_healthy' }, } ); expect( config.services[ 'tests-wordpress' ].depends_on ).toEqual( { 'tests-mysql': { condition: 'service_healthy' }, } ); } ); describe( 'testsEnvironment', () => { it( 'should omit tests services when testsEnvironment is false', () => { const dockerConfig = buildDockerComposeConfig( { testsEnvironment: false, workDirectoryPath: '/path', env: { development: CONFIG, tests: CONFIG, }, } ); // Development services should exist. expect( dockerConfig.services.mysql ).toBeDefined(); expect( dockerConfig.services.wordpress ).toBeDefined(); expect( dockerConfig.services.cli ).toBeDefined(); expect( dockerConfig.services.phpmyadmin ).toBeDefined(); // Tests services should not exist. expect( dockerConfig.services[ 'tests-mysql' ] ).toBeUndefined(); expect( dockerConfig.services[ 'tests-wordpress' ] ).toBeUndefined(); expect( dockerConfig.services[ 'tests-cli' ] ).toBeUndefined(); expect( dockerConfig.services[ 'tests-phpmyadmin' ] ).toBeUndefined(); } ); it( 'should omit tests volumes when testsEnvironment is false', () => { const dockerConfig = buildDockerComposeConfig( { testsEnvironment: false, workDirectoryPath: '/path', env: { development: CONFIG, tests: CONFIG, }, } ); // Development volumes should exist. expect( dockerConfig.volumes.wordpress ).toBeDefined(); expect( dockerConfig.volumes.mysql ).toBeDefined(); expect( dockerConfig.volumes[ 'user-home' ] ).toBeDefined(); // Tests volumes should not exist. expect( dockerConfig.volumes[ 'tests-wordpress' ] ).toBeUndefined(); expect( dockerConfig.volumes[ 'mysql-test' ] ).toBeUndefined(); expect( dockerConfig.volumes[ 'tests-user-home' ] ).toBeUndefined(); } ); it( 'should include tests services by default', () => { const dockerConfig = buildDockerComposeConfig( { workDirectoryPath: '/path', env: { development: CONFIG, tests: CONFIG, }, } ); expect( dockerConfig.services[ 'tests-mysql' ] ).toBeDefined(); expect( dockerConfig.services[ 'tests-wordpress' ] ).toBeDefined(); expect( dockerConfig.services[ 'tests-cli' ] ).toBeDefined(); } ); } ); } ); describe( 'getLoopbackPortConfig', () => { it( 'returns Apache Listen and VirtualHost edits for a non-default port using an anchored sed pattern', () => { const out = getLoopbackPortConfig( 8888 ); expect( out ).toContain( 'Listen 8888' ); expect( out ).toContain( '/etc/apache2/ports.conf' ); expect( out ).toContain( '<VirtualHost *:80 *:8888>' ); expect( out ).toContain( '/etc/apache2/sites-enabled/000-default.conf' ); // Guard against a future "simplification" to a greedy s/80/.../g // that would also match e.g. unrelated "80" substrings. expect( out ).not.toMatch( /s\|80\|/ ); expect( out ).toMatch( /s\|<VirtualHost \\\*:80>\|/ ); } ); it( 'returns an empty string for port 80 (Apache already listens there)', () => { expect( getLoopbackPortConfig( 80 ) ).toBe( '' ); } ); it( 'returns an empty string for port 443 (wp-env does not configure SSL)', () => { expect( getLoopbackPortConfig( 443 ) ).toBe( '' ); } ); } ); describe( 'wordpressDockerFileContents', () => { it( 'injects the resolved per-environment port into the generated Dockerfile', () => { const config = { xdebug: 'off', spx: 'off', env: { development: { port: 8888, phpVersion: null }, tests: { port: 8889, phpVersion: null }, }, }; const dockerfile = wordpressDockerFileContents( 'tests', config ); // Proves getLoopbackPortConfig is wired in AND that each environment // uses its own port (not the development port). expect( dockerfile ).toContain( 'Listen 8889' ); expect( dockerfile ).not.toContain( 'Listen 8888' ); } ); } );