Skip to content

PMM-14544 new navigation tests#855

Open
kiranvuyurru wants to merge 37 commits intomainfrom
PMM-14544-new-navigation
Open

PMM-14544 new navigation tests#855
kiranvuyurru wants to merge 37 commits intomainfrom
PMM-14544-new-navigation

Conversation

@kiranvuyurru
Copy link
Contributor

@kiranvuyurru kiranvuyurru commented Jan 5, 2026

  1. verify the collapse and expand of the left menu
  2. Traverse all menu and check no 404 response
  3. non admin RBAC
  4. Time range persists on various dashboards
  5. old navigation menu not visible and iframe visibility test
  6. Node and service persistence check

Comment on lines 286 to 296
mouseHoverOnPmmLogo = async () => {
const pmmLogo = this.elements.sidebar.locator('rect');

const rectBox = await pmmLogo.boundingBox();
if (rectBox) {
await this.page.mouse.move(
rectBox.x + rectBox.width / 2,
rectBox.y + rectBox.height / 2
);
}
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you tried just using pmmLogo.hover()?

You can even pass coordinates if really needed (but I don't think it's needed)
https://playwright.dev/docs/api/class-locator#locator-hover

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried pmmlogo.hover(), it did not work.


await leftNavigation.elements.openLeftNavigationButton.click();
await expect(leftNavigation.elements.closeLeftNavigationButton).toBeVisible();
await expect(leftNavigation.elements.openLeftNavigationButton).not.toBeVisible();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prefer toBeHidden instead of not toBeVisible as it's more readable

@peterSirotnak Do you think we should enable it as a eslint plugin?

eslint-plugin-playwright/no-useless-not

await leftNavigation.elements.openLeftNavigationButton.click();
}

await leftNavigation.traverseAllMenuItems();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this test, testing?

We don't have any assertions/expects anywhere in the method or the test

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with @travagliad . There is no need to create a method which is not used anywhere else. Same applies to other methods in the leftNavigation class
@kiranvuyurru lets move the code into the test and wrap with test.step annotations for code readability

pls use test.step everywhere possible

leftNavigation: LeftNavigation;
}>({
cliHelper: async ({}, use) => {
cliHelper: async ({ }, use) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't be changing formatting of code on PRs otherwise we end up on a review hell anytime we push, if it's auto formatting try to change your rules so it doesn't happen or push without autoformatting on existing files

await leftNavigation.elements.home.click();
await leftNavigation.elements.timePickerOpenButton.click();
await leftNavigation.getTimeRangeOption(selectedTimeRange).click();
await page.waitForLoadState('domcontentloaded');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prefer web assertions instead of load states as this is flaky

https://playwright.dev/docs/best-practices#use-web-first-assertions

@travagliad
Copy link
Contributor

travagliad commented Jan 6, 2026

I see many playwright methods like .click() on the spec file, while this works the reason we have page objects is to abstract the test files and move all playwright logic like this method to the page objects, so when someone non technical or even us, reads the test code we can understand what the test does without going into the details of the test. So I think this should be refactored to have every playwright logic inside page object files.

Also, not having expects in a test isn't ideal, the reason being that all test are supposed to be asserting something, or expecting for something, so for better understanding of a test we should have:

steps coming from the pages objects (So the methods should have a descriptive name) and expects in the end to understand what is being tested

If you need help refactoring it let me know

public get elements() {
return {
// parent menu items
home: this.page.locator('//*[@data-testid="navitem-home-page"]'),
Copy link
Contributor

@yurkovychv yurkovychv Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use this.page.getByTestId() everywhere

export default class LeftNavigation {

public readonly simpleMenuItems = ['home', 'qan', 'help'] as const;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for so many empty lines.


const grafanaIframe = '#grafana-iframe';

export default class LeftNavigation {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export default class LeftNavigation {
export default class LeftNavigation extends BasePage {


export type MenuItem = Locator | (() => Locator) | { [key: string]: MenuItem };

const grafanaIframe = '#grafana-iframe';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove

return this.page.frameLocator(grafanaIframe);
}

selectMenuItem = async (item: string): Promise<void> => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
selectMenuItem = async (item: string): Promise<void> => {
selectMenuItem = async (item: SomeInteface with defined object): Promise<void> => {

Do this so we have specific options.

}
};

const traverseAllMenuItems = async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this to page object.

return newPage;
}

switchPage = (page: Page) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this to base page.

}
}

newTab = async (): Promise<Page> => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this to base page

oldLeftMenu: () => this.page.getByTestId('data-testid navigation mega-menu'),
};

iframe(): FrameLocator {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already in base page, remove.

@kiranvuyurru kiranvuyurru force-pushed the PMM-14544-new-navigation branch 2 times, most recently from 8aa1241 to ed701a1 Compare January 16, 2026 16:12
constructor(page: Page) { super(page); }
public elements = {
// parent menu items
home: () => this.page.getByTestId('navitem-home-page'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why all locators are functions?

await leftNavigation.selectMenuItem({ path: 'mysql' });
const selectedNode = await leftNavigation.selectNode(4, /client_container_\d+/);
await leftNavigation.grafanaIframe().getByText(selectedNode).waitFor({ state: 'visible', timeout: 10000 });
await expect(leftNavigation.grafanaIframe().getByText(selectedNode)).toBeVisible();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we have this locator in the page object? to not have .grafanaIframe() everywhere?

@kiranvuyurru kiranvuyurru force-pushed the PMM-14544-new-navigation branch from 78bf848 to 63ce711 Compare January 21, 2026 17:11
await expect(leftNavigation.buttons.oldLeftMenu).toBeHidden();
});
await pmmTest.step('Verify iframe hidden on Help page', async () => {
// await leftNavigation.selectMenuItem({ path: 'help' });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove commented text

}


// creates non admin user
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove comments

Comment on lines 41 to 44
this.buttons = {
// parent menu items
home: this.page.getByTestId('navitem-home-page'),
mysql: this.page.getByTestId('navitem-mysql'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
this.buttons = {
// parent menu items
home: this.page.getByTestId('navitem-home-page'),
mysql: this.page.getByTestId('navitem-mysql'),
this.buttons = {
home: this.page.getByTestId('navitem-home-page'),
mysql: {
locator: this.page.getByTestId('navitem-mysql'),
elements: {
overview: this.page.getByTestId('navitem-mysql-overview'),
summary: this.page.getByTestId('navitem-mysql-summary'),
highAvailability: this.page.getByTestId('navitem-mysql-high-availability'),
ha: {
groupReplication: this.page.getByTestId('navitem-mysql-group-replication-summary'),
replication: this.page.getByTestId('navitem-mysql-replication-summary'),
pxcGaleraCluster: this.page.getByTestId('navitem-pxc-cluster-summary'),
pxcGaleraNode: this.page.getByTestId('navitem-pxc-node-summary'),
pxcGaleraNodes: this.page.getByTestId('navitem-pxc-nodes-compare'),
commandHandler: this.page.getByTestId('navitem-mysql-command-handler-counters-compare'),
innodbDetails: this.page.getByTestId('navitem-mysql-innodb-details'),
innodbCompression: this.page.getByTestId('navitem-mysql-innodb-compression-details'),
performanceSchema: this.page.getByTestId('navitem-mysql-performance-schema-details'),
queryResponseTime: this.page.getByTestId('navitem-mysql-query-response-time-details'),
tableDetails: this.page.getByTestId('navitem-mysql-table-details'),
tokudbDetails: this.page.getByTestId('navitem-mysql-tokudb-details'),
otherDashboards: this.page.getByTestId('navitem-mysql-other-dashboards'),
}
}

Do this for each database type and all menus with submenus. Also remove comments.

public readonly elements;

public readonly simpleMenuItems = ['home', 'qan', 'help'] as const;
public readonly menuWithChildren = [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace with method that finds menu with children maybe also with variable timerange: true also for simpleMenuItems dashboardsToVerifyTimeRange

});
};

public selectTimeRange = async (timeRange: string): Promise<void> => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this to base page

return this.selectVariableValue(dashboardIndex);
};

public selectNode = async (dashboardIndex: number): Promise<string> => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move selecting methods to base page

async ({ page, leftNavigation }) => {
pmmTest.slow();
const ignore404 = (url: string) => url.includes('/settings') || url.includes('/admin_config');
const responseAfterClick = async (locator: Locator, name: string) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this method in the test? Not in the page object?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this has assertions

Refactored e2e test files and page objects for improved readability and consistency, including formatting, arrow function usage, and type improvements. Updated the IPageObject interface to support nested locators. No functional changes were made to test logic.
@kiranvuyurru kiranvuyurru force-pushed the PMM-14544-new-navigation branch from d94fbda to f11db83 Compare January 30, 2026 16:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants