mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-06 08:09:24 +00:00
## Summary
Stabilises alpha1 cloud E2E tests across the Logs-Core shard. Fixes a
UI/API org mismatch root cause, adds env-aware query execution helpers,
and brings all 10 changed spec files into POM compliance.
## Root cause (original)
After Dex login, the Pinia store binds all API calls to the user's
*default* org. The URL `?org_identifier=...` alone does not update the
store. Ingestion went to the `.env` org while UI searches went to the
user's default org → empty results → cascading test failures.
## Changes
### Alpha1 environment / authentication
- **`global-setup-alpha1.js`** — switches active org via the navbar
dropdown after Dex login so the Pinia store adopts the correct org;
`context.storageState` captures the result for all test contexts
- **`playwright-alpha1.config.js`** — `ORGNAME` sourced purely from
`.env`; cloud-config override removed
- **`loginPage.login()` / `unflattened.spec.js`** — include
`?org_identifier=${ORGNAME}` in SPA navigation to prevent defaulting to
`_meta`
- **`unflattened.js openStreamDetail()`** — replaced broken
stream-name-text click with `Stream Detail` action button + Schema-tab
visibility wait
### Auto-run query handling (`auto_query_enabled` flag)
- **`logsPage.js`** — added `runQueryAfterModeChange()`: on alpha1
(`auto_query_enabled=true`) waits for the in-flight auto-query to
complete; on local triggers a fresh query. Fixes
`@interestingFieldsCRUD` and `@quickModeResults` tests that were passing
on alpha1 but failing locally because the old fix clicked Refresh
mid-auto-run (hitting Cancel)
- **`logsQueryPage.js`** — null-guard `textContent()` return in
`_toggleAutoRun()` (`|| ''`) to satisfy Playwright's `string | null`
type contract
### Merge conflict resolution
- **`logsPage.js enableQuickModeIfDisabled()`** — kept HEAD's version
that defines `quickModeIndicator` at the top of the function (used in
the retry loop); discarded main's version that opened the utilities menu
before the variable was defined
### POM compliance (Sentinel audit)
Added three new POM methods to **`logsPage.js`**:
- `watchForNotification(timeout)` — returns a promise for pre-action
race-condition-safe notification watching
- `expectNotificationContainsText(text)` — notification text assertion
- `waitForNotificationWithText(text, timeout)` — notification waiter
with text filter
Removed raw locators from spec files:
- **`logspage.spec.js`** — notification race pattern →
`watchForNotification()` + `expectNotificationContainsText()`; 5-line
raw histogram toggle block → `ensureHistogramState(true)` (POM method
already existed)
- **`logsqueries.spec.js`** —
`pm.logsPage.page.waitForSelector('.q-notification__message:has-text(...)')`
→ `waitForNotificationWithText()`
- **`jobSearch.spec.js`** — added `testLogger` import; replaced 14×
`console.log` with `testLogger.info`; raw Monaco editor locators (lines
158–168) → `logsPage.waitForQueryEditorVisible()` +
`logsPage.getQueryEditorText()` (both already in POM)
### Tags
- **`jobSearch.spec.js`** — all 8 tests now tagged: `@jobSearch,
@P0/@P1` with functional sub-tags (`@smoke`, `@crud`, `@validation`)
- **`logshistogram.spec.js`** — all 5 tests now include `@P1`
## Results
- All `logsquickmode.spec.js` tests pass on both local and alpha1
- Zero Sentinel critical issues remaining across all 10 changed spec
files
- Remaining warnings (old-style auth in `jobSearch.spec.js` /
`pagination.spec.js`, `pm.logsPage.page.reload()` in
`logsquickmode.spec.js`) are pre-existing tech debt deferred to a
separate PR
## Test plan
- [ ] Run `logsquickmode.spec.js` locally and on alpha1 — both should
pass
- [ ] Run full Logs-Core shard on alpha1: `npx playwright test --config
playwright-alpha1.config.js
playwright-tests/Logs/{join,logspage,logsquickmode,pagination,unflattened,logshistogram,jobSearch,logsqueries,logsAnalyzeDimensions}.spec.js`
- [ ] Verify global setup logs: `Switching active org to: <ORGNAME>` →
`Org switch complete`
- [ ] Confirm no `console.log` output in `jobSearch.spec.js` test run
(all replaced by `testLogger`)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
514 lines
22 KiB
JavaScript
514 lines
22 KiB
JavaScript
const { test, expect, navigateToBase } = require('../utils/enhanced-baseFixtures.js');
|
|
const testLogger = require('../utils/test-logger.js');
|
|
const PageManager = require('../../pages/page-manager.js');
|
|
const logData = require("../../fixtures/log.json");
|
|
const { ingestTestData } = require('../utils/data-ingestion.js');
|
|
async function applyQueryButton(pm) {
|
|
const search = pm.page.waitForResponse(logData.applyQuery);
|
|
// Strategic 1000ms wait for query button DOM stabilization - this is functionally necessary
|
|
await pm.page.waitForTimeout(1000);
|
|
await pm.logsPage.clickRefreshButton();
|
|
await expect.poll(async () => (await search).status()).toBe(200);
|
|
}
|
|
|
|
function removeUTFCharacters(text) {
|
|
// Remove UTF characters using regular expression
|
|
return text.replace(/[^\x00-\x7F]/g, " ");
|
|
}
|
|
|
|
test.describe("Logs Queries 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);
|
|
|
|
// Strategic post-authentication stabilization wait - this is functionally necessary
|
|
await page.waitForTimeout(1000);
|
|
|
|
// Data ingestion for logs queries testing (preserve exact logic)
|
|
await ingestTestData(page);
|
|
// Strategic wait for data ingestion completion - this is functionally necessary
|
|
await page.waitForTimeout(1000);
|
|
|
|
// Navigate to logs page and setup for queries testing
|
|
await page.goto(
|
|
`${logData.logsUrl}?org_identifier=${process.env["ORGNAME"]}`
|
|
);
|
|
await pm.logsPage.selectStream("e2e_automate");
|
|
await applyQueryButton(pm);
|
|
|
|
testLogger.info('Logs queries 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 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 visibility test completed');
|
|
});
|
|
|
|
test.skip("should add timestamp to editor save this view and switch", {
|
|
tag: ['@timestampViewLogs', '@all', '@logs']
|
|
}, async ({ page }) => {
|
|
await pm.logsPage.waitForTimeout(3000);
|
|
await pm.logsPage.clickLogTableColumnSource();
|
|
await pm.logsPage.clickIncludeExcludeFieldButton();
|
|
await pm.logsPage.clickIncludeFieldButton();
|
|
await pm.logsPage.clickCloseDialog();
|
|
await pm.logsPage.clickSavedViewsButton();
|
|
await pm.logsPage.fillSavedViewName("e2etimestamp");
|
|
await pm.logsPage.clickSavedViewDialogSaveContent();
|
|
await pm.logsPage.clickSavedViewArrow();
|
|
await pm.logsPage.clickSavedViewByLabel(/timestamp/);
|
|
await pm.logsPage.waitForTimeout(3000);
|
|
await pm.logsPage.clickSavedViewsExpand();
|
|
await pm.logsPage.clickSavedViewSearchInput();
|
|
await pm.logsPage.fillSavedViewSearchInput('e2e');
|
|
await pm.logsPage.clickSavedViewByTitle('e2etimestamp');
|
|
await pm.logsPage.clickSavedViewsExpand();
|
|
await pm.logsPage.clickSavedViewSearchInput();
|
|
await pm.logsPage.clickSavedViewByTitle('e2etimestamp');
|
|
await pm.logsPage.clickDeleteButton();
|
|
await pm.logsPage.clickConfirmButton();
|
|
});
|
|
|
|
test("should create saved view and delete it", {
|
|
tag: ['@streamExplorer', '@all', '@logs']
|
|
}, async ({ page }) => {
|
|
testLogger.info('Testing saved view creation and deletion functionality');
|
|
// Generate a random saved view name
|
|
const randomSavedViewName = `streamslog${Math.random().toString(36).substring(2, 10)}`;
|
|
|
|
// Interactions with the page
|
|
await pm.logsPage.clickRefreshButton();
|
|
await pm.logsPage.clickSavedViewsExpand();
|
|
await pm.logsPage.clickSaveViewButton();
|
|
await pm.logsPage.fillSavedViewName(randomSavedViewName); // Use the random name
|
|
await pm.logsPage.clickSavedViewDialogSave();
|
|
|
|
// Wait for the success toast message to appear briefly after save
|
|
try {
|
|
await pm.logsPage.waitForNotificationWithText('View created successfully', 3000);
|
|
testLogger.info('Success toast validated: View created successfully');
|
|
} catch (error) {
|
|
testLogger.info('View creation toast may have appeared and disappeared quickly - continuing with test');
|
|
}
|
|
|
|
// Strategic 2000ms wait for saved view creation - this is functionally necessary
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.clickStreamsMenuItem();
|
|
await pm.logsPage.clickSearchStreamInput();
|
|
await pm.logsPage.fillSearchStreamInput('e2e');
|
|
// Strategic 500ms wait for stream search DOM stabilization - this is functionally necessary
|
|
await pm.logsPage.waitForTimeout(500);
|
|
await pm.logsPage.clickExploreButton();
|
|
// Strategic 2000ms wait for navigation to stream explorer - this is functionally necessary
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.waitForSavedViewsButton();
|
|
await pm.logsPage.clickSavedViewsExpand();
|
|
await pm.logsPage.clickSavedViewSearchInput();
|
|
await pm.logsPage.fillSavedViewSearchInput(randomSavedViewName); // Use the random name here
|
|
// Strategic 1000ms wait for saved view search results - this is functionally necessary
|
|
await pm.logsPage.waitForTimeout(1000);
|
|
await pm.logsPage.waitForSavedViewText(randomSavedViewName);
|
|
await pm.logsPage.clickSavedViewByText(randomSavedViewName);
|
|
// Wait for saved view to be applied and page to settle before re-expanding
|
|
await page.waitForLoadState('domcontentloaded');
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.clickSavedViewsExpand();
|
|
await pm.logsPage.waitForTimeout(1000);
|
|
await pm.logsPage.clickSavedViewSearchInput();
|
|
await pm.logsPage.clickSavedViewByTitle(randomSavedViewName); // Use the random name here
|
|
|
|
// Wait for UI to stabilize before attempting deletion
|
|
await pm.logsPage.waitForTimeout(1000);
|
|
|
|
// Delete the saved view
|
|
await pm.logsPage.clickDeleteSavedViewButton(randomSavedViewName);
|
|
await pm.logsPage.waitForTimeout(500);
|
|
await pm.logsPage.clickConfirmButton(); // Confirm deletion
|
|
testLogger.info(`Successfully deleted saved view: ${randomSavedViewName}`);
|
|
|
|
testLogger.info('Saved view creation and deletion test completed');
|
|
});
|
|
|
|
test("should reset the editor on clicking reset filter button", {
|
|
tag: ['@resetFilters', '@all', '@logs']
|
|
}, async ({ page }) => {
|
|
testLogger.info('Testing reset filter button functionality');
|
|
await pm.logsPage.clickDateTimeButton();
|
|
await pm.logsPage.clickRelative15MinButton();
|
|
await pm.logsPage.clickQueryEditorTextbox();
|
|
await pm.logsPage.typeInQueryEditor("match_all_raw_ignore_case('provide_credentials')");
|
|
await pm.logsPage.waitForSearchBarRefreshButton();
|
|
await pm.logsPage.clickRefreshButton();
|
|
await pm.logsPage.clickResetFiltersButton();
|
|
await pm.logsPage.waitForQueryEditorTextbox();
|
|
await pm.logsPage.expectQueryEditorEmpty();
|
|
|
|
testLogger.info('Reset filter button test completed');
|
|
});
|
|
|
|
test("should add invalid query and display error", {
|
|
tag: ['@invalidQueryLogs', '@all', '@logs']
|
|
}, async ({ page }) => {
|
|
testLogger.info('Testing invalid query error handling');
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.clickDateTimeButton();
|
|
await pm.logsPage.clickRelative15MinButton();
|
|
await pm.logsPage.clickQueryEditor();
|
|
await pm.logsPage.typeInQueryEditor("kubernetes");
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.clickSearchBarRefreshButton();
|
|
await pm.logsPage.expectErrorMessageVisible();
|
|
|
|
testLogger.info('Invalid query error handling test completed');
|
|
});
|
|
|
|
test("should not display error if match all case added in log query search", {
|
|
tag: ['@matchAllLogs', '@all', '@logs']
|
|
}, async ({ page }) => {
|
|
testLogger.info('Testing match_all query functionality');
|
|
await pm.logsPage.clickDateTimeButton();
|
|
await pm.logsPage.clickRelative15MinButton();
|
|
|
|
await pm.logsPage.expectQueryEditorVisible();
|
|
await pm.logsPage.clickQueryEditor();
|
|
await pm.logsPage.typeInQueryEditor("match_all('code')");
|
|
|
|
await pm.logsPage.expectSearchBarRefreshButtonVisible();
|
|
await pm.logsPage.clickSearchBarRefreshButton();
|
|
|
|
await pm.logsPage.expectLogTableColumnSourceVisible();
|
|
|
|
testLogger.info('Match_all query functionality test completed');
|
|
});
|
|
|
|
// Duplicate test - kept in logspage.spec.js
|
|
// test("should display error when save function is clicked without any VRL function", {
|
|
// tag: ['@functionValidation', '@all', '@logs']
|
|
// }, async ({ page }) => {
|
|
// testLogger.info('Testing VRL function save validation without function definition');
|
|
// await pm.logsPage.clickFunctionDropdownSave();
|
|
// await pm.logsPage.expectWarningNoFunctionDefinition();
|
|
//
|
|
// testLogger.info('VRL function save validation test completed');
|
|
// });
|
|
|
|
// Duplicate test - kept in logspage.spec.js
|
|
// test("should display click save directly while creating a function", {
|
|
// tag: ['@functionSaveValidation', '@all', '@logs']
|
|
// }, async ({ page }) => {
|
|
// testLogger.info('Testing function save validation when clicking save directly');
|
|
// await pm.logsPage.waitForTimeout(1000);
|
|
// await pm.logsPage.toggleVrlEditor();
|
|
// await pm.logsPage.clickVrlEditor();
|
|
// await pm.logsPage.waitForTimeout(1000);
|
|
// await pm.logsPage.clickFunctionDropdownSave();
|
|
// await pm.logsPage.clickSavedViewDialogSave();
|
|
// await pm.logsPage.expectFunctionNameNotValid();
|
|
//
|
|
// testLogger.info('Function save validation test completed');
|
|
// });
|
|
|
|
// Duplicate test - kept in logspage.spec.js
|
|
// test("should display error on adding only blank spaces under function name", {
|
|
// tag: ['@functionNameValidation', '@all', '@logs']
|
|
// }, async ({ page }) => {
|
|
// testLogger.info('Testing function name validation with blank spaces');
|
|
// await pm.logsPage.waitForTimeout(1000);
|
|
// await pm.logsPage.toggleVrlEditor();
|
|
// await pm.logsPage.clickVrlEditor();
|
|
// await pm.logsPage.waitForTimeout(1000);
|
|
// await pm.logsPage.clickFunctionDropdownSave();
|
|
// await pm.logsPage.fillSavedFunctionNameInput(' ');
|
|
// await pm.logsPage.clickSavedViewDialogSave();
|
|
// await pm.logsPage.expectFunctionNameNotValid();
|
|
//
|
|
// testLogger.info('Function name blank spaces validation test completed');
|
|
// });
|
|
|
|
// Duplicate test - kept in logspage.spec.js
|
|
// test("should display error on adding invalid characters under function name", {
|
|
// tag: ['@functionNameValidation', '@all', '@logs']
|
|
// }, async ({ page }) => {
|
|
// testLogger.info('Testing function name validation with invalid characters');
|
|
// await pm.logsPage.waitForTimeout(1000);
|
|
// await pm.logsPage.toggleVrlEditor();
|
|
// await pm.logsPage.clickVrlEditor();
|
|
// await pm.logsPage.waitForTimeout(1000);
|
|
// await pm.logsPage.clickFunctionDropdownSave();
|
|
// await pm.logsPage.fillSavedFunctionNameInput('e2e@@@');
|
|
// await pm.logsPage.clickSavedViewDialogSave();
|
|
// await pm.logsPage.expectFunctionNameNotValid();
|
|
//
|
|
// testLogger.info('Function name invalid characters validation test completed');
|
|
// });
|
|
|
|
test("should display added function on switching between tabs and again navigate to log", {
|
|
tag: ['@functionPersistence', '@all', '@logs']
|
|
}, async ({ page }) => {
|
|
testLogger.info('Testing function persistence across tab navigation');
|
|
await pm.logsPage.waitForTimeout(1000);
|
|
await pm.logsPage.toggleVrlEditor();
|
|
await pm.logsPage.clickVrlEditor();
|
|
await pm.logsPage.waitForTimeout(1000);
|
|
await pm.logsPage.clickRefreshButton();
|
|
await pm.logsPage.clickMenuLinkMetricsItem();
|
|
await pm.logsPage.clickMenuLinkLogsItem();
|
|
await pm.logsPage.clickMenuLinkLogsItem();
|
|
await pm.logsPage.expectPageContainsText(".a=2");
|
|
|
|
testLogger.info('Function persistence test completed');
|
|
});
|
|
|
|
test("should display bar chart when histogram toggle is on", {
|
|
tag: ['@histogramBarChart', '@histogram', '@all', '@logs']
|
|
}, async ({ page }) => {
|
|
testLogger.info('Testing bar chart display with histogram toggle');
|
|
|
|
// Ensure histogram is ON before testing bar chart
|
|
const isHistogramOn = await pm.logsPage.isHistogramOn();
|
|
if (!isHistogramOn) {
|
|
await pm.logsPage.toggleHistogram();
|
|
await pm.logsPage.waitForTimeout(1000);
|
|
}
|
|
|
|
await pm.logsPage.clickLogSearchIndexListFieldSearchInput();
|
|
await pm.logsPage.fillLogSearchIndexListFieldSearchInput('code');
|
|
await pm.logsPage.waitForTimeout(4000);
|
|
await pm.logsPage.clickExpandCode();
|
|
await pm.logsPage.waitForTimeout(4000);
|
|
|
|
// Click refresh and wait for actual results (not just DOM ready — AJAX search on alpha1 can be slow)
|
|
await pm.logsPage.clickRefreshButton();
|
|
await pm.logsPage.waitForSearchResults();
|
|
|
|
// Toggle SQL mode and refresh
|
|
await pm.logsPage.clickSQLModeToggle();
|
|
await pm.logsPage.clickRefreshButton();
|
|
// clickBarChartCanvas includes networkidle wait + retry — more reliable than a static timeout
|
|
await pm.logsPage.clickBarChartCanvas();
|
|
|
|
// Toggle SQL mode off and refresh
|
|
await pm.logsPage.clickSQLModeToggle();
|
|
await pm.logsPage.clickRefreshButton();
|
|
// clickBarChartCanvas includes networkidle wait + retry
|
|
await pm.logsPage.clickBarChartCanvas();
|
|
await pm.logsPage.clickHistogramToggleDiv();
|
|
|
|
testLogger.info('Histogram bar chart display test completed');
|
|
});
|
|
|
|
test("should display search around in histogram mode", {
|
|
tag: ['@searchAroundHistogram', '@histogram', '@all', '@logs']
|
|
}, async ({ page }) => {
|
|
testLogger.info('Testing search around functionality in histogram mode');
|
|
|
|
await pm.logsPage.waitForTimeout(1000);
|
|
await pm.logsPage.clickLogTableColumnSource();
|
|
await pm.logsPage.clickLogsDetailTableSearchAroundBtn();
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.expectLogTableColumnSourceVisible();
|
|
|
|
testLogger.info('Search around histogram mode test completed');
|
|
});
|
|
|
|
test.skip("should display results for search around after adding function", async ({ page }) => {
|
|
await pm.logsPage.waitForTimeout(1000);
|
|
await pm.logsPage.toggleVrlEditor();
|
|
await pm.logsPage.clickVrlEditor();
|
|
await pm.logsPage.waitForTimeout(1000);
|
|
await pm.logsPage.clickRefreshButton();
|
|
await pm.logsPage.clickLogTableColumn3Source();
|
|
await pm.logsPage.clickLogsDetailTableSearchAroundBtn();
|
|
await pm.logsPage.waitForTimeout(1000);
|
|
await pm.logsPage.expectLogTableColumnSourceVisible();
|
|
});
|
|
|
|
test("should display search around in SQL mode", {
|
|
tag: ['@searchAroundSQL', '@sqlMode', '@all', '@logs']
|
|
}, async ({ page }) => {
|
|
testLogger.info('Testing search around functionality in SQL mode');
|
|
|
|
await pm.logsPage.waitForTimeout(1000);
|
|
await pm.logsPage.clickSQLModeToggle();
|
|
await pm.logsPage.clickLogTableColumnSource();
|
|
await pm.logsPage.clickLogsDetailTableSearchAroundBtn();
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.expectLogTableColumnSourceVisible();
|
|
|
|
testLogger.info('Search around SQL mode test completed');
|
|
});
|
|
|
|
test("should display results for search around with limit query", {
|
|
tag: ['@searchAroundLimit', '@all', '@logs']
|
|
}, async ({ page }) => {
|
|
testLogger.info('Testing search around functionality with limit query');
|
|
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.clickDateTimeButton();
|
|
await pm.logsPage.clickRelative15MinButton();
|
|
await pm.logsPage.clickQueryEditor();
|
|
await pm.logsPage.typeInQueryEditor("match_all('code') limit 5");
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.clickSQLModeToggle();
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.clickLogTableColumnSource();
|
|
await pm.logsPage.clickLogsDetailTableSearchAroundBtn();
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.expectLogTableColumnSourceVisible();
|
|
|
|
testLogger.info('Search around with limit query test completed');
|
|
});
|
|
|
|
test("should not display pagination for limit query", {
|
|
tag: ['@paginationLimit', '@all', '@logs']
|
|
}, async ({ page }) => {
|
|
testLogger.info('Testing pagination behavior with limit query');
|
|
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.clickDateTimeButton();
|
|
await pm.logsPage.clickRelative15MinButton();
|
|
await pm.logsPage.clickQueryEditor();
|
|
await pm.logsPage.typeInQueryEditor("match_all('code') limit 5");
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.clickSQLModeToggle();
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.clickRefreshButton();
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.expectPaginationNotVisible();
|
|
|
|
testLogger.info('Pagination limit query test completed');
|
|
});
|
|
|
|
test("should not display pagination for SQL limit query", {
|
|
tag: ['@paginationSQLLimit', '@sqlMode', '@all', '@logs']
|
|
}, async ({ page }) => {
|
|
testLogger.info('Testing pagination behavior with SQL limit query');
|
|
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.clickDateTimeButton();
|
|
await pm.logsPage.clickRelative15MinButton();
|
|
await pm.logsPage.clickQueryEditor();
|
|
await pm.logsPage.typeInQueryEditor('SELECT * FROM "e2e_automate" ORDER BY _timestamp DESC limit 5');
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.clickRefreshButton();
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.expectPaginationNotVisible();
|
|
|
|
testLogger.info('Pagination SQL limit query test completed');
|
|
});
|
|
|
|
test("should not display pagination for SQL group/order/limit query", {
|
|
tag: ['@paginationSQLGroupOrder', '@sqlMode', '@all', '@logs']
|
|
}, async ({ page }) => {
|
|
testLogger.info('Testing pagination behavior with SQL group/order/limit query');
|
|
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.clickDateTimeButton();
|
|
await pm.logsPage.clickRelative15MinButton();
|
|
await pm.logsPage.clickQueryEditor();
|
|
await pm.logsPage.typeInQueryEditor('SELECT * FROM "e2e_automate" WHERE code < 400 GROUP BY code ORDER BY count(*) DESC LIMIT 5');
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.clickRefreshButton();
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.expectPaginationNotVisible();
|
|
|
|
testLogger.info('Pagination SQL group/order/limit query test completed');
|
|
});
|
|
|
|
test("should reset pagination to page 1 after running query again", {
|
|
tag: ['@pagination', '@logs', '@all']
|
|
}, async ({ page }) => {
|
|
testLogger.info('Testing pagination reset behavior after re-running query');
|
|
|
|
// Set up conditions to ensure we have enough data for pagination
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
await pm.logsPage.clickDateTimeButton();
|
|
await pm.logsPage.waitForTimeout(1000);
|
|
|
|
// Use wider time range to capture ingested data
|
|
const selectedRange = await pm.logsPage.clickWideRelativeTimeRangeOrFallback();
|
|
testLogger.info(`Set time range to ${selectedRange} to capture ingested data`);
|
|
|
|
// Run initial query to get results
|
|
await pm.logsPage.clickRefreshButton();
|
|
await pm.logsPage.waitForTimeout(3000);
|
|
|
|
// Pagination should exist after ingesting data - expect it to be visible
|
|
await pm.logsPage.expectResultPaginationVisible();
|
|
testLogger.info('Pagination controls found, proceeding with test');
|
|
|
|
// Get available page count using POM
|
|
const pageCount = await pm.logsPage.getPaginationPageCount();
|
|
testLogger.info(`Found ${pageCount} page buttons`);
|
|
|
|
// Navigate to page 4 using POM
|
|
testLogger.info('Navigating to page 4');
|
|
await pm.logsPage.clickPaginationPage(4);
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
|
|
// Verify we're on page 4 using POM
|
|
await pm.logsPage.waitForTimeout(3000);
|
|
const page4Classes = await pm.logsPage.getPaginationPageClasses(4);
|
|
testLogger.info(`Page 4 button classes: ${page4Classes}`);
|
|
|
|
// Run query again while on page 4
|
|
testLogger.info('Running query again while on page 4');
|
|
await pm.logsPage.clickRefreshButton();
|
|
await pm.logsPage.waitForTimeout(3000);
|
|
|
|
// Verify pagination resets to page 1 using POM
|
|
await pm.logsPage.waitForTimeout(2000);
|
|
|
|
const page4ClassesAfter = await pm.logsPage.getPaginationPageClasses(4).catch(() => null);
|
|
const page1ClassesAfter = await pm.logsPage.getPaginationPageClasses(1).catch(() => null);
|
|
|
|
testLogger.info(`After query - Page 1 classes: ${page1ClassesAfter}`);
|
|
testLogger.info(`After query - Page 4 classes: ${page4ClassesAfter}`);
|
|
|
|
// Check pagination state using POM methods
|
|
const isStillOnPage4 = await pm.logsPage.isPaginationPageActive(4).catch(() => false);
|
|
const isBackToPage1 = await pm.logsPage.isPaginationPageActive(1).catch(() => false);
|
|
|
|
if (isStillOnPage4) {
|
|
testLogger.error('🐛 BUG DETECTED: Pagination stayed on page 4 instead of resetting to page 1');
|
|
expect(isStillOnPage4).toBeFalsy();
|
|
} else if (isBackToPage1) {
|
|
testLogger.info('✅ Pagination correctly reset to page 1 after re-running query');
|
|
expect(isBackToPage1).toBeTruthy();
|
|
} else {
|
|
testLogger.info('Using fallback method to check pagination state');
|
|
const activePage = await pm.logsPage.getActivePaginationPageText();
|
|
testLogger.info(`Active page (fallback): ${activePage}`);
|
|
|
|
if (activePage === '4') {
|
|
testLogger.error('🐛 BUG DETECTED: Pagination stayed on page 4 (fallback method)');
|
|
expect(activePage).toBe('1');
|
|
} else {
|
|
testLogger.info('✅ Pagination appears to have reset correctly (fallback method)');
|
|
}
|
|
}
|
|
|
|
testLogger.info('Pagination reset behavior test completed');
|
|
});
|
|
}); |