-
Notifications
You must be signed in to change notification settings - Fork 702
CONSOLE-5281: Migrate Cypress E2E tests to Playwright (batch 2) #16454
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
Open
rhamilto
wants to merge
1
commit into
openshift:main
Choose a base branch
from
rhamilto:CONSOLE-5281
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| import { expect } from '@playwright/test'; | ||
| import yaml from 'js-yaml'; | ||
|
|
||
| import BasePage from './base-page'; | ||
|
|
||
| type AlertmanagerConfig = { | ||
| global?: Record<string, any>; | ||
| receivers?: AlertmanagerReceiver[]; | ||
| route?: any; | ||
| inhibit_rules?: any[]; | ||
| }; | ||
|
|
||
| type AlertmanagerReceiver = { | ||
| name: string; | ||
| [key: string]: any; | ||
| }; | ||
|
|
||
| export class AlertmanagerPage extends BasePage { | ||
| private readonly createReceiverButton = this.page.getByTestId('create-receiver'); | ||
| private readonly receiverNameInput = this.page.getByTestId('receiver-name'); | ||
| private readonly receiverTypeDropdown = this.page.getByTestId('receiver-type'); | ||
| private readonly saveChangesButton = this.page.getByTestId('save-changes'); | ||
| private readonly advancedConfigButton = this.page.getByTestId('advanced-configuration'); | ||
|
|
||
| async navigateToAlertmanager(): Promise<void> { | ||
| await this.goTo('/settings/cluster/alertmanagerconfig'); | ||
| await this.createReceiverButton.waitFor({ state: 'visible' }); | ||
| } | ||
|
|
||
| async navigateToYAMLPage(): Promise<void> { | ||
| await this.goTo('/settings/cluster/alertmanageryaml'); | ||
| // Wait for editor toolbar to load (indicates editor is ready) | ||
| await this.page.getByRole('button', { name: 'Copy code to clipboard' }).waitFor(); | ||
| } | ||
|
|
||
| async navigateToEditReceiver(receiverName: string): Promise<void> { | ||
| await this.goTo(`/settings/cluster/alertmanagerconfig/receivers/${receiverName}/edit`); | ||
| await this.saveChangesButton.waitFor({ state: 'visible' }); | ||
| } | ||
|
|
||
| async createReceiver(receiverName: string, receiverTypeConfig: string): Promise<void> { | ||
| await this.robustClick(this.createReceiverButton); | ||
| await this.receiverNameInput.fill(receiverName); | ||
|
|
||
| // Open receiver type dropdown and select | ||
| await this.robustClick(this.receiverTypeDropdown); | ||
| const typeOption = this.page.getByTestId(`receiver-type-${receiverTypeConfig}`); | ||
| await this.robustClick(typeOption); | ||
| } | ||
|
|
||
| async save(): Promise<void> { | ||
| await expect(this.saveChangesButton).toBeEnabled(); | ||
| await this.robustClick(this.saveChangesButton); | ||
| // Wait for the save to complete and redirect back to the receiver list | ||
| await this.createReceiverButton.waitFor({ state: 'visible', timeout: 30_000 }); | ||
| } | ||
|
|
||
| async showAdvancedConfiguration(): Promise<void> { | ||
| const button = this.advancedConfigButton.locator('button'); | ||
| await this.robustClick(button); | ||
| } | ||
|
|
||
| async getYAMLContent(): Promise<string> { | ||
| // Get content from Monaco editor | ||
| const content = await this.page.evaluate(() => { | ||
| const monacoEditor = (window as any).monaco?.editor?.getModels()?.[0]; | ||
| return monacoEditor?.getValue() || ''; | ||
| }); | ||
|
|
||
| return content; | ||
| } | ||
|
|
||
| async setYAMLContent(content: string): Promise<void> { | ||
| await this.page.evaluate((text) => { | ||
| const monacoEditor = (window as any).monaco?.editor?.getModels()?.[0]; | ||
| monacoEditor?.setValue(text); | ||
| }, content); | ||
| } | ||
|
|
||
| async validateReceiverInList(receiverName: string): Promise<void> { | ||
| // Navigate to list page and wait for the receiver to appear. | ||
| // The alertmanager config propagation can take a few seconds after the secret | ||
| // is patched, so retry navigation until the receiver row is visible. | ||
| await expect(async () => { | ||
| await this.navigateToAlertmanager(); | ||
| await expect(this.page.getByRole('row', { name: new RegExp(receiverName) })).toBeVisible({ | ||
| timeout: 5_000, | ||
| }); | ||
| }).toPass({ intervals: [2_000, 3_000, 5_000], timeout: 30_000 }); | ||
|
|
||
| // Check that integration type cell is visible | ||
| const integrationTypeCell = this.page.getByTestId( | ||
| `data-view-cell-${receiverName}-integration-types`, | ||
| ); | ||
| await expect(integrationTypeCell).toBeVisible(); | ||
|
|
||
| // Check that routing labels cell is visible | ||
| const routingLabelsCell = this.page.getByTestId( | ||
| `data-view-cell-${receiverName}-routing-labels`, | ||
| ); | ||
| await expect(routingLabelsCell).toBeVisible(); | ||
| } | ||
| } | ||
|
|
||
| export function getGlobalsAndReceiverConfig( | ||
| receiverName: string, | ||
| configName: string, | ||
| yamlContent: string, | ||
| ): { | ||
| globals: any; | ||
| receiverConfig: any; | ||
| } { | ||
| const parsed = yaml.load(yamlContent); | ||
| const config: AlertmanagerConfig = | ||
| typeof parsed === 'object' && parsed !== null ? (parsed as AlertmanagerConfig) : ({} as AlertmanagerConfig); | ||
| const receiver: AlertmanagerReceiver | undefined = config.receivers?.find( | ||
| (r) => r.name === receiverName, | ||
| ); | ||
|
|
||
| return { | ||
| globals: config.global || {}, | ||
| receiverConfig: receiver?.[configName]?.[0] || {}, | ||
| }; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| import { Page } from '@playwright/test'; | ||
|
|
||
| /** | ||
| * Helper class for navigating using the primary navigation menu | ||
| */ | ||
| export class Navigation { | ||
| constructor(private page: Page) {} | ||
|
|
||
| /** | ||
| * Navigate using the primary nav by expanding a nav section and clicking a link | ||
| * @param section - The nav section to expand (e.g., "Administration", "Workloads") | ||
| * @param link - The link to click within that section (e.g., "CustomResourceDefinitions", "Pods") | ||
| */ | ||
| async navigateViaNav(section: string, link: string): Promise<void> { | ||
| // Navigate to home first to ensure app is loaded | ||
| await this.page.goto('/'); | ||
| const sectionButton = this.page.getByRole('button', { name: section }); | ||
| await sectionButton.waitFor({ state: 'visible' }); | ||
|
|
||
| await sectionButton.click(); | ||
| await this.page.getByRole('link', { name: link }).click(); | ||
|
rhamilto marked this conversation as resolved.
|
||
| await this.page.waitForLoadState('domcontentloaded'); | ||
| } | ||
|
rhamilto marked this conversation as resolved.
|
||
|
|
||
| /** | ||
| * Navigate to CustomResourceDefinitions via Administration nav | ||
| */ | ||
| async navigateToCRDs(): Promise<void> { | ||
| await this.navigateViaNav('Administration', 'CustomResourceDefinitions'); | ||
| } | ||
|
|
||
| /** | ||
| * Navigate to a specific page via Administration nav | ||
| */ | ||
| async navigateToAdministration(link: string): Promise<void> { | ||
| await this.navigateViaNav('Administration', link); | ||
| } | ||
|
|
||
| /** | ||
| * Navigate to a specific page via Workloads nav | ||
| */ | ||
| async navigateToWorkloads(link: string): Promise<void> { | ||
| await this.navigateViaNav('Workloads', link); | ||
| } | ||
|
|
||
| /** | ||
| * Navigate to a specific page via Compute nav | ||
| */ | ||
| async navigateToCompute(link: string): Promise<void> { | ||
| await this.navigateViaNav('Compute', link); | ||
| } | ||
|
|
||
| /** | ||
| * Navigate to a specific page via Storage nav | ||
| */ | ||
| async navigateToStorage(link: string): Promise<void> { | ||
| await this.navigateViaNav('Storage', link); | ||
| } | ||
|
|
||
| /** | ||
| * Navigate to a specific page via User Management nav | ||
| */ | ||
| async navigateToUserManagement(link: string): Promise<void> { | ||
| await this.navigateViaNav('User Management', link); | ||
| } | ||
| } | ||
47 changes: 47 additions & 0 deletions
47
frontend/e2e/tests/console/cluster-settings/alertmanager/alertmanager-test-utils.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| import KubernetesClient from '../../../../clients/kubernetes-client'; | ||
|
|
||
| export const DEFAULT_ALERTMANAGER_YAML = `global: | ||
| resolve_timeout: 5m | ||
| inhibit_rules: | ||
| - equal: | ||
| - namespace | ||
| - alertname | ||
| source_match: | ||
| severity: critical | ||
| target_match_re: | ||
| severity: warning|info | ||
| - equal: | ||
| - namespace | ||
| - alertname | ||
| source_match: | ||
| severity: warning | ||
| target_match_re: | ||
| severity: info | ||
| receivers: | ||
| - name: Default | ||
| - name: Watchdog | ||
| - name: Critical | ||
| route: | ||
| group_by: | ||
| - namespace | ||
| group_interval: 5m | ||
| group_wait: 30s | ||
| receiver: Default | ||
| repeat_interval: 12h | ||
| routes: | ||
| - matchers: | ||
| - alertname = Watchdog | ||
| receiver: Watchdog | ||
| - matchers: | ||
| - severity = critical | ||
| receiver: Critical`; | ||
|
|
||
| export async function resetAlertmanagerConfig(k8sClient: KubernetesClient): Promise<void> { | ||
| await k8sClient.patchSecret('alertmanager-main', 'openshift-monitoring', [ | ||
| { | ||
| op: 'replace', | ||
| path: '/data/alertmanager.yaml', | ||
| value: Buffer.from(DEFAULT_ALERTMANAGER_YAML).toString('base64'), | ||
| }, | ||
| ]); | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.