Skip to content

Commit

Permalink
testsuite/playwright-ui: make existing tests to pass
Browse files Browse the repository at this point in the history
Updated test files to pass with existing tests.
Branded test requires signup config to be copied to local folder.

Issue:
#6598

Change-Id: If1d9617d4cc2a8dd1862f843c792f5b5b219ec2e
  • Loading branch information
VitaliiShpital authored and Storj Robot committed Dec 21, 2023
1 parent 00608ec commit 445cd8d
Show file tree
Hide file tree
Showing 20 changed files with 175 additions and 102 deletions.
5 changes: 5 additions & 0 deletions testsuite/playwright-ui/lib/BaseTest.ts
Expand Up @@ -8,6 +8,7 @@ import { NavigationMenu } from '@pages/NavigationMenu';
import { BucketsPage } from '@pages/BucketsPage';
import { SignupPage } from '@pages/SignupPage';
import { AllProjectsPage } from '@pages/AllProjectsPage';
import { Common } from '@pages/Common';

const test = baseTest.extend<{
loginPage: LoginPage;
Expand All @@ -16,6 +17,7 @@ const test = baseTest.extend<{
bucketsPage: BucketsPage;
signupPage: SignupPage;
allProjectsPage: AllProjectsPage;
common: Common;
}>({
loginPage: async ({ page }, use) => {
await use(new LoginPage(page));
Expand All @@ -35,6 +37,9 @@ const test = baseTest.extend<{
allProjectsPage: async ({ page }, use) => {
await use(new AllProjectsPage(page));
},
common: async ({ page }, use) => {
await use(new Common(page));
},
});

export default test;
27 changes: 23 additions & 4 deletions testsuite/playwright-ui/package-lock.json
Expand Up @@ -13,13 +13,15 @@
"@slack/socket-mode": "1.3.2",
"@slack/types": "2.8.0",
"@slack/web-api": "6.8.0",
"@types/uuid": "9.0.7",
"@typescript-eslint/eslint-plugin": "6.14.0",
"@typescript-eslint/parser": "6.14.0",
"allure-commandline": "2.23.0",
"allure-playwright": "2.4.0",
"eslint": "8.56.0",
"mocha-multi-reporters": "1.5.1",
"playwright-slack-report": "1.0.19"
"playwright-slack-report": "1.0.19",
"uuid": "9.0.1"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
Expand Down Expand Up @@ -278,6 +280,11 @@
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz",
"integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A=="
},
"node_modules/@types/uuid": {
"version": "9.0.7",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.7.tgz",
"integrity": "sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g=="
},
"node_modules/@types/ws": {
"version": "7.4.7",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz",
Expand Down Expand Up @@ -523,6 +530,14 @@
"uuid": "^8.3.0"
}
},
"node_modules/allure-js-commons/node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/allure-playwright": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/allure-playwright/-/allure-playwright-2.4.0.tgz",
Expand Down Expand Up @@ -2229,9 +2244,13 @@
}
},
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"bin": {
"uuid": "dist/bin/uuid"
}
Expand Down
9 changes: 6 additions & 3 deletions testsuite/playwright-ui/package.json
Expand Up @@ -9,9 +9,10 @@
"browser-debug": "DEBUG=pw:browser* npx playwright test",
"lint": "eslint . --ext .ts --fix",
"posttest": "npm run allure:generate && npm run allure:local",
"prerun-dev": "chmod +x ./scripts/prerun-dev.sh && ./scripts/prerun-dev.sh",
"test": "npx playwright test ./tests/",
"test-debug": "DEBUG=pw:browser* npx playwright test ./tests/login.test.ts --trace on",
"test-dev": "npx playwright test ./tests/bucket.test.ts --headed --project=chromium --trace on"
"test-debug": "DEBUG=pw:browser* npx playwright test ./tests/bucket.test.ts --trace on",
"test-dev": "npm run prerun-dev && npx playwright test ./tests/ --headed --project=chromium-hd --trace on"
},
"license": "ISC",
"dependencies": {
Expand All @@ -21,10 +22,12 @@
"@slack/web-api": "6.8.0",
"@typescript-eslint/parser": "6.14.0",
"@typescript-eslint/eslint-plugin": "6.14.0",
"@types/uuid": "9.0.7",
"allure-commandline": "2.23.0",
"allure-playwright": "2.4.0",
"eslint": "8.56.0",
"mocha-multi-reporters": "1.5.1",
"playwright-slack-report": "1.0.19"
"playwright-slack-report": "1.0.19",
"uuid": "9.0.1"
}
}
Expand Up @@ -5,4 +5,8 @@ export class AllProjectsPageObjects {
static ALL_PROJECTS_HEADER_TITLE_XPATH = `//span[contains(text(),'My Projects')]`;
static OPEN_PROJECT_BUTTON_TEXT = `Open Project`;
static PROJECT_ITEM_XPATH = `//*[contains(@class, 'project-item')]`;
static CREATE_PROJECT_BUTTON_XPATH = `//div[contains(@class, 'container') and contains(.//span, ' Create a Project')]`;
static CONFIRM_CREATE_PROJECT_BUTTON_XPATH = `//div[contains(@class, 'container') and contains(.//span, ' Create Project -->')]`;
static NEW_PROJECT_NAME_FIELD_XPATH = `//input[@id='Project Name']`;
static SKIP_ONBOARDING_LABEL = ` Skip and go directly to dashboard `;
}
Expand Up @@ -4,24 +4,18 @@
export class BucketsPageObjects {
static ENCRYPTION_PASSPHRASE_XPATH = `//input[@id='Encryption Passphrase']`;
static CONTINUE_BUTTON_PASSPHRASE_MODAL_XPATH = `//div[contains(@class, 'container') and contains(.//span, ' Continue ->')]`;
static DOWNLOAD_BUTTON_XPATH = `//div[contains(@class, 'container') and contains(.//span, ' Download')]`;
static SHARE_BUTTON_XPATH = `div:nth-child(4) > .button-icon`;
static DOWNLOAD_NOTIFICATION = `//p[contains(text(),'Keep this download link private.If you want to share, use the Share option.')]`;
static OBJECT_MAP_TEXT_XPATH = `//div[contains(text(),'Nodes storing this file')]`;
static OBJECT_MAP_IMAGE_XPATH = `//*[contains(@class, 'object-map')]`;
static OBJECT_PREVIEW_BUTTON_XPATH = `//div[contains(@class, 'button-icon')]`;
static OBJECT_MAP_IMAGE_XPATH = `//*[contains(@class, 'modal__map')]`;
static COPY_LINK_BUTTON_XPATH = `//div[contains(@class, 'container') and contains(.//span, ' Copy Link')]`;
static COPIED_TEXT = `Copied!`;
static CLOSE_MODAL_BUTTON_XPATH = `.mask__wrapper__container__close`;
static CLOSE_FILE_PREVIEW_BUTTON_XPATH = `//body/div[@id='app']/div[2]/div[1]/div[2]/div[5]/div[1]`;
static COPIED_TEXT = `Link Copied`;
static NEW_FOLDER_BUTTON_TEXT = `New Folder`;
static NEW_FOLDER_NAME_FIELD_XPATH = `//input[@id='Folder name']`;
static CREATE_FOLDER_BUTTON_TEXT = `Create Folder`;
static DELETE_BUTTON_XPATH = `//p[contains(text(),'Delete')]`;
static YES_BUTTON_XPATH = `//*[contains(@class, 'delete-confirmation__options__item yes')]`;
static VIEW_BUCKET_DETAILS_BUTTON_CSS = `.bucket-settings-nav__dropdown__itprivateem`;
static VIEW_BUCKET_DETAILS_BUTTON_CSS = `.bucket-settings-nav__dropdown__item__label`;
static BUCKET_SETTINGS_BUTTON_CSS = `.bucket-settings-nav`;
static SHARE_BUCKET_BUTTON_XPATH = '//p[contains(text(),\'Share bucket\')]';
static COPY_BUTTON_SHARE_BUCKET_MODAL_XPATH = `//span[contains(text(),'Copy')]`;

// Create new bucket flow
static NEW_BUCKET_BUTTON_XPATH = `//p[contains(text(),'New Bucket')]`;
Expand All @@ -30,7 +24,7 @@ export class BucketsPageObjects {
static ENTER_PASSPHRASE_RADIO_BUTTON_XPATH = `//h4[contains(text(),'Enter passphrase')]`;
static PASSPHRASE_INPUT_NEW_BUCKET_XPATH = `//input[@id='Your Passphrase']`;
static CHECKMARK_ENTER_PASSPHRASE_XPATH = `//label[contains(text(),'I understand, and I have saved the passphrase.')]`;
static BUCKET_NAME_DELETE_BUCKET_MODAL_XPATH = `//input[@id='Bucket Name']`;
static CONFIRM_DELETE_BUTTON_XPATH = `//div[contains(@class, 'container') and contains(.//span, ' Confirm Delete Bucket')]`;
static BUCKET_NAME_DELETE_BUCKET_MODAL_XPATH = `//input[@id='Type the name of the bucket to confirm']`;
static CONFIRM_DELETE_BUTTON_XPATH = `//div[contains(@class, 'container') and contains(.//span, 'Delete Bucket')]`;
static DELETE_BUCKET_XPATH = `//p[contains(text(),'Delete Bucket')]`;
}
@@ -0,0 +1,7 @@
// Copyright (C) 2023 Storj Labs, Inc.
// See LICENSE for copying information.

export class CommonObjects {
static CLOSE_MODAL_BUTTON_XPATH = `.mask__wrapper__container__close`;
static LOADER_XPATH = `//div[contains(@class, 'loader')]`;
}
Expand Up @@ -4,5 +4,4 @@
export class LoginPageObjects {
static EMAIL_EDITBOX_ID = `//input[@id='Email Address']`;
static PASSWORD_EDITBOX_ID = `//input[@id='Password']`;
static SIGN_IN_BUTTON_XPATH = `//div[contains(@class, 'container login-area__content-area__container__button') and contains(.//span, 'Sign In')]`;
}
Expand Up @@ -8,17 +8,19 @@ export class SignupPageObjects {
static INPUT_PASSWORD_XPATH = `//input[@id='Password']`;
static INPUT_RETYPE_PASSWORD_XPATH = `//input[@id='Retype Password']`;
static TOS_CHECKMARK_BUTTON_XPATH = `.checkmark-container`;
static CREATE_ACCOUNT_BUTTON_XPATH = `//div[contains(@class, 'container') and contains(.//span, ' Get Started')]`;

// SIGNUP SUCCESS PAGE
static SIGNUP_SUCCESS_MESSAGE_XPATH = `//h2[contains(text(),"You're almost there!")]`;
static GOTO_LOGIN_PAGE_BUTTON_XPATH = `//a[contains(text(),'Go to Login page')]`;

// IX BRANDED SIGNUP
static CREATE_ACCOUNT_BUTTON_XPATH = `//body/div[@id='app']/div[@id='app']/div[1]/div[1]/div[2]/div[1]/div[10]`;
static IX_BRANDED_CREATE_ACCOUNT_BUTTON_XPATH = `//div[contains(@class, 'container') and contains(.//span, ' Create an iX-Storj Account')]`;
static IX_BRANDED_HEADER_TEXT_XPATH = `//h1[contains(text(),'Globally Distributed Storage for TrueNAS')]`;
static IX_BRANDED_SUBHEADER_TEXT_XPATH = `//p[contains(text(),'iX and Storj have partnered to offer a secure, hig')]`;

// BUSINESS TAB
static IX_BRANDED_PERSONAL_BUTTON_XPATH = `//li[contains(text(),'Personal')]`;
static IX_BRANDED_BUSINESS_BUTTON_XPATH = `//li[contains(text(),'Business')]`;
static COMPANY_NAME_INPUT_XPATH = `//input[@id='Company Name']`;
static POSITION_INPUT_XPATH = `//input[@id='Position']`;
Expand Down
Expand Up @@ -7,6 +7,13 @@ import type { Page } from '@playwright/test';
export class AllProjectsPage {
constructor(readonly page: Page) {}

async createProject(name: string): Promise<void> {
await this.page.locator(AllProjectsPageObjects.CREATE_PROJECT_BUTTON_XPATH).first().click();
await this.page.locator(AllProjectsPageObjects.NEW_PROJECT_NAME_FIELD_XPATH).fill(name);
await this.page.locator(AllProjectsPageObjects.CONFIRM_CREATE_PROJECT_BUTTON_XPATH).click();
await this.page.getByText(AllProjectsPageObjects.SKIP_ONBOARDING_LABEL).click();
}

async clickOnProject(name: string): Promise<void> {
await this.page.locator(AllProjectsPageObjects.ALL_PROJECTS_HEADER_TITLE_XPATH).isVisible();
const listItem = this.page.locator(AllProjectsPageObjects.PROJECT_ITEM_XPATH, { hasText: name });
Expand Down
37 changes: 7 additions & 30 deletions testsuite/playwright-ui/pageFactory/pageRepository/BucketsPage.ts
Expand Up @@ -24,20 +24,18 @@ export class BucketsPage {
await this.page.locator(BucketsPageObjects.CONTINUE_BUTTON_PASSPHRASE_MODAL_XPATH).click();
}

async downloadFileByName(name: string): Promise<void> {
const uiTestFile = this.page.getByText(name);
async downloadFromPreview(name: string): Promise<void> {
const uiTestFile = this.page.getByText(name, { exact: true }).nth(1);
await expect(uiTestFile).toBeVisible();
await uiTestFile.click();
await Promise.all([
this.page.waitForEvent('download'),
this.page.locator(BucketsPageObjects.DOWNLOAD_BUTTON_XPATH).click(),
this.page.locator(BucketsPageObjects.OBJECT_PREVIEW_BUTTON_XPATH).nth(2).click(),
]);
await expect(this.page.getByText('Keep this download link private.If you want to share, use the Share option.')).toBeVisible();

}

async clickShareButton(): Promise<void> {
await this.page.locator(BucketsPageObjects.SHARE_BUTTON_XPATH).click();
await this.page.locator(BucketsPageObjects.OBJECT_PREVIEW_BUTTON_XPATH).nth(3).click();
}

async clickCopyLinkButton(): Promise<void> {
Expand All @@ -52,20 +50,16 @@ export class BucketsPage {
}

async verifyObjectMapIsVisible(): Promise<void> {
await this.page.locator(BucketsPageObjects.OBJECT_MAP_TEXT_XPATH).isVisible();
await this.page.locator(BucketsPageObjects.OBJECT_PREVIEW_BUTTON_XPATH).nth(1).click();
await this.page.locator(BucketsPageObjects.OBJECT_MAP_IMAGE_XPATH).isVisible();
}

async verifyImagePreviewIsVisible(): Promise<void> {
await this.page.getByRole('img', { name: 'preview' }).isVisible();
}

async closeModal(): Promise<void> {
await this.page.locator(BucketsPageObjects.CLOSE_MODAL_BUTTON_XPATH).click();
}

async closeFilePreview(): Promise<void> {
await this.page.locator(BucketsPageObjects.CLOSE_FILE_PREVIEW_BUTTON_XPATH).click();
await this.page.locator(BucketsPageObjects.OBJECT_PREVIEW_BUTTON_XPATH).nth(4).click();
}

async openFileDropdownByName(name: string): Promise<void> {
Expand All @@ -88,11 +82,6 @@ export class BucketsPage {
await this.page.getByText(BucketsPageObjects.CREATE_FOLDER_BUTTON_TEXT).click();
}

async openFileByName(name: string): Promise<void> {
await this.page.getByText(name).click();
await this.page.locator(`//p[contains(text(),'${name}')]`).isVisible();
}

async openBucketSettings(): Promise<void> {
await this.page.locator(BucketsPageObjects.BUCKET_SETTINGS_BUTTON_CSS).click();
}
Expand Down Expand Up @@ -134,7 +123,7 @@ export class BucketsPage {
}

async clickNewBucketButton(): Promise<void> {
await this.page.locator(BucketsPageObjects.NEW_BUCKET_BUTTON_XPATH).click();
await this.page.locator(BucketsPageObjects.NEW_BUCKET_BUTTON_XPATH).nth(0).click();
}

async enterNewBucketName(name: string): Promise<void> {
Expand All @@ -145,18 +134,6 @@ export class BucketsPage {
await this.page.locator(BucketsPageObjects.CONTINUE_BUTTON_CREATE_BUCKET_FLOW_XPATH).click();
}

async clickEnterPassphraseRadioButton(): Promise<void> {
await this.page.locator(BucketsPageObjects.ENTER_PASSPHRASE_RADIO_BUTTON_XPATH).click();
}

async enterNewBucketPassphrase(passphrase: string): Promise<void> {
await this.page.locator(BucketsPageObjects.PASSPHRASE_INPUT_NEW_BUCKET_XPATH).fill(passphrase);
}

async clickConfirmCheckmark(): Promise<void> {
await this.page.locator(BucketsPageObjects.CHECKMARK_ENTER_PASSPHRASE_XPATH).click();
}

async openBucketDropdownByName(name: string): Promise<void> {
const row = await this.page.waitForSelector('*css=tr >> text=' + name);
const button = await row.$('th:nth-child(7)');
Expand Down
23 changes: 23 additions & 0 deletions testsuite/playwright-ui/pageFactory/pageRepository/Common.ts
@@ -0,0 +1,23 @@
// Copyright (C) 2023 Storj Labs, Inc.
// See LICENSE for copying information.

import { expect, Page } from '@playwright/test';
import { CommonObjects } from '@objects/CommonObjects';
import { testConfig } from '../../testConfig';

export class Common {
constructor(readonly page: Page) {}

async goToAllProjects(): Promise<void> {
await this.page.goto(`${testConfig.host}${testConfig.port}/all-projects`);
}

async closeModal(): Promise<void> {
await this.page.locator(CommonObjects.CLOSE_MODAL_BUTTON_XPATH).click();
}

async waitLoading(): Promise<void> {
const loader = this.page.locator(CommonObjects.LOADER_XPATH);
await expect(loader).toBeHidden();
}
}
Expand Up @@ -9,7 +9,13 @@ export class LoginPage {
constructor(readonly page: Page) {}

async navigateToURL(): Promise<void> {
await this.page.goto(testConfig.host+testConfig.port);
await this.page.goto(`${testConfig.host}${testConfig.port}/login`);
}

async loginByCreds(email: string, password: string): Promise<void> {
await this.page.locator(LoginPageObjects.EMAIL_EDITBOX_ID).fill(email);
await this.page.locator(LoginPageObjects.PASSWORD_EDITBOX_ID).fill(password);
await this.page.locator('span').filter({ hasText: 'Sign In' }).click();
}

async loginToApplication(): Promise<void> {
Expand Down
23 changes: 14 additions & 9 deletions testsuite/playwright-ui/pageFactory/pageRepository/SignupPage.ts
Expand Up @@ -9,21 +9,30 @@ import { testConfig } from '../../testConfig';
export class SignupPage {
constructor(readonly page: Page) {}

async navigateToSignup(): Promise<void> {
await this.page.goto(`${testConfig.host}${testConfig.port}/signup`);
}

async navigateToPartnerSignup(): Promise<void> {
await this.page.goto(testConfig.host + testConfig.port + '/signup?partner=ix-storj-1');
await this.page.goto(`${testConfig.host}${testConfig.port}/signup?partner=ix-storj-1`);
}

async clickOnPersonalButton(): Promise<void> {
await this.page.locator(SignupPageObjects.IX_BRANDED_PERSONAL_BUTTON_XPATH).click();
}

async clickOnBusinessButton(): Promise<void> {
await this.page.locator(SignupPageObjects.IX_BRANDED_BUSINESS_BUTTON_XPATH).click();
}

async signupApplicationPersonal(name: string, email: string, password: string): Promise<void> {
async signupApplicationPersonal(name: string, email: string, password: string, branded = false): Promise<void> {
await this.clickOnPersonalButton();
await this.page.locator(SignupPageObjects.INPUT_NAME_XPATH).fill(name);
await this.page.locator(SignupPageObjects.INPUT_EMAIL_XPATH).fill(email);
await this.page.locator(SignupPageObjects.INPUT_PASSWORD_XPATH).fill(password);
await this.page.locator(SignupPageObjects.INPUT_RETYPE_PASSWORD_XPATH).fill(password);
await this.clickOnEveryCheckmark();
await this.page.locator(SignupPageObjects.CREATE_ACCOUNT_BUTTON_XPATH).click();
await this.page.locator(branded ? SignupPageObjects.IX_BRANDED_CREATE_ACCOUNT_BUTTON_XPATH : SignupPageObjects.CREATE_ACCOUNT_BUTTON_XPATH).click();
}

async clickOnEveryCheckmark(): Promise<void> {
Expand All @@ -34,21 +43,17 @@ export class SignupPage {
}
}

async signupApplicationBusiness(name: string, email: string, password: string, company: string, position: string): Promise<void> {
async signupApplicationBusiness(name: string, email: string, password: string, company: string, position: string, branded = false): Promise<void> {
await this.clickOnBusinessButton();
await this.page.locator(SignupPageObjects.COMPANY_NAME_INPUT_XPATH).fill(company);
await this.page.locator(SignupPageObjects.POSITION_INPUT_XPATH).fill(position);
await this.signupApplicationPersonal(name, email, password);
await this.signupApplicationPersonal(name, email, password, branded);
}

async verifySuccessMessage(): Promise<void> {
await expect(this.page.locator(SignupPageObjects.SIGNUP_SUCCESS_MESSAGE_XPATH)).toBeVisible();
}

async clickOnGotoLoginPage(): Promise<void> {
await this.page.locator(SignupPageObjects.GOTO_LOGIN_PAGE_BUTTON_XPATH).click();
}

async verifyIXBrandedHeader(): Promise<void> {
await expect(this.page.locator(SignupPageObjects.IX_BRANDED_HEADER_TEXT_XPATH)).toBeVisible();
}
Expand Down

0 comments on commit 445cd8d

Please sign in to comment.