Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RHIDP-744 [Test Automation] Automate RHDH theme customization - E2E #1368

Merged
merged 1 commit into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 });
}
}
Loading