|
|
@@ -4,6 +4,17 @@ import os from "node:os"
|
|
|
import path from "node:path"
|
|
|
import { execSync } from "node:child_process"
|
|
|
import { modKey, serverUrl } from "./utils"
|
|
|
+import {
|
|
|
+ sessionItemSelector,
|
|
|
+ dropdownMenuTriggerSelector,
|
|
|
+ dropdownMenuContentSelector,
|
|
|
+ titlebarRightSelector,
|
|
|
+ popoverBodySelector,
|
|
|
+ listItemSelector,
|
|
|
+ listItemKeySelector,
|
|
|
+ listItemKeyStartsWithSelector,
|
|
|
+} from "./selectors"
|
|
|
+import type { createSdk } from "./utils"
|
|
|
|
|
|
export async function defocus(page: Page) {
|
|
|
await page.mouse.click(5, 5)
|
|
|
@@ -158,3 +169,103 @@ export function sessionIDFromUrl(url: string) {
|
|
|
const match = /\/session\/([^/?#]+)/.exec(url)
|
|
|
return match?.[1]
|
|
|
}
|
|
|
+
|
|
|
+export async function hoverSessionItem(page: Page, sessionID: string) {
|
|
|
+ const sessionEl = page.locator(sessionItemSelector(sessionID)).first()
|
|
|
+ await expect(sessionEl).toBeVisible()
|
|
|
+ await sessionEl.hover()
|
|
|
+ return sessionEl
|
|
|
+}
|
|
|
+
|
|
|
+export async function openSessionMoreMenu(page: Page, sessionID: string) {
|
|
|
+ const sessionEl = await hoverSessionItem(page, sessionID)
|
|
|
+
|
|
|
+ const menuTrigger = sessionEl.locator(dropdownMenuTriggerSelector).first()
|
|
|
+ await expect(menuTrigger).toBeVisible()
|
|
|
+ await menuTrigger.click()
|
|
|
+
|
|
|
+ const menu = page.locator(dropdownMenuContentSelector).first()
|
|
|
+ await expect(menu).toBeVisible()
|
|
|
+ return menu
|
|
|
+}
|
|
|
+
|
|
|
+export async function clickMenuItem(menu: Locator, itemName: string | RegExp, options?: { force?: boolean }) {
|
|
|
+ const item = menu.getByRole("menuitem").filter({ hasText: itemName }).first()
|
|
|
+ await expect(item).toBeVisible()
|
|
|
+ await item.click({ force: options?.force })
|
|
|
+}
|
|
|
+
|
|
|
+export async function confirmDialog(page: Page, buttonName: string | RegExp) {
|
|
|
+ const dialog = page.getByRole("dialog").first()
|
|
|
+ await expect(dialog).toBeVisible()
|
|
|
+
|
|
|
+ const button = dialog.getByRole("button").filter({ hasText: buttonName }).first()
|
|
|
+ await expect(button).toBeVisible()
|
|
|
+ await button.click()
|
|
|
+}
|
|
|
+
|
|
|
+export async function openSharePopover(page: Page) {
|
|
|
+ const rightSection = page.locator(titlebarRightSelector)
|
|
|
+ const shareButton = rightSection.getByRole("button", { name: "Share" }).first()
|
|
|
+ await expect(shareButton).toBeVisible()
|
|
|
+
|
|
|
+ const popoverBody = page
|
|
|
+ .locator(popoverBodySelector)
|
|
|
+ .filter({ has: page.getByRole("button", { name: /^(Publish|Unpublish)$/ }) })
|
|
|
+ .first()
|
|
|
+
|
|
|
+ const opened = await popoverBody
|
|
|
+ .isVisible()
|
|
|
+ .then((x) => x)
|
|
|
+ .catch(() => false)
|
|
|
+
|
|
|
+ if (!opened) {
|
|
|
+ await shareButton.click()
|
|
|
+ await expect(popoverBody).toBeVisible()
|
|
|
+ }
|
|
|
+ return { rightSection, popoverBody }
|
|
|
+}
|
|
|
+
|
|
|
+export async function clickPopoverButton(page: Page, buttonName: string | RegExp) {
|
|
|
+ const button = page.getByRole("button").filter({ hasText: buttonName }).first()
|
|
|
+ await expect(button).toBeVisible()
|
|
|
+ await button.click()
|
|
|
+}
|
|
|
+
|
|
|
+export async function clickListItem(
|
|
|
+ container: Locator | Page,
|
|
|
+ filter: string | RegExp | { key?: string; text?: string | RegExp; keyStartsWith?: string },
|
|
|
+): Promise<Locator> {
|
|
|
+ let item: Locator
|
|
|
+
|
|
|
+ if (typeof filter === "string" || filter instanceof RegExp) {
|
|
|
+ item = container.locator(listItemSelector).filter({ hasText: filter }).first()
|
|
|
+ } else if (filter.keyStartsWith) {
|
|
|
+ item = container.locator(listItemKeyStartsWithSelector(filter.keyStartsWith)).first()
|
|
|
+ } else if (filter.key) {
|
|
|
+ item = container.locator(listItemKeySelector(filter.key)).first()
|
|
|
+ } else if (filter.text) {
|
|
|
+ item = container.locator(listItemSelector).filter({ hasText: filter.text }).first()
|
|
|
+ } else {
|
|
|
+ throw new Error("Invalid filter provided to clickListItem")
|
|
|
+ }
|
|
|
+
|
|
|
+ await expect(item).toBeVisible()
|
|
|
+ await item.click()
|
|
|
+ return item
|
|
|
+}
|
|
|
+
|
|
|
+export async function withSession<T>(
|
|
|
+ sdk: ReturnType<typeof createSdk>,
|
|
|
+ title: string,
|
|
|
+ callback: (session: { id: string; title: string }) => Promise<T>,
|
|
|
+): Promise<T> {
|
|
|
+ const session = await sdk.session.create({ title }).then((r) => r.data)
|
|
|
+ if (!session?.id) throw new Error("Session create did not return an id")
|
|
|
+
|
|
|
+ try {
|
|
|
+ return await callback(session)
|
|
|
+ } finally {
|
|
|
+ await sdk.session.delete({ sessionID: session.id }).catch(() => undefined)
|
|
|
+ }
|
|
|
+}
|