(frontend) add utilities for e2e tests

Added several utilities to facilitate maintenance and test writing
This commit is contained in:
Nathan Panchout
2026-02-06 15:39:36 +01:00
committed by Manuel Raynaud
parent f0f894023b
commit a70fd4e517
9 changed files with 392 additions and 29 deletions
@@ -1,16 +1,36 @@
import { expect, Page } from "@playwright/test";
import { expect } from "@playwright/test";
import { PageOrLocator } from "./utils/types-utils";
export const getRowItem = async (page: Page, itemName: string) => {
const row = page
const getRowLocator = (page: PageOrLocator, itemName: string) => {
return page
.getByRole("row", { name: itemName })
.filter({ hasText: itemName })
.first();
};
export const expectRowItem = async (page: PageOrLocator, itemName: string) => {
const row = getRowLocator(page, itemName);
await expect(row).toBeVisible();
};
export const expectRowItemIsNotVisible = async (
page: PageOrLocator,
itemName: string
) => {
const row = getRowLocator(page, itemName);
await expect(row).not.toBeVisible();
};
export const getRowItem = async (page: PageOrLocator, itemName: string) => {
const row = getRowLocator(page, itemName);
await expect(row).toBeVisible();
return row;
};
export const getRowItemActions = async (page: Page, itemName: string) => {
export const getRowItemActions = async (
page: PageOrLocator,
itemName: string
) => {
const row = await getRowItem(page, itemName);
const actions = row
.getByRole("button", {
@@ -23,13 +43,13 @@ export const getRowItemActions = async (page: Page, itemName: string) => {
};
export const clickOnRowItemActions = async (
page: Page,
page: PageOrLocator,
itemName: string,
actionName: string
) => {
const actions = await getRowItemActions(page, itemName);
await actions.click({ force: true }); // Because dnd-kit add an aria-disabled attribute on parent and playwright don't interact with it
const action = page.getByRole("menuitem", { name: "Info" });
const action = page.getByRole("menuitem", { name: actionName });
await expect(action).toBeVisible();
await action.click();
};
@@ -1,8 +1,9 @@
import { expect, Page } from "@playwright/test";
import { expectTreeItemIsSelected } from "./utils-tree";
import { PageOrLocator } from "./utils/types-utils";
export const expectExplorerBreadcrumbs = async (
page: Page,
page: PageOrLocator,
expected: string[],
hidden: string[] = []
) => {
@@ -34,3 +35,28 @@ export const expectCurrentFolder = async (
);
await expectExplorerBreadcrumbs(page, expected);
};
export const expectDefaultRoute = async (
page: Page,
breadcrumbLabel: string,
route: string
) => {
const defaultRouteButton = page.getByTestId("default-route-button");
await expect(defaultRouteButton).toBeVisible();
await expect(defaultRouteButton).toContainText(breadcrumbLabel);
const currentUrl = page.url();
expect(currentUrl).toContain(route);
};
export const clickOnBreadcrumbButtonAction = async (
page: Page,
actionName: string
) => {
const breadcrumbs = page.getByTestId("explorer-breadcrumbs");
await expect(breadcrumbs).toBeVisible();
const lastBreadcrumbButton = breadcrumbs
.getByTestId("breadcrumb-button")
.last();
await lastBreadcrumbButton.click();
await page.getByRole("menuitem", { name: actionName }).click();
};
@@ -1,5 +1,6 @@
import { expect, Page } from "@playwright/test";
import { getItemTree, openTreeNode } from "./utils-tree";
import { getRowItem } from "./utils-embedded-grid";
export const createWorkspace = async (page: Page, workspaceName: string) => {
await page.getByRole("button", { name: "add Create" }).click();
@@ -20,3 +21,26 @@ export const createFolder = async (page: Page, folderName: string) => {
await page.getByRole("textbox", { name: "Folder name" }).fill(folderName);
await page.getByRole("button", { name: "Create" }).click();
};
export const createFolderInCurrentFolder = async (
page: Page,
folderName: string
) => {
await page.getByTestId("create-folder-button").click();
await page.getByTestId("create-folder-input").click();
await page.getByTestId("create-folder-input").fill(folderName);
await page.getByRole("button", { name: "Create" }).click();
const folderItem = await getRowItem(page, folderName);
await expect(folderItem).toBeVisible();
return folderItem;
};
export const deleteCurrentFolder = async (page: Page) => {
const breadcrumbs = page.getByTestId("explorer-breadcrumbs");
await expect(breadcrumbs).toBeVisible();
const lastBreadcrumbButton = breadcrumbs
.getByTestId("breadcrumb-button")
.last();
await lastBreadcrumbButton.click();
await page.getByRole("menuitem", { name: "Delete" }).click();
};
@@ -0,0 +1,50 @@
import { Page, expect } from "@playwright/test";
import {
expectDefaultRoute,
expectExplorerBreadcrumbs,
} from "./utils-explorer";
import { getRowItem } from "./utils-embedded-grid";
import { clickOnItemInTree } from "./utils-tree";
export const clickToRecent = async (page: Page) => {
await page.getByRole("link", { name: "Recents" }).click();
await expectDefaultRoute(page, "Recents", "/explorer/items/recent");
};
export const clickToMyFiles = async (page: Page) => {
await page.getByRole("link", { name: "My files" }).click();
await expectDefaultRoute(page, "My files", "/explorer/items/my_files");
};
export const clickToSharedWithMe = async (page: Page) => {
await page.getByRole("link", { name: "Shared with me" }).click();
await expectDefaultRoute(
page,
"Shared with me",
"/explorer/items/shared-with-me"
);
};
export const clickToTrash = async (page: Page) => {
await page.getByRole("link", { name: "Trash" }).click();
const breadcrumbs = page.getByTestId("trash-page-breadcrumbs");
await expect(breadcrumbs).toBeVisible();
await expect(breadcrumbs).toContainText("Trash");
const currentUrl = page.url();
expect(currentUrl).toContain("/explorer/trash");
};
export const clickToFavorites = async (page: Page) => {
await clickOnItemInTree(page, "Starred");
await expectDefaultRoute(page, "Starred", "/explorer/items/favorites");
};
export const navigateToFolder = async (
page: Page,
folderName: string,
expectedBreadcrumbs: string[]
) => {
const folderItem = await getRowItem(page, folderName);
await folderItem.dblclick();
await expectExplorerBreadcrumbs(page, expectedBreadcrumbs);
};
@@ -1,19 +1,20 @@
import { expect, Page } from "@playwright/test";
export const getItemTree = async (page: Page, itemTitle: string) => {
export const getItemTree = async (
page: Page,
itemTitle: string,
isVisible: boolean = true
) => {
const item = page.getByRole("treeitem").filter({ hasText: itemTitle });
let itemTree = item.first();
await expect(itemTree).toBeVisible();
if (isVisible) {
await expect(itemTree).toBeVisible();
} else {
await expect(itemTree).not.toBeVisible();
}
return itemTree;
};
export const toggleItemInTree = async (page: Page, itemTitle: string) => {
const item = await getItemTree(page, itemTitle);
const arrow = item.getByText("keyboard_arrow_right");
await expect(arrow).toBeVisible();
await arrow.click();
};
export const getItemContent = async (page: Page, itemTitle: string) => {
const item = await getItemTree(page, itemTitle);
const itemContent = item.getByTestId("tree_item_content");
@@ -49,19 +50,6 @@ export const clickOnMoreActionsButtonFromItem = async (
await moreActionsButton.click();
};
export const addChildrenFromTreeItem = async (
page: Page,
itemTitle: string,
childrenTitle: string
) => {
await clickOnAddChildrenButtonFromItem(page, itemTitle);
const modal = page.getByRole("dialog");
await expect(modal).toBeVisible();
await page.getByText("Folder name").click();
await page.getByRole("textbox", { name: "Folder name" }).fill(childrenTitle);
await page.getByRole("button", { name: "Create" }).click();
};
export const openTreeNode = async (page: Page, itemTitle: string) => {
const item = await getItemTree(page, itemTitle);
await expect(item).toBeVisible();
@@ -0,0 +1,60 @@
import { expect } from "@playwright/test";
import { PageOrLocator } from "./types-utils";
import { getRowItem } from "../utils-embedded-grid";
export const getMoveFolderModal = async (page: PageOrLocator) => {
const moveFolderModal = page.getByLabel("Move folder modal");
await expect(moveFolderModal).toBeVisible();
return moveFolderModal;
};
export const getMoveConfirmationModal = async (page: PageOrLocator) => {
const moveConfirmationModal = page.getByLabel("Move confirmation modal");
await expect(moveConfirmationModal).toBeVisible();
return moveConfirmationModal;
};
export const expectMoveFolderModal = async (page: PageOrLocator) => {
await getMoveFolderModal(page); // getMoveFolderModal already checks if the modal is visible
};
export const acceptMoveItem = async (page: PageOrLocator) => {
const moveFolderModal = await getMoveFolderModal(page);
await moveFolderModal.getByRole("button", { name: "Move here" }).click();
const moveConfirmationModal = await getMoveConfirmationModal(page);
await expect(
moveConfirmationModal.getByText("Transfer rights")
).toBeVisible();
await expect(
moveConfirmationModal.getByText("You are about to move the")
).toBeVisible();
await moveConfirmationModal
.getByRole("button", { name: "Move anyway" })
.click();
};
export const searchAndSelectItem = async (
page: PageOrLocator,
itemName: string
) => {
const moveFolderModal = await getMoveFolderModal(page);
await moveFolderModal.getByPlaceholder("Search for a folder").click();
await moveFolderModal.getByPlaceholder("Search for a folder").fill(itemName);
await expect(moveFolderModal.getByText("Search results")).toBeVisible();
const folderToSelect = await getRowItem(moveFolderModal, itemName);
await folderToSelect.dblclick();
};
export const clickAndAcceptMoveToRoot = async (page: PageOrLocator) => {
const moveFolderModal = await getMoveFolderModal(page);
await moveFolderModal.getByRole("button", { name: "Move to root" }).click();
const moveConfirmationModal = await getMoveConfirmationModal(page);
await expect(
moveConfirmationModal.getByText(
"Moved documents will be accessible via your 'My files' tab. People who had access to the documents only through inherited rights from a parent will no longer be able to access them."
)
).toBeVisible();
await moveConfirmationModal
.getByRole("button", { name: "Move anyway" })
.click();
};
@@ -0,0 +1,162 @@
import { Page, expect } from "@playwright/test";
import { clickOnBreadcrumbButtonAction } from "../utils-explorer";
export const getShareModal = async (page: Page) => {
return page.getByLabel("Share modal");
};
export const expectShareModal = async (page: Page) => {
const shareModal = await getShareModal(page);
await expect(shareModal).toBeVisible();
return shareModal;
};
export const openShareModal = async (page: Page) => {
await clickOnBreadcrumbButtonAction(page, "Share");
const shareModal = await expectShareModal(page);
return shareModal;
};
export const closeShareModal = async (page: Page) => {
const shareModal = await getShareModal(page);
await shareModal.getByRole("button", { name: "Close" }).click();
await expect(shareModal).not.toBeVisible();
};
export const getMemberItem = async (page: Page, userName: string) => {
const shareModal = await getShareModal(page);
const membersList = shareModal.getByTestId("members-list");
const memberItem = membersList
.getByTestId("share-member-item")
.filter({ hasText: userName });
return memberItem;
};
export const expectUserInMembersList = async (
page: Page,
userName: string,
role: string
) => {
const memberItem = await getMemberItem(page, userName);
await expect(memberItem).toBeVisible();
await expect(memberItem).toContainText(role);
return memberItem;
};
export const expectAllowedRoles = async (
page: Page,
userName: string,
allowedRoles: string[],
notAllowedRoles: string[]
) => {
const memberItem = await getMemberItem(page, userName);
await expect(memberItem).toBeVisible();
const roleDropdown = memberItem.getByTestId("access-role-dropdown-button");
await expect(roleDropdown).toBeVisible();
await roleDropdown.click();
for (const role of allowedRoles) {
const roleItem = page.getByRole("menuitem", { name: role });
await expect(roleItem).toBeVisible();
await expect(roleItem).toBeEnabled();
}
for (const role of notAllowedRoles) {
const roleItem = page.getByRole("menuitem", { name: role });
await expect(roleItem).toBeVisible();
await expect(roleItem).toBeDisabled();
}
await closeDropdowns(page);
};
export const selectLinkReach = async (page: Page, linkReach: string) => {
const linkReachDropdown = page.getByTestId(
"share-link-reach-dropdown-button"
);
await linkReachDropdown.click();
const linkReachItem = page.getByRole("menuitem", { name: linkReach });
await linkReachItem.click();
};
export const expectLinkReachSelected = async (
page: Page,
linkReach: string
) => {
const linkReachDropdown = page.getByTestId(
"share-link-reach-dropdown-button"
);
await expect(linkReachDropdown).toBeVisible();
await linkReachDropdown.click();
const linkReachItem = page.getByRole("menuitem", { name: linkReach });
await expect(linkReachItem).toBeVisible();
await expect(linkReachItem).toContainText("check"); // we have the right icon
await closeDropdowns(page);
};
export const closeDropdowns = async (page: Page) => {
await page.locator("body").click();
};
export const expectAllowedLinkReach = async (
page: Page,
allowedLinkReach: string[],
notAllowedLinkReach: string[]
) => {
const shareModal = await getShareModal(page);
const linkReachDropdown = shareModal.getByTestId(
"share-link-reach-dropdown-button"
);
await expect(linkReachDropdown).toBeVisible();
await linkReachDropdown.click();
for (const linkReach of allowedLinkReach) {
const roleItem = page.getByRole("menuitem", { name: linkReach });
await expect(roleItem).toBeVisible();
await expect(roleItem).toBeEnabled();
}
for (const linkReach of notAllowedLinkReach) {
const roleItem = page.getByRole("menuitem", { name: linkReach });
await expect(roleItem).toBeVisible();
await expect(roleItem).toBeDisabled();
}
await closeDropdowns(page);
};
export const getUserSearchResult = async (page: Page, userName: string) => {
const shareModal = await getShareModal(page);
const userSearchList = shareModal.getByTestId("search-users-list");
await expect(userSearchList).toBeVisible();
const userSearchItem = userSearchList
.getByTestId("search-user-item")
.filter({ hasText: userName });
return userSearchItem;
};
export const selectRoleUser = async (page: Page, userRole: string) => {
await page.getByTestId("access-role-dropdown-button").click();
await page.getByRole("menuitem", { name: userRole }).click();
};
export const shareCurrentItemWithWebkitUser = async (
page: Page,
userRole: string = "Reader"
) => {
await clickOnBreadcrumbButtonAction(page, "Share");
const shareModal = await expectShareModal(page);
await expect(
shareModal.getByRole("combobox", { name: "Quick search input" })
).toBeVisible();
await shareModal
.getByRole("combobox", { name: "Quick search input" })
.click();
await shareModal
.getByRole("combobox", { name: "Quick search input" })
.fill("webkit");
const userSearchItem = await getUserSearchResult(page, "user@webkit.test");
await expect(userSearchItem).toBeVisible();
await userSearchItem.click();
await selectRoleUser(page, userRole);
await page.getByRole("button", { name: "Share" }).click();
await expectUserInMembersList(page, "user@webkit.test", userRole);
};
@@ -0,0 +1,30 @@
import { Page, expect } from "@playwright/test";
import { getItemTree, openTreeNode } from "../utils-tree";
import {
clickOnRowItemActions,
expectRowItem,
expectRowItemIsNotVisible,
} from "../utils-embedded-grid";
import { clickToFavorites } from "../utils-navigate";
export const verifyItemIsStarred = async (page: Page, itemName: string) => {
await openTreeNode(page, "Starred");
await getItemTree(page, itemName); // get and verify the item is in the tree
await clickToFavorites(page);
await expectRowItem(page, itemName);
};
export const verifyItemIsNotStarred = async (page: Page, itemName: string) => {
await openTreeNode(page, "Starred");
await getItemTree(page, itemName, false);
await clickToFavorites(page);
await expectRowItemIsNotVisible(page, itemName);
};
export const starItem = async (page: Page, itemName: string) => {
await clickOnRowItemActions(page, itemName, "Star");
};
export const unstarItem = async (page: Page, itemName: string) => {
await clickOnRowItemActions(page, itemName, "Unstar");
};
@@ -0,0 +1,3 @@
import { Locator, Page } from "@playwright/test";
export type PageOrLocator = Page | Locator;