Skip to content

Commit

Permalink
Merge develop
Browse files Browse the repository at this point in the history
  • Loading branch information
Khadreal committed Sep 24, 2024
2 parents f929e77 + 221c9d2 commit 0e8eb9d
Show file tree
Hide file tree
Showing 7 changed files with 421 additions and 11 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"test:lcp": "$npm_package_config_testCommand --tags @lcp",
"test:test": "$npm_package_config_testCommand --tags @test",
"test:lrc": "$npm_package_config_testCommand --tags @lrc",
"test:performancehints": "$npm_package_config_testCommand --tags @performancehints",
"healthcheck": "ts-node healthcheck.ts",
"wp-env": "wp-env"
},
Expand Down
53 changes: 53 additions & 0 deletions src/features/performance-hints.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
@setup @performancehints
Feature: Clear lcp/performance hints data tests

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

Scenario: C16387 - Should clear performance hints data when click clear PH in admin bar
Given performance hints data added to DB
When clear performance hints is clicked in admin bar
Then data is removed from the performance hints tables

Scenario: C16389 - Should clear performance hints when change permalinks
Given performance hints data added to DB
When permalink structure is changed to '/%postname%'
Then data is removed from the performance hints tables

Scenario: C16390 - Should clear performance hints when switch theme
Given performance hints data added to DB
And switching the theme
Then data is removed from the performance hints tables
Then theme 'Twenty Twenty' is activated

Scenario: Should clear performance hints of the current URL
Given I log out
And I visit beacon driven page 'atf-lrc-1' with browser dimension 1600 x 700
And I visit beacon driven page 'atf-lrc-2' with browser dimension 1600 x 700
And data for 'atf-lrc-1' present in the performance hints tables
And data for 'atf-lrc-2' present in the performance hints tables
And I am logged in
And I go to 'atf-lrc-1'
When clear performance hints for this URL is clicked in admin bar
Then data for 'atf-lrc-1' is removed from the performance hints tables
Then data for 'atf-lrc-2' present in the performance hints tables

Scenario: C16388 - Should clear performance hints of the URL when edited
Given I log out
And I visit beacon driven page 'atf-lrc-1' with browser dimension 1600 x 700
And data for 'atf-lrc-1' present in the performance hints tables
And I am logged in
And I go to 'atf-lrc-1'
When I edit the content of post
Then data for 'atf-lrc-1' is removed from the performance hints tables

Scenario: C16388 - Should clear performance hints of the URL when deleted
Given I log out
And I visit beacon driven page 'atf-lrc-1' with browser dimension 1600 x 700
And data for 'atf-lrc-1' present in the performance hints tables
And I am logged in
When 'atf-lrc-1' page is deleted
Then data for 'atf-lrc-1' is removed from the performance hints tables
Then untrash and republish 'atf-lrc-1' page
26 changes: 25 additions & 1 deletion src/support/steps/general.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ When('I visit page {string} with browser dimension {int} x {int}', async functio
*/
When('I visit scenario urls', async function (this:ICustomWorld) {
await this.page.setViewportSize({
width: 1600,
width: 1600,
height: 700,
});
const liveUrl = SCENARIO_URLS;
Expand All @@ -276,6 +276,23 @@ When('I visit scenario urls', async function (this:ICustomWorld) {
await this.utils.visitPage(liveUrl[key].path);
}
});
/**
* Executes the step to visit beacon driven page in a specific browser dimension.
*/
When('I visit beacon driven page {string} with browser dimension {int} x {int}', async function (this:ICustomWorld, page, width, height) {
await this.page.setViewportSize({
width: width,
height: height,
});

await this.utils.visitPage(page);

// Wait the beacon to add an attribute `beacon-complete` to true before fetching from DB.
await this.page.waitForFunction(() => {
const beacon = document.querySelector('[data-name="wpr-wpr-beacon"]');
return beacon && beacon.getAttribute('beacon-completed') === 'true';
});
});

/**
* Executes the step to scroll to the bottom of the page.
Expand All @@ -284,6 +301,13 @@ When('I scroll to bottom of page', async function (this:ICustomWorld) {
await this.utils.scrollDownBottomOfAPage();
});

/**
* Executes the step to change permalink structure.
*/
When('permalink structure is changed to {string}', async function (this: ICustomWorld, structure: string) {
await this.utils.permalinkChanged(structure);
});

/**
* Executes the step to assert the presence of specific text.
*/
Expand Down
144 changes: 144 additions & 0 deletions src/support/steps/performance-hints.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/**
* @fileoverview
* This module contains Cucumber step definitions using Playwright for asserting performance hints data clearing from DB,
* both ATF and LRC tables
*
* @requires {@link ../../common/custom-world}
* @requires {@link @playwright/test}
* @requires {@link @cucumber/cucumber}
*/

import { ICustomWorld } from "../../common/custom-world";
import { WP_BASE_URL } from '../../../config/wp.config';
import { When, Then, Given } from '@cucumber/cucumber';
import { dbQuery, getWPTablePrefix, getPostDataFromTitle, updatePostStatus } from "../../../utils/commands";
import { extractFromStdout, seedData, checkData } from "../../../utils/helpers";

/*
* Executes step to add hardcoded data to DB: ATF & LRC tables
*/
Given('performance hints data added to DB', async function (this: ICustomWorld) {
const tablePrefix = await getWPTablePrefix();
const tableNames = [
`${tablePrefix}wpr_above_the_fold`,
`${tablePrefix}wpr_lazy_render_content`
];

// Define the data to be inserted
const data = [
// eslint-disable-next-line @typescript-eslint/naming-convention
{ url: `${WP_BASE_URL}/a`, is_mobile: 0, status: 'completed' },
// eslint-disable-next-line @typescript-eslint/naming-convention
{ url: `${WP_BASE_URL}/b`, is_mobile: 0, status: 'completed' },
// eslint-disable-next-line @typescript-eslint/naming-convention
{ url: `${WP_BASE_URL}/c`, is_mobile: 0, status: 'completed' }
];

await Promise.all(tableNames.map(async (tableName) => {
await dbQuery(`TRUNCATE TABLE ${tableName}`);
}));

await seedData(tableNames, data);
});

When('clear performance hints is clicked in admin bar', async function (this: ICustomWorld) {
await this.page.locator('#wp-admin-bar-wp-rocket').hover();
await this.page.waitForSelector('#wp-admin-bar-clear-performance-hints', { state: 'visible' });
await this.page.locator('#wp-admin-bar-clear-performance-hints').click();
await this.page.waitForSelector('text=WP Rocket: Critical images and Lazy Render data was cleared!', { state: 'visible' });
});

When('clear performance hints for this URL is clicked in admin bar', async function (this: ICustomWorld) {
await this.page.locator('#wp-admin-bar-wp-rocket').hover();
await this.page.waitForSelector('#wp-admin-bar-clear-performance-hints-data-url', { state: 'visible' });
await this.page.locator('#wp-admin-bar-clear-performance-hints-data-url').click();
});

/*
* Executes the step to check all data has been cleared from ATF & LRC tables
* (home URL ignored as its the quickest to re-appear on prewarmup)
*/
Then('data is removed from the performance hints tables', async function (this: ICustomWorld) {
const tablePrefix = await getWPTablePrefix();
const tables = [`${tablePrefix}wpr_above_the_fold`, `${tablePrefix}wpr_lazy_render_content`];
const data = [
{ url: `${WP_BASE_URL}/a` },
{ url: `${WP_BASE_URL}/b` },
{ url: `${WP_BASE_URL}/c` }
];

await checkData(tables, data);
});

/*
* Executes the step to check data has been cleared from ATF & LRC tables for specific URL
*/
Then('data for {string} is removed from the performance hints tables', async function (this: ICustomWorld, permalink: string) {
const tablePrefix = await getWPTablePrefix();
const tables = [`${tablePrefix}wpr_above_the_fold`, `${tablePrefix}wpr_lazy_render_content`];
const data = [
{ url: `${WP_BASE_URL}/${permalink}` }
];

await checkData(tables, data);
});

/*
* Executes the step to check data still exists in the ATF & LRC tables for specific URL
*/
Then('data for {string} present in the performance hints tables', async function (this: ICustomWorld, permalink: string) {
const tablePrefix = await getWPTablePrefix();
const tables = [`${tablePrefix}wpr_above_the_fold`, `${tablePrefix}wpr_lazy_render_content`];
const data = [
{ url: `${WP_BASE_URL}/${permalink}` }
];

await checkData(tables, data, true);
});

When('switching the theme', async function (this: ICustomWorld) {
await this.utils.gotoThemes();
await this.page.locator('#wpbody-content > div.wrap > div.theme-browser.rendered > div > div:nth-child(2) > div.theme-id-container').hover();
await this.page.waitForSelector('#wpbody-content > div.wrap > div.theme-browser.rendered > div > div:nth-child(2) > div.theme-id-container > div > a.button.activate', { state: 'visible' });
await this.page.locator('#wpbody-content > div.wrap > div.theme-browser.rendered > div > div:nth-child(2) > div.theme-id-container > div > a.button.activate').click();
});

When ('I edit the content of post', async function (this: ICustomWorld) {
await this.page.waitForSelector('#wp-admin-bar-edit', { state: 'visible' });
await this.page.locator('#wp-admin-bar-edit').click();

// Check for 'Update' button.
const updateButton = this.page.getByRole('button', { name: 'Update', exact: true });

try {
// Wait for the 'Update' button.
await updateButton.waitFor({ state: 'visible' });
await updateButton.click();
} catch (error) {
// If 'Update' is not found, check for 'Save' button for WP version >= 6.6.2.
const saveButton = this.page.getByRole('button', { name: 'Save', exact: true });

// Wait for the 'Save' button.
await saveButton.waitFor({ state: 'visible' });
await saveButton.click();
}

await this.page.waitForSelector('[aria-label="Dismiss this notice"]', { state: 'visible' });
});

When ('{string} page is deleted', async function (this: ICustomWorld, permalink: string) {
await this.utils.gotoPages();
await this.page.locator('#post-search-input').fill(permalink);
await this.page.locator('#search-submit').click();
await this.page.locator('td.title.column-title.has-row-actions.column-primary.page-title > strong > a').hover();
await this.page.waitForSelector('div.row-actions > span.trash > a', { state: 'visible' });
await this.page.locator('div.row-actions > span.trash > a').click();
await this.page.waitForSelector('#message', { state: 'visible' });
});


Then ('untrash and republish {string} page', async function (this: ICustomWorld, permalink: string) {
const postDataStdout = await getPostDataFromTitle(permalink, 'trash', 'ID,post_title');
const postData = await extractFromStdout(postDataStdout);
await updatePostStatus(parseInt(postData[0].ID, 10), 'publish');
});
51 changes: 49 additions & 2 deletions utils/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,11 +272,27 @@ export async function installRemotePlugin(url: string): Promise<void> {
* @returns {Promise<void>} - A Promise that resolves when the uninstallation is completed.
*/
export async function uninstallPlugin(plugin: string): Promise<void> {
if(await isPluginInstalled(plugin)) {
await wp(`plugin uninstall --deactivate ${plugin}`);
const plugins = plugin.split(' ');
for (const p of plugins) {
if (await isPluginInstalled(p)) {
await wp(`plugin uninstall --deactivate ${p}`);
}
}
}

/**
* Update Permalink.
*
* @function
* @name updatePermalinkStructure
* @async
* @param {string} structure - The permalink structure.
* @returns {Promise<void>} - A Promise that resolves when the permalink structure is updated.
*/
export async function updatePermalinkStructure(structure: string): Promise<void> {
await wp(`option update permalink_structure ${structure}`);
}

/**
* Executes a SQL query on the WordPress database using WP-CLI.
*
Expand Down Expand Up @@ -439,4 +455,35 @@ export async function testSshConnection(): Promise<string> {
}
}

/**
* Performs a post search action by title using wp cli.
*
* @param {string} title Post Title.
* @param {string} status Post Status.
* @param {string} fields Post fields to return.
* @return {Promise<string>} A Promise that resolves when the post search is executed.
*/
export async function getPostDataFromTitle(title: string, status: string, fields: string): Promise<string> {
const command = wrapSSHPrefix(`wp post list --post_status=${status} --post_type=page --fields=${fields} --title='${title}'
`);
const result = exec(command, { silent: true });

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

return result.stdout;
}

/**
* Updates post status using wp cli.
*
* @param {string} id Post ID.
* @param {string} status Post Status.
* @return {Promise<void>} A Promise that resolves when the post search is executed.
*/
export async function updatePostStatus(id: number, status: string): Promise<void> {
await wp(`post update ${id} --post_status=${status}`);
}

export default wp;
Loading

0 comments on commit 0e8eb9d

Please sign in to comment.