Skip to content

Commit 41ae35a

Browse files
authored
Merge pull request #307 from wp-media/develop
Merge dev to trunk and release 1.2.1
2 parents d05ce8e + 4d8fff6 commit 41ae35a

25 files changed

+643
-340
lines changed

config/wp.config.sample.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,11 @@ const BACKWPUP_INFOS = {
4444
password: '',
4545
port: '21',
4646
ssl: false,
47-
passiveMode: true
47+
passiveMode: true,
48+
// Set this to string with the path of the FTP root directory if SSH access is available for it
49+
sshDirectory: null,
50+
// Set this to the SSH username if SSH access is available for it
51+
sshUsername: null
4852
}
4953
} as const;
5054

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"test:test": "$npm_package_config_testCommand --tags @test",
2727
"test:lrc": "$npm_package_config_testCommand --tags @lrc",
2828
"test:cpcss": "$npm_package_config_testCommand --tags @cpcss",
29+
"test:cdn": "$npm_package_config_testCommand --tags @cdn",
2930
"test:performancehints": "$npm_package_config_testCommand --tags @performancehints",
3031
"healthcheck": "ts-node healthcheck.ts",
3132
"push-report": "ts-node report.ts",

src/backwpup/features/backup.feature

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,16 @@ Feature: Should be able to backup
1616
And I should see 'mixed' job cards
1717
Then the backup should be added to the table
1818
When I click on common backup now button
19-
Then '1' backup is generated and added to history
19+
Then '1' backup is generated and added to history
20+
21+
Scenario: Schedule backup job to generate backup
22+
Given I install plugin 'https://github.com/wp-media/wp-rocket-e2e-test-helper/raw/main/helper-plugin/show-time.zip'
23+
And plugin 'show-time' is activated
24+
And I go '/wp-admin/admin.php?page=backwpup'
25+
When I click '.js-backwpup-onboarding-step-2' button to continue
26+
And I click '.js-backwpup-onboarding-step-3' button to continue
27+
When I Configure web server storage
28+
And I go '/wp-admin/admin.php?page=backwpup'
29+
And I Schedule backup
30+
And I go '/wp-admin/admin.php?page=backwpup'
31+
Then '1' backup is generated and added to history

src/backwpup/features/delete-plugin.feature

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,19 @@ Feature: Should successfully delete BackWPup plugin
33

44
Background:
55
Given I am logged in
6+
And I delete backwpup plugin
7+
And plugin is installed 'backwpup-pro'
68

79
Scenario: Should delete the plugin successfully after install
8-
Given plugin is installed 'backwpup-pro'
910
When I delete backwpup plugin
1011
Then backwpup should delete successfully
1112

1213
Scenario: Should delete the plugin successfully after activate
13-
Given plugin is installed 'backwpup-pro'
1414
And plugin is activated
1515
When I delete backwpup plugin
1616
Then backwpup should delete successfully
1717

1818
Scenario: Should delete the plugin successfully after 1st backup
19-
Given plugin is installed 'backwpup-pro'
2019
And plugin is activated
2120
When I go '/wp-admin/admin.php?page=backwpup'
2221
And I click '.js-backwpup-onboarding-step-2' button to continue

src/backwpup/steps/general.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,35 @@ When('I click on manual backup of a job', async function (this: ICustomWorld) {
112112
await this.page.waitForLoadState('networkidle');
113113
});
114114

115+
When('I Schedule backup', async function (this: ICustomWorld) {
116+
this.initialBackups = await captureBackupTableData(this.page)
117+
const timeText = await this.page.locator('#wp-admin-bar-current_time_display .ab-item').textContent();
118+
const timeMatch = timeText.match(/(\d{2}):(\d{2}):(\d{2})/);
119+
const currentHours = parseInt(timeMatch[1], 10);
120+
const currentMinutes = parseInt(timeMatch[2], 10);
121+
122+
const totalMinutes = currentHours * 60 + currentMinutes + 2;
123+
const scheduleHours = Math.floor(totalMinutes / 60) % 24;
124+
const scheduleMinutes = totalMinutes % 60;
125+
126+
const timeValue = `${scheduleHours.toString().padStart(2, '0')}:${scheduleMinutes.toString().padStart(2, '0')}`;
127+
128+
await this.page.locator('button[data-content="frequency"].js-backwpup-load-and-open-sidebar').first().click();
129+
await this.page.waitForSelector('#sidebar-frequency', { state: 'visible' });
130+
await this.page.selectOption('#backwpup_frequency', 'daily');
131+
await this.page.fill('input[name="start_time"]', timeValue);
132+
133+
await this.page.locator('button#save-job-settings').click();
134+
135+
await this.page.waitForLoadState('networkidle');
136+
137+
await this.page.waitForTimeout(3 * 60 * 1000);
138+
});
139+
115140
const captureBackupTableData = async (page: Page): Promise<BackupRowData[]> => {
116-
const rows = await page.locator('table tbody tr').all();
141+
const selector = 'table tbody tr';
142+
await page.locator(selector).first().waitFor({ state: 'visible' }).catch(() => null);
143+
const rows = await page.locator(selector).all();
117144
const backups: BackupRowData[] = [];
118145

119146
for (const row of rows) {

src/backwpup/support/hooks.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ import { PageUtils } from "../../../utils/page-utils";
55
import { Before, After} from "@cucumber/cucumber";
66
import {StorageUtils} from "../utils/storage";
77
import {configurations} from "../../../utils/configurations";
8-
import {rm, testSshConnection} from "../../../utils/commands";
8+
import {rm, testSshConnection, uninstallPlugin} from "../../../utils/commands";
99
import {WP_SSH_ROOT_DIR} from "../../../config/wp.config";
1010
import {Page} from "@playwright/test";
11-
11+
import {BACKWPUP_INFOS} from "../../../config/wp.config";
12+
import { getFolderNameFromHost } from "../utils/helpers";
1213

1314
/**
1415
* Before each test scenario with the @bwpupsetup tag, performs setup tasks.
@@ -26,7 +27,7 @@ Before({tags: '@bwpupsetup'}, async function(this: ICustomWorld, {pickle}) {
2627
/**
2728
* After every test, delete data
2829
*/
29-
After(async function (this: ICustomWorld) {
30+
After({ tags: '@bwpup or @bwpupsetup' }, async function (this: ICustomWorld) {
3031
await deleteAllData(this.page);
3132
try {
3233
await testSshConnection();
@@ -35,16 +36,41 @@ After(async function (this: ICustomWorld) {
3536
await rm(backwpupFolder);
3637
const backwpupRestoreFolder = `${WP_SSH_ROOT_DIR}wp-content/uploads/backwpup-restore`;
3738
await rm(backwpupRestoreFolder);
39+
// Remove any BackWPup plugin zip files that may have been uploaded during tests.
40+
const backwpupPluginZips = `${WP_SSH_ROOT_DIR}wp-content/uploads/**/**/backwpup*.zip`;
41+
await rm(backwpupPluginZips);
3842

3943
// Remove BackWPup plugin
4044
await this.utils.deactivateBackWpViaUi();
4145
await this.utils.removeBackWpViaUi();
46+
await uninstallPlugin('show-time');
4247
} catch (error) {
4348
console.error('Setup failed: ', error.message);
4449
throw new Error('Setup failed: ' + error.message);
4550
}
4651
});
4752

53+
After({tags: '@bwpupstorageftp'}, async function(this: ICustomWorld) {
54+
// Nothing to do if no SSH access for FTP is set
55+
if (!BACKWPUP_INFOS.ftp.sshDirectory || !BACKWPUP_INFOS.ftp.sshUsername) return;
56+
try {
57+
// Clear FTP storage
58+
const sshConfig = {
59+
host: BACKWPUP_INFOS.ftp.host,
60+
username: BACKWPUP_INFOS.ftp.sshUsername
61+
};
62+
await testSshConnection({...sshConfig});
63+
const directoryName = getFolderNameFromHost();
64+
const destination = `${BACKWPUP_INFOS.ftp.sshDirectory}/${directoryName}/*`;
65+
await rm(destination, {
66+
...sshConfig
67+
});
68+
} catch (error) {
69+
// Catch error and fail silently, as FTP cleanup is not critical
70+
console.error('FTP Cleanup failed: ', error.message);
71+
}
72+
});
73+
4874
async function deleteAllData(page: Page): Promise<void> {
4975
const response = await page.goto(`${configurations.baseUrl}/wp-admin/admin.php?page=backwpup`);
5076
// We check status, because for some tests, the plugin will be uninstalled before getting here

src/backwpup/utils/helpers.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { configurations } from "../../../utils/configurations";
12
import { ICustomWorld } from "../../common/custom-world";
23
import { Page } from '@playwright/test';
34

@@ -107,3 +108,23 @@ export const configureWebServerStorage = async (page: ICustomWorld['page']): Pro
107108
await page.click('.js-backwpup-onboarding-submit-form');
108109
await waitForBackupJobCompletion(page);
109110
};
111+
112+
/**
113+
* Generates a filesystem-friendly folder name derived from the configured base URL's hostname.
114+
*
115+
* The function parses `configurations.baseUrl`, extracts the hostname portion, and replaces
116+
* all dot characters ('.') with hyphens ('-') to produce a directory-safe name.
117+
*
118+
* Examples:
119+
* - "https://example.com" -> "example-com"
120+
* - "https://sub.domain.co.uk" -> "sub-domain-co-uk"
121+
*
122+
* @returns The directory name based on the hostname with dots replaced by hyphens.
123+
* @throws {TypeError} If `configurations.baseUrl` is not a valid URL and the URL constructor fails.
124+
* @remarks Relies on the global/module `configurations.baseUrl` value being available.
125+
*/
126+
export const getFolderNameFromHost = (): string => {
127+
const domain = new URL(configurations.baseUrl).hostname;
128+
const directoryName = domain.replace(/\./g, '-');
129+
return directoryName;
130+
}

src/backwpup/utils/storage.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {Page} from "@playwright/test";
22
import {Locators, Selector} from "../../../utils/types";
33
import {Sections} from "../../common/sections";
44
import {BACKWPUP_INFOS} from "../../../config/wp.config";
5+
import { getFolderNameFromHost } from "./helpers";
56

67
export class StorageUtils {
78
/**
@@ -125,10 +126,10 @@ export class StorageUtils {
125126
// Checkboxes
126127
await this.page.locator('#ftpssl').setChecked(BACKWPUP_INFOS.ftp.ssl, { force: true });
127128
await this.page.locator('#ftppasv').setChecked(BACKWPUP_INFOS.ftp.passiveMode, { force: true });
128-
const currentValue = await this.page.locator('#ftpdir').inputValue();
129129
const timestamp = Date.now();
130+
const directoryName = getFolderNameFromHost();
130131
// Changing the directory name to prevent old backups to appear and affect the test
131-
await this.page.locator('#ftpdir').fill(`${currentValue}${timestamp}`);
132+
await this.page.locator('#ftpdir').fill(`${directoryName}/${timestamp}`);
132133
await this.page.click('.js-backwpup-test-FTP-storage');
133134

134135
await this.page.waitForResponse(response =>

src/common/selectors.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,7 @@ export const selectors: Selectors = {
6262
await activateFromPopUp(page, state, "text=Activate combine CSS")
6363
}
6464
},
65-
cpcss:{
66-
type: FieldType.checkbox,
67-
element: "#optimize_css_delivery",
68-
target: "label[for=optimize_css_delivery]",
69-
after: async (page: Page): Promise<void> => {
70-
await page.locator("#wpr-radio-async_css").click();
71-
},
72-
},
73-
65+
7466
rucss:{
7567
type: FieldType.checkbox,
7668
element: "#optimize_css_delivery",
@@ -83,6 +75,15 @@ export const selectors: Selectors = {
8375
await page.locator("text=Activate Remove Unused CSS").click();
8476
}
8577
},
78+
cpcss:{
79+
type: FieldType.checkbox,
80+
element: "#optimize_css_delivery",
81+
target: "label[for=optimize_css_delivery]",
82+
after: async (page: Page): Promise<void> => {
83+
await page.locator("#wpr-radio-async_css").click();
84+
},
85+
},
86+
8687
minifyJs: {
8788
type: FieldType.checkbox,
8889
element: "#minify_js",

src/features/cdn-banner.feature

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
@cdn @setup
2+
Feature: CDN banner
3+
4+
Background:
5+
Given I am logged in
6+
And plugin is installed 'new_release'
7+
And plugin is activated
8+
And I am on the page '/wp-admin/options-general.php?page=wprocket#page_cdn'
9+
10+
Scenario: Should validate that CDN purchase banner is displayed
11+
Given I must see the banner 'High performance Content Delivery Network (CDN) with'
12+
And I click on '.wpr-rocketcdn-open'
13+
Then I must see the banner 'Login in to your WP Rocket Account to continue' in iframe '#rocketcdn-iframe'
14+

0 commit comments

Comments
 (0)