Skip to content

Commit

Permalink
RHIDP-744 [Test Automation] Automate RHDH theme customization - E2E (#…
Browse files Browse the repository at this point in the history
…1368)

Refactor custom theme E2E test and update uihelper functions

Improve error handling in UIhelper.ts

Added try-catch to handle potential errors while scrolling elements into view during end-to-end testing in UIhelper.ts. A warning will now be logged in the console if an error occurs to aid debugging and troubleshooting.

Signed-off-by: Gustavo Lira <guga.java@gmail.com>
  • Loading branch information
gustavolira committed Jul 10, 2024
1 parent 89a58cf commit 3582db4
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ data:
headerColor1: "rgb(248, 248, 248)"
headerColor2: "rgb(248, 248, 248)"
navigationIndicatorColor: "rgb(255,95,21)"
dark:
primaryColor: '#ab75cf'
headerColor1: 'rgb(0, 0, 208)'
headerColor2: 'rgb(255, 246, 140)'
navigationIndicatorColor: 'rgb(244, 238, 169)'
backend:
auth:
keys:
Expand Down
60 changes: 29 additions & 31 deletions e2e-tests/playwright/e2e/custom-theme.spec.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,48 @@
import { test, Page, expect } from '@playwright/test';
import { UIhelper } from '../utils/UIhelper';
import { test, Page, TestInfo } from '@playwright/test';
import { Common, setupBrowser } from '../utils/Common';
import { ThemeVerifier } from '../utils/custom-theme/theme-verifier';

let page: Page;

test.describe('CustomTheme should be applied', () => {
let common: Common;
let uiHelper: UIhelper;
let themeVerifier: ThemeVerifier;

test.beforeAll(async ({ browser }, testInfo) => {
page = (await setupBrowser(browser, testInfo)).page;
common = new Common(page);
uiHelper = new UIhelper(page);
themeVerifier = new ThemeVerifier(page);

await common.loginAsGuest();
});

/* eslint-disable-next-line no-empty-pattern */
test('Verify that theme colors are applied and make screenshots', async ({} /* NOSONAR */, testInfo) => {
await uiHelper.openSidebar('Settings');

const header = await page.locator('header').first();
await expect(header).toHaveCSS(
'background-image',
// eslint-disable-next-line no-empty-pattern
test('Verify that theme light colors are applied and make screenshots', async ({}, testInfo: TestInfo) => {
await themeVerifier.setTheme('Light');
await themeVerifier.verifyHeaderGradient(
'none, linear-gradient(90deg, rgb(248, 248, 248), rgb(248, 248, 248))',
);
await themeVerifier.verifyBorderLeftColor('rgb(255, 95, 21)');
await themeVerifier.takeScreenshotAndAttach(
'screenshots/custom-theme-light-inspection.png',
testInfo,
'custom-theme-light-inspection',
);
//await themeVerifier.verifyPrimaryColors('rgb(255, 95, 21)') //TODO: comment out when the primary color issue is fixed (RHIDP-3107)
});

await page.screenshot({
path: 'screenshots/cusotm-theme-inspection.png',
fullPage: true,
});

await testInfo.attach('cusotm-theme-inspection', {
path: 'screenshots/cusotm-theme-inspection.png',
});

await page.locator('[name=pin]').click();

await page.screenshot({
path: 'screenshots/cusotm-theme-inspection-collapsed.png',
fullPage: true,
});
await testInfo.attach('cusotm-theme-inspection-collapsed', {
path: 'screenshots/cusotm-theme-inspection-collapsed.png',
});

await common.signOut();
// eslint-disable-next-line no-empty-pattern
test('Verify that theme dark colors are applied and make screenshots', async ({}, testInfo: TestInfo) => {
await themeVerifier.setTheme('Dark');
await themeVerifier.verifyHeaderGradient(
'none, linear-gradient(90deg, rgb(0, 0, 208), rgb(255, 246, 140))',
);
await themeVerifier.verifyBorderLeftColor('rgb(244, 238, 169)');
await themeVerifier.takeScreenshotAndAttach(
'screenshots/custom-theme-dark-inspection.png',
testInfo,
'custom-theme-dark-inspection',
);
// await themeVerifier.verifyPrimaryColors('#ab75cf') //TODO: comment out when the primary color issue is fixed (RHIDP-3107)
});
});
7 changes: 6 additions & 1 deletion e2e-tests/playwright/e2e/github-happy-path.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,19 +115,24 @@ test.describe.serial('GitHub Happy path', () => {
});

test('Click on the arrows to verify that the next/previous/first/last pages of PRs are loaded', async () => {
console.log('Fetching all PRs from GitHub');
const allPRs = await BackstageShowcase.getGithubPRs('all', true);

console.log('Clicking on ALL button');
await uiHelper.clickButton('ALL', { force: true });
await backstageShowcase.verifyPRRows(allPRs, 0, 5);

console.log('Clicking on Next Page button');
await backstageShowcase.clickNextPage();
await backstageShowcase.verifyPRRows(allPRs, 5, 10);

// Calculate the starting index of the first PR on the last page, 5 PRs per page.
const lastPagePRs = Math.floor((allPRs.length - 1) / 5) * 5;

console.log('Clicking on Last Page button');
await backstageShowcase.clickLastPage();
await backstageShowcase.verifyPRRows(allPRs, lastPagePRs, allPRs.length);

console.log('Clicking on Previous Page button');
await backstageShowcase.clickPreviousPage();
await backstageShowcase.verifyPRRows(allPRs, lastPagePRs - 5, lastPagePRs);
});
Expand Down
4 changes: 4 additions & 0 deletions e2e-tests/playwright/support/pageObjects/global-obj.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@ export const waitsObjs = {

export const UIhelperPO = {
MuiButtonLabel: 'span[class^="MuiButton-label"]',
MuiToggleButtonLabel: 'span[class^="MuiToggleButton-label"]',
MuiBoxLabel: 'div[class*="MuiBox-root"] label',
MuiTableHead: 'th[class*="MuiTableCell-root"]',
MuiTableCell: 'td[class*="MuiTableCell-root"]',
MuiTableRow: 'tr[class*="MuiTableRow-root"]',
MuiTypographyColorPrimary: '.MuiTypography-colorPrimary',
MuiSwitchColorPrimary: '.MuiSwitch-colorPrimary',
MuiButtonTextPrimary: '.MuiButton-textPrimary',
MuiCard: cardHeading =>
`//div[contains(@class,'MuiCardHeader-root') and descendant::*[text()='${cardHeading}']]/..`,
MuiTable: 'table.MuiTable-root',
Expand Down
14 changes: 12 additions & 2 deletions e2e-tests/playwright/utils/APIHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export class APIHelper {
body?: string | object,
): Promise<APIResponse> {
const context = await request.newContext();
const options = {
const options: any = {
method: method,
headers: {
Accept: 'application/vnd.github+json',
Expand All @@ -26,11 +26,21 @@ export class APIHelper {
return response;
}

static async getGithubPaginatedRequest(url, pageNo = 1, response = []) {
static async getGithubPaginatedRequest(
url: string,
pageNo = 1,
response: any[] = [],
): Promise<any[]> {
const fullUrl = `${url}&page=${pageNo}`;
const result = await this.githubRequest('GET', fullUrl);
const body = await result.json();

if (!Array.isArray(body)) {
throw new Error(
`Expected array but got ${typeof body}: ${JSON.stringify(body)}`,
);
}

if (body.length === 0) {
return response;
}
Expand Down
59 changes: 54 additions & 5 deletions e2e-tests/playwright/utils/UIhelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { UIhelperPO } from '../support/pageObjects/global-obj';

export class UIhelper {
private page: Page;
private selectors: { [key: string]: string };

constructor(page: Page) {
this.page = page;
Expand Down Expand Up @@ -46,6 +45,15 @@ export class UIhelper {
return button;
}

async clickBtnByTitleIfNotPressed(title: string) {
const button = this.page.locator(`button[title="${title}"]`);
const isPressed = await button.getAttribute('aria-pressed');

if (isPressed === 'false') {
await button.click();
}
}

async verifyDivHasText(divText: string) {
await expect(
this.page.locator(`div`).filter({ hasText: divText }),
Expand Down Expand Up @@ -125,10 +133,25 @@ export class UIhelper {
.locator(`tr>td`)
.getByText(rowText, { exact: exact })
.first();
await rowLocator.waitFor({ state: 'visible' });
await rowLocator.waitFor({ state: 'attached' });
await rowLocator.scrollIntoViewIfNeeded();
await expect(rowLocator).toBeVisible();

try {
await rowLocator.waitFor({ state: 'visible', timeout: 10000 });
await rowLocator.waitFor({ state: 'attached', timeout: 10000 });

try {
await rowLocator.scrollIntoViewIfNeeded();
} catch (error) {
console.warn(
`Warning: Could not scroll element into view. Error: ${error.message}`,
);
}

await expect(rowLocator).toBeVisible();
} catch (error) {
console.error(
`Error: Failed to verify row with text "${rowText}". Error: ${error.message}`,
);
}
}
}

Expand Down Expand Up @@ -247,4 +270,30 @@ export class UIhelper {
const rowCount = await this.page.locator(rowSelector).count();
expect(rowCount).toBeGreaterThan(0);
}

// Function to convert hexadecimal to RGB or return RGB if it's already in RGB
toRgb(color: string): string {
if (color.startsWith('rgb')) {
return color;
}

const bigint = parseInt(color.slice(1), 16);
const r = (bigint >> 16) & 255;
const g = (bigint >> 8) & 255;
const b = bigint & 255;
return `rgb(${r}, ${g}, ${b})`;
}

async checkCssColor(page: Page, selector: string, expectedColor: string) {
const elements = await page.locator(selector);
const count = await elements.count();
const expectedRgbColor = this.toRgb(expectedColor);

for (let i = 0; i < count; i++) {
const color = await elements
.nth(i)
.evaluate(el => window.getComputedStyle(el).color);
expect(color).toBe(expectedRgbColor);
}
}
}
60 changes: 60 additions & 0 deletions e2e-tests/playwright/utils/custom-theme/theme-verifier.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Page, expect, TestInfo } from '@playwright/test';
import { UIhelper } from '../UIhelper';
import { UIhelperPO } from '../../support/pageObjects/global-obj';

export class ThemeVerifier {
private readonly page: Page;
private uiHelper: UIhelper;

constructor(page: Page) {
this.page = page;
this.uiHelper = new UIhelper(page);
}

async setTheme(theme: 'Light' | 'Dark') {
await this.uiHelper.openSidebar('Settings');
await this.uiHelper.clickBtnByTitleIfNotPressed(`Select theme ${theme}`);
}

async verifyHeaderGradient(expectedGradient: string) {
const header = await this.page.locator('main header');
await expect(header).toHaveCSS('background-image', expectedGradient);
}

async verifyBorderLeftColor(expectedColor: string) {
const locator = await this.page.locator("a[aria-label='Settings']");
await expect(locator).toHaveCSS(
'border-left',
`3px solid ${expectedColor}`,
);
}

async verifyPrimaryColors(colorPrimary: string) {
await this.uiHelper.checkCssColor(
this.page,
UIhelperPO.MuiTypographyColorPrimary,
colorPrimary,
);
await this.uiHelper.checkCssColor(
this.page,
UIhelperPO.MuiSwitchColorPrimary,
colorPrimary,
);
await this.uiHelper.openSidebar('Catalog');
await this.uiHelper.checkCssColor(
this.page,
UIhelperPO.MuiButtonTextPrimary,
colorPrimary,
);
await this.uiHelper.openSidebar('Settings');
}

async takeScreenshotAndAttach(
screenshotPath: string,
testInfo: TestInfo,
description: string,
) {
await this.page.screenshot({ path: screenshotPath, fullPage: true });
await testInfo.attach(description, { path: screenshotPath });
}
}

0 comments on commit 3582db4

Please sign in to comment.