Files
openobserve/tests/ui-testing/playwright-tests/Logs/logsquickmode.spec.js
T
c99cb0d516 fix(logs): logs finesse phase 1 — severity inference, auto-run, free-text FTS search, J/K, line permalinks (#15234)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Neha P <neha@openobserve.ai>
2026-10-12 16:50:32 +00:00

285 lines
13 KiB
JavaScript

const { test, expect, navigateToBase } = require('../utils/enhanced-baseFixtures.js');
const PageManager = require('../../pages/page-manager.js');
const logData = require("../../fixtures/log.json");
const logsdata = require("../../../test-data/logs_data.json");
const testLogger = require('../utils/test-logger.js');
// Utility Functions
function removeUTFCharacters(text) {
return text.replace(/[^\x00-\x7F]/g, " ");
}
async function applyQueryButton(page) {
testLogger.step('Applying query button');
const pm = new PageManager(page);
await pm.logsPage.runQueryAndWaitForResults();
// Accept any definite post-query state: results table, no-events, or error.
// Tests that require actual rows call waitForSearchResults() in their body.
await pm.logsPage.waitForSearchResultOrEmpty();
testLogger.debug('Query applied and page reached a definite state');
}
test.describe("Logs Quickmode testcases", () => {
test.describe.configure({ mode: 'parallel' });
let pm; // Page Manager instance
test.beforeEach(async ({ page }, testInfo) => {
// Initialize test setup
testLogger.testStart(testInfo.title, testInfo.file);
// Navigate to base URL with authentication
await navigateToBase(page);
pm = new PageManager(page);
// Navigate to logs page
const logsUrl = `${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}`;
testLogger.navigation('Navigating to logs page', { url: logsUrl });
await page.goto(logsUrl);
await page.waitForLoadState('domcontentloaded');
// Simple setup - select stream
try {
await pm.logsPage.selectStream("e2e_automate");
testLogger.info('Stream selected successfully');
} catch (error) {
testLogger.warn('Stream selection failed, continuing test', { error: error.message });
}
// Apply query to load data
await applyQueryButton(page);
// Enable quick mode toggle if it's not already enabled - using page object method
try {
await pm.logsPage.enableQuickModeIfDisabled();
testLogger.info('Quick mode enabled');
} catch (error) {
testLogger.warn('Quick mode toggle failed', { error: error.message });
}
// Click all fields button using page object
try {
await pm.logsPage.clickAllFieldsButton();
testLogger.info('All fields button clicked');
} catch (error) {
testLogger.warn('All fields button click failed', { error: error.message });
}
// Reset SQL mode to OFF so that clickSQLModeToggle reliably turns it ON.
// If a previous test (or localStorage restore) left the editor in SQL mode,
// clickSQLModeToggle would clear the editor instead of building a SELECT query.
try {
await pm.logsPage.disableSqlModeIfNeeded();
testLogger.info('SQL mode reset to OFF');
} catch (error) {
testLogger.warn('SQL mode reset failed, continuing', { error: error.message });
}
testLogger.info('Test setup completed');
});
test.afterEach(async ({ page }) => {
try {
// await pm.commonActions.flipStreaming();
testLogger.info('Streaming flipped after test');
} catch (error) {
testLogger.warn('Streaming flip failed', { error: error.message });
}
});
test("should click on interesting fields icon and display query in editor", {
tag: ['@interestingFieldsLogs', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing interesting fields and query editor');
await pm.logsPage.fillIndexFieldSearchInput("kubernetes_pod_id");
// Use ensureFieldIsInteresting so that if the field is already starred (e.g. from
// localStorage from a previous run) we don't accidentally remove it via toggle.
await pm.logsPage.ensureFieldIsInteresting("kubernetes_pod_id");
await pm.logsPage.clickSQLModeToggle();
await pm.logsPage.waitForQueryEditorTextbox();
await pm.logsPage.expectInterestingFieldInEditor("_timestamp,kubernetes_pod_id");
testLogger.info('Interesting fields and query editor test completed');
});
test("should display quick mode toggle button", {
tag: ['@quickModeLogs', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing quick mode toggle button visibility');
await pm.logsPage.expectQuickModeToggleVisible();
testLogger.info('Quick mode toggle button visible');
});
// Bug #10821 test moved to RegressionSet/logs-regression-bugs.spec.js
test("should click on interesting fields icon in histogram mode and run query", {
tag: ['@interestingFieldsHistogramModeLogs', '@histogram', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing interesting fields in histogram mode');
await pm.logsPage.fillIndexFieldSearchInput("kubernetes_pod_id");
testLogger.info('Validated: field search input filtered to "kubernetes_pod_id"');
await pm.logsPage.ensureFieldIsInteresting("kubernetes_pod_id");
testLogger.info('Validated: "kubernetes_pod_id" marked as an interesting field via sidebar button');
await pm.logsPage.clickSearchBarRefreshButton();
testLogger.info('Validated: search refresh triggered with interesting field selection active');
// Marking a field "interesting" adds it to the query, not as its own table
// column. In the default (non-SQL) view the table renders the FTS body
// column (or the generic "source" column), so assert that results rendered
// rather than a dedicated kubernetes_pod_id column.
await pm.logsPage.expectLogTableColumnSourceVisible();
testLogger.info('Validated: results rendered in histogram mode with interesting field active');
testLogger.info('Interesting fields histogram mode test completed');
});
test("should display error on entering random text in histogram mode when quick mode is on", {
tag: ['@errorHandlingHistogramModeLogs', '@histogram', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing error handling with random text in histogram mode');
// SELECT keeps SQL mode active so the unknown field reaches backend validation.
await pm.logsPage.enableSqlModeIfNeeded();
await pm.logsPage.waitForQueryEditorTextbox();
await pm.logsPage.typeQuery('SELECT oooo FROM "e2e_automate"');
await pm.logsPage.expectQueryEditorContainsText("SELECT oooo");
await pm.logsPage.waitForSearchBarRefreshButton();
await pm.logsPage.clickSearchBarRefreshButton();
// expectErrorMessageVisible auto-waits via expect().toBeVisible()
await pm.logsPage.expectErrorMessageVisible();
testLogger.info('Error handling histogram mode test completed');
});
test("should display selected interestesing field and order by - as default in editor", {
tag: ['@interestingFieldsSqlModeLogs', '@sqlMode', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing interesting fields SQL mode default behavior');
await pm.logsPage.fillIndexFieldSearchInput("kubernetes_pod_id");
await pm.logsPage.ensureFieldIsInteresting("kubernetes_pod_id");
await pm.logsPage.clickSQLModeToggle();
await pm.logsPage.waitForQueryEditorTextbox();
await pm.logsPage.expectQueryEditorVisible();
testLogger.info('Interesting fields SQL mode test completed');
});
test("should adding/removing interesting field removes it from editor and results too", {
tag: ['@interestingFieldsCRUD', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing interesting fields add/remove functionality');
await pm.logsPage.fillIndexFieldSearchInput("kubernetes_container_name");
await pm.logsPage.ensureFieldIsInteresting("kubernetes_container_name");
await pm.logsPage.fillIndexFieldSearchInput("level");
await pm.logsPage.ensureFieldIsInteresting("level");
await pm.logsPage.clickSQLModeToggle();
await pm.logsPage.waitForQueryEditorTextbox();
await pm.logsPage.runQueryAfterModeChange();
// Interesting fields drive the SQL SELECT but are not pinned as table columns,
// so the custom-query view renders the generic "source" column. (Helper is
// mode-aware: passes on source OR any rendered column.)
await pm.logsPage.expectLogTableColumnSourceVisible();
await pm.logsPage.clickInterestingFieldButton("level");
await pm.logsPage.expectQueryEditorNotContainsText("level");
await pm.logsPage.clickSearchBarRefreshButton();
await pm.logsPage.expectLogTableColumnSourceVisible();
// The "source" cell renders the full row JSON; assert its rendered text is not
// the literal header label "source" (i.e. real data is present).
await pm.logsPage.expectLogTableColumnSourceNotHaveText("source");
testLogger.info('Interesting fields add/remove test completed');
});
test("should display order by in sql mode by default even after page reload", {
tag: ['@sqlModeOrderBy', '@sqlMode', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing SQL mode order by persistence after page reload');
await pm.logsPage.fillIndexFieldSearchInput("kubernetes_pod_id");
await pm.logsPage.ensureFieldIsInteresting("kubernetes_pod_id");
await pm.logsPage.clickSQLModeToggle();
await pm.logsPage.clickSearchBarRefreshButton();
await page.waitForURL(
(url) => url.searchParams.get('sql_mode') === 'true' && url.searchParams.has('query'),
{ timeout: 30000 }
);
await pm.logsPage.page.reload();
// Use domcontentloaded, not networkidle: with streaming enabled (cloud/alpha) the
// long-lived SSE/search connections keep the network busy, so networkidle never
// settles and times out. expectQueryEditorContainsText below already waits for the
// Monaco editor to mount and hydrate its model value, so it is the real readiness gate.
await pm.logsPage.page.waitForLoadState('domcontentloaded');
await pm.logsPage.expectQueryEditorContainsText('SELECT _timestamp,kubernetes_pod_id FROM "e2e_automate"');
testLogger.info('SQL mode order by persistence test completed');
});
test("should display results without adding timestamp in quick mode", {
tag: ['@quickModeResults', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing quick mode results without timestamp');
await pm.logsPage.fillIndexFieldSearchInput("kubernetes_pod_id");
testLogger.info('Validated: field search input filtered to "kubernetes_pod_id"');
await pm.logsPage.ensureFieldIsInteresting("kubernetes_pod_id");
testLogger.info('Validated: "kubernetes_pod_id" marked as an interesting field');
await pm.logsPage.clickSQLModeToggle();
testLogger.info('Validated: switched to SQL mode');
await pm.logsPage.waitForQueryEditorTextbox();
await pm.logsPage.runQueryAfterModeChange();
// The interesting field drives the SQL SELECT but is not pinned as a column,
// so the custom-query view renders the generic "source" column. (Helper is
// mode-aware: passes on source OR any rendered column.)
await pm.logsPage.expectLogTableColumnSourceVisible();
testLogger.info('Validated: results rendered — query ran without auto-injecting _timestamp in quick mode');
testLogger.info('Quick mode results test completed');
});
test("should click timestamp field and then search for kubernetes_pod_id field", {
tag: ['@fieldInteraction', '@all', '@logs']
}, async ({ page }) => {
testLogger.info('Testing timestamp field click and kubernetes_pod_id field search');
// Check if _timestamp field exists and click it
await pm.logsPage.clickTimestampField();
testLogger.info('Validated: "_timestamp" field found in field list and clicked');
// Click on schema button
await pm.logsPage.clickSchemaButton();
testLogger.info('Validated: schema panel opened');
// Search and click kubernetes_pod_id field
await pm.logsPage.fillIndexFieldSearchInput("kubernetes_pod_id");
testLogger.info('Validated: field search input filtered to "kubernetes_pod_id"');
await pm.logsPage.ensureFieldIsInteresting("kubernetes_pod_id");
testLogger.info('Validated: "kubernetes_pod_id" marked as an interesting field');
// Click on infoschema button
await pm.logsPage.clickInfoSchemaButton();
testLogger.info('Validated: info-schema panel opened');
// Click Clear button
await pm.logsPage.clickClearButton();
testLogger.info('Validated: clear button clicked — field selections cleared');
// Remove kubernetes_pod_id as interesting field
await pm.logsPage.clickInterestingFieldButton("kubernetes_pod_id");
testLogger.info('Validated: "kubernetes_pod_id" removed as an interesting field');
// Assert that _timestamp still exists
await pm.logsPage.expectTimestampFieldVisible();
testLogger.info('Validated: "_timestamp" field is still visible after clearing kubernetes_pod_id — field persistence confirmed');
testLogger.info('Timestamp field click and kubernetes_pod_id field search completed');
});
});