test: fix flaky Alerts OSelect dropdowns (click trigger, not root div) (#12869)

## Problem

The scheduled **main** Playwright Regression run failed in the
**Alerts-Regression** shard ([run
28097849118](https://github.com/openobserve/openobserve/actions/runs/28097849118/job/83192928864))
with 2 tests failing on the **same** locator `[data-test$="-popover"]
[data-test$="-option"]` (dropdown options never found):

- `alerts-bugs.spec.js` › "Template should not appear twice in override
template input" (`@bug-10110`)
- `alerts-regression.spec.js` › "Bug #9967: PromQL alert creation"
(`@bug-9967`)

## Root cause

The alert form selects were migrated to the **OSelect** (reka-ui
popover) component. OSelect forwards the consumer's `data-test` onto an
**inner `<button data-test="...-trigger">`**, while the root element is
a plain `<div>`. Both tests clicked the **root `<div>`**, which does
**not** toggle the reka popover — `aria-expanded` stays `false`, the
popover never opens, and the option locator times out.

This is not caused by #12855; it reproduces on an older build too. The
codebase already had the correct pattern elsewhere (group-by select
clicks `[data-test$="-trigger"]`).

## Fix

- New shared helper `openOSelectDropdown(page, rootLocator)`
(`tests/ui-testing/pages/alertsPages/oselectHelpers.js`) that clicks the
inner `-trigger` and **retries until `aria-expanded="true"`** — the reka
trigger can open-then-close on a single Playwright click.
- `alertsPage.openAdvancedTemplateOverrideSelect()` uses the helper; the
spec now calls that page-object method (no raw locator in the spec).
- Routed **all 8** destination-dropdown open sites in
`alertCreationWizard.js` through the same helper (DRY; the same latent
bug affected every one).

## Validation (local, against running o2)

| Spec | Result |
|------|--------|
| `alerts-bugs.spec.js` | **4 passed** |
| `alerts-regression.spec.js` | **5 passed** (incl. Bug #9967 PromQL) |

Both originally-failing tests are green; no regressions across the
changed destination sites. Passed a Sentinel code-quality review (0
critical).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Shrinath Rao 2026-06-24 20:06:41 +05:30 committed by GitHub
parent b0f4b0e46f
commit 0afbe40fe4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 45 additions and 10 deletions

View File

@ -10,6 +10,7 @@
import { expect } from '@playwright/test';
import testLogger from '../../playwright-tests/utils/test-logger.js';
import { openOSelectDropdown } from './oselectHelpers.js';
export class AlertCreationWizard {
constructor(page, commonActions, locators) {
@ -153,7 +154,7 @@ export class AlertCreationWizard {
// Destination selection with fallback
const destinationDropdown = this.page.locator('[data-test="alert-destinations-select"]');
await destinationDropdown.waitFor({ state: 'visible', timeout: 10000 });
await destinationDropdown.click();
await openOSelectDropdown(this.page, destinationDropdown);
await this.page.waitForTimeout(1000);
// Destination dropdown is OSelect (Reka Listbox) post-migration.
@ -265,7 +266,7 @@ export class AlertCreationWizard {
// Destination selection with fallback
const destinationSection = this.page.locator('[data-test="alert-destinations-select"]');
await destinationSection.waitFor({ state: 'visible', timeout: 10000 });
await destinationSection.click();
await openOSelectDropdown(this.page, destinationSection);
await this.page.waitForTimeout(1000);
const visibleDestMenuDefItems = this.page.locator('[data-test$="-popover"] [data-test$="-option"]');
@ -449,7 +450,7 @@ export class AlertCreationWizard {
// Destination selection using v3 data-test locator
const destinationDropdown = this.page.locator('[data-test="alert-destinations-select"]');
await destinationDropdown.waitFor({ state: 'visible', timeout: 5000 });
await destinationDropdown.click();
await openOSelectDropdown(this.page, destinationDropdown);
await this.page.waitForTimeout(1000);
const visibleDestMenuSqlItems = this.page.locator('[data-test$="-popover"] [data-test$="-option"]');
@ -619,7 +620,7 @@ export class AlertCreationWizard {
// Select destination for REAL-TIME alerts
const destinationDropdown = this.page.locator('[data-test="alert-destinations-select"]');
await destinationDropdown.waitFor({ state: 'visible', timeout: 10000 });
await destinationDropdown.click();
await openOSelectDropdown(this.page, destinationDropdown);
await this.page.waitForTimeout(1000);
// Use popover selector for destination
@ -804,7 +805,7 @@ export class AlertCreationWizard {
const destinationDropdown = this.page.locator('[data-test="alert-destinations-select"]');
await destinationDropdown.waitFor({ state: 'visible', timeout: 5000 });
await destinationDropdown.click();
await openOSelectDropdown(this.page, destinationDropdown);
await this.page.waitForTimeout(1000);
// Use popover selector for destination
@ -1294,7 +1295,7 @@ export class AlertCreationWizard {
const destinationDropdown = this.page.locator('[data-test="alert-destinations-select"]');
await destinationDropdown.waitFor({ state: 'visible', timeout: 10000 });
await destinationDropdown.click();
await openOSelectDropdown(this.page, destinationDropdown);
await this.page.waitForTimeout(1000);
// Use popover selector for destination
@ -1547,7 +1548,7 @@ export class AlertCreationWizard {
// Destination (v3 uses data-test locator)
const destinationDropdown = this.page.locator('[data-test="alert-destinations-select"]');
await destinationDropdown.waitFor({ state: 'visible', timeout: 5000 });
await destinationDropdown.click();
await openOSelectDropdown(this.page, destinationDropdown);
await this.page.waitForTimeout(1000);
const visibleDestMenuAggItems = this.page.locator('[data-test$="-popover"] [data-test$="-option"]');
@ -1747,7 +1748,7 @@ export class AlertCreationWizard {
// Select destination (v3 uses data-test locator)
const destinationDropdown = this.page.locator('[data-test="alert-destinations-select"]');
await destinationDropdown.waitFor({ state: 'visible', timeout: 5000 });
await destinationDropdown.click();
await openOSelectDropdown(this.page, destinationDropdown);
await this.page.waitForTimeout(1000);
const visibleDestMenuPromqlItems = this.page.locator('[data-test$="-popover"] [data-test$="-option"]');

View File

@ -18,6 +18,7 @@ import { expect } from '@playwright/test';
import fs from 'fs';
import { CommonActions } from '../commonActions';
import { AlertCreationWizard } from './alertCreationWizard.js';
import { openOSelectDropdown } from './oselectHelpers.js';
import { AlertManagement } from './alertManagement.js';
import { AlertBulkOperations } from './alertBulkOperations.js';
const testLogger = require('../../playwright-tests/utils/test-logger.js');
@ -836,6 +837,13 @@ export class AlertsPage {
return this.page.locator(this.locators.advancedTemplateOverrideSelect).first();
}
/**
* Open the Advanced-tab template override OSelect dropdown.
*/
async openAdvancedTemplateOverrideSelect() {
await openOSelectDropdown(this.page, this.getAdvancedTemplateOverrideSelect());
}
// ==================== FOLDER OPERATIONS ====================
generateRandomString() {

View File

@ -0,0 +1,26 @@
/**
* Helpers for interacting with the OSelect (reka-ui popover) component used
* across the alert forms.
*/
/**
* Reliably open an OSelect dropdown given its root locator.
*
* OSelect forwards the consumer's `data-test` onto an inner `<button>`-trigger;
* clicking the root wrapper does NOT toggle the reka-ui popover. The trigger can
* also open-then-close on a single Playwright click, so we click until the
* popover reports open (`aria-expanded="true"`).
*
* @param {import('@playwright/test').Page} page
* @param {import('@playwright/test').Locator} rootLocator OSelect root, e.g. [data-test="...-select"]
* @param {{ retries?: number, settleMs?: number }} [options]
*/
export async function openOSelectDropdown(page, rootLocator, { retries = 5, settleMs = 400 } = {}) {
const trigger = rootLocator.locator('[data-test$="-trigger"]').first();
await trigger.waitFor({ state: 'visible', timeout: 5000 });
for (let i = 0; i < retries; i++) {
if ((await trigger.getAttribute('aria-expanded')) === 'true') return;
await trigger.click();
await page.waitForTimeout(settleMs);
}
}

View File

@ -216,8 +216,8 @@ test.describe("Alerts Regression Bugs — Batch 1", () => {
await expect(templateOverrideSelect, 'Template override select should be visible').toBeVisible({ timeout: 3000 });
testLogger.info('✓ Template override field found');
// Open the select dropdown and pick a template
await templateOverrideSelect.click();
// Open the select dropdown and pick a template (page object clicks the OSelect trigger).
await pm.alertsPage.openAdvancedTemplateOverrideSelect();
await page.waitForTimeout(500);
const templateOption = pm.alertsPage.getFirstMenuItem();