import { Locator, Page, expect } from '@playwright/test'; import { selectDropdownValue, selectValuePickerValue } from './forms'; import { goToOnCallPage } from './navigation'; const MAX_RETRIES = 5; const ALERT_GROUP_REGISTERED_TEXT = 'alert group registered'; const getIncidentTimelineList = async (page: Page): Promise => { const incidentTimelineList = page.getByTestId('incident-timeline-list'); await incidentTimelineList.waitFor({ state: 'visible' }); return incidentTimelineList; }; /** * recursively refreshes the page waiting for the background celery workers to have done their job of * escalating the alert group */ const incidentTimelineContainsStep = async (page: Page, triggeredStepText: string, retryNum = 0): Promise => { if (retryNum > MAX_RETRIES) { return Promise.resolve(false); } const incidentTimelineList = await getIncidentTimelineList(page); if (!incidentTimelineList.getByText(triggeredStepText)) { await page.reload({ waitUntil: 'networkidle' }); return incidentTimelineContainsStep(page, triggeredStepText, (retryNum += 1)); } return true; }; /** * recursively refreshes the page waiting for the background celery workers to have done their job of * creating the alert group */ export const filterAlertGroupsTableByIntegrationAndGoToDetailPage = async ( page: Page, integrationName: string, retryNum = 0 ): Promise => { if (retryNum > MAX_RETRIES) { throw new Error('we were not able to properly filter the alert groups table by integration'); } await goToOnCallPage(page, 'alert-groups'); // filter by integration const selectElement = await selectDropdownValue({ page, selectType: 'grafanaSelect', placeholderText: 'Filter results...', value: 'Integration', }); await selectElement.type(integrationName); await selectValuePickerValue(page, integrationName, false); try { /** * wait for up to 2 seconds for the alert groups to be filtered, if the first row does not correspond * to `integrationName` assume that the background workers have not created it yet and lets * recursively retry this function */ await page.waitForTimeout(2000); expect(await page.locator('table > tbody > tr [data-testid=integration-name]').textContent()).toBe(integrationName); await page.locator('table > tbody > tr [data-testid=integration-url]').click(); } catch (err) { return filterAlertGroupsTableByIntegrationAndGoToDetailPage(page, integrationName, (retryNum += 1)); } }; export const verifyThatAlertGroupIsRoutedCorrectlyButNotEscalated = async ( page: Page, integrationName: string, routedText: string ): Promise => { await filterAlertGroupsTableByIntegrationAndGoToDetailPage(page, integrationName); /** * incidentTimelineContainsStep recursively reloads the alert group page until the engine * background workers have processed/escalated the alert group */ expect(await incidentTimelineContainsStep(page, ALERT_GROUP_REGISTERED_TEXT)).toBe(true); const incidentTimelineList = await getIncidentTimelineList(page); expect(incidentTimelineList).toContainText(routedText); expect(incidentTimelineList).not.toContainText('triggered step'); }; export const verifyThatAlertGroupIsTriggered = async ( page: Page, integrationName: string, triggeredStepText: string ): Promise => { await filterAlertGroupsTableByIntegrationAndGoToDetailPage(page, integrationName); expect(await incidentTimelineContainsStep(page, triggeredStepText)).toBe(true); }; export const resolveFiringAlert = async (page: Page) => { await goToOnCallPage(page, 'alert-groups'); await page.getByText('Firing').nth(2).click({force: true}); await page.getByLabel('Context menu').getByText('Resolve').click(); };