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

Closes #57: Test that beacon script captures right image on template #64

Merged
81 changes: 79 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"test:delayjs:flatsome": "THEME=flatsome $npm_package_config_testCommand --tags @delayjs",
"test:delayjs:divi": "THEME=Divi $npm_package_config_testCommand --tags @delayjs",
"test:delayjs:astra": "THEME=astra $npm_package_config_testCommand --tags @delayjs",
"test:lcp": "$npm_package_config_testCommand --tags @lcp",
"test:test": "$npm_package_config_testCommand --tags @test",
"wp-env": "wp-env"
},
Expand Down Expand Up @@ -50,7 +51,9 @@
},
"homepage": "https://github.com/wp-media/wp-rocket-e2e#readme",
"dependencies": {
"@types/axios": "^0.14.0",
"@types/ssh2": "^1.11.13",
"axios": "^1.6.8",
"backstopjs": "^6.2.2",
"json-diff": "^1.0.6",
"node-ssh": "^13.1.0",
Expand Down
2 changes: 1 addition & 1 deletion src/features/delay-js.feature
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Feature: No Regression with delayjs script udpate
And I save settings 'cache' 'mobileDeviceSeparateCache'
When theme is activated
And I log out
And visit page '' in mobile view
And I visit '' in mobile view
And expand mobile menu
And I click on link
Then page navigated to the new page 'https://e2e.rocketlabsqa.ovh/about-us'
Expand Down
35 changes: 35 additions & 0 deletions src/features/lcp-beacon-script.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@lcp @setup
Feature: Beacon script captures the right images.

Background:
Given I am logged in
And plugin is installed 'new_release'
And plugin is activated

Scenario: Beacon captures expected images in desktop
When I log out
And I visit the following urls in 'desktop'
| path | atfs |
| lcp_bg_inline_template | /wp-content/rocket-test-data/images/lcp/testjpeg.jpeg |
| lcp_bg_samestyle_template | wp-content/rocket-test-data/images/lcp/testjpg.jpg |
| lcp_img_loadedbydynamicjs_template | http://www.google.com/intl/en_com/images/logo_plain.png |
| lcp_img_loadedbyjs_template | /test.png, https://new.rocketlabsqa.ovh/wp-content/rocket-test-data/images/istockphoto-1184692500-612x612.webp |
| lcp_with_space_after_title | /wp-content/rocket-test-data/images/test_inline2.jpeg |
| lcp_test_template | /wp-content/rocket-test-data/images/lipsum_logo.jpg |
| lcp_bg_responsive_webkit_template | /wp-content/rocket-test-data/image/test3.webp, /wp-content/rocket-test-data/images/lcp/testwebp.webp |
| lcp_regular_image_template | /test.png, /wp-content/rocket-test-data/images/test_inline2.jpeg, /wp-content/rocket-test-data/images/Przechwytywanie.PNG, /wp-content/rocket-test-data/images/file_example_JPG_100kB.jpg |
Then lcp and atf should be as expected in 'desktop'

Scenario: Beacon captures expected images in mobile
When I log out
And I visit the following urls in 'mobile'
| path | atfs |
| lcp_bg_inline_template | /wp-content/rocket-test-data/images/test_inline2.jpeg |
| lcp_bg_samestyle_template | https://new.rocketlabsqa.ovh/wp-content/rocket-test-data/images/lcp/testavif.avif |
| lcp_img_loadedbydynamicjs_template | http://www.google.com/intl/en_com/images/logo_plain.png |
| lcp_img_loadedbyjs_template | /test.png, https://new.rocketlabsqa.ovh/wp-content/rocket-test-data/images/istockphoto-1184692500-612x612.webp |
| lcp_with_space_after_title | https://new.rocketlabsqa.ovh/wp-content/rocket-test-data/images/test_inline2.jpeg |
| lcp_test_template | /wp-content/rocket-test-data/images/test_internal2.jpg, https://new.rocketlabsqa.ovh/wp-content/rocket-test-data/images/lipsum_logo.jpg |
| lcp_bg_responsive_webkit_template | https://rocketlabsqa.ovh/wp-content/rocket-test-data/images/fixtheissue.jpg |
| lcp_regular_image_template | /test.png, /wp-content/rocket-test-data/images/test_inline2.jpeg, /wp-content/rocket-test-data/images/lcp/testPng.png, /wp-content/rocket-test-data/images/Przechwytywanie.PNG, /wp-content/rocket-test-data/images/file_example_JPG_100kB.jpg, /wp-content/rocket-test-data/images/img_nature.jpg, /wp-content/rocket-test-data/images/mountain.webp |
Then lcp and atf should be as expected in 'mobile'
2 changes: 1 addition & 1 deletion src/support/steps/general.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ When('theme is activated', async function (this:ICustomWorld) {
/**
* Executes the step visit a page in mobile view.
*/
When('visit page {string} in mobile view', async function (this:ICustomWorld, page) {
When('I visit {string} in mobile view', async function (this:ICustomWorld, page) {
await this.page.setViewportSize({
width: 500,
height: 480,
Expand Down
130 changes: 130 additions & 0 deletions src/support/steps/lcp-beacon-script.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/**
* @fileoverview
* This module contains Cucumber step definitions using Playwright for deleting the WP Rocket plugin.
* It includes steps for confirming the deletion, navigating to the plugins page, deactivating the plugin,
* handling deactivation modal, initiating the deletion process, and asserting successful deletion.
*
* @requires {@link ../../common/custom-world}
* @requires {@link @playwright/test}
* @requires {@link @cucumber/cucumber}
*/
import { ICustomWorld } from "../../common/custom-world";
import { expect } from "@playwright/test";
import { Given, Then } from "@cucumber/cucumber";
import { LcpDataTable, LcpData, Row } from "../../../utils/types";
import axios from 'axios';
import { dbQuery, getWPTablePrefix } from "../../../utils/commands";
import { extractFromStdout } from "../../../utils/helpers";
import { WP_BASE_URL } from '../../../config/wp.config';

let data: LcpDataTable[],
truthy: boolean = true,
failMsg: string = "";

const [actual, expected]: [LcpData, LcpData] = [{}, {}];

/**
* Executes step to visit page based on the form factor(desktop/mobile) and get the LCP/ATF data from DB.
*/
Given('I visit the following urls in {string}', async function (this: ICustomWorld, formFactor: string, dataTable) {
let sql: string,
result: string,
resultFromStdout: Row[];

// Set page to be visited in mobile.
if ( formFactor === 'mobile' ) {
await this.page.setViewportSize({
width: 360,
height: 640,
});
}

data = dataTable.rows();

const tablePrefix: string = await getWPTablePrefix();

// Visit page.
for (const row of data) {
const url: string = `${WP_BASE_URL}/${row[0]}`;
await this.utils.visitPage(row[0]);
// Wait for 2 seconds before fetching from DB.
await this.page.waitForTimeout(2000);

// Get the LCP/ATF from the DB
sql = `SELECT lcp, viewport FROM ${tablePrefix}wpr_above_the_fold WHERE url LIKE "%${row[0]}%"`;
result = await dbQuery(sql);
resultFromStdout = await extractFromStdout(result);

// Populate the actual data.
actual[row[0]] = {
url: url,
lcp: resultFromStdout[0].lcp,
viewport: resultFromStdout[0].viewport
}
}
});

/**
* Executes the step to assert that LCP & ATF should be as expected.
*/
Then('lcp and atf should be as expected in {string}', async function (this: ICustomWorld, formFactor: string) {
let apiUrl: string;

// Get the LCP from the PSI
for (const row of data) {
const url: string = `${WP_BASE_URL}/${row[0]}`;
apiUrl = `https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=${encodeURIComponent(url+'?nowprocket')}/&fields=lighthouseResult.audits&strategy=${formFactor}`;

try {
const response = await axios.get(apiUrl);
const data = response.data;
const lcp: string = data.lighthouseResult.audits['prioritize-lcp-image'] && data.lighthouseResult.audits['prioritize-lcp-image'].details ? data.lighthouseResult.audits['prioritize-lcp-image'].details.debugData.initiatorPath[0].url : '';

// Populate the expected data.
expected[row[0]] = {
url: url,
lcp: lcp,
viewport: row[1]
}
} catch (error) {
console.error(`Error fetching PageSpeed Insight for ${url}:`, error);
}
}

// Make assertions.
for (const key in actual) {
if (Object.hasOwnProperty.call(actual, key)) {
const [url, actualLcp, expectedLcp, actualViewport, expectedViewport] = [actual[key].url, actual[key].lcp, expected[key].lcp, actual[key].viewport, expected[key].viewport];

// Check if expected lcp is present in actual lcp.
if (!actualLcp.includes(expectedLcp)) {
truthy = false;
failMsg += `Expected LCP - ${expectedLcp} for ${url} is not present in actual - ${actualLcp}\n\n\n`;
}

// Cater for multiple expected viewport candidates.
if (expectedViewport.includes(',')) {
const viewports = expectedViewport.split(',').map(item => item.trim());

for (const viewport of viewports) {
if (!actualViewport.includes(viewport)) {
truthy = false;
failMsg += `Expected Viewport - ${viewport} for ${url} is not present in actual - ${actualViewport}\n\n\n`;
}
}
// Treat single viewport candidate.
} else{
if (!actualViewport.includes(expectedViewport)) {
truthy = false;
failMsg += `Expected Viewport - ${expectedViewport} for ${url} is not present in actual - ${actualViewport}\n\n\n`;
}
}
}
}

if ( failMsg !== '' ) {
console.log(failMsg);
}

expect(truthy, failMsg).toBeTruthy();
});
52 changes: 52 additions & 0 deletions utils/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,4 +242,56 @@ export async function generateUsers(users: Array<{name: string, email: string, r
})
}

/**
* Wraps a command with the appropriate prefix for SSH.
*
* @param {string} command - The command to be wrapped.
* @returns {string} - The wrapped command.
*/
function wrapSSHPrefix(command: string): string {
const cwd = getWPDir(configurations);

if(configurations.type === ServerType.external) {
return `ssh ${configurations.ssh.username}@${configurations.ssh.address} -i ${configurations.ssh.key} -t "cd ${cwd} && ${command}"`;
}
}

/**
* Performs a sql query using wp cli.
*
* @param {string} sql SQL Query.
* @return {Promise<string>} A Promise that resolves when the query is executed.
*/
export async function dbQuery(sql: string): Promise<string> {
sql = sql.replaceAll('"', '\\"');

const command = wrapSSHPrefix(`wp db query '${sql}'`);
const result = exec(command, { silent: true });

if (result.code === 1) {
return '';
}

return result.stdout;
}

/**
* Gets the WordPress Table Prefix.
*
* @return {Promise<string>} A Promise that resolves when the query is executed.
*/
export async function getWPTablePrefix(): Promise<string> {
const command = wrapSSHPrefix(`wp config get table_prefix`);
const result = exec(command, { silent: true });

if (result.code === 1) {
return '';
}

let tablePrefix: string = result.stdout;
tablePrefix = tablePrefix.replace(/\r?\n/g, "");

return tablePrefix;
}

export default wp;
Loading
Loading