Skip to content
Open
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
94 changes: 85 additions & 9 deletions tests/e2e/specs/install.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* External dependencies
*/
import { writeFileSync, readFileSync } from 'node:fs';
import { execFileSync } from 'node:child_process';
import { join } from 'node:path';

/**
Expand All @@ -11,6 +12,54 @@ import { test, expect } from '@wordpress/e2e-test-utils-playwright';

let wpConfigOriginal;

// The prefix used to trick WP into "not installed" mode. Kept as a single
// constant since it has to stay in sync between the config rewrite and the
// cleanup query below.
const TEST_TABLE_PREFIX = 'wp_e2e_';

const TEST_TABLES = [
'commentmeta', 'comments', 'links', 'options', 'postmeta', 'posts',
'term_relationships', 'term_taxonomy', 'termmeta', 'terms', 'usermeta', 'users',
];

/**
* Drops any tables left over under TEST_TABLE_PREFIX.
*
* Called both before the prefix swap (in case a previous run crashed and
* left stale tables behind — otherwise this run fails once and only
* "self-heals" on the next run) and after it (so the next run starts clean).
*
* `wp eval` exits 0 even when a `$wpdb->query()` call inside it returns
* false, so each DROP's result is checked explicitly and reported via
* `WP_CLI::error()`, which does set a non-zero exit code — otherwise a
* failed cleanup would silently report as a passing test.
*/
function dropE2eTables() {
const dropTablesPhp = TEST_TABLES
.map( ( table ) => `
$result = $wpdb->query( "DROP TABLE IF EXISTS ${ TEST_TABLE_PREFIX }${ table }" );
if ( false === $result ) {
WP_CLI::error( "Failed to drop ${ TEST_TABLE_PREFIX }${ table }: {$wpdb->last_error}" );
}
` )
.join( '' );

execFileSync(
process.execPath,
[
join( process.cwd(), 'tools/local-env/scripts/docker.js' ),
'exec',
'--user',
'wp_php',
'cli',
'wp',
'eval',
`global $wpdb; ${ dropTablesPhp }`,
],
{ stdio: 'inherit' }
);
}

test.describe( 'WordPress installation process', () => {
const wpConfig = join(
process.cwd(),
Expand All @@ -19,25 +68,52 @@ test.describe( 'WordPress installation process', () => {


test.beforeEach( async () => {
// Read this before the cleanup call below, which can throw. Otherwise,
// if it does, `afterEach` runs anyway (Playwright always runs it) and
// crashes trying to restore `wp-config.php` from an unset variable,
// masking the real cleanup error behind a confusing second one.
wpConfigOriginal = readFileSync( wpConfig, 'utf-8' );

dropE2eTables();

// Changing the table prefix tricks WP into new install mode.
writeFileSync(
wpConfig,
wpConfigOriginal.replace( `$table_prefix = 'wp_';`, `$table_prefix = 'wp_e2e_';` )
const wpConfigPatched = wpConfigOriginal.replace(
`$table_prefix = 'wp_';`,
`$table_prefix = '${ TEST_TABLE_PREFIX }';`
);

// A prior run killed after this rewrite but before `afterEach` restores
// it leaves wp-config.php stranded on TEST_TABLE_PREFIX. `.replace()`
// then silently no-ops instead of throwing, and since the tables were
// just cleared above, the site looks freshly uninstalled under the
// already-stranded prefix — the test would pass while leaving the
// checkout stuck. Fail loudly here instead.
if ( wpConfigPatched === wpConfigOriginal ) {
throw new Error(
`wp-config.php does not contain the default table prefix. An interrupted run may have left it on '${ TEST_TABLE_PREFIX }'.`
);
}

writeFileSync( wpConfig, wpConfigPatched );
} );

test.afterEach( async () => {
writeFileSync( wpConfig, wpConfigOriginal );

// The test completes a full install under TEST_TABLE_PREFIX. Drop
// those tables, otherwise the next run finds a pre-existing install
// and never reaches the installation screen it's meant to be testing.
dropE2eTables();
} );

test( 'should install WordPress with pre-existing database credentials', async ( { page } ) => {
await page.goto( '/' );

await expect(
page,
'should redirect to the installation page'
).toHaveURL( /wp-admin\/install\.php$/ );
// The config file was just rewritten on the host; retry the navigation
// (not just the URL check) since the container's view of the file can
// lag behind the write by a request or two.
await expect( async () => {
await page.goto( '/' );
expect( page.url() ).toMatch( /wp-admin\/install\.php$/ );
}, 'should redirect to the installation page' ).toPass( { timeout: 10_000 } );

await expect(
page.getByText( /WordPress database error/ ),
Expand Down
Loading