mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-04 08:09:27 +00:00
Co-authored-by: Shrinath-O2 <214651540+Shrinath-O2@users.noreply.github.com>
This commit is contained in:
co-authored by
Shrinath-O2
parent
cd0eff459d
commit
71f6702dee
@@ -280,7 +280,7 @@ export class PipelinesPage {
|
||||
this.addConditionDeleteBtn = page.locator('[data-test="add-condition-drawer"] [data-test="o-drawer-neutral-btn"]');
|
||||
this.scheduledAlertTabs = page.locator('[data-test="scheduled-alert-tabs"]');
|
||||
this.nestedGroups = page.locator('.el-border');
|
||||
this.operatorLabels = page.locator('span.tw\\:lowercase');
|
||||
this.operatorLabels = page.locator('[data-test="alert-conditions-operator-label"]');
|
||||
this.firstConditionLabel = page.locator('[data-test="add-condition-section"]').getByText('if', { exact: true }).first();
|
||||
this.noteContainer = page.locator('[data-test="add-condition-note-container"]');
|
||||
this.noteHeading = page.locator('[data-test="add-condition-note-heading"]');
|
||||
@@ -1625,6 +1625,30 @@ export class PipelinesPage {
|
||||
await this.page.waitForTimeout(300);
|
||||
}
|
||||
|
||||
async fillUnaryCondition(columnName, operator, index = 0) {
|
||||
// Select the column (mirror fillCondition's column step) then the unary
|
||||
// operator. Unary operators (is_null / is_not_null / is_empty /
|
||||
// is_not_empty) render no value input, so never fill a value here.
|
||||
const triggers = this.columnSelectTrigger;
|
||||
const wrappers = this.columnSelect;
|
||||
const trigCount = await triggers.count();
|
||||
if (trigCount > 0) {
|
||||
await triggers.nth(index).click();
|
||||
} else {
|
||||
await wrappers.nth(index).click();
|
||||
}
|
||||
await this.columnSelectPopover.first().waitFor({ state: 'visible', timeout: 5000 }).catch(() => {});
|
||||
const searchCount = await this.columnSelectSearch.count();
|
||||
if (searchCount > 0) {
|
||||
await this.columnSelectSearch.first().fill(columnName);
|
||||
}
|
||||
await this.columnOptionByName(columnName).waitFor({ state: 'visible', timeout: 10000 });
|
||||
await this.columnOptionByName(columnName).click();
|
||||
await this.page.waitForTimeout(300);
|
||||
|
||||
await this.selectOperatorFromMenu(operator);
|
||||
}
|
||||
|
||||
async addNewCondition() {
|
||||
await this.addConditionButton.first().click();
|
||||
await this.page.waitForTimeout(500);
|
||||
@@ -1921,6 +1945,44 @@ export class PipelinesPage {
|
||||
await this.conditionRequiredToast.first().waitFor({ state: 'visible', timeout: 10000 });
|
||||
}
|
||||
|
||||
async verifyNoConditionError() {
|
||||
// A successful save surfaces no inline schema error. Used to prove a
|
||||
// unary condition (value-exempt) saved without the "fill all fields" error.
|
||||
await expect(this.conditionRequiredToast).toHaveCount(0);
|
||||
}
|
||||
|
||||
async verifyValueInputCount(expectedCount) {
|
||||
// Count value inputs (v-if-removed for unary operators, present for binary).
|
||||
await expect(this.valueInput).toHaveCount(expectedCount);
|
||||
}
|
||||
|
||||
async verifyOperatorSelected(operator, index = 0) {
|
||||
// The operator OFormSelect renders in reka-Select mode (non-listbox), so
|
||||
// its trigger carries no `data-test-selected-value`; it shows the selected
|
||||
// label as text. Unary operators map wire value -> display label.
|
||||
const labelByOperator = {
|
||||
is_null: 'Is Null',
|
||||
is_not_null: 'Is Not Null',
|
||||
is_empty: 'Is Empty',
|
||||
is_not_empty: 'Is Not Empty',
|
||||
};
|
||||
const expectedLabel = labelByOperator[operator] ?? operator;
|
||||
await expect(this.operatorSelectTrigger.nth(index)).toContainText(expectedLabel);
|
||||
}
|
||||
|
||||
async verifyUnaryOperatorsOffered() {
|
||||
// Open the operator menu and assert each unary option is offered by its
|
||||
// snake_case `data-test-value` (the OSelect option value, not the label).
|
||||
await this.operatorSelectTrigger.first().waitFor({ state: 'visible', timeout: 15000 });
|
||||
await this.operatorSelectTrigger.first().click();
|
||||
for (const operator of ["is_null", "is_not_null", "is_empty", "is_not_empty"]) {
|
||||
const option = this.page.locator(
|
||||
`[data-test="alert-conditions-operator-select-option"][data-test-value="${operator}"]`,
|
||||
).first();
|
||||
await expect(option).toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
async fillPartialCondition(columnName) {
|
||||
// OSelect: click trigger to open, then type in the search input
|
||||
await this.columnSelectTrigger.first().click();
|
||||
|
||||
@@ -274,6 +274,10 @@ test.describe("Pipeline Conditions - Comprehensive Tests", () => {
|
||||
await page.waitForTimeout(300);
|
||||
await pageManager.pipelinesPage.fillCondition("kubernetes_host", "=", "value-B", 1);
|
||||
|
||||
// Guard: the OR toggle took effect on condition B's join before we rely on
|
||||
// the A OR B combination below.
|
||||
await pageManager.pipelinesPage.verifyOperatorLabel("OR", 0);
|
||||
|
||||
// Condition C with AND (default)
|
||||
await pageManager.pipelinesPage.addNewCondition();
|
||||
await pageManager.pipelinesPage.fillCondition("kubernetes_pod_name", "=", "value-C", 2);
|
||||
@@ -281,11 +285,10 @@ test.describe("Pipeline Conditions - Comprehensive Tests", () => {
|
||||
// Verify 3 conditions exist
|
||||
await pageManager.pipelinesPage.verifyConditionCount(3);
|
||||
|
||||
// Verify operators are set correctly
|
||||
const operatorLabels = pageManager.pipelinesPage.operatorLabels;
|
||||
if (await operatorLabels.count() >= 2) {
|
||||
await pageManager.pipelinesPage.verifyOperatorLabel("OR", 0);
|
||||
}
|
||||
// Verify BOTH join operators unconditionally: A OR B AND C. The first join
|
||||
// (B) is OR, the second (C) is AND — no `count() >= 2` guard, both must hold.
|
||||
await pageManager.pipelinesPage.verifyOperatorLabel("OR", 0);
|
||||
await pageManager.pipelinesPage.verifyOperatorLabel("AND", 1);
|
||||
|
||||
await pageManager.pipelinesPage.saveConditionAndCompletePipeline(pipelineName);
|
||||
|
||||
@@ -389,12 +392,23 @@ test.describe("Pipeline Conditions - Comprehensive Tests", () => {
|
||||
await pageManager.pipelinesPage.addNewCondition();
|
||||
await pageManager.pipelinesPage.fillCondition("kubernetes_host", "!=", "excluded", 1);
|
||||
|
||||
// Add Contains operator condition
|
||||
await pageManager.pipelinesPage.addNewCondition();
|
||||
await pageManager.pipelinesPage.fillCondition("kubernetes_pod_name", "Contains", "include", 2);
|
||||
|
||||
// Add NotContains operator condition
|
||||
await pageManager.pipelinesPage.addNewCondition();
|
||||
await pageManager.pipelinesPage.fillCondition("kubernetes_pod_name", "NotContains", "ignore", 2);
|
||||
await pageManager.pipelinesPage.fillCondition("kubernetes_namespace_name", "NotContains", "ignore", 3);
|
||||
|
||||
// Verify all 3 conditions exist
|
||||
await pageManager.pipelinesPage.verifyConditionCount(3);
|
||||
// Verify all 4 conditions exist
|
||||
await pageManager.pipelinesPage.verifyConditionCount(4);
|
||||
|
||||
// Assert each row's operator actually took effect — the count alone would
|
||||
// let a wrong/failed operator selection pass.
|
||||
await pageManager.pipelinesPage.verifyOperatorSelected(">=", 0);
|
||||
await pageManager.pipelinesPage.verifyOperatorSelected("!=", 1);
|
||||
await pageManager.pipelinesPage.verifyOperatorSelected("Contains", 2);
|
||||
await pageManager.pipelinesPage.verifyOperatorSelected("NotContains", 3);
|
||||
|
||||
await pageManager.pipelinesPage.saveConditionAndCompletePipeline(pipelineName);
|
||||
|
||||
@@ -403,4 +417,103 @@ test.describe("Pipeline Conditions - Comprehensive Tests", () => {
|
||||
await pageManager.pipelinesPage.openPipelineMenu();
|
||||
await pageManager.pipelinesPage.deletePipelineByName(pipelineName);
|
||||
});
|
||||
|
||||
test("should hide the value input for a unary is_null operator and save without error", {
|
||||
tag: ['@all', '@pipelines', '@pipelinesConditions', '@condition-null-empty-operators']
|
||||
}, async ({ page }) => {
|
||||
await pageManager.pipelinesPage.createPipelineWithCondition(`e2e_conditions_operators${streamSuffix}`);
|
||||
await pageManager.pipelinesPage.verifyConditionDialogOpen();
|
||||
|
||||
// Select column + unary operator (no value input for unary operators).
|
||||
await pageManager.pipelinesPage.fillUnaryCondition("kubernetes_container_name", "is_null", 0);
|
||||
|
||||
// The value input is v-if-removed for a unary operator.
|
||||
await pageManager.pipelinesPage.verifyValueInputCount(0);
|
||||
|
||||
// Saving a unary condition is complete without a value: no inline error and
|
||||
// the drawer closes (the condition node appears on the canvas).
|
||||
await pageManager.pipelinesPage.saveCondition();
|
||||
await pageManager.pipelinesPage.verifyNoConditionError();
|
||||
await pageManager.pipelinesPage.verifyConditionDialogClosed();
|
||||
});
|
||||
|
||||
test("should round-trip a saved unary operator on edit and restore the value input for a binary operator", {
|
||||
tag: ['@all', '@pipelines', '@pipelinesConditions', '@condition-null-empty-operators']
|
||||
}, async ({ page }) => {
|
||||
const pipelineName = `pipeline-null-empty-roundtrip-${Math.random().toString(36).substring(7)}`;
|
||||
currentPipelineName = pipelineName;
|
||||
|
||||
await pageManager.pipelinesPage.createPipelineWithCondition(`e2e_conditions_operators${streamSuffix}`);
|
||||
await pageManager.pipelinesPage.fillUnaryCondition("kubernetes_container_name", "is_null", 0);
|
||||
await pageManager.pipelinesPage.verifyValueInputCount(0);
|
||||
await pageManager.pipelinesPage.saveConditionAndCompletePipeline(pipelineName);
|
||||
|
||||
// Reopen the saved pipeline and edit its condition node.
|
||||
await pageManager.pipelinesPage.openPipelineMenu();
|
||||
await page.waitForTimeout(1000);
|
||||
await pageManager.pipelinesPage.openPipelineForEdit(pipelineName);
|
||||
await pageManager.pipelinesPage.clickConditionNode();
|
||||
await pageManager.pipelinesPage.verifyConditionDialogOpen();
|
||||
|
||||
// The unary operator round-trips and the value input stays hidden on load.
|
||||
await pageManager.pipelinesPage.verifyOperatorSelected("is_null", 0);
|
||||
await pageManager.pipelinesPage.verifyValueInputCount(0);
|
||||
|
||||
// Switching to a binary operator restores the value input for that row.
|
||||
await pageManager.pipelinesPage.selectOperatorFromMenu("=");
|
||||
await pageManager.pipelinesPage.verifyValueInputCount(1);
|
||||
|
||||
// Cleanup
|
||||
await pageManager.pipelinesPage.openPipelineMenu();
|
||||
await page.waitForTimeout(1000);
|
||||
await pageManager.pipelinesPage.deletePipelineByName(pipelineName);
|
||||
});
|
||||
|
||||
test("should offer all four unary operators in the condition operator dropdown", {
|
||||
tag: ['@all', '@pipelines', '@pipelinesConditions', '@condition-null-empty-operators']
|
||||
}, async ({ page }) => {
|
||||
await pageManager.pipelinesPage.createPipelineWithCondition(`e2e_conditions_operators${streamSuffix}`);
|
||||
await pageManager.pipelinesPage.verifyConditionDialogOpen();
|
||||
|
||||
// Select a column so the operator menu is in its interactive state.
|
||||
await pageManager.pipelinesPage.fillPartialCondition("kubernetes_container_name");
|
||||
|
||||
// All four unary operators are offered.
|
||||
await pageManager.pipelinesPage.verifyUnaryOperatorsOffered();
|
||||
});
|
||||
|
||||
test("should still require a value for a binary operator after unary operators are added", {
|
||||
tag: ['@all', '@pipelines', '@pipelinesConditions', '@pipelinesValidation', '@condition-null-empty-operators']
|
||||
}, async ({ page }) => {
|
||||
await pageManager.pipelinesPage.createPipelineWithCondition(`e2e_conditions_operators${streamSuffix}`);
|
||||
await pageManager.pipelinesPage.fillPartialCondition("kubernetes_container_name");
|
||||
await pageManager.pipelinesPage.selectOperatorFromMenu("=");
|
||||
|
||||
// Guard: the binary operator actually took effect before asserting its error.
|
||||
await pageManager.pipelinesPage.verifyOperatorSelected("=", 0);
|
||||
|
||||
// A binary operator still requires a value: saving with an empty value
|
||||
// surfaces the inline schema error (unary exemption did not weaken this).
|
||||
await pageManager.pipelinesPage.tryToSaveWithoutValidConditions();
|
||||
await pageManager.pipelinesPage.verifyNotificationVisible();
|
||||
});
|
||||
|
||||
test("should clear a previously entered value when switching to a unary operator", {
|
||||
tag: ['@all', '@pipelines', '@pipelinesConditions', '@condition-null-empty-operators']
|
||||
}, async ({ page }) => {
|
||||
await pageManager.pipelinesPage.createPipelineWithCondition(`e2e_conditions_operators${streamSuffix}`);
|
||||
|
||||
// Enter a binary condition with a stale value.
|
||||
await pageManager.pipelinesPage.fillCondition("kubernetes_container_name", "=", "stale-value", 0);
|
||||
|
||||
// Switching to a unary operator drops the stale value and hides the input.
|
||||
await pageManager.pipelinesPage.selectOperatorFromMenu("is_null");
|
||||
await pageManager.pipelinesPage.verifyValueInputCount(0);
|
||||
|
||||
// Switching back to a binary operator restores the input, now empty —
|
||||
// proving the stale value did not leak into the form.
|
||||
await pageManager.pipelinesPage.selectOperatorFromMenu("=");
|
||||
await pageManager.pipelinesPage.verifyValueInputCount(1);
|
||||
await pageManager.pipelinesPage.verifyConditionValueInputValue("", 0);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user