Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Boost: Refactor and add new e2e tests #21819

Merged
merged 71 commits into from
Dec 15, 2021
Merged
Show file tree
Hide file tree
Changes from 70 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
b75b876
Merge branch 'master' into add/boost-e2e-tests
davidlonjon Nov 18, 2021
1adae1a
WIP: Refactor and create new e2e tests
davidlonjon Nov 19, 2021
5bcd249
WIP: Refactor and create new e2e tests
davidlonjon Nov 19, 2021
5cf05e9
Merge branch 'master' into add/boost-e2e-tests
davidlonjon Nov 23, 2021
7b19032
Merge branch 'master' into add/boost-e2e-tests
davidlonjon Nov 25, 2021
12b31ac
Fix tests following recent refactoring migrating Jest to Playwright
davidlonjon Nov 25, 2021
f6234f0
WIP: Refactor tests
davidlonjon Nov 26, 2021
ff0aada
Merge branch 'master' into add/boost-e2e-tests
davidlonjon Nov 30, 2021
d082ba7
Fix coding standards for consistency
davidlonjon Nov 30, 2021
9d22935
Merge branch 'master' into add/boost-e2e-tests
davidlonjon Dec 2, 2021
82ad690
Merge branch 'master' into add/boost-e2e-tests
davidlonjon Dec 2, 2021
a1f372e
WIP: Refactor and extend E2E tests
davidlonjon Dec 2, 2021
c706c77
Fix tests name
davidlonjon Dec 2, 2021
cd1eb83
Fix test name
davidlonjon Dec 2, 2021
3b0860d
Reduce timeout
davidlonjon Dec 2, 2021
a3f77ac
Improve test assertion
davidlonjon Dec 2, 2021
75753d5
Add a E2E test for the render blocking js module
davidlonjon Dec 2, 2021
505ecd0
Refactor the test for the Lazy images module
davidlonjon Dec 2, 2021
cbf5486
Add a new prerequisite to install the jitm package before tests
davidlonjon Dec 2, 2021
d39b001
Change connection tests order
davidlonjon Dec 2, 2021
f8966a1
Remove useless prerequisite for connection test
davidlonjon Dec 2, 2021
bbe3868
Fix line break
davidlonjon Dec 2, 2021
23f53c2
Improve build package command
davidlonjon Dec 2, 2021
ac66eec
Fix test content
davidlonjon Dec 3, 2021
75c72c9
Improve the modules common tests
davidlonjon Dec 3, 2021
e4f163e
WIP: Add Critical CSS module related E2E tests
davidlonjon Dec 3, 2021
fee8d30
Install required packages for testing inside the worfklow rather than…
davidlonjon Dec 3, 2021
fa5407a
[not verified] Revert "Install required packages for testing inside t…
davidlonjon Dec 3, 2021
be7ff06
Merge branch 'master' into add/boost-e2e-tests
davidlonjon Dec 7, 2021
6401306
Merge branch 'master' into add/boost-e2e-tests
davidlonjon Dec 7, 2021
47499fd
Remove not needed prerequesite
davidlonjon Dec 7, 2021
d89739b
Refactor the specs directory structure and remove useless test
davidlonjon Dec 7, 2021
716e37f
Implement some common/general E2E tests
davidlonjon Dec 7, 2021
c1359a1
Rename test description
davidlonjon Dec 7, 2021
75e0882
Merge branch 'master' into add/boost-e2e-tests
davidlonjon Dec 9, 2021
a28e13f
Remove useless export statements
davidlonjon Dec 9, 2021
ab0650d
Fix logging message
davidlonjon Dec 9, 2021
8623d2a
Make sure that the ensurePluginsState prerequisite is run only on a l…
davidlonjon Dec 9, 2021
ea71fac
Remove the describe tests grouping as not required in the context of …
davidlonjon Dec 9, 2021
8ef943c
Add missing page.close statements
davidlonjon Dec 9, 2021
f3c3731
Removing the use of the TestContentPage in favor to the PostFrontEnd …
davidlonjon Dec 9, 2021
e2a724d
Refactor to remove locator statements from the tests
davidlonjon Dec 9, 2021
02b4110
Remove a page close statement which may break tests
davidlonjon Dec 9, 2021
eb6a173
Remove helper file not needed anymore
davidlonjon Dec 9, 2021
01615f1
Refactor the way to check if the site score is loading to make it mor…
davidlonjon Dec 9, 2021
633bd10
Refactor tests check
davidlonjon Dec 9, 2021
a7e401b
Add back the page close statement
davidlonjon Dec 9, 2021
4352bde
Create a new common Themes page
davidlonjon Dec 10, 2021
2daa3b8
Create a new sidebar page method to navigate to the themes page
davidlonjon Dec 10, 2021
65eab89
Fix test description
davidlonjon Dec 10, 2021
c56fdca
Fix test comment
davidlonjon Dec 10, 2021
a927675
Implement a new Critical CSS related test
davidlonjon Dec 10, 2021
59a0d70
Fix test description
davidlonjon Dec 10, 2021
3ab2683
Relocate tests conment
davidlonjon Dec 10, 2021
4d8b9fe
Add new Critical CSS related tests
davidlonjon Dec 10, 2021
4633f39
Merge branch 'master' into add/boost-e2e-tests
davidlonjon Dec 10, 2021
4e5d268
Update the README file
davidlonjon Dec 10, 2021
5642fc2
Merge branch 'master' into add/boost-e2e-tests
davidlonjon Dec 14, 2021
00b2af4
Ensure a clean env pre-requisite before running test
davidlonjon Dec 14, 2021
a4af447
Increase timeout
davidlonjon Dec 14, 2021
4a998c9
Fix typo
davidlonjon Dec 14, 2021
4c2c3de
Standardize the way new pages are created
davidlonjon Dec 14, 2021
2261a6f
Fix typo
davidlonjon Dec 14, 2021
b3fe283
Improve methods naming
davidlonjon Dec 14, 2021
36fc009
Merge branch 'master' into add/boost-e2e-tests
Dec 15, 2021
edea4ec
Don't setup load promises before navigation; Playwright doesn't work …
Dec 15, 2021
4bd8587
Ensure jetpack is active before ensuring it's connected
Dec 15, 2021
abad901
Don't use .serial; tests don't rely on previous tests, so can continu…
Dec 15, 2021
bb12a7c
Use `test.describe.serial` for `Modules` test suit
haqadn Dec 15, 2021
9463596
Add more apiEndpointsRegex
haqadn Dec 15, 2021
ae7fdce
Merge branch 'master' into add/boost-e2e-tests
Dec 15, 2021
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
81 changes: 74 additions & 7 deletions projects/plugins/boost/app/lib/class-cli.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,14 @@ public function reset_settings() {
*
* ## EXAMPLES
*
* wp jetpack module activate critical-css
* wp jetpack module deactivate critical-css
* wp jetpack-boost module activate critical-css
* wp jetpack-boost module deactivate critical-css
*
* @param array $args Command arguments.
*/
public function module( $args ) {
$action = isset( $args[0] ) ? $args[0] : null;

if ( ! $action ) {
\WP_CLI::error( __( 'Please specify a valid action.', 'jetpack-boost' ) );
}

$module_slug = null;

if ( isset( $args[1] ) ) {
Expand All @@ -83,7 +79,8 @@ public function module( $args ) {
);
}
} else {
\WP_CLI::error( __( 'Please specify a valid module.', 'jetpack-boost' ) );
/* translators: Placeholder is list of available modules. */
\WP_CLI::error( sprintf( __( 'Please specify a valid module. It should be one of %s', 'jetpack-boost' ), wp_json_encode( Jetpack_Boost::AVAILABLE_MODULES_DEFAULT ) ) );
}

switch ( $action ) {
Expand Down Expand Up @@ -113,4 +110,74 @@ private function set_module_status( $module_slug, $status ) {
sprintf( __( "'%1\$s' has been %2\$s.", 'jetpack-boost' ), $module_slug, $status_label )
);
}

/**
* Manage Jetpack Boost connection
*
* ## OPTIONS
*
* <activate|deactivate|status>
* : The action to take.
* ---
* options:
* - activate
* - deactivate
* - status
* ---
*
* ## EXAMPLES
*
* wp jetpack-boost connection activate
* wp jetpack-boost connection deactivate
* wp jetpack-boost connection status
*
* @param array $args Command arguments.
*/
public function connection( $args ) {
$action = isset( $args[0] ) ? $args[0] : null;

switch ( $action ) {
case 'activate':
$result = $this->jetpack_boost->connection->register();
if ( true === $result ) {
\WP_CLI::success( __( 'Boost is connected to WP.com', 'jetpack-boost' ) );
} else {
\WP_CLI::Error( __( 'Boost could not be connected to WP.com', 'jetpack-boost' ) );
}
break;
case 'deactivate':
require_once ABSPATH . '/wp-admin/includes/plugin.php';

if ( is_plugin_active_for_network( JETPACK_BOOST_PATH ) ) {
$this->jetpack_boost->connection->deactivate_disconnect_network();
} else {
$this->jetpack_boost->connection->disconnect();
}

\WP_CLI::success( __( 'Boost is disconnected from WP.com', 'jetpack-boost' ) );
break;
case 'status':
$is_connected = $this->jetpack_boost->connection->is_connected();
if ( $is_connected ) {
\WP_CLI::line( 'connected' );
} else {
\WP_CLI::line( 'disconnected' );
}
break;
}
}

/**
* Reset Jetpack Boost
*
* ## EXAMPLE
*
* wp jetpack-boost reset
*/
public function reset() {
$this->jetpack_boost->deactivate();
$this->jetpack_boost->uninstall();
$this->jetpack_boost->config()->reset();
\WP_CLI::success( 'Reset successfully' );
}
}
4 changes: 4 additions & 0 deletions projects/plugins/boost/changelog/add-boost-e2e-tests
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: added

Refactor and add new core E2E tests
21 changes: 18 additions & 3 deletions projects/plugins/boost/tests/e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,24 @@ To decrypt the config file (a8c only):

Typically, the workflow is the same as the one described in the Jetpack E2E [documentation](../../../jetpack/tests/e2e/README.md). You can follow the same workflow but running the commands inside the Jetpack Boost E2E tests folder.

However, Boost has some shortcuts to get the environment started and run all the tests by running the following commands from the root of the Jetpack Boost repository:
However,below is a quick reminder of the critical steps to run the tests.

- `pnpm test-e2e:start` - This will command will start the e2e testing environment and the tunnel.
From the root of the repo (this has to be done only once or when pulling new changes):

1. run `pnpm install` - This command will install the monorepo NPM dependencies.
2. run `jetpack build plugins/jetpack` - This command will install Jetpack NPM and Composer dependencies as well as building the asset files.
3. run `jetpack build plugins/boost` - This command will install Jetpack Boost NPM and Composer dependencies as well as building the asset files.

From the `projects/plugins/boost/tests/e2e` folder:

4. run `pnpm install` - This will install the Jetpack Boost E2E tests NPM dependencies.
5. run `pnpm run test-decrypt-config` - This command will decrypt the config and create/overwrite the local test config file .
6. run `pnpm run env-start && pnpm run tunnel-on` - This command will start the e2e testing environment and the tunnel.
7. run `pnpm run test-e2e` - This command will run the e2e tests.

However, Boost has some shortcuts to get the environment started and run all the tests by running the following commands from the root of the Jetpack Boost folder:

- `pnpm test-e2e:decrypt-config` - This command will decrypt the config and create/overwrite the local test config file .
- `pnpm test-e2e:start` - This command will start the e2e testing environment and the tunnel.
- `pnpm test-e2e:run` - This command will run the e2e tests.
- `pnpm test-e2e:stop` - This command will stop the e2e testing environment.
- `pnpm test-e2e:decrypt-config` - This command will decrypt the config and create/overwrite the local test config file .
109 changes: 101 additions & 8 deletions projects/plugins/boost/tests/e2e/lib/env/prerequisites.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import logger from 'jetpack-e2e-commons/logger.cjs';
import { execWpCommand } from 'jetpack-e2e-commons/helpers/utils-helper.cjs';

import { expect } from '@playwright/test';
import { JetpackBoostPage } from '../pages/index.js';

export function boostPrerequisitesBuilder() {
export function boostPrerequisitesBuilder( page ) {
const state = {
testPostTitles: [],
clean: undefined,
modules: { active: undefined, inactive: undefined },
connected: undefined,
jetpackDeactivated: undefined,
};

return {
Expand All @@ -16,15 +22,30 @@ export function boostPrerequisitesBuilder() {
state.modules.inactive = modules;
return this;
},
withConnection( shouldBeConnected ) {
state.connected = shouldBeConnected;
return this;
},
withTestContent( testPostTitles = [] ) {
state.testPostTitles = testPostTitles;
return this;
},
withCleanEnv() {
state.clean = true;
return this;
},
async build() {
await buildPrerequisites( state );
await buildPrerequisites( state, page );
},
};
}

async function buildPrerequisites( state ) {
async function buildPrerequisites( state, page ) {
const functions = {
modules: () => ensureModulesState( state.modules ),
connected: () => ensureConnectedState( state.connected, page ),
testPostTitles: () => ensureTestPosts( state.testPostTitles ),
clean: () => ensureCleanState( state.clean ),
};

logger.prerequisites( JSON.stringify( state, null, 2 ) );
Expand Down Expand Up @@ -54,19 +75,91 @@ export async function ensureModulesState( modules ) {
logger.prerequisites( 'Cannot find list of modules to deactivate!' );
}
}

export async function activateModules( modulesList ) {
for ( const module of modulesList ) {
export async function activateModules( modules ) {
for ( const module of modules ) {
logger.prerequisites( `Activating module ${ module }` );
const result = await execWpCommand( `jetpack-boost module activate ${ module }` );
expect( result ).toMatch( new RegExp( `Success: .* has been activated.`, 'i' ) );
}
}

export async function deactivateModules( modulesList ) {
for ( const module of modulesList ) {
export async function deactivateModules( modules ) {
for ( const module of modules ) {
logger.prerequisites( `Deactivating module ${ module }` );
const result = await execWpCommand( `jetpack-boost module deactivate ${ module }` );
expect( result ).toMatch( new RegExp( `Success: .* has been deactivated.`, 'i' ) );
}
}

export async function ensureConnectedState( requiredConnected = undefined, page ) {
const isConnected = await checkIfConnected();

if ( requiredConnected && isConnected ) {
logger.prerequisites( 'Jetpack Boost is already connected, moving on' );
} else if ( requiredConnected && ! isConnected ) {
logger.prerequisites( 'Connecting Jetpack Boost' );
await connect( page );
} else if ( ! requiredConnected && isConnected ) {
logger.prerequisites( 'Disconnecting Jetpack Boost' );
await disconnect();
} else {
logger.prerequisites( 'Jetpack Boost is already disconnected, moving on' );
}
}

export async function connect( page ) {
logger.prerequisites( `Connecting Boost plugin to WP.com` );
// Boost cannot be connected to WP.com using the WP-CLI because the site is considered
// as a localhost site. The only solution is to do it via the site itself running under the localtunnel.
const jetpackBoostPage = await JetpackBoostPage.visit( page );
await jetpackBoostPage.connect();
await jetpackBoostPage.waitForApiResponse( 'connection' );
await jetpackBoostPage.isOverallScoreHeaderShown();
}

export async function disconnect() {
logger.prerequisites( `Disconnecting Boost plugin to WP.com` );
const cliCmd = 'jetpack-boost connection deactivate';
const result = await execWpCommand( cliCmd );
expect( result ).toEqual( 'Success: Boost is disconnected from WP.com' );
}

export async function checkIfConnected() {
const cliCmd = 'jetpack-boost connection status';
const result = await execWpCommand( cliCmd );
if ( typeof result !== 'object' ) {
return result === 'connected';
}
const txt = result.toString();
if ( txt.includes( "Error: 'jetpack-boost' is not a registered wp command" ) ) {
return false;
}
throw result;
}

async function ensureTestPosts( testPostTitles ) {
const testPostTitlesCommands = {
'Hello World with image':
"post create --post_status='publish' --post_title='Hello World with image' --post_content='<h1>Hello World with image</h1><div><p>This is just a test post with an image</p><img src=\"https://picsum.photos/seed/picsum/600/600\" alt=\"placeholder Image\"></div>'",
'Hello World with JavaScript':
'post create --post_status=\'publish\' --post_title=\'Hello World with JavaScript\' --post_content=\'<h1>Hello World with JavaScript</h1><div class="render-blocking-js"><script id="blockingScript">document.getElementById("testDiv").style.display = "block";</script></div><div id="testDiv" style="display: none">This is made visible by JavaScript</div>\'',
};
for ( const testPostTitle of testPostTitles ) {
if ( testPostTitle in testPostTitlesCommands ) {
const result = await execWpCommand( 'post list --fields=post_title' );
if ( result.includes( testPostTitle ) ) {
logger.prerequisites( 'The test content post already exists' );
} else {
logger.prerequisites( 'Creating test content post...' );
await execWpCommand( testPostTitlesCommands[ testPostTitle ] );
}
}
}
}

async function ensureCleanState( shouldReset ) {
if ( shouldReset ) {
logger.prerequisites( 'Resetting Jetpack Boost' );
await execWpCommand( 'jetpack-boost reset' );
}
}
9 changes: 0 additions & 9 deletions projects/plugins/boost/tests/e2e/lib/pages/Homepage.js

This file was deleted.

1 change: 1 addition & 0 deletions projects/plugins/boost/tests/e2e/lib/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as JetpackBoostPage } from './wp-admin/JetpackBoostPage.js';
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { resolveSiteUrl } from 'jetpack-e2e-commons/helpers/utils-helper.cjs';

const apiEndpointsRegex = {
'critical-css-status': /jetpack-boost\/v1\/module\/critical-css\/status/,
'lazy-images-status': /jetpack-boost\/v1\/module\/lazy-images\/status/,
'render-blocking-js-status': /jetpack-boost\/v1\/module\/render-blocking-js\/status/,
'speed-scores-update': /jetpack-boost\/v1\/speed-scores\/\w*\/update/,
};

Expand All @@ -12,6 +14,27 @@ export default class JetpackBoostPage extends WpPage {
super( page, { expectedSelectors: [ '#jb-settings' ], url } );
}

async connect() {
const button = await this.page.$( '.jb-connection button' );
await button.click();
}

async isFreshlyConnected() {
await this.connect();
await this.waitForApiResponse( 'connection' );
return await this.isSiteScoreLoading();
}

async isOverallScoreHeaderShown() {
return await this.isElementVisible( '.jb-site-score' );
}

async isSiteScoreLoading() {
const selector = await this.waitForElementToBeVisible( '.jb-site-score' );
const classNames = await selector.getAttribute( 'class' );
return classNames.includes( 'loading' );
}

async waitForApiResponse( apiEndpointId ) {
await this.page.waitForResponse(
response =>
Expand Down Expand Up @@ -41,4 +64,37 @@ export default class JetpackBoostPage extends WpPage {
} );
return Number( await speedBar.$eval( '.jb-score-bar__score', e => e.textContent ) );
}

async isTheCriticalCssMetaInformationVisible() {
const selector = '.jb-critical-css__meta';
return this.page.isVisible( selector );
}

async waitForCriticalCssMetaInfoVisibility() {
const selector = '.jb-critical-css__meta';
return this.waitForElementToBeVisible( selector, 3 * 60 * 1000 );
}

async waitForCriticalCssGenerationProgressUIVisibility() {
const selector = '.jb-critical-css-progress';
return this.waitForElementToBeVisible( selector );
}

async isTheCriticalCssFailureMessageVisible() {
const selector = '.jb-critical-css__meta .failures';
return this.page.isVisible( selector );
}

async navigateToCriticalCSSAdvancedRecommendations() {
await this.page.click( 'text=Advanced Recommendations' );
}

async isCriticalCSSAdvancedRecommendationsVisible() {
const selector = '.jb-critical-css__advanced';
return this.waitForElementToBeVisible( selector );
}

async navigateToMainSettingsPage() {
await this.page.click( 'text=Go back' );
}
}
5 changes: 4 additions & 1 deletion projects/plugins/boost/tests/e2e/lib/setupTests.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { chromium } from '@playwright/test';
import { prerequisitesBuilder } from 'jetpack-e2e-commons/env/prerequisites.js';
import { boostPrerequisitesBuilder } from './env/prerequisites.js';

export default async function () {
const browser = await chromium.launch();
const page = await browser.newPage();
await prerequisitesBuilder( page ).withLoggedIn( true ).withConnection( true ).build();
await prerequisitesBuilder( page ).withLoggedIn( true ).withActivePlugins( [ 'boost' ] ).build();
await boostPrerequisitesBuilder( page ).withCleanEnv( true ).withConnection( true ).build();
await page.close();
}
Loading