diff --git a/tests/e2e/00-installation.spec.ts b/tests/e2e/00-installation.spec.ts index e604f30b..4de46a5c 100644 --- a/tests/e2e/00-installation.spec.ts +++ b/tests/e2e/00-installation.spec.ts @@ -1,9 +1,10 @@ import { test, expect } from './rancher-test'; import { RancherCommonPage } from './pages/rancher-common.page'; import { RancherExtensionsPage } from './pages/rancher-extensions.page'; -import { OverviewPage } from './pages/overview.page'; +import { KubewardenPage } from './pages/kubewarden.page'; import { PolicyServersPage } from './pages/policyservers.page'; import { policyTitles } from './pages/basepolicypage'; +import { RancherAppsPage } from './pages/rancher-apps.page'; // source (yarn dev) | rc (add github repo) | released (just install) const ORIGIN = process.env.ORIGIN || (process.env.API ? 'source' : 'rc'); @@ -42,14 +43,12 @@ test('01 Enable extension support', async({ page, ui }) => { test('02 Install extension', async({ page }) => { // Add UI charts repository if (ORIGIN === 'rc') { - const rancher = new RancherCommonPage(page); - - await rancher.addRepository('kubewarden-extension-rc', 'https://rancher.github.io/kubewarden-ui/'); + const apps = new RancherAppsPage(page); + await apps.addRepository('kubewarden-extension-rc', 'https://rancher.github.io/kubewarden-ui/'); } // Install or developer load extension const extensions = new RancherExtensionsPage(page); - await extensions.goto(); if (ORIGIN === 'source') { await extensions.developerLoad('http://127.0.0.1:4500/kubewarden-0.0.1/kubewarden-0.0.1.umd.min.js'); @@ -59,8 +58,7 @@ test('02 Install extension', async({ page }) => { }); test('03 Install kubewarden', async({ page, ui }) => { - const kwPage = new OverviewPage(page); - + const kwPage = new KubewardenPage(page); await kwPage.installKubewarden(); // Check UI is active @@ -72,31 +70,24 @@ test('03 Install kubewarden', async({ page, ui }) => { test('04 Install default policyserver', async({ page, ui }) => { const psPage = new PolicyServersPage(page); + const kwPage = new KubewardenPage(page); - // Check banner is also visible on overview page - const kwPage = new OverviewPage(page); - + // Banner is visible on Overview page await kwPage.goto(); await expect(psPage.noDefaultPsBanner).toBeVisible(); - + // Banner is visible on Policy Servers page await psPage.goto(); await expect(psPage.noDefaultPsBanner).toBeVisible(); + await page.getByRole('button', { name: 'Install Chart', exact: true }).click(); await expect(page).toHaveURL(/.*\/apps\/charts\/install.*chart=kubewarden-defaults/); // Handle PolicyServer Installer Dialog - await expect(page.getByRole('heading', { name: 'Install: Step 1' })).toBeVisible(); - await page.getByRole('button', { name: 'Next' }).click(); - - await expect(page.getByRole('heading', { name: 'Install: Step 2' })).toBeVisible(); - await psPage.installDefaultDialog({ enable: true, mode: 'monitor' }); - - await page.getByRole('button', { name: 'Install' }).click(); - await expect(ui.helmPassRegex('rancher-kubewarden-defaults')).toBeVisible({ timeout: 40_000 }); + await psPage.installDefault({recommended: true, mode: 'monitor'}) }); test('05 Whitelist artifacthub', async({ page }) => { - const kwPage = new OverviewPage(page); + const kwPage = new KubewardenPage(page); await page.goto('/dashboard/c/local/kubewarden/policies.kubewarden.io.clusteradmissionpolicy/create'); await expect(page.getByRole('heading', { name: 'Custom Policy' })).toBeVisible(); diff --git a/tests/e2e/10-landing.spec.ts b/tests/e2e/10-landing.spec.ts index d2d40a31..b312268b 100644 --- a/tests/e2e/10-landing.spec.ts +++ b/tests/e2e/10-landing.spec.ts @@ -1,11 +1,11 @@ import { test, expect } from './rancher-test'; -import { OverviewPage } from './pages/overview.page'; +import { KubewardenPage } from './pages/kubewarden.page'; import { PolicyServersPage } from './pages/policyservers.page'; import { AdmissionPoliciesPage } from './pages/admissionpolicies.page'; import { ClusterAdmissionPoliciesPage } from './pages/clusteradmissionpolicies.page'; test('Kubewarden Landing page', async({ page, ui }) => { - const kwPage = new OverviewPage(page); + const kwPage = new KubewardenPage(page); await kwPage.goto(); await expect(page.getByRole('heading', { name: 'Welcome to Kubewarden' })).toBeVisible() diff --git a/tests/e2e/50-policyreports.spec.ts b/tests/e2e/50-policyreports.spec.ts index fda9eb55..598f7392 100644 --- a/tests/e2e/50-policyreports.spec.ts +++ b/tests/e2e/50-policyreports.spec.ts @@ -29,8 +29,8 @@ test('PolicyReports', async({ page, ui }) => { await den.getByRole('textbox').fill('unsafelbl') // Customize because audit for "*" rules is skipped - await capPage.editYaml() - await ui.editYaml(ui.page, d => { + await ui.openYamlEditor() + await ui.editYaml(d => { d.spec.rules[0].apiGroups[0] = "" d.spec.rules[0].apiVersions[0] = "v1" d.spec.rules[0].resources[0] = "namespaces" diff --git a/tests/e2e/60-tracing.spec.ts b/tests/e2e/60-tracing.spec.ts new file mode 100644 index 00000000..a8a8661c --- /dev/null +++ b/tests/e2e/60-tracing.spec.ts @@ -0,0 +1,66 @@ +import { test, expect } from './rancher-test'; +import { Chart, RancherAppsPage } from './pages/rancher-apps.page'; +import { PolicyServersPage } from './pages/policyservers.page'; + +/** + * Expect timeout has to be increased after telemetry installation on local cluster + * + */ +test('Install opentelemetry & jaeger', async ({ page }) => { + const apps = new RancherAppsPage(page) + const otelChart: Chart = { title: 'opentelemetry-operator', name: 'opentelemetry-operator', namespace: 'open-telemetry', version: '0.38.0', check: 'opentelemetry-operator' } + const jaegerChart: Chart = { title: 'Jaeger Operator', namespace: 'jaeger', check: "jaeger-operator" } + + // Install OpenTelemetry + await apps.addRepository('open-telemetry', 'https://open-telemetry.github.io/opentelemetry-helm-charts') + await apps.installChart(otelChart) + + // Install Jaeger + await apps.installChart(jaegerChart, d => { + d.jaeger.create = "true" + d.rbac.clusterRole = "true" + }) +}); + +test('Enable tracing in Kubewarden', async ({ page, ui }) => { + const apps = new RancherAppsPage(page) + await apps.updateApp('rancher-kubewarden-controller', d => { + d.telemetry.enabled = true + d.telemetry.tracing.jaeger.endpoint = "jaeger-operator-jaeger-collector.jaeger.svc.cluster.local:14250" + d.telemetry.tracing.jaeger.tls = {} + d.telemetry.tracing.jaeger.tls.insecure = true + }) + + // Wait until kubewarden controller and policyserver are restarted, it takes around 1m + await ui.shell(`for i in $(seq 60); do + echo "Retry #$i"; k logs -l app=kubewarden-policy-server-default -n cattle-kubewarden-system -c otc-container | grep -F 'Everything is ready.' && break || sleep 5; + done`) +}); + +test('Check traces are visible', async ({ page, ui }) => { + const tracingTab = page.getByRole('tablist').locator('li#policy-tracing') + const policiesTab = page.getByRole('tablist').locator('li#related-policies') + const logline = ui.getRow('tracing-privpod').row.first() + + const psPage = new PolicyServersPage(page) + await psPage.goto() + + // Create trace log line + await ui.shell('k run tracing-privpod --image=nginx:alpine --privileged') + console.warn('Workaround: Opentelemetry not installed warning before I generate traces') + await page.reload() + + // Check logs on policy server + await ui.getRow('default').open() + await tracingTab.click() + await expect(logline).toBeVisible() + + // Check logs on the policy + await policiesTab.click() + await ui.getRow('no-privileged-pod').open() + await tracingTab.click() + await expect(logline).toBeVisible() + + // Cleanup + await ui.shell('k delete pod tracing-privpod') +}) diff --git a/tests/e2e/components/table-row.ts b/tests/e2e/components/table-row.ts index b982a5dd..27532f9b 100644 --- a/tests/e2e/components/table-row.ts +++ b/tests/e2e/components/table-row.ts @@ -1,6 +1,18 @@ import { expect, Locator } from '@playwright/test'; import { RancherUI } from '../pages/rancher-ui'; +/** + * Builds xpath expression to get column index by it's name + * @param name Name of the table column + * @returns xpath expression to get index of the column + */ +function xpath_colIndex(...names: string[]):string { + // Transform: names > normalize-space(.)="names[0]" [or ...] + const selector = names.map(str => `normalize-space(.)="${str}"`).join(" or ") + // Find thead > th with requested name and count how many th was before it + return `count(ancestor::table[1]/thead/tr/th[${selector}]/preceding-sibling::th)+1` +} + export class TableRow { private readonly ui: RancherUI @@ -10,8 +22,8 @@ export class TableRow { /** * - * @param page required by actions menu since it's not child of the table - * @param name of the row, has to be a link to the resource + * @param page is required by row actions menu since it's not child of the table + * @param name of the row, it is searched under "Name" column by default * @param group When there are multiple tbodies filter by group-tab * */ @@ -22,7 +34,7 @@ export class TableRow { } this.ui = ui - this.row = tbody.locator('tr.main-row').filter({has: ui.page.getByRole('link', {name: name, exact: true})}) + this.row = tbody.locator(`xpath=tr[td[${xpath_colIndex("Name")}][normalize-space(.)="${name}"]]`) this.name = this.column('Name') this.status = this.column('Status', 'State') } @@ -37,11 +49,12 @@ export class TableRow { await expect(this.status).toHaveText('Active', {timeout: timeout}) } + /** + * @param names header of the column, you can provide alternative names (State|Status) + * @returns table cell (td) that is under requested column. Returns first cell if no match was found + */ column(...names: string[]) { - // Transform: names > normalize-space(.)="names[0]" [or ...] - const selector = names.map(str => `normalize-space(.)="${str}"`).join(" or ") - // https://stackoverflow.com/questions/14745478/how-to-select-table-column-by-column-header-name-with-xpath - return this.row.locator(`xpath=/td[count(ancestor::table[1]/thead/tr/th[${selector}]/preceding-sibling::th)+1]`) + return this.row.locator(`xpath=td[${xpath_colIndex(...names)}]`) } async action(name: string) { diff --git a/tests/e2e/exec.spec.ts b/tests/e2e/exec.spec.ts index a2fa305c..0388dd62 100644 --- a/tests/e2e/exec.spec.ts +++ b/tests/e2e/exec.spec.ts @@ -1,10 +1,10 @@ import { test } from './rancher-test' -import { type Chart, RancherCommonPage } from './pages/rancher-common.page'; +import { type Chart, RancherAppsPage } from './pages/rancher-apps.page'; const charts: Chart[] = [ - {title: 'Jaeger Operator', namespace: 'jaeger', name: "jaeger-operator"}, - {title: 'Monitoring', project: '(None)', name: "rancher-monitoring"}, - {title: 'Kubewarden', project: 'Default', name: "rancher-kubewarden-controller"}, + {title: 'Jaeger Operator', namespace: 'jaeger', check: "jaeger-operator"}, + {title: 'Monitoring', project: '(None)', check: "rancher-monitoring"}, + {title: 'Kubewarden', project: 'Default', check: "rancher-kubewarden-controller"}, ] // Install chart from apps menu @@ -12,15 +12,15 @@ const charts: Chart[] = [ test('appInstall', async({ page}) => { const chart = charts.find(o => o.title === process.env.app) || charts[0] - const rancher = new RancherCommonPage(page) - await rancher.installApp(chart) + const apps = new RancherAppsPage(page) + await apps.installChart(chart) }); // Upgrade without any changes will reload app yaml (patched by kubectl) // app='Jaeger Operator' pw test exec -g 'appUpdate' --headed test('appUpdate', async({ page }) => { - const chart = charts.find(o => o.title === process.env.app) || charts[0] + const app = process.env.app || 'jaeger-operator' - const rancher = new RancherCommonPage(page) - await rancher.updateApp(chart) + const apps = new RancherAppsPage(page) + await apps.updateApp(app) }); diff --git a/tests/e2e/pages/basepolicypage.ts b/tests/e2e/pages/basepolicypage.ts index 08f867d0..3439c36d 100644 --- a/tests/e2e/pages/basepolicypage.ts +++ b/tests/e2e/pages/basepolicypage.ts @@ -54,14 +54,6 @@ export class BasePolicyPage extends BasePage { await this.ui.checkbox('Ignore Rancher Namespaces').setChecked(checked) } - async editYaml() { - // Give generated fields time to get registered - await this.page.waitForTimeout(200) - // Show yaml with edited settings - await this.page.getByRole('button', { name: 'Edit YAML' }).click() - await expect(this.page.getByTestId('kw-policy-config-yaml-editor')).toBeVisible() - } - async open(p: Policy) { // Open list of policies await this.ui.createBtn.click() @@ -91,7 +83,7 @@ export class BasePolicyPage extends BasePage { // Extra policy settings if (p.settings) { await p.settings(this.ui) - await this.editYaml() + await this.ui.openYamlEditor() } } diff --git a/tests/e2e/pages/overview.page.ts b/tests/e2e/pages/kubewarden.page.ts similarity index 83% rename from tests/e2e/pages/overview.page.ts rename to tests/e2e/pages/kubewarden.page.ts index f83ed676..d047dfda 100644 --- a/tests/e2e/pages/overview.page.ts +++ b/tests/e2e/pages/kubewarden.page.ts @@ -1,7 +1,8 @@ import { expect, Locator, Page } from '@playwright/test'; import { BasePage } from './basepage'; +import { RancherAppsPage } from './rancher-apps.page'; -export class OverviewPage extends BasePage { +export class KubewardenPage extends BasePage { readonly createPsBtn: Locator; readonly createApBtn: Locator; readonly createCapBtn: Locator; @@ -58,21 +59,21 @@ export class OverviewPage extends BasePage { // ================================================================================================== // Rancher Application Metadata - await this.page.getByRole('button', { name: 'Next' }).click(); + const apps = new RancherAppsPage(this.page) + await expect(apps.step1).toBeVisible() + await apps.nextBtn.click() + await expect(apps.step2).toBeVisible() + // Rancher Application Values const schedule = this.ui.input('Schedule') await expect(schedule).toHaveValue('*/60 * * * *') await schedule.fill('*/1 * * * *') await this.ui.checkbox('Enable Policy Reporter').check() - // Enable telemetry - // await page.getByRole('button', { name: 'Edit YAML' }).click() - // await editYaml(page, d => d.telemetry.enabled = true ) - // await page.getByRole('button', { name: 'Compare Changes' }).click() - - await this.page.getByRole('button', { name: 'Install' }).click(); - await expect(this.ui.helmPassRegex('rancher-kubewarden-crds')).toBeVisible({ timeout: 30_000 }); - await expect(this.ui.helmPassRegex('rancher-kubewarden-controller')).toBeVisible({ timeout: 60_000 }); + // Start installation + await apps.installBtn.click() + await apps.waitHelmSuccess('rancher-kubewarden-crds') + await apps.waitHelmSuccess('rancher-kubewarden-controller') } async whitelistArtifacthub() { diff --git a/tests/e2e/pages/policyservers.page.ts b/tests/e2e/pages/policyservers.page.ts index 3af5f1bb..a416b880 100644 --- a/tests/e2e/pages/policyservers.page.ts +++ b/tests/e2e/pages/policyservers.page.ts @@ -1,5 +1,7 @@ -import { Locator, Page } from '@playwright/test'; +import type { Locator, Page } from '@playwright/test'; +import { expect } from '@playwright/test'; import { BasePage } from './basepage'; +import { RancherAppsPage } from './rancher-apps.page'; export class PolicyServersPage extends BasePage { readonly noDefaultPsBanner: Locator; @@ -33,12 +35,24 @@ export class PolicyServersPage extends BasePage { await this.ui.getRow(name).delete() } - async installDefaultDialog(recommended: {enable: boolean, mode?: 'monitor' | 'protect'}) { - await this.ui.checkbox('Enable recommended policies').check() + async installDefault(options?: {recommended?: boolean, mode?: 'monitor' | 'protect'}) { + const apps = new RancherAppsPage(this.page) + // Skip metadata + await expect(apps.step1).toBeVisible() + await apps.nextBtn.click() + await expect(apps.step2).toBeVisible() - if (recommended.enable && recommended.mode) { - await this.ui.select('Execution mode', recommended.mode) + // Handle questions + if (options?.recommended) { + await this.ui.checkbox('Enable recommended policies').setChecked(options.recommended) } - }; + if (options?.mode) { + await this.ui.select('Execution mode', options.mode) + } + + // Install + await apps.installBtn.click(); + await apps.waitHelmSuccess('rancher-kubewarden-defaults') + } } diff --git a/tests/e2e/pages/rancher-apps.page.ts b/tests/e2e/pages/rancher-apps.page.ts new file mode 100644 index 00000000..7178b93c --- /dev/null +++ b/tests/e2e/pages/rancher-apps.page.ts @@ -0,0 +1,125 @@ +import type { Locator, Page } from '@playwright/test'; +import { expect } from '@playwright/test'; +import { BasePage } from './basepage'; + +export interface Chart { + title: string, // Exact chart title displayed in Rancher + check: string, // Used to check for helm success, chart name or tgz + name?: string, // Desired chart name + version?: string, + namespace?: string, + project?: string, +} + +export class RancherAppsPage extends BasePage { + readonly step1: Locator + readonly step2: Locator + readonly nextBtn: Locator + readonly installBtn: Locator + readonly updateBtn: Locator + + constructor(page: Page) { + super(page, "dashboard/c/local/apps/charts") + this.step1 = page.getByRole('heading', { name: 'Install: Step 1' }) + this.step2 = page.getByRole('heading', { name: 'Install: Step 2' }) + this.nextBtn = page.getByRole('button', { name: 'Next' }) + this.installBtn = page.getByRole('button', { name: 'Install' }) + this.updateBtn = page.getByRole('button', { name: 'Update' }) + } + + /** + * Add helm charts repository to local cluster + * @param name + * @param url Git or http(s) url of the repository + */ + async addRepository(name: string, url: string) { + await this.page.goto('dashboard/c/local/apps/catalog.cattle.io.clusterrepo/create') + + await this.ui.input('Name *').fill(name) + if (url.endsWith('.git')) { + await this.page.getByRole('radio', { name: 'Git repository' }).check() + await this.ui.input('Git Repo URL *').fill(url) + } else { + await this.page.getByRole('radio', { name: 'http(s) URL' }).check() + await this.ui.input('Index URL *').fill(url) + } + await this.page.getByRole('button', { name: 'Create' }).click(); + + // Check repository state is Active + await this.ui.getRow(name).toBeActive() + } + + /** + * Build regex matching successfull chart installation + * SUCCESS: helm upgrade ... rancher-kubewarden-defaults /home/shell/helm/kubewarden-defaults-1.7.3.tgz + * SUCCESS: helm [install|upgrade] [--generate-name=true|name] /home/shell/helm/opentelemetry-operator-0.38.0.tgz + */ + async waitHelmSuccess(text: string, timeout=60_000) { + // Can't match ^..$ because output is sometimes mixed up + const regex = new RegExp(`SUCCESS: helm.*${text}`) + const passedMsg = this.page.locator('div.logs-container').locator('span.msg').getByText(regex) + await expect(passedMsg).toBeVisible({ timeout: timeout }) + } + + async installChart(chart: Chart, yamlPatch?: Function | string, options?:{timeout?: number}) { + // Select chart by title + await this.page.goto('dashboard/c/local/apps/charts') + await expect(this.page.getByRole('heading', { name: 'Charts', exact: true })).toBeVisible() + await this.page.locator('.grid > .item').getByRole('heading', { name: chart.title, exact: true }).click() + + if (chart.version) { + const versionPane = this.page.getByRole('heading', { name: 'Chart Versions', exact: true }).locator('..') + await versionPane.getByText('Show More', { exact: true }).click() + // Active version is bold text, not active are links + await versionPane.getByText(chart.version, { exact: true }).click() + await expect(versionPane.locator(`b:text-is("${chart.version}")`)).toBeVisible() + } + await this.installBtn.click() + + // Chart metadata + await expect(this.step1).toBeVisible() + if (chart.name) { + await this.ui.input('Name').fill(chart.name) + } + if (chart.namespace) { + await this.ui.select('Namespace *', 'Create a New Namespace') + await this.ui.input('Namespace').fill(chart.namespace) + } + if (chart.project) { + await this.ui.select('Install into Project', chart.project) + } + await this.nextBtn.click() + + // Chart questions + if (yamlPatch) { + await this.ui.openYamlEditor() + await this.ui.editYaml(yamlPatch) + await this.page.getByRole('button', { name: 'Compare Changes', exact: true }).click() + } + + // Installation & Wait + await this.installBtn.click() + await this.waitHelmSuccess(chart.check, options?.timeout) + } + + // Without parameters only for upgrade/reload + async updateApp(name: string, yamlPatch?: Function | string, options?:{timeout?: number}) { + await this.page.goto('dashboard/c/local/apps/catalog.cattle.io.app') + await expect(this.page.getByRole('heading', { name: 'Installed Apps' })).toBeVisible() + + await this.ui.getRow(name).action('Edit/Upgrade') + await expect(this.page.getByRole('heading', { name: name })).toBeVisible() + await this.nextBtn.click() + + // Chart questions + if (yamlPatch) { + await this.ui.openYamlEditor() + await this.ui.editYaml(yamlPatch) + await this.page.getByRole('button', { name: 'Compare Changes', exact: true }).click() + } + + await this.updateBtn.click() + await this.waitHelmSuccess(name, options?.timeout) + } + +} diff --git a/tests/e2e/pages/rancher-common.page.ts b/tests/e2e/pages/rancher-common.page.ts index 31aa2f4b..014dc82a 100644 --- a/tests/e2e/pages/rancher-common.page.ts +++ b/tests/e2e/pages/rancher-common.page.ts @@ -1,13 +1,6 @@ import { expect, Page } from '@playwright/test'; import { BasePage } from './basepage'; -export interface Chart { - title: string, - name: string, - namespace?: string, - project?: string, -} - export class RancherCommonPage extends BasePage { constructor(page: Page) { @@ -79,62 +72,4 @@ export class RancherCommonPage extends BasePage { await this.ui.checkbox('Enable Extension developer features').setChecked(enabled) } - /** - * Add helm charts repository to local cluster - * @param name - * @param url Git or http(s) url of the repository - */ - async addRepository(name:string, url:string) { - await this.page.goto('dashboard/c/local/apps/catalog.cattle.io.clusterrepo/create') - - await this.ui.input('Name *').fill(name) - if (url.endsWith('.git')) { - await this.page.getByRole('radio', { name: 'Git repository' }).check() - await this.ui.input('Git Repo URL *').fill(url) - } else { - await this.page.getByRole('radio', { name: 'http(s) URL' }).check() - await this.ui.input('Index URL *').fill(url) - } - await this.page.getByRole('button', { name: 'Create' }).click(); - - // Check repository state is Active - await this.ui.getRow(name).toBeActive() - } - - async installApp(chart: Chart) { - // Select chart - await this.page.goto('dashboard/c/local/apps/charts') - await expect(this.page.getByRole('heading', { name: 'Charts', exact: true })).toBeVisible() - await this.page.locator('.grid > .item').getByRole('heading', { name: chart.title, exact: true }).click() - await this.page.getByRole('button', { name: 'Install' }).click() - - // Select namespace or project - if (chart.namespace) { - await expect(this.page.getByRole('heading', { name: 'Install: Step 1' })).toBeVisible() - await this.ui.select('Namespace *', 'Create a New Namespace') - await this.ui.input('Namespace').fill(chart.namespace) - } - if (chart.project) { - await this.ui.select('Install into Project', chart.project) - } - - // Installation & Wait - await this.page.getByRole('button', { name: 'Next' }).click() // readme - await this.page.getByRole('button', { name: 'Install' }).click() - await expect(this.ui.helmPassRegex(chart.name)).toBeVisible({timeout:300_000}) - } - - // Without parameters only for upgrade/reload - async updateApp(chart: Chart) { - await this.page.goto('dashboard/c/local/apps/catalog.cattle.io.app') - await expect(this.page.getByRole('heading', { name: 'Installed Apps' })).toBeVisible() - - await this.ui.getRow(chart.name).action('Edit/Upgrade') - await expect(this.page.getByRole('heading', { name: chart.name })).toBeVisible() - - await this.page.getByRole('button', { name: 'Next' }).click() // version - await this.page.getByRole('button', { name: 'Update' }).click() - await expect(this.ui.helmPassRegex(chart.name)).toBeVisible({timeout:300_000}) - } - } diff --git a/tests/e2e/pages/rancher-ui.ts b/tests/e2e/pages/rancher-ui.ts index e6dded53..32917fa0 100644 --- a/tests/e2e/pages/rancher-ui.ts +++ b/tests/e2e/pages/rancher-ui.ts @@ -63,21 +63,21 @@ export class RancherUI { // ================================================================================================== // Helper functions - /** - * Build regex matching successfull chart installation - */ - helmPassRegex(name: string) { - const re = new RegExp(`SUCCESS: helm .* ${name} \/home`) - return this.page.locator('.logs-container').getByText(re) + async openYamlEditor() { + // Give generated fields time to get registered + await this.page.waitForTimeout(200) + // Show yaml with edited settings + await this.page.getByRole('button', { name: 'Edit YAML' }).click() + await expect(this.page.locator('div.CodeMirror')).toBeVisible() } /** * Usage: - * await editYaml(page, d => d.telemetry.enabled = true ) - * await editYaml(page, '{"policyServer": {"telemetry": { "enabled": false }}}') + * await editYaml(d => d.telemetry.enabled = true ) + * await editYaml('{"policyServer": {"telemetry": { "enabled": false }}}') */ - async editYaml(page: Page, source: Function|string) { - const cmEditor = page.locator('div.CodeMirror-lines[role="presentation"]') + async editYaml(source: Function|string) { + const cmEditor = this.page.locator('div.CodeMirror-lines[role="presentation"]') // Load yaml from code editor await expect(cmEditor).toBeVisible() @@ -94,9 +94,9 @@ export class RancherUI { merge(cmYaml, jsyaml.load(source)) } // Paste edited yaml - await page.locator('.CodeMirror-code').click() - await page.keyboard.press('Control+A'); - await page.keyboard.insertText(jsyaml.dump(cmYaml)) + await this.page.locator('.CodeMirror-code').click() + await this.page.keyboard.press('Control+A'); + await this.page.keyboard.insertText(jsyaml.dump(cmYaml)) } /** @@ -117,7 +117,7 @@ export class RancherUI { await input.fill(cmd + ' || echo ERREXIT-$?') await input.press('Enter') // Wait - command finished when prompt is empty - await expect(prompt.getByText(/^>\s+$/)).toBeVisible({timeout: 60_000}) + await expect(prompt.getByText(/^>\s+$/)).toBeVisible({timeout: 5*60_000}) // Verify command exit status await expect(win.getByText(/ERREXIT-[0-9]+/), {message: 'Shell command finished with an error'}).not.toBeVisible({timeout: 1}) } diff --git a/tests/e2e/policies.spec.ts b/tests/e2e/policies.spec.ts index 655afd2e..02d1db96 100644 --- a/tests/e2e/policies.spec.ts +++ b/tests/e2e/policies.spec.ts @@ -88,14 +88,14 @@ async function setupVerifyImageSignatures(ui: RancherUI) { await ui.select('Signature Type', 'GithubAction') await ui.page.getByRole('button', {name: 'Add', exact: true}).click() await ui.input('Image*').fill('ghcr.io/kubewarden/*') - await ui.editYaml(ui.page, d => d.githubActions.owner = "kubewarden") + await ui.editYaml(d => d.githubActions.owner = "kubewarden") } async function setupEnvironmentVariablePolicy(ui: RancherUI) { await ui.page.getByRole('tab', { name: 'Settings' }).click() await ui.page.getByRole('button', {name: 'Add', exact: true}).click() await ui.select('Reject Operator', 'anyIn') - await ui.editYaml(ui.page, d => d.environmentVariables[0].name = "novar") + await ui.editYaml(d => d.environmentVariables[0].name = "novar") } async function setupUserGroupPSP(ui: RancherUI) { diff --git a/tests/playwright.config.ts b/tests/playwright.config.ts index 9b213e5a..3342eb7d 100644 --- a/tests/playwright.config.ts +++ b/tests/playwright.config.ts @@ -22,7 +22,9 @@ export default defineConfig({ // ===== Rancher specific config ===== /* Maximum time one test can run for. */ - timeout: 7 * 60_0000, + timeout: 7 * 60_000, + /* Expect timeout - increase from 5s to 10s because rancher is slow when loading pages */ + expect: { timeout: 10_000 }, /* Whether to report slow test files. */ reportSlowTests: null, /* Path to the global setup file. */ @@ -37,7 +39,7 @@ export default defineConfig({ /* Timeout for navigation actions like page.goto() */ navigationTimeout: 60_000, /* Slows down Playwright operations by the specified amount of milliseconds. */ - // launchOptions: { slowMo: 100 }, + // launchOptions: { slowMo: 200 }, ignoreHTTPSErrors: true, storageState: 'storageState.json',