Skip to content

Commit

Permalink
Build/Test Tools: add new end-to-end tests for edge cases such as mai…
Browse files Browse the repository at this point in the history
…ntenance mode.

Sometimes errors only occur in unusual code paths such as the maintenance mode or installation screens. Due to lack of tests for these scenarios in core, such errors are usually only noticed very late. This change adds new end-to-end (e2e) tests to prevent regressions in the following areas:

- Maintenance mode (presence of a `.maintenance` file)
- Fatal error handler (simulated with an mu-plugin that causes an error)
- Installation screen (verifying full installation flow & that there are no database errors)

Thanks to these tests, an issue was already found and addressed in the default `wp_die` handler, as `wp_robots_noindex_embeds` and `wp_robots_noindex_search` used to cause PHP warnings due to `$wp_query` not existing.

In the future, these tests can be extended to also test scenarios like localized error pages via `wp_load_translations_early()`.

Fixes #61240.

git-svn-id: https://develop.svn.wordpress.org/trunk@58430 602fd350-edb4-49c9-b593-d223f7449a82
  • Loading branch information
swissspidy authored and dilipbheda committed Jun 18, 2024
1 parent 4b45e3e commit 296854f
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/wp-includes/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -3862,6 +3862,9 @@ function _default_wp_die_handler( $message, $title = '', $args = array() ) {
<?php
if ( function_exists( 'wp_robots' ) && function_exists( 'wp_robots_no_robots' ) && function_exists( 'add_filter' ) ) {
add_filter( 'wp_robots', 'wp_robots_no_robots' );
// Prevent warnings because of $wp_query not existing.
remove_filter( 'wp_robots', 'wp_robots_noindex_embeds' );
remove_filter( 'wp_robots', 'wp_robots_noindex_search' );
wp_robots();
}
?>
Expand Down
46 changes: 46 additions & 0 deletions tests/e2e/specs/fatal-error-handler.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* External dependencies
*/
import { existsSync, mkdirSync, writeFileSync, unlinkSync } from 'node:fs';
import { join } from 'node:path';

/**
* WordPress dependencies
*/
import { test, expect } from '@wordpress/e2e-test-utils-playwright';

test.describe( 'Fatal error handler', () => {
const muPlugins = join(
process.cwd(),
process.env.LOCAL_DIR ?? 'src',
'wp-content/mu-plugins'
);
const muPluginFile = join( muPlugins, 'fatal-error.php' );

test.beforeAll( async () => {
const muPluginCode = `<?php new NonExistentClass();`;

if ( ! existsSync( muPlugins ) ) {
mkdirSync( muPlugins, { recursive: true } );
}
writeFileSync( muPluginFile, muPluginCode );
} );

test.afterAll( async () => {
unlinkSync( muPluginFile );
} );

test( 'should display fatal error notice', async ( { admin, page } ) => {
await admin.visitAdminPage( '/' );

await expect(
page.getByText( /Fatal error:/ ),
'should display PHP error message'
).toBeVisible();

await expect(
page.getByText( /There has been a critical error on this website/ ),
'should display WordPress fatal error handler message'
).toBeVisible();
} );
} );
85 changes: 85 additions & 0 deletions tests/e2e/specs/install.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/**
* External dependencies
*/
import { writeFileSync, readFileSync } from 'node:fs';
import { join } from 'node:path';

/**
* WordPress dependencies
*/
import { test, expect } from '@wordpress/e2e-test-utils-playwright';

let wpConfigOriginal;

test.describe( 'WordPress installation process', () => {
const wpConfig = join(
process.cwd(),
'wp-config.php',
);


test.beforeEach( async () => {
wpConfigOriginal = readFileSync( wpConfig, 'utf-8' );
// Changing the table prefix tricks WP into new install mode.
writeFileSync(
wpConfig,
wpConfigOriginal.replace( `$table_prefix = 'wp_';`, `$table_prefix = 'wp_e2e_';` )
);
} );

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

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$/ );

Check failure on line 40 in tests/e2e/specs/install.test.js

View workflow job for this annotation

GitHub Actions / Test with SCRIPT_DEBUG disabled / Run E2E tests

[chromium] › install.test.js:34:6 › WordPress installation process › should install WordPress with pre-existing database credentials

1) [chromium] › install.test.js:34:6 › WordPress installation process › should install WordPress with pre-existing database credentials Error: should redirect to the installation page Expected pattern: /wp-admin\/install\.php$/ Received string: "http://localhost:8889/" Call log: - expect.toHaveURL with timeout 5000ms - waiting for locator(':root') - locator resolved to <html lang="en-US">…</html> - unexpected value "http://localhost:8889/" - waiting for locator(':root') - locator resolved to <html lang="en-US">…</html> - unexpected value "http://localhost:8889/" - locator resolved to <html lang="en-US">…</html> - unexpected value "http://localhost:8889/" - locator resolved to <html lang="en-US">…</html> - unexpected value "http://localhost:8889/" - locator resolved to <html lang="en-US">…</html> - unexpected value "http://localhost:8889/" - locator resolved to <html lang="en-US">…</html> - unexpected value "http://localhost:8889/" - locator resolved to <html lang="en-US">…</html> - unexpected value "http://localhost:8889/" - locator resolved to <html lang="en-US">…</html> - unexpected value "http://localhost:8889/" - locator resolved to <html lang="en-US">…</html> - unexpected value "http://localhost:8889/" 38 | page, 39 | 'should redirect to the installation page' > 40 | ).toHaveURL( /wp-admin\/install\.php$/ ); | ^ 41 | 42 | await expect( 43 | page.getByText( /WordPress database error/ ), at /home/runner/work/wordpress-develop/wordpress-develop/tests/e2e/specs/install.test.js:40:5

await expect(
page.getByText( /WordPress database error/ ),
'should not have any database errors'
).not.toBeVisible();

// First page: language selector. Keep default English (US).
await page.getByRole( 'button', { name: 'Continue' } ).click();

// Second page: enter site name, username & password.

await expect( page.getByRole( 'heading', { name: 'Welcome' } ) ).toBeVisible();

// This information matches tools/local-env/scripts/install.js.

await page.getByLabel( 'Site Title' ).fill( 'WordPress Develop' );
await page.getByLabel( 'Username' ).fill( 'admin' );
await page.getByLabel( 'Password', { exact: true } ).fill( '' );
await page.getByLabel( 'Password', { exact: true } ).fill( 'password' );
await page.getByLabel( /Confirm use of weak password/ ).check()
await page.getByLabel( 'Your Email' ).fill( 'test@test.com' );

await page.getByRole( 'button', { name: 'Install WordPress' } ).click();

// Installation finished, can now log in.

await expect( page.getByRole( 'heading', { name: 'Success!' } ) ).toBeVisible();

await page.getByRole( 'link', { name: 'Log In' } ).click();

await expect(
page,
'should redirect to the login page'
).toHaveURL( /wp-login\.php$/ );

await page.getByLabel( 'Username or Email Address' ).fill( 'admin' );
await page.getByLabel( 'Password', { exact: true } ).fill( 'password' );

await page.getByRole( 'button', { name: 'Log In' } ).click();

await expect(
page.getByRole( 'heading', { name: 'Welcome to WordPress', level: 2 })
).toBeVisible();
} );
} );
33 changes: 33 additions & 0 deletions tests/e2e/specs/maintenance-mode.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* External dependencies
*/
import { writeFileSync, unlinkSync } from 'node:fs';
import { join } from 'node:path';

/**
* WordPress dependencies
*/
import { test, expect } from '@wordpress/e2e-test-utils-playwright';

test.describe( 'Maintenance mode', () => {
const documentRoot = join(
process.cwd(),
process.env.LOCAL_DIR ?? 'src',
);
const maintenanceLockFile = join( documentRoot, '.maintenance' );

test.beforeAll( async () => {
writeFileSync( maintenanceLockFile, '<?php $upgrading = 10000000000; ?>' ); // Year 2286.
} );

test.afterAll( async () => {
unlinkSync( maintenanceLockFile );
} );

test( 'should display maintenance mode page', async ( { page } ) => {
await page.goto( '/' );
await expect(
page.getByText( /Briefly unavailable for scheduled maintenance\. Check back in a minute\./ )
).toBeVisible();
} );
} );

0 comments on commit 296854f

Please sign in to comment.