Files
openobserve/tests/ui-testing/playwright-tests/Traces/traceQueryEditor.spec.js
T

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`);
});
});