-
Notifications
You must be signed in to change notification settings - Fork 15
Add QAN URL state persistence tests #1139
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -241,3 +241,92 @@ pmmTest('PMM-T2252 Verify RTA overview CSV export @rta', async ({ page, queryAna | |
| expect(csvOperationIds).toEqual(uiOperationIds); | ||
| }); | ||
| }); | ||
|
|
||
| pmmTest( | ||
| 'PMM-T2265 Verify RTA overview table state is stored in the URL and restored after refresh @rta', | ||
| async ({ page, queryAnalytics }) => { | ||
| const { rta } = queryAnalytics; | ||
|
|
||
| await rta.buttons.pauseRealTimeAnalytics.click(); | ||
| await rta.filterQueriesByText('db.runCommand'); | ||
| await rta.inputs.rowsLimit.click(); | ||
| await rta.builders.rowsPerPageOption('10').click(); | ||
| await rta.clickElapsedTimeHeader(); | ||
|
|
||
| await expect | ||
| .poll(() => new URL(page.url()).searchParams.get('overview.f.queryText')) | ||
| .toBe('db.runCommand'); | ||
| await expect.poll(() => new URL(page.url()).searchParams.get('overview.pageSize')).toBe('10'); | ||
| await expect.poll(() => new URL(page.url()).searchParams.get('overview.sort')).not.toBeNull(); | ||
|
|
||
| const urlBeforeReload = new URL(page.url()); | ||
| const serviceIds = urlBeforeReload.searchParams.getAll('serviceIds'); | ||
|
|
||
| await page.reload(); | ||
| await rta.elements.realTimeTable.waitFor({ state: 'visible' }); | ||
| await rta.openFiltersIfHidden(); | ||
|
|
||
| await expect(rta.inputs.filterByQueryText).toHaveValue('db.runCommand'); | ||
| await expect(rta.inputs.rowsLimit).toHaveText('10'); | ||
| await expect(rta.elements.elapsedTimeColumnHeader).toHaveAccessibleName( | ||
| /Elapsed time Sorted by Elapsed time descending/, | ||
| ); | ||
| expect(new URL(page.url()).searchParams.getAll('serviceIds')).toEqual(serviceIds); | ||
| }, | ||
|
Comment on lines
+245
to
+277
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win Add readable
As per coding guidelines, “Use Playwright's 📍 Affects 2 files
🤖 Prompt for AI AgentsSource: Coding guidelines |
||
| ); | ||
|
|
||
| pmmTest( | ||
| 'PMM-T2266 Verify RTA elapsed-time decimal filter and URL restoration @rta', | ||
| async ({ page, queryAnalytics }) => { | ||
| const { rta } = queryAnalytics; | ||
|
|
||
| await rta.elements.realTimeTableRow.first().waitFor({ state: 'visible' }); | ||
| await rta.buttons.pauseRealTimeAnalytics.click(); | ||
| await rta.openFilters(); | ||
|
|
||
| const rowsBeforeFilter = await rta.elements.realTimeTableRow.count(); | ||
| const durations = (await rta.elements.durationCells.allTextContents()).map(Number.parseFloat); | ||
| const shortestDuration = Math.min(...durations); | ||
| const longestDuration = Math.max(...durations); | ||
| const decimalMinimum = String(Number(((shortestDuration + longestDuration) / 2).toFixed(2))); | ||
| const decimalMaximum = String(longestDuration); | ||
|
|
||
| expect(longestDuration).toBeGreaterThan(shortestDuration); | ||
|
|
||
| await rta.inputs.minimumDuration.fill(decimalMinimum); | ||
| await rta.inputs.maximumDuration.fill(decimalMaximum); | ||
| await expect | ||
| .poll(async () => { | ||
| const values = await rta.elements.durationCells.allTextContents(); | ||
|
|
||
| return ( | ||
| values.length > 0 && | ||
| values.length < rowsBeforeFilter && | ||
| values.every( | ||
| (value) => | ||
| Number.parseFloat(value) >= Number(decimalMinimum) && | ||
| Number.parseFloat(value) <= Number(decimalMaximum), | ||
| ) | ||
| ); | ||
| }) | ||
| .toBeTruthy(); | ||
|
|
||
| const durationParameterName = 'overview.f.queryExecutionDurationMs'; | ||
|
|
||
| await expect | ||
| .poll(() => new URL(page.url()).searchParams.get(durationParameterName)) | ||
| .toEqual(expect.stringContaining(decimalMinimum)); | ||
| await expect | ||
| .poll(() => new URL(page.url()).searchParams.get(durationParameterName)) | ||
| .toEqual(expect.stringContaining(decimalMaximum)); | ||
|
|
||
| const durationParameterValue = new URL(page.url()).searchParams.get(durationParameterName); | ||
|
|
||
| await page.reload(); | ||
| await rta.openFiltersIfHidden(); | ||
|
|
||
| await expect(rta.inputs.minimumDuration).toHaveValue(decimalMinimum); | ||
| await expect(rta.inputs.maximumDuration).toHaveValue(decimalMaximum); | ||
| expect(new URL(page.url()).searchParams.get(durationParameterName)).toBe(durationParameterValue); | ||
| }, | ||
| ); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| import pmmTest from '@fixtures/pmmTest'; | ||
| import { Timeouts } from '@helpers/timeouts'; | ||
| import StoredMetricsPage from '@pages/qan/storedMetrics/storedMetrics.page'; | ||
| import { expect, type ConsoleMessage } from '@playwright/test'; | ||
|
|
||
| pmmTest.beforeEach(async ({ grafanaHelper, page, queryAnalytics }) => { | ||
| await grafanaHelper.authorize(); | ||
| await page.goto(queryAnalytics.url); | ||
| await queryAnalytics.storedMetrics.elements.iframe.waitFor({ | ||
| state: 'visible', | ||
| timeout: Timeouts.THIRTY_SECONDS, | ||
| }); | ||
| }); | ||
|
|
||
| pmmTest( | ||
| 'PMM-T2268 Verify QAN shared URL restores filters and pagination @rta', | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Add the This QAN test declares only As per coding guidelines, “Tag tests for CI filtering, using applicable tags such as 🤖 Prompt for AI AgentsSource: Coding guidelines |
||
| async ({ context, page, queryAnalytics }) => { | ||
| const { storedMetrics } = queryAnalytics; | ||
| const mongoDbLabel = storedMetrics.builders.serviceTypeLabel('mongodb'); | ||
| const errors: string[] = []; | ||
|
|
||
| const collectErrors = (message: ConsoleMessage) => { | ||
| if (message.type() === 'error') errors.push(message.text()); | ||
| }; | ||
|
|
||
| page.on('console', collectErrors); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win Make test cleanup unconditional. If an assertion fails after Line 26, As per coding guidelines, “Make tests idempotent and clean up resources created during tests.” Also applies to: 55-68 🤖 Prompt for AI AgentsSource: Coding guidelines |
||
| await mongoDbLabel.scrollIntoViewIfNeeded(); | ||
| await mongoDbLabel.click(); | ||
|
|
||
| const secondPaginationItem = storedMetrics.builders.paginationItem('2'); | ||
|
|
||
| await expect(secondPaginationItem).toBeVisible({ timeout: Timeouts.THIRTY_SECONDS }); | ||
| await secondPaginationItem.click(); | ||
|
|
||
| for (let index = 0; index < 4; index++) { | ||
| await mongoDbLabel.click(); | ||
| } | ||
|
|
||
| for (const pageNumber of ['1', '2', '1', '2']) { | ||
| await storedMetrics.builders.paginationItem(pageNumber).click(); | ||
| } | ||
|
|
||
| for (const value of ['a', 'ab', 'abc', '']) { | ||
| await storedMetrics.inputs.search.fill(value); | ||
| } | ||
|
|
||
| // eslint-disable-next-line playwright/no-wait-for-timeout -- allow debounce and console errors to settle | ||
| await page.waitForTimeout(Timeouts.HALF_SECOND); | ||
|
|
||
| await expect.poll(() => new URL(page.url()).searchParams.has('dimensionSearchText')).toBeFalsy(); | ||
| await expect.poll(() => new URL(page.url()).searchParams.get('page_number')).toBe('2'); | ||
| await expect.poll(() => new URL(page.url()).searchParams.getAll('var-service_type')).toContain('mongodb'); | ||
|
|
||
| const sharedUrl = page.url(); | ||
| const sharedPage = await context.newPage(); | ||
|
|
||
| await sharedPage.goto(sharedUrl); | ||
|
|
||
| const sharedStoredMetrics = new StoredMetricsPage(sharedPage); | ||
|
|
||
| await expect(sharedStoredMetrics.builders.serviceTypeFilter('mongodb')).toBeChecked({ | ||
| timeout: Timeouts.THIRTY_SECONDS, | ||
| }); | ||
| await expect(sharedStoredMetrics.builders.paginationItem('2')).toHaveClass(/ant-pagination-item-active/); | ||
|
|
||
| page.off('console', collectErrors); | ||
| expect(errors).toEqual([]); | ||
| await sharedPage.close(); | ||
| }, | ||
| ); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Select a service before verifying
serviceIdsrestoration.This test does not change the selected service state. It can pass with an empty
serviceIdslist. Select a known service, then assert its URL value before and after reload.🤖 Prompt for AI Agents