From b95969ca00f5878c1fa5b275d0887371280a191d Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Thu, 4 Apr 2024 09:30:36 +0100 Subject: [PATCH 01/15] Updated step and step definition --- src/features/delay-js.feature | 2 +- src/support/steps/general.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/features/delay-js.feature b/src/features/delay-js.feature index 941c59c..7909ece 100644 --- a/src/features/delay-js.feature +++ b/src/features/delay-js.feature @@ -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' diff --git a/src/support/steps/general.ts b/src/support/steps/general.ts index 89fd6e4..32a859b 100644 --- a/src/support/steps/general.ts +++ b/src/support/steps/general.ts @@ -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, From e833006e1225230c5dbcf91fc184e86086a728e3 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Thu, 4 Apr 2024 09:31:14 +0100 Subject: [PATCH 02/15] Added new commands --- utils/commands.ts | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/utils/commands.ts b/utils/commands.ts index 559cb23..929632a 100644 --- a/utils/commands.ts +++ b/utils/commands.ts @@ -242,4 +242,50 @@ export async function generateUsers(users: Array<{name: string, email: string, r }) } +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} A Promise that resolves when the query is executed. + */ +export async function dbQuery(sql: string): Promise { + 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} A Promise that resolves when the query is executed. + */ +export async function getWPTablePrefix(): Promise { + 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; \ No newline at end of file From 83b20fd25f10c86ce0ce8e8d0e380bd3c4e10e24 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Thu, 4 Apr 2024 09:31:42 +0100 Subject: [PATCH 03/15] New helper function to extract stdout --- utils/helpers.ts | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/utils/helpers.ts b/utils/helpers.ts index 4b3aa5c..df79bea 100644 --- a/utils/helpers.ts +++ b/utils/helpers.ts @@ -16,7 +16,7 @@ import type { Page } from '@playwright/test'; import backstop from 'backstopjs'; // Interfaces -import { ExportedSettings, VRurlConfig, Viewport } from '../utils/types'; +import { ExportedSettings, VRurlConfig, Viewport, Row } from '../utils/types'; import { uiReflectedSettings } from './exclusions'; import { WP_BASE_URL } from '../config/wp.config'; @@ -367,3 +367,32 @@ export const deleteFolder = async(folderPath: string): Promise => { console.error(`Error deleting folder "${folderPath}": ${error.message}`); } } + +export const extractFromStdout = async(data: string): Promise => { + // Split the data into lines + const lines: string[] = data.trim().split('\n'); + + // Extract headers from the first line + const headers: string[] = lines[0].split('\t'); + + // Initialize an array to store objects + const result: Row[] = []; + + // Iterate over the remaining lines and create objects + for (let i: number = 1; i < lines.length; i++) { + const values: string[] = lines[i].split('\t'); + const obj: Row = {} as Row; + for (let j: number = 0; j < headers.length; j++) { + // Use keyof Row to ensure type safety + let value: string = values[j]; + // Perform multiple replacements until no more backslashes are found + while (value.includes('\\\\')) { + value = value.replace(/\\\\/g, ''); + } + obj[headers[j] as keyof Row] = value; + } + result.push(obj); + } + + return result; +} From ea1d7e39030ccb77ff26a55c235bd3726295f43d Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Thu, 4 Apr 2024 09:32:06 +0100 Subject: [PATCH 04/15] Defined new types --- utils/types.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/utils/types.ts b/utils/types.ts index ef5c098..2258009 100644 --- a/utils/types.ts +++ b/utils/types.ts @@ -98,4 +98,19 @@ export type Viewport = { name: string; width: number; height: number; -}; \ No newline at end of file +}; + +export interface LcpDataTable { + key: string; + value: string; +} +export interface LcpData { + [key: string]: { + lcp: string, + viewport: string + } +} + +export interface Row { + [key: string]: string +} \ No newline at end of file From 57c20c84897f839f1760cbf9f25d860d093893b2 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Thu, 4 Apr 2024 09:33:26 +0100 Subject: [PATCH 05/15] New gherkin step --- src/features/lcp-beacon-script.feature | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/features/lcp-beacon-script.feature diff --git a/src/features/lcp-beacon-script.feature b/src/features/lcp-beacon-script.feature new file mode 100644 index 0000000..2488ba8 --- /dev/null +++ b/src/features/lcp-beacon-script.feature @@ -0,0 +1,27 @@ +@lcp @setup @lcpbeacon +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 + Given I log out + And I visit the following urls in 'desktop' + | path | urls | atfs | + | lcp_bg_inline_template | https://e2e.rocketlabsqa.ovh/lcp_bg_inline_template/ | /wp-content/rocket-test-data/images/lcp/testjpeg.jpeg | + | lcp_bg_samestyle_template | https://e2e.rocketlabsqa.ovh/lcp_bg_samestyle_template/ | wp-content/rocket-test-data/images/lcp/testjpg.jpg | + | lcp_img_loadedbydynamicjs_template | https://e2e.rocketlabsqa.ovh/lcp_img_loadedbydynamicjs_template/ | http://www.google.com/intl/en_com/images/logo_plain.png | + | lcp_img_loadedbyjs_template | https://e2e.rocketlabsqa.ovh/lcp_img_loadedbyjs_template/ | /test.png, https://new.rocketlabsqa.ovh/wp-content/rocket-test-data/images/istockphoto-1184692500-612x612.webp | + Then lcp and atf should be as expected in 'desktop' + + Scenario: Beacon captures expected images in mobile + Given I log out + And I visit the following urls in 'mobile' + | path | urls | atfs | + | lcp_bg_inline_template | https://e2e.rocketlabsqa.ovh/lcp_bg_inline_template/ | /wp-content/rocket-test-data/images/test_inline2.jpeg | + | lcp_bg_samestyle_template | https://e2e.rocketlabsqa.ovh/lcp_bg_samestyle_template/ | https://new.rocketlabsqa.ovh/wp-content/rocket-test-data/images/lcp/testavif.avif | + | lcp_img_loadedbydynamicjs_template | https://e2e.rocketlabsqa.ovh/lcp_img_loadedbydynamicjs_template/ | http://www.google.com/intl/en_com/images/logo_plain.png | + | lcp_img_loadedbyjs_template | https://e2e.rocketlabsqa.ovh/lcp_img_loadedbyjs_template/ | /test.png, https://new.rocketlabsqa.ovh/wp-content/rocket-test-data/images/istockphoto-1184692500-612x612.webp | + Then lcp and atf should be as expected in 'mobile' From 3b4a208462fc24793b833db823bab8d434c81bfc Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Thu, 4 Apr 2024 09:34:02 +0100 Subject: [PATCH 06/15] Added new step definition --- src/support/steps/lcp-beacon-script.ts | 130 +++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 src/support/steps/lcp-beacon-script.ts diff --git a/src/support/steps/lcp-beacon-script.ts b/src/support/steps/lcp-beacon-script.ts new file mode 100644 index 0000000..89618eb --- /dev/null +++ b/src/support/steps/lcp-beacon-script.ts @@ -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"; + +let data: LcpDataTable[], + truthy: boolean = true, + failMsg: string = ""; + +const [actual, expected]: [LcpData, LcpData] = [{}, {}]; + +Given('I clear critical images', async function (this: ICustomWorld) { + await this.utils.wprDropdown(); + await this.page.locator('#wp-admin-bar-clean-saas a').click(); +}); + +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 !== 'desktop' ) { + await this.page.setViewportSize({ + width: 360, + height: 640, + }); + } + + data = dataTable.rows(); + + const tablePrefix: string = await getWPTablePrefix(); + + // Visit page. + for (const row of data) { + 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]] = { + lcp: resultFromStdout[0].lcp, + viewport: resultFromStdout[0].viewport + } + } + + console.log(actual); +}); + +/** + * 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) { + apiUrl = `https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=${encodeURIComponent(row[1]+'?nowprocket')}/&fields=lighthouseResult.audits&strategy=${formFactor}`; + + try { + const response = await axios.get(apiUrl); + const data = response.data; + + // Populate the expected data. + expected[row[0]] = { + lcp: data.lighthouseResult.audits['prioritize-lcp-image'].details.debugData.initiatorPath[0].url, + viewport: row[2] + } + } catch (error) { + console.error(`Error fetching PageSpeed Insight for ${row[1]}:`, error); + } + } + + console.log(expected); + + // Make assertions. + for (const key in actual) { + if (Object.hasOwnProperty.call(actual, key)) { + const [actualLcp, expectedLcp, actualViewport, expectedViewport] = [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} is not present in actual - ${actualLcp}\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} is not present in actual - ${actualViewport}\n`; + } + } + // Treat single viewport candidate. + } else{ + if (!actualViewport.includes(expectedViewport)) { + truthy = false; + failMsg += `Expected Viewport - ${expectedViewport} is not present in actual - ${actualViewport}\n`; + } + } + } + } + + if ( failMsg !== '' ) { + console.log(failMsg); + } + + expect(truthy, failMsg).toBeTruthy(); +}); \ No newline at end of file From 3c22be7e3d3df7f01f9e24742108d5c7b173e7c3 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Thu, 4 Apr 2024 09:35:37 +0100 Subject: [PATCH 07/15] Added new script and axios package --- package-lock.json | 81 +++++++++++++++++++++++++++++++++++++++++++++-- package.json | 3 ++ 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0a7bd40..5a5f90a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,11 +9,13 @@ "version": "1.0.0", "license": "ISC", "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", - "node-zip": "^1.1.1", + "node-zip": "^1.0.1", "playwright": "^1.34.3", "shelljs": "^0.8.5", "ssh2": "^1.14.0", @@ -785,6 +787,15 @@ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true }, + "node_modules/@types/axios": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.0.tgz", + "integrity": "sha512-KqQnQbdYE54D7oa/UmYVMZKq7CO4l8DEENzOKc4aBRwxCXSlJXGz83flFx5L7AWrOQnmuN3kVsRdt+GZPPjiVQ==", + "deprecated": "This is a stub types definition for axios (https://github.com/mzabriskie/axios). axios provides its own type definitions, so you don't need @types/axios installed!", + "dependencies": { + "axios": "*" + } + }, "node_modules/@types/backstopjs": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/@types/backstopjs/-/backstopjs-6.1.1.tgz", @@ -1353,6 +1364,21 @@ "lodash": "^4.17.14" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/backstopjs": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/backstopjs/-/backstopjs-6.2.2.tgz", @@ -1775,6 +1801,17 @@ "node": ">=0.1.90" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", @@ -2013,6 +2050,14 @@ "node": ">=8" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -2689,6 +2734,38 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -5698,4 +5775,4 @@ } } } -} \ No newline at end of file +} diff --git a/package.json b/package.json index 8280d62..442f7a9 100755 --- a/package.json +++ b/package.json @@ -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:lcpbeacon": "$npm_package_config_testCommand --tags @lcpbeacon", "test:test": "$npm_package_config_testCommand --tags @test", "wp-env": "wp-env" }, @@ -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", From 0d798c428915277bd68d230e2cd3719e42bd5696 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Thu, 4 Apr 2024 10:06:25 +0100 Subject: [PATCH 08/15] Updated tag and script --- package.json | 2 +- src/features/lcp-beacon-script.feature | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 442f7a9..19a51f9 100755 --- a/package.json +++ b/package.json @@ -20,7 +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:lcpbeacon": "$npm_package_config_testCommand --tags @lcpbeacon", + "test:lcp": "$npm_package_config_testCommand --tags @lcp", "test:test": "$npm_package_config_testCommand --tags @test", "wp-env": "wp-env" }, diff --git a/src/features/lcp-beacon-script.feature b/src/features/lcp-beacon-script.feature index 2488ba8..02cffef 100644 --- a/src/features/lcp-beacon-script.feature +++ b/src/features/lcp-beacon-script.feature @@ -1,4 +1,4 @@ -@lcp @setup @lcpbeacon +@lcp @setup Feature: Beacon script captures the right images. Background: From 54d10c03132f1fe7912fee399a1b4a862cc4eeab Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Thu, 4 Apr 2024 10:08:38 +0100 Subject: [PATCH 09/15] Update form factor condition --- src/support/steps/lcp-beacon-script.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/support/steps/lcp-beacon-script.ts b/src/support/steps/lcp-beacon-script.ts index 89618eb..dabad53 100644 --- a/src/support/steps/lcp-beacon-script.ts +++ b/src/support/steps/lcp-beacon-script.ts @@ -33,7 +33,7 @@ Given('I visit the following urls in {string}', async function (this: ICustomWor resultFromStdout: Row[]; // Set page to be visited in mobile. - if ( formFactor !== 'desktop' ) { + if ( formFactor === 'mobile' ) { await this.page.setViewportSize({ width: 360, height: 640, From 82b277b5397e488a747b3f084d59185b237f5218 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Thu, 4 Apr 2024 11:33:43 +0100 Subject: [PATCH 10/15] Updated step definition --- src/support/steps/lcp-beacon-script.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/support/steps/lcp-beacon-script.ts b/src/support/steps/lcp-beacon-script.ts index dabad53..83bfce4 100644 --- a/src/support/steps/lcp-beacon-script.ts +++ b/src/support/steps/lcp-beacon-script.ts @@ -57,6 +57,7 @@ Given('I visit the following urls in {string}', async function (this: ICustomWor // Populate the actual data. actual[row[0]] = { + url: row[1], lcp: resultFromStdout[0].lcp, viewport: resultFromStdout[0].viewport } @@ -78,10 +79,12 @@ Then('lcp and atf should be as expected in {string}', async function (this: ICus 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]] = { - lcp: data.lighthouseResult.audits['prioritize-lcp-image'].details.debugData.initiatorPath[0].url, + url: row[1], + lcp: lcp, viewport: row[2] } } catch (error) { @@ -94,12 +97,12 @@ Then('lcp and atf should be as expected in {string}', async function (this: ICus // Make assertions. for (const key in actual) { if (Object.hasOwnProperty.call(actual, key)) { - const [actualLcp, expectedLcp, actualViewport, expectedViewport] = [actual[key].lcp, expected[key].lcp, actual[key].viewport, expected[key].viewport]; + 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} is not present in actual - ${actualLcp}\n`; + failMsg += `Expected LCP - ${expectedLcp} for ${url} is not present in actual - ${actualLcp}\n\n\n`; } // Cater for multiple expected viewport candidates. @@ -109,14 +112,14 @@ Then('lcp and atf should be as expected in {string}', async function (this: ICus for (const viewport of viewports) { if (!actualViewport.includes(viewport)) { truthy = false; - failMsg += `Expected Viewport - ${viewport} is not present in actual - ${actualViewport}\n`; + 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} is not present in actual - ${actualViewport}\n`; + failMsg += `Expected Viewport - ${expectedViewport} for ${url} is not present in actual - ${actualViewport}\n\n\n`; } } } From 0e5faaa04d2058ff99d66211afe617517f9e2651 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Thu, 4 Apr 2024 11:34:02 +0100 Subject: [PATCH 11/15] Updated type definition --- utils/types.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/types.ts b/utils/types.ts index 2258009..8cfd687 100644 --- a/utils/types.ts +++ b/utils/types.ts @@ -106,6 +106,7 @@ export interface LcpDataTable { } export interface LcpData { [key: string]: { + url: string, lcp: string, viewport: string } From 4b7ef04d0638b1e8ea7beee2019ce13583f06532 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Thu, 4 Apr 2024 11:34:25 +0100 Subject: [PATCH 12/15] Updated Gherkin steps --- src/features/lcp-beacon-script.feature | 32 ++++++++++++++++---------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/features/lcp-beacon-script.feature b/src/features/lcp-beacon-script.feature index 02cffef..47c03ee 100644 --- a/src/features/lcp-beacon-script.feature +++ b/src/features/lcp-beacon-script.feature @@ -7,21 +7,29 @@ Feature: Beacon script captures the right images. And plugin is activated Scenario: Beacon captures expected images in desktop - Given I log out + When I log out And I visit the following urls in 'desktop' - | path | urls | atfs | - | lcp_bg_inline_template | https://e2e.rocketlabsqa.ovh/lcp_bg_inline_template/ | /wp-content/rocket-test-data/images/lcp/testjpeg.jpeg | - | lcp_bg_samestyle_template | https://e2e.rocketlabsqa.ovh/lcp_bg_samestyle_template/ | wp-content/rocket-test-data/images/lcp/testjpg.jpg | - | lcp_img_loadedbydynamicjs_template | https://e2e.rocketlabsqa.ovh/lcp_img_loadedbydynamicjs_template/ | http://www.google.com/intl/en_com/images/logo_plain.png | - | lcp_img_loadedbyjs_template | https://e2e.rocketlabsqa.ovh/lcp_img_loadedbyjs_template/ | /test.png, https://new.rocketlabsqa.ovh/wp-content/rocket-test-data/images/istockphoto-1184692500-612x612.webp | + | path | urls | atfs | + | lcp_bg_inline_template | https://e2e.rocketlabsqa.ovh/lcp_bg_inline_template/ | /wp-content/rocket-test-data/images/lcp/testjpeg.jpeg | + | lcp_bg_samestyle_template | https://e2e.rocketlabsqa.ovh/lcp_bg_samestyle_template/ | wp-content/rocket-test-data/images/lcp/testjpg.jpg | + | lcp_img_loadedbydynamicjs_template | https://e2e.rocketlabsqa.ovh/lcp_img_loadedbydynamicjs_template/ | http://www.google.com/intl/en_com/images/logo_plain.png | + | lcp_img_loadedbyjs_template | https://e2e.rocketlabsqa.ovh/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://e2e.rocketlabsqa.ovh/lcp_with_space_after_title/ | https://new.rocketlabsqa.ovh/wp-content/rocket-test-data/images/test_inline2.jpeg | + | lcp_test_template | https://e2e.rocketlabsqa.ovh/lcp_test_template/ | https://new.rocketlabsqa.ovh/wp-content/rocket-test-data/images/lipsum_logo.jpg | + | lcp_bg_responsive_webkit_template | https://e2e.rocketlabsqa.ovh/lcp_bg_responsive_webkit_template | https://e2e.rocketlabsqa.ovh/wp-content/rocket-test-data/image/test3.webp, /wp-content/rocket-test-data/images/lcp/testwebp.webp | + | lcp_regular_image_template | https://e2e.rocketlabsqa.ovh/lcp_regular_image_template/ | /test.png, https://e2e.rocketlabsqa.ovh/wp-content/rocket-test-data/images/test_inline2.jpeg, https://e2e.rocketlabsqa.ovh/wp-content/rocket-test-data/images/Przechwytywanie.PNG, https://e2e.rocketlabsqa.ovh/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 - Given I log out + When I log out And I visit the following urls in 'mobile' - | path | urls | atfs | - | lcp_bg_inline_template | https://e2e.rocketlabsqa.ovh/lcp_bg_inline_template/ | /wp-content/rocket-test-data/images/test_inline2.jpeg | - | lcp_bg_samestyle_template | https://e2e.rocketlabsqa.ovh/lcp_bg_samestyle_template/ | https://new.rocketlabsqa.ovh/wp-content/rocket-test-data/images/lcp/testavif.avif | - | lcp_img_loadedbydynamicjs_template | https://e2e.rocketlabsqa.ovh/lcp_img_loadedbydynamicjs_template/ | http://www.google.com/intl/en_com/images/logo_plain.png | - | lcp_img_loadedbyjs_template | https://e2e.rocketlabsqa.ovh/lcp_img_loadedbyjs_template/ | /test.png, https://new.rocketlabsqa.ovh/wp-content/rocket-test-data/images/istockphoto-1184692500-612x612.webp | + | path | urls | atfs | + | lcp_bg_inline_template | https://e2e.rocketlabsqa.ovh/lcp_bg_inline_template/ | /wp-content/rocket-test-data/images/test_inline2.jpeg | + | lcp_bg_samestyle_template | https://e2e.rocketlabsqa.ovh/lcp_bg_samestyle_template/ | https://new.rocketlabsqa.ovh/wp-content/rocket-test-data/images/lcp/testavif.avif | + | lcp_img_loadedbydynamicjs_template | https://e2e.rocketlabsqa.ovh/lcp_img_loadedbydynamicjs_template/ | http://www.google.com/intl/en_com/images/logo_plain.png | + | lcp_img_loadedbyjs_template | https://e2e.rocketlabsqa.ovh/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://e2e.rocketlabsqa.ovh/lcp_with_space_after_title/ | https://new.rocketlabsqa.ovh/wp-content/rocket-test-data/images/test_inline2.jpeg | + | lcp_test_template | https://e2e.rocketlabsqa.ovh/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://e2e.rocketlabsqa.ovh/lcp_bg_responsive_webkit_template | https://rocketlabsqa.ovh/wp-content/rocket-test-data/images/fixtheissue.jpg | + | lcp_regular_image_template | https://e2e.rocketlabsqa.ovh/lcp_regular_image_template/ | /test.png, https://e2e.rocketlabsqa.ovh/wp-content/rocket-test-data/images/test_inline2.jpeg, https://e2e.rocketlabsqa.ovh/wp-content/rocket-test-data/images/lcp/testPng.png, https://e2e.rocketlabsqa.ovh/wp-content/rocket-test-data/images/Przechwytywanie.PNG, https://e2e.rocketlabsqa.ovh/wp-content/rocket-test-data/images/file_example_JPG_100kB.jpg, https://e2e.rocketlabsqa.ovh/wp-content/rocket-test-data/images/img_nature.jpg, https://e2e.rocketlabsqa.ovh/wp-content/rocket-test-data/images/mountain.webp | Then lcp and atf should be as expected in 'mobile' From 9f937a1add1f0fa33face33461eb6a222818f3d7 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Thu, 4 Apr 2024 14:12:35 +0100 Subject: [PATCH 13/15] Updated doc blocks and remove console logs --- src/support/steps/lcp-beacon-script.ts | 12 +++--------- utils/commands.ts | 6 ++++++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/support/steps/lcp-beacon-script.ts b/src/support/steps/lcp-beacon-script.ts index 83bfce4..eab8b11 100644 --- a/src/support/steps/lcp-beacon-script.ts +++ b/src/support/steps/lcp-beacon-script.ts @@ -22,11 +22,9 @@ let data: LcpDataTable[], const [actual, expected]: [LcpData, LcpData] = [{}, {}]; -Given('I clear critical images', async function (this: ICustomWorld) { - await this.utils.wprDropdown(); - await this.page.locator('#wp-admin-bar-clean-saas a').click(); -}); - +/** + * 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, @@ -62,8 +60,6 @@ Given('I visit the following urls in {string}', async function (this: ICustomWor viewport: resultFromStdout[0].viewport } } - - console.log(actual); }); /** @@ -92,8 +88,6 @@ Then('lcp and atf should be as expected in {string}', async function (this: ICus } } - console.log(expected); - // Make assertions. for (const key in actual) { if (Object.hasOwnProperty.call(actual, key)) { diff --git a/utils/commands.ts b/utils/commands.ts index 929632a..344124e 100644 --- a/utils/commands.ts +++ b/utils/commands.ts @@ -242,6 +242,12 @@ 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); From d31bb05d73ba4566c03540dc03c419bad26b9ca8 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Fri, 5 Apr 2024 10:33:39 +0100 Subject: [PATCH 14/15] Removed Hardcoded base url --- src/features/lcp-beacon-script.feature | 36 +++++++++++++------------- src/support/steps/lcp-beacon-script.ts | 15 ++++++----- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/features/lcp-beacon-script.feature b/src/features/lcp-beacon-script.feature index 47c03ee..819e74c 100644 --- a/src/features/lcp-beacon-script.feature +++ b/src/features/lcp-beacon-script.feature @@ -9,27 +9,27 @@ Feature: Beacon script captures the right images. Scenario: Beacon captures expected images in desktop When I log out And I visit the following urls in 'desktop' - | path | urls | atfs | - | lcp_bg_inline_template | https://e2e.rocketlabsqa.ovh/lcp_bg_inline_template/ | /wp-content/rocket-test-data/images/lcp/testjpeg.jpeg | - | lcp_bg_samestyle_template | https://e2e.rocketlabsqa.ovh/lcp_bg_samestyle_template/ | wp-content/rocket-test-data/images/lcp/testjpg.jpg | - | lcp_img_loadedbydynamicjs_template | https://e2e.rocketlabsqa.ovh/lcp_img_loadedbydynamicjs_template/ | http://www.google.com/intl/en_com/images/logo_plain.png | - | lcp_img_loadedbyjs_template | https://e2e.rocketlabsqa.ovh/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://e2e.rocketlabsqa.ovh/lcp_with_space_after_title/ | https://new.rocketlabsqa.ovh/wp-content/rocket-test-data/images/test_inline2.jpeg | - | lcp_test_template | https://e2e.rocketlabsqa.ovh/lcp_test_template/ | https://new.rocketlabsqa.ovh/wp-content/rocket-test-data/images/lipsum_logo.jpg | - | lcp_bg_responsive_webkit_template | https://e2e.rocketlabsqa.ovh/lcp_bg_responsive_webkit_template | https://e2e.rocketlabsqa.ovh/wp-content/rocket-test-data/image/test3.webp, /wp-content/rocket-test-data/images/lcp/testwebp.webp | - | lcp_regular_image_template | https://e2e.rocketlabsqa.ovh/lcp_regular_image_template/ | /test.png, https://e2e.rocketlabsqa.ovh/wp-content/rocket-test-data/images/test_inline2.jpeg, https://e2e.rocketlabsqa.ovh/wp-content/rocket-test-data/images/Przechwytywanie.PNG, https://e2e.rocketlabsqa.ovh/wp-content/rocket-test-data/images/file_example_JPG_100kB.jpg | + | 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 | urls | atfs | - | lcp_bg_inline_template | https://e2e.rocketlabsqa.ovh/lcp_bg_inline_template/ | /wp-content/rocket-test-data/images/test_inline2.jpeg | - | lcp_bg_samestyle_template | https://e2e.rocketlabsqa.ovh/lcp_bg_samestyle_template/ | https://new.rocketlabsqa.ovh/wp-content/rocket-test-data/images/lcp/testavif.avif | - | lcp_img_loadedbydynamicjs_template | https://e2e.rocketlabsqa.ovh/lcp_img_loadedbydynamicjs_template/ | http://www.google.com/intl/en_com/images/logo_plain.png | - | lcp_img_loadedbyjs_template | https://e2e.rocketlabsqa.ovh/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://e2e.rocketlabsqa.ovh/lcp_with_space_after_title/ | https://new.rocketlabsqa.ovh/wp-content/rocket-test-data/images/test_inline2.jpeg | - | lcp_test_template | https://e2e.rocketlabsqa.ovh/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://e2e.rocketlabsqa.ovh/lcp_bg_responsive_webkit_template | https://rocketlabsqa.ovh/wp-content/rocket-test-data/images/fixtheissue.jpg | - | lcp_regular_image_template | https://e2e.rocketlabsqa.ovh/lcp_regular_image_template/ | /test.png, https://e2e.rocketlabsqa.ovh/wp-content/rocket-test-data/images/test_inline2.jpeg, https://e2e.rocketlabsqa.ovh/wp-content/rocket-test-data/images/lcp/testPng.png, https://e2e.rocketlabsqa.ovh/wp-content/rocket-test-data/images/Przechwytywanie.PNG, https://e2e.rocketlabsqa.ovh/wp-content/rocket-test-data/images/file_example_JPG_100kB.jpg, https://e2e.rocketlabsqa.ovh/wp-content/rocket-test-data/images/img_nature.jpg, https://e2e.rocketlabsqa.ovh/wp-content/rocket-test-data/images/mountain.webp | + | 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' diff --git a/src/support/steps/lcp-beacon-script.ts b/src/support/steps/lcp-beacon-script.ts index eab8b11..891fdbe 100644 --- a/src/support/steps/lcp-beacon-script.ts +++ b/src/support/steps/lcp-beacon-script.ts @@ -15,6 +15,7 @@ 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, @@ -44,7 +45,8 @@ Given('I visit the following urls in {string}', async function (this: ICustomWor // Visit page. for (const row of data) { - await this.utils.visitPage(row[0]); + const url: string = `${WP_BASE_URL}/${row[0]}`; + await this.utils.visitPage(url); // Wait for 2 seconds before fetching from DB. await this.page.waitForTimeout(2000); @@ -55,7 +57,7 @@ Given('I visit the following urls in {string}', async function (this: ICustomWor // Populate the actual data. actual[row[0]] = { - url: row[1], + url: url, lcp: resultFromStdout[0].lcp, viewport: resultFromStdout[0].viewport } @@ -70,7 +72,8 @@ Then('lcp and atf should be as expected in {string}', async function (this: ICus // Get the LCP from the PSI for (const row of data) { - apiUrl = `https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=${encodeURIComponent(row[1]+'?nowprocket')}/&fields=lighthouseResult.audits&strategy=${formFactor}`; + 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); @@ -79,12 +82,12 @@ Then('lcp and atf should be as expected in {string}', async function (this: ICus // Populate the expected data. expected[row[0]] = { - url: row[1], + url: url, lcp: lcp, - viewport: row[2] + viewport: row[1] } } catch (error) { - console.error(`Error fetching PageSpeed Insight for ${row[1]}:`, error); + console.error(`Error fetching PageSpeed Insight for ${url}:`, error); } } From da3af620e393db3f25eaed18b6067381d739b01a Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Fri, 5 Apr 2024 11:28:46 +0100 Subject: [PATCH 15/15] Parse correct argument --- src/support/steps/lcp-beacon-script.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/support/steps/lcp-beacon-script.ts b/src/support/steps/lcp-beacon-script.ts index 891fdbe..ee84837 100644 --- a/src/support/steps/lcp-beacon-script.ts +++ b/src/support/steps/lcp-beacon-script.ts @@ -46,7 +46,7 @@ Given('I visit the following urls in {string}', async function (this: ICustomWor // Visit page. for (const row of data) { const url: string = `${WP_BASE_URL}/${row[0]}`; - await this.utils.visitPage(url); + await this.utils.visitPage(row[0]); // Wait for 2 seconds before fetching from DB. await this.page.waitForTimeout(2000);