mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-04 00:08:55 +00:00
255 lines
9.4 KiB
JavaScript
255 lines
9.4 KiB
JavaScript
// traceQueryEditor.spec.js
|
|
// Tests for OpenObserve Traces feature - Query Editor and filtering functionality
|
|
// Following the modular pattern from Logs tests
|
|
|
|
const { test, expect, navigateToBase } = require('../utils/enhanced-baseFixtures.js');
|
|
const testLogger = require('../utils/test-logger.js');
|
|
const PageManager = require('../../pages/page-manager.js');
|
|
|
|
test.describe("Trace Query Editor testcases", () => {
|
|
test.describe.configure({ mode: 'serial' });
|
|
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);
|
|
|
|
// Post-authentication stabilization wait
|
|
await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {});
|
|
|
|
// Navigate to traces page
|
|
await pm.tracesPage.navigateToTraces();
|
|
|
|
// Select the default stream as data is ingested for it only
|
|
await pm.tracesPage.isStreamSelectVisible()
|
|
await pm.tracesPage.selectTraceStream('default');
|
|
await page.waitForTimeout(2000);
|
|
|
|
|
|
testLogger.info('Test setup completed for trace query editor');
|
|
});
|
|
|
|
test.afterEach(async ({ }, testInfo) => {
|
|
testLogger.testEnd(testInfo.title, testInfo.status);
|
|
});
|
|
|
|
// P0 - Critical Path Tests
|
|
test("P0: Use query editor to run basic trace search", {
|
|
tag: ['@traceQueryEditor', '@traces', '@query', '@smoke', '@P0', '@all']
|
|
}, async ({ page }) => {
|
|
testLogger.info('Testing query editor for basic trace search');
|
|
|
|
// Enter search query
|
|
await pm.tracesPage.enterTraceQuery("service_name='api-gateway'");
|
|
|
|
// Verify query appears in editor using page object
|
|
const editorContent = await pm.tracesPage.getQueryEditorContent();
|
|
expect(editorContent).toContain("service_name='api-gateway'");
|
|
testLogger.info('Query entered successfully in editor');
|
|
|
|
// Set time range and run search
|
|
await pm.tracesPage.setTimeRange('15m');
|
|
await pm.tracesPage.runSearch();
|
|
|
|
// Wait for search to complete with retry logic
|
|
let searchCompleted = false;
|
|
for (let i = 0; i < 3; i++) {
|
|
await page.waitForTimeout(2000);
|
|
const hasResults = await pm.tracesPage.hasTraceResults();
|
|
const hasNoResults = await pm.tracesPage.isNoResultsVisible();
|
|
|
|
if (hasResults || hasNoResults) {
|
|
searchCompleted = true;
|
|
testLogger.info(`Search completed on attempt ${i + 1}: Results=${hasResults}, NoResults=${hasNoResults}`);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Verify search completed
|
|
expect(searchCompleted).toBeTruthy();
|
|
|
|
// If results exist, verify they match the filter using page object
|
|
if (await pm.tracesPage.hasTraceResults()) {
|
|
const serviceNameVisible = await pm.tracesPage.isTextVisibleInResults('api-gateway');
|
|
if (serviceNameVisible) {
|
|
testLogger.info('Results correctly filtered by service name');
|
|
}
|
|
}
|
|
|
|
testLogger.info('Basic trace search completed successfully');
|
|
});
|
|
|
|
// P1 - Core Functionality Tests
|
|
test("P1: Filter traces by expanding and selecting field values", {
|
|
tag: ['@traceQueryEditor', '@traces', '@query', '@functional', '@P1', '@all']
|
|
}, async ({ page }) => {
|
|
testLogger.info('Testing field expansion and filtering by clicking field values');
|
|
|
|
// Initial setup and search
|
|
await pm.tracesPage.setupTraceSearch();
|
|
|
|
// Expand status_code field
|
|
const expanded = await pm.tracesPage.expandTraceField('status_code');
|
|
|
|
if (expanded) {
|
|
// Select status_code='2' value
|
|
const selected = await pm.tracesPage.selectFieldValue('status_code', '2');
|
|
|
|
if (selected) {
|
|
// Verify filter appears in query editor using page object
|
|
const editorContent = await pm.tracesPage.getQueryEditorContent();
|
|
|
|
if (editorContent.includes('status_code=')) {
|
|
testLogger.info('Status code filter successfully applied');
|
|
}
|
|
|
|
// Run query with filter
|
|
await pm.tracesPage.runSearch();
|
|
await page.waitForTimeout(2000);
|
|
|
|
// Verify query was applied
|
|
expect(editorContent.includes('status_code') || selected).toBeTruthy();
|
|
} else {
|
|
testLogger.info('Could not select status_code value - field may not have value 2');
|
|
// Verify expansion worked
|
|
expect(expanded).toBeTruthy();
|
|
}
|
|
} else {
|
|
// Try alternative field - service_name
|
|
const serviceExpanded = await pm.tracesPage.expandTraceField('service_name');
|
|
|
|
if (serviceExpanded) {
|
|
await pm.tracesPage.selectFieldValue('service_name', 'api-gateway');
|
|
await pm.tracesPage.runSearch();
|
|
await page.waitForTimeout(2000);
|
|
expect(serviceExpanded).toBeTruthy();
|
|
} else {
|
|
// Verify search still works
|
|
const hasResults = await pm.tracesPage.hasTraceResults();
|
|
const noResults = await pm.tracesPage.isNoResultsVisible();
|
|
expect(hasResults || noResults).toBeTruthy();
|
|
}
|
|
}
|
|
});
|
|
|
|
// NOTE: "P1: Click on trace result to view span details" test removed per Rule 4 (No duplicates)
|
|
// This functionality is already covered by:
|
|
// - "P0: View trace details from search results" in tracesSearch.spec.js
|
|
// - "P1: Verify trace span attributes and values" test below
|
|
// - Multiple tests in traceDetails.spec.js
|
|
|
|
// NOTE: "P1: Filter traces by service name from span details" test removed per Rule 4 (No duplicates)
|
|
// This functionality is already covered by:
|
|
// - traceDetails.spec.js tests which verify trace detail interactions
|
|
// - The trace details navigation is validated in other passing tests
|
|
|
|
// P2 - Edge Cases
|
|
test("P2: View error spans and their details", {
|
|
tag: ['@traceQueryEditor', '@traces', '@query', '@edge', '@P2', '@all']
|
|
}, async ({ page }) => {
|
|
testLogger.info('Testing error span viewing');
|
|
|
|
// Setup and run initial search
|
|
await pm.tracesPage.setupTraceSearch();
|
|
|
|
// Look for traces with errors using page object
|
|
const hasErrorTraces = await pm.tracesPage.hasErrorTracesWithPattern();
|
|
if (hasErrorTraces) {
|
|
await pm.tracesPage.clickFirstErrorTrace();
|
|
testLogger.info('Clicked on trace with errors');
|
|
|
|
await page.waitForTimeout(2000);
|
|
|
|
// Look for ERROR status in the span details using page object
|
|
const errorCellVisible = await pm.tracesPage.isErrorStatusVisible();
|
|
if (errorCellVisible) {
|
|
await pm.tracesPage.clickCell('ERROR');
|
|
testLogger.info('Found and clicked ERROR status cell');
|
|
}
|
|
|
|
// Check for status code 2 (error) using page object
|
|
const statusCode2Visible = await pm.tracesPage.isStatusCode2Visible();
|
|
if (statusCode2Visible) {
|
|
testLogger.info('Found error status code 2');
|
|
}
|
|
|
|
// Verify error trace was opened
|
|
expect(errorCellVisible || statusCode2Visible || await pm.tracesPage.isTraceDetailsTreeVisible()).toBeTruthy();
|
|
} else {
|
|
testLogger.info('No traces with errors found');
|
|
// Verify search completed properly
|
|
const hasResults = await pm.tracesPage.hasTraceResults();
|
|
const noResults = await pm.tracesPage.isNoResultsVisible();
|
|
expect(hasResults || noResults).toBeTruthy();
|
|
}
|
|
});
|
|
|
|
|
|
test("P1: Verify trace span attributes and values", {
|
|
tag: ['@traceQueryEditor', '@traces', '@query', '@functional', '@P1', '@all']
|
|
}, async ({ page }) => {
|
|
testLogger.info('Testing trace span attributes');
|
|
|
|
// Setup and run search
|
|
await pm.tracesPage.setupTraceSearch();
|
|
|
|
// Check if we have results
|
|
const hasResults = await pm.tracesPage.hasTraceResults();
|
|
if (!hasResults) {
|
|
throw new Error('Precondition failed: No trace results available. Ensure trace data is ingested.');
|
|
}
|
|
|
|
// Click on first trace result
|
|
await pm.tracesPage.clickFirstTraceResult();
|
|
|
|
// Wait with retry for trace details to render (UI may be slow)
|
|
let detailsTreeVisible = false;
|
|
let anyDetailsVisible = false;
|
|
let clickSuccessful = false;
|
|
|
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
await page.waitForTimeout(2000);
|
|
detailsTreeVisible = await pm.tracesPage.isTraceDetailsTreeVisible();
|
|
anyDetailsVisible = await pm.tracesPage.isAnyTraceDetailVisible();
|
|
clickSuccessful = await pm.tracesPage.isTraceClickSuccessful();
|
|
|
|
if (detailsTreeVisible || anyDetailsVisible) {
|
|
testLogger.info(`Trace details visible on attempt ${attempt + 1}`);
|
|
break;
|
|
}
|
|
|
|
// If click was successful, UI may show trace details inline
|
|
if (clickSuccessful) {
|
|
testLogger.info(`Trace click successful on attempt ${attempt + 1} - UI may show details inline`);
|
|
break;
|
|
}
|
|
|
|
testLogger.info(`Waiting for trace details, attempt ${attempt + 1}`);
|
|
}
|
|
|
|
// Look for common trace attributes using page object
|
|
const attributes = ['status_code', 'service_name', 'span_name', 'duration'];
|
|
let foundAttributes = 0;
|
|
|
|
for (const attr of attributes) {
|
|
const attrVisible = await pm.tracesPage.isAttributeCellVisible(attr);
|
|
if (attrVisible) {
|
|
testLogger.info(`Found attribute: ${attr}`);
|
|
foundAttributes++;
|
|
|
|
// Try to click on the attribute to see its value
|
|
await pm.tracesPage.clickAttributeCell(attr);
|
|
}
|
|
}
|
|
|
|
// Verify at least some attributes were found, trace details are visible, or click was handled
|
|
expect(foundAttributes > 0 || detailsTreeVisible || anyDetailsVisible || clickSuccessful).toBeTruthy();
|
|
testLogger.info(`Found ${foundAttributes} of ${attributes.length} expected attributes`);
|
|
});
|
|
|
|
});
|