From cf4e54ec6a081aa891e1e9324fde6e7663931114 Mon Sep 17 00:00:00 2001 From: Alberto Gutierrez Date: Fri, 1 Nov 2024 22:22:40 +0100 Subject: [PATCH] feat(kiali): remove playwright tests legacy (#2452) * feat(kiali): remove playwright tests legacy * Update package.json * Update plugins/kiali/package.json --------- Co-authored-by: Paul Schultz --- .changeset/strong-years-tease.md | 2 + plugins/kiali/package.json | 3 +- plugins/kiali/playwright.config.ts | 34 --- plugins/kiali/tests/entityGraphCard.spec.ts | 28 -- plugins/kiali/tests/entityResources.spec.ts | 198 ------------- plugins/kiali/tests/kiali.spec.ts | 25 -- plugins/kiali/tests/kialiHelper.ts | 51 ---- plugins/kiali/tests/kialiPage.spec.ts | 294 -------------------- 8 files changed, 3 insertions(+), 632 deletions(-) create mode 100644 .changeset/strong-years-tease.md delete mode 100644 plugins/kiali/playwright.config.ts delete mode 100644 plugins/kiali/tests/entityGraphCard.spec.ts delete mode 100644 plugins/kiali/tests/entityResources.spec.ts delete mode 100644 plugins/kiali/tests/kiali.spec.ts delete mode 100644 plugins/kiali/tests/kialiHelper.ts delete mode 100644 plugins/kiali/tests/kialiPage.spec.ts diff --git a/.changeset/strong-years-tease.md b/.changeset/strong-years-tease.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/strong-years-tease.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/plugins/kiali/package.json b/plugins/kiali/package.json index 3be1a7072a..ad1860f93a 100644 --- a/plugins/kiali/package.json +++ b/plugins/kiali/package.json @@ -30,8 +30,7 @@ "test": "backstage-cli package test --passWithNoTests --coverage", "tsc": "tsc", "prettier:check": "prettier --ignore-unknown --check .", - "prettier:fix": "prettier --ignore-unknown --write .", - "ui-test": "start-server-and-test start localhost:3000 'playwright test'" + "prettier:fix": "prettier --ignore-unknown --write ." }, "dependencies": { "@backstage/catalog-model": "^1.7.0", diff --git a/plugins/kiali/playwright.config.ts b/plugins/kiali/playwright.config.ts deleted file mode 100644 index 0802a5e45d..0000000000 --- a/plugins/kiali/playwright.config.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { defineConfig, devices } from '@playwright/test'; - -/** - * See https://playwright.dev/docs/test-configuration. - */ -export default defineConfig({ - testDir: './tests', - /* Run tests in files in parallel */ - fullyParallel: true, - /* Fail the build on CI if you accidentally left test.only in the source code. */ - forbidOnly: !!process.env.CI, - /* Retry on CI only */ - retries: process.env.CI ? 2 : 0, - /* Run tests in sequence. */ - workers: 1, - /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: process.env.CI ? 'github' : 'list', - /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ - use: { - baseURL: process.env.PLUGIN_BASE_URL || 'http://localhost:3000', - /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: 'on-first-retry', - screenshot: 'only-on-failure', - video: 'retain-on-failure', - }, - - /* Configure projects for major browsers */ - projects: [ - { - name: 'chromium', - use: { ...devices['Desktop Chrome'] }, - }, - ], -}); diff --git a/plugins/kiali/tests/entityGraphCard.spec.ts b/plugins/kiali/tests/entityGraphCard.spec.ts deleted file mode 100644 index 372fb4dc4a..0000000000 --- a/plugins/kiali/tests/entityGraphCard.spec.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { expect, Page, test } from '@playwright/test'; - -import { Common } from './kialiHelper'; - -test.describe('Entity traffic graph', () => { - let page: Page; - let common: Common; - - test.describe('kiali traffic graph', () => { - test.beforeAll(async ({ browser }) => { - const context = await browser.newContext(); - page = await context.newPage(); - common = new Common(page); - - await common.loginAsGuest(); - await page.goto('/kiali-graph-card'); - }); - - // List container is loaded - test('Graph content', async () => { - expect(page.locator('[data-test="kiali-graph-card"]')).toBeDefined(); - }); - - test('Product page node', async () => { - expect(page.locator('[data-test="node-productpage"]')).toBeDefined(); - }); - }); -}); diff --git a/plugins/kiali/tests/entityResources.spec.ts b/plugins/kiali/tests/entityResources.spec.ts deleted file mode 100644 index 08477933ac..0000000000 --- a/plugins/kiali/tests/entityResources.spec.ts +++ /dev/null @@ -1,198 +0,0 @@ -import { expect, Page, test } from '@playwright/test'; - -import { Common } from './kialiHelper'; - -test.describe('Entity resources', () => { - let page: Page; - let common: Common; - - test.describe('kiali resources', () => { - test.beforeAll(async ({ browser }) => { - const context = await browser.newContext(); - page = await context.newPage(); - common = new Common(page); - - await common.loginAsGuest(); - await page.goto('/kiali-entity-card'); - page.locator('[data-test="kiali-tabbed-card"]'); - }); - - // List container is loaded - test('Workloads content', async () => { - expect(page.locator('[data-test="virtual-list"]')).toBeDefined(); - }); - - // Update time - test('Update since time', async () => { - await page - .getByRole('button') - .filter({ hasText: /Last 10m/ }) - .click(); - await page - .getByRole('option') - .filter({ hasText: /Last 1h/ }) - .click(); - expect( - page.getByRole('button').filter({ hasText: /Last 1h/ }), - ).toBeDefined(); - }); - - // Validate columns - test('All columns are valid', async () => { - const columns = [ - 'HEALTH', - 'NAME', - 'NAMESPACE', - 'TYPE', - 'LABELS', - 'DETAILS', - ]; - const tableHead = page.locator('.MuiTableHead-root'); - for (let i = 0; i < columns.length; i++) { - await expect(tableHead).toContainText(columns[i]); - } - }); - - // Validate health - test('heath for workload details', async () => { - const icon = page - .locator( - '[data-test="VirtualItem_ClusterKubernetes_Nsbookinfo_Deployment_details-v1"]', - ) - .locator('[data-test="health"]'); - await icon.hover({ force: true }).then(async () => { - const tooltip = await page.locator('[role="tooltip"]'); - await expect(tooltip).toContainText(`Healthy`); - await expect(tooltip).toContainText(`details-v1: 1 / 1`); - }); - }); - - // Validate tags - test('tags for workload details', async () => { - await page - .locator( - '[data-test="VirtualItem_ClusterKubernetes_Nsbookinfo_Deployment_details-v1"]', - ) - .locator('.MuiChip-label') - .hover(); - const tooltip = page.locator('.MuiTooltip-popper'); - await expect(tooltip).toContainText(`app=details`); - await expect(tooltip).toContainText(`version=v1`); - }); - - // After click on a workload, the drawer is open - test('Workloads Drawer', async () => { - await page.locator('#drawer_bookinfo_details-v1').click(); - expect(page.locator('[data-test="drawer"]')).toBeDefined(); - }); - - // Verify drawer date - test('Workload Drawer Data', async () => { - const wbadge = page.locator('[data-test="w-badge"]'); - expect(wbadge).toBeDefined(); - await expect(wbadge).toContainText('W'); - - const title = page.locator('[data-test="workload-title"]'); - expect(title).toBeDefined(); - await expect(title).toContainText('details-v1'); - - const health = title.locator('[data-test="health"]'); - expect(health).toBeDefined(); - await health.hover(); - const tooltip = page.getByRole('tooltip'); - await expect(tooltip).toContainText('Pod Status'); - - const labels = page.locator('[data-test="app-label-container"]'); - await expect(labels).toContainText('app=details'); - const versionLabels = page.locator( - '[data-test="version-label-container"]', - ); - await expect(versionLabels).toContainText('version=v1'); - expect(page.locator('[data-test="help-icon"]')).toBeDefined(); - - const appLinks = page.locator('[data-test="App_bookinfo_details"]'); - await expect(appLinks).toContainText('A'); - await expect(appLinks).toContainText('details'); - - const serviceLinks = page.locator('[data-test="Service_details"]'); - await expect(serviceLinks).toContainText('S'); - await expect(serviceLinks).toContainText('details'); - }); - - // The drawer is closed - test('Close drawer', async () => { - await page.locator('#close_drawer').click(); - expect(page.locator('[data-test="services-tab"]')).toBeDefined(); - }); - - // The services tab is working - test('Services tab', async () => { - await page.locator('[data-test="services-tab"]').click(); - expect(page.locator('#drawer_bookinfo_details')).toBeDefined(); - }); - - // Check service Istio Configs - test('Service productpage istio config', async () => { - const productRow = page - .locator( - '[data-test="VirtualItem_ClusterKubernetes_Nsbookinfo_productpage"]', - ) - .getByRole('gridcell'); - expect(productRow.filter({ hasText: /bookinfo-gateway/ })).toBeDefined(); - expect(productRow.locator('#pfbadge-G')).toBeDefined(); - expect(productRow.filter({ hasText: /bookinfo/ })).toBeDefined(); - expect(productRow.locator('#pfbadge-VS')).toBeDefined(); - }); - - // Click in Service details - test('Service details for productpage', async () => { - await page - .locator( - '[data-test="VirtualItem_ClusterKubernetes_Nsbookinfo_productpage"]', - ) - .locator('#drawer_bookinfo_productpage') - .click(); - expect(page.locator('[data-test="drawer"]')).toBeDefined(); - expect(page.locator('#ServiceDescriptionCard')).toBeDefined(); - expect(page.locator('#pfbadge-S')).toBeDefined(); - }); - - // Navigate to workload - test('Go to workload link', async () => { - await page.getByRole('link', { name: 'productpage-v1' }).click(); - expect(page.locator('[data-test="drawer"]')).toBeDefined(); - expect(page.locator('#pfbadge-W')).toBeDefined(); - // Then, close the drawer - await page.locator('#close_drawer').click(); - expect(page.locator('[data-test="services-tab"]')).toBeDefined(); - }); - - // The apps tab is working - test('Applications tab', async () => { - await page.locator('[data-test="apps-tab"]').click(); - expect(page.locator('#drawer_bookinfo_details')).toBeDefined(); - }); - - // Applications details - test('Application details', async () => { - await page.locator('#drawer_travel-agency_travels').click(); - expect(page.locator('[data-test="drawer"]')).toBeDefined(); - expect(page.locator('#AppDescriptionCard')).toBeDefined(); - expect(page.locator('#pfbadge-A')).toBeDefined(); - }); - - // Applications details - test('Applicatoin istio details', async () => { - const productRow = page - .locator( - '[data-test="VirtualItem_ClusterKubernetes_Nsbookinfo_productpage"]', - ) - .getByRole('gridcell'); - expect(productRow.filter({ hasText: /bookinfo-gateway/ })).toBeDefined(); - expect(productRow.locator('#pfbadge-G')).toBeDefined(); - // Then, close the drawer - await page.locator('#close_drawer').click(); - expect(page.locator('[data-test="services-tab"]')).toBeDefined(); - }); - }); -}); diff --git a/plugins/kiali/tests/kiali.spec.ts b/plugins/kiali/tests/kiali.spec.ts deleted file mode 100644 index 03ab55ddb4..0000000000 --- a/plugins/kiali/tests/kiali.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { expect, Page, test } from '@playwright/test'; - -import { Common } from './kialiHelper'; - -test.describe('Kiali plugin', () => { - let page: Page; - let common: Common; - test.describe('kiali errors', () => { - test.beforeAll(async ({ browser }) => { - const context = await browser.newContext(); - page = await context.newPage(); - common = new Common(page); - - await common.loginAsGuest(); - await page.goto('/kiali-error'); - await page.locator('[data-test="Kiali Errors"]'); - }); - - test('Networking error', async () => { - await expect( - page.locator('[data-test="Warning: Error reaching Kiali"]'), - ).toBeDefined(); - }); - }); -}); diff --git a/plugins/kiali/tests/kialiHelper.ts b/plugins/kiali/tests/kialiHelper.ts deleted file mode 100644 index cb747b2440..0000000000 --- a/plugins/kiali/tests/kialiHelper.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { expect, type Locator, type Page } from '@playwright/test'; - -export { kialiData } from '../dev/__fixtures__'; - -export class Common { - page: Page; - - constructor(page: Page) { - this.page = page; - } - - async verifyHeading(heading: string) { - const headingLocator = this.page - .locator('h1, h2, h3, h4, h5, h6') - .filter({ hasText: heading }) - .first(); - await headingLocator.waitFor({ state: 'visible', timeout: 30000 }); - await expect(headingLocator).toBeVisible(); - } - - async clickButton( - label: string, - clickOpts?: Parameters[0], - getByTextOpts: Parameters[1] = { exact: true }, - ) { - const muiButtonLabel = 'span[class^="MuiButton-label"]'; - const selector = `${muiButtonLabel}:has-text("${label}")`; - const button = this.page - .locator(selector) - .getByText(label, getByTextOpts) - .first(); - await button.waitFor({ state: 'visible' }); - await button.click(clickOpts); - } - - async waitForSideBarVisible() { - await this.page.waitForSelector('nav a', { timeout: 120000 }); - } - - async loginAsGuest() { - await this.page.goto('/'); - // TODO - Remove it after https://issues.redhat.com/browse/RHIDP-2043. A Dynamic plugin for Guest Authentication Provider needs to be created - this.page.on('dialog', async dialog => { - await dialog.accept(); - }); - - await this.verifyHeading('Select a sign-in method'); - await this.clickButton('Enter'); - await this.waitForSideBarVisible(); - } -} diff --git a/plugins/kiali/tests/kialiPage.spec.ts b/plugins/kiali/tests/kialiPage.spec.ts deleted file mode 100644 index bb1931420f..0000000000 --- a/plugins/kiali/tests/kialiPage.spec.ts +++ /dev/null @@ -1,294 +0,0 @@ -import { expect, Page, test } from '@playwright/test'; - -import { Common, kialiData } from './kialiHelper'; - -const CONFIG = kialiData.config; -const NAMESPACES = kialiData.namespaces; -const STATUS = kialiData.status; -const BOOKINFO_APPS = kialiData.apps.bookinfo; -const BOOKINFO_SERVICES = kialiData.services.bookinfo; -const BOOKINFO_WORKLOADS = kialiData.workloads.bookinfo; - -async function checkReportedItems( - type: string, - ns: string, - objects: any, - page: any, -): Promise { - const ns_card = await page.locator(`data-test=overview-card-${ns}`); - await page.click('[aria-label="Health for"]'); - await page.click(`[data-value=${type}]`); - - const icon = await ns_card.locator('data-test=overview-app-health'); - await icon.hover(); - const list = await page.locator('data-test=overview-status'); - - // Wait for the list to appear - await page.waitForSelector('data-test=overview-status'); - - let i = 0; - for (const object of Object.entries(objects)) { - if (i === 5) { - break; - } - await icon.hover({ force: true }).then(async () => { - await expect(list).toContainText(`${object[1].name}`); - }); - i++; - } - const expected = type === 'app' ? 'application' : type; - await expect( - ns_card.locator(`data-test=overview-type-${type}`), - ).toContainText(`${Object.entries(objects).length} ${expected}s`); -} - -function filterByIstioInjectionEnabled(jsonArray: any): any { - return jsonArray.filter( - json => - (json.labels && json.labels['istio-injection'] === 'enabled') || - (json.name && json.name === 'istio-system'), - ); -} -const visibleNamespaces = filterByIstioInjectionEnabled(NAMESPACES); - -test.describe('Kiali page', () => { - let page: Page; - let common: Common; - test.describe('overview', () => { - test.beforeAll(async ({ browser }) => { - const context = await browser.newContext(); - page = await context.newPage(); - common = new Common(page); - await common.loginAsGuest(); - }); - test.beforeEach(async () => { - page.reload(); - }); - - test('Home cluster is visible', async () => { - await expect(page.locator('data-test=home-cluster')).toHaveText( - CONFIG.clusters.Kubernetes.name, - ); - }); - - test('About page can be opened', async () => { - await page.click('data-test=help-button'); - await expect(page.locator('data-test=Kiali')).toContainText( - STATUS.status['Kiali version'], - ); - await expect(page.locator('data-test=Kiali')).toContainText( - STATUS.status['Kiali commit hash'], - ); - await expect(page.locator('data-test=Kiali container')).toContainText( - STATUS.status['Kiali container version'], - ); - await expect(page.locator('data-test=Service Mesh')).toContainText( - STATUS.status['Mesh name'], - ); - await expect(page.locator('data-test=Service Mesh')).toContainText( - STATUS.status['Mesh version'], - ); - - for (const external of STATUS.externalServices) { - let text; - if (external.version) { - text = external.version; - } else { - text = 'N/A'; - } - await expect(page.locator(`data-test=${external.name}`)).toContainText( - text, - ); - } - }); - - test('MessageCenter can be opened', async () => { - await page.click('data-test=message-center'); - await expect( - page.locator('data-test=message-center-modal'), - ).toBeVisible(); - await expect(page.locator('data-test=message-center-summary')).toHaveText( - 'Notifications 2 Unread Messages', - ); - await page.click('data-test=message-center-summary'); - await page.locator( - 'data-test=message-center-messages [data-test=drawer-message]', - ); - }); - - test('Detail of a message in MessageCenter can be opened', async () => { - await page.click('data-test=message-center'); - await page.click('data-test=message-center-summary'); - await page.click('data-test=show-message-detail'); - await expect(page.locator('data-test=message-detail').first()).toHaveText( - 'grafana URL is not set in Kiali configuration', - ); - }); - - test('Detail of a message in MessageCenter can be closed', async () => { - await page.click('data-test=message-center'); - await page.click('data-test=message-center-summary'); - await page.click('data-test=show-message-detail'); - await page.click('data-test=hide-message-detail'); - await expect( - page.locator('data-test=message-detail').first(), - ).toBeHidden(); - }); - - test('Messages can be marked as read', async () => { - await page.click('data-test=message-center'); - await page.click('data-test=message-center-summary'); - await page.click('data-test=mark-as-read'); - await expect(page.locator('data-test=message-center-summary')).toHaveText( - 'Notifications 0 Unread Messages', - ); - }); - - test('Messages can be cleared', async () => { - await page.click('data-test=message-center'); - await page.click('data-test=message-center-summary'); - await page.click('data-test=clear-all'); - await expect(page.locator('data-test=message-center-summary')).toHaveText( - 'Notifications 0 Unread Messages', - ); - await expect( - page.locator('data-test=message-center-messages'), - ).toHaveText('No Messages Available'); - await expect(page.locator('data-test=drawer-message')).toHaveCount(0); - }); - - test('User is visible', async () => { - if (CONFIG.authStrategy === 'anonymous') { - await expect(page.locator('data-test=user')).toHaveText( - 'User : anonymous', - ); - } - // There could be an else branch with non-anonymous auth strategies, but there is not enough test data in the fixtures for this. - }); - - test('Check namespaces visible to Kiali', async () => { - await page.click('data-test=namespace-selector'); - for (const ns of visibleNamespaces) { - await expect(page.locator(`ul[role="listbox"]`)).toContainText(ns.name); - } - await expect(page.locator('ul[role="listbox"] > li')).toHaveCount( - visibleNamespaces.length, - ); - }); - - test('No namespaces are selected', async () => { - await page.click('data-test=namespace-selector'); - for (const ns of visibleNamespaces) { - await page.click(`ul[role="listbox"] > li:has-text("${ns.name}")`); - } - for (const ns of visibleNamespaces) { - await expect( - page.locator(`data-test=overview-card-${ns.name}`), - ).toHaveCount(0); - } - }); - - test('All namespaces are selected', async () => { - for (const ns of visibleNamespaces) { - await expect( - page.locator(`data-test=overview-card-${ns.name}`), - ).toHaveCount(1); - } - }); - - test('Namespace card should have labels', async () => { - const ns = visibleNamespaces[0]; - const ns_card = await page.locator(`data-test=overview-card-${ns.name}`); - const icon = await ns_card.locator('data-test=labels-info-icon'); - await icon.hover(); - const list = await page.locator('data-test=namespace-labels'); - - // Wait for the list to appear - await page.waitForSelector('data-test=namespace-labels'); - - for (const [key, value] of Object.entries(ns.labels)) { - await icon.hover({ force: true }).then(async () => { - await expect(list).toContainText(`${key}=${value}`); - }); - } - await expect(ns_card.locator('#labels_info')).toContainText( - `${Object.entries(ns.labels).length} labels`, - ); - }); - - test('Apps should be reported in the namespace card', async () => { - const ns = BOOKINFO_APPS.namespace.name; - await checkReportedItems('app', ns, BOOKINFO_APPS.applications, page); - }); - - test('Services should be reported in the namespace card', async () => { - const ns = BOOKINFO_SERVICES.namespace.name; - await checkReportedItems('service', ns, BOOKINFO_SERVICES.services, page); - }); - - test('Workloads should be reported in the namespace card', async () => { - const ns = BOOKINFO_WORKLOADS.namespace.name; - await checkReportedItems( - 'workload', - ns, - BOOKINFO_WORKLOADS.workloads, - page, - ); - }); - - test('Healthy apps should be reported in the namespace card', async () => { - const ns_card = await page.locator(`data-test=overview-card-bookinfo`); - const icon = await ns_card.locator('data-test=overview-app-health'); - await icon.hover(); - await page.waitForSelector('data-test=overview-status'); - await expect(ns_card.locator('data-test=Healthy-status')).toBeDefined(); - }); - - test('Degraded apps should be reported in the namespace card', async () => { - const ns_card = await page.locator( - `data-test=overview-card-travel-agency`, - ); - const icon = await ns_card - .locator('[aria-label="Overview status"]') - .first(); - await icon.hover(); - await page.waitForSelector('data-test=overview-status'); - await expect(ns_card.locator('data-test=Degraded-status')).toBeDefined(); - }); - - test('Failed apps should be reported in the namespace card', async () => { - const ns_card = await page.locator( - `data-test=overview-card-travel-control`, - ); - const icon = await ns_card.locator('[aria-label="Overview status"]'); - await icon.hover(); - await page.waitForSelector('data-test=overview-status'); - await expect(ns_card.locator('data-test=Failure-status')).toBeDefined(); - }); - - test('Istio config with success should be reported in the namespace card', async () => { - const ns_card = await page.locator( - `data-test=overview-card-travel-agency`, - ); - await expect( - ns_card.locator('data-test=validation-icon-correct'), - ).toBeVisible(); - }); - - test('Istio config with warning should be reported in the namespace card', async () => { - const ns_card = await page.locator( - `data-test=overview-card-travel-control`, - ); - await expect( - ns_card.locator('data-test=validation-icon-warning'), - ).toBeVisible(); - }); - - test('Istio config with error should be reported in the namespace card', async () => { - const ns_card = await page.locator(`data-test=overview-card-bookinfo`); - await expect( - ns_card.locator('data-test=validation-icon-error'), - ).toBeVisible(); - }); - }); -});