diff --git a/web/e2e/pages/live.page.ts b/web/e2e/pages/live.page.ts new file mode 100644 index 0000000000..814064944b --- /dev/null +++ b/web/e2e/pages/live.page.ts @@ -0,0 +1,55 @@ +/** + * Live dashboard + single-camera page object. + * + * Encapsulates selectors and viewport-conditional openers for the + * Live route. Does NOT own assertions — specs call expect on the + * locators returned from these getters. + */ + +import type { Locator, Page } from "@playwright/test"; +import { BasePage } from "./base.page"; + +export class LivePage extends BasePage { + constructor(page: Page, isDesktop: boolean) { + super(page, isDesktop); + } + + /** The camera card wrapper on the dashboard, keyed by camera name. */ + cameraCard(name: string): Locator { + return this.page.locator(`[data-camera='${name}']`); + } + + /** Back button on the single-camera view header (desktop text). */ + get backButton(): Locator { + return this.page.getByText("Back", { exact: true }); + } + + /** History button on the single-camera view header (desktop text). */ + get historyButton(): Locator { + return this.page.getByText("History", { exact: true }); + } + + /** All CameraFeatureToggle elements (active + inactive). */ + get featureToggles(): Locator { + // Use div selector to exclude NavItem anchor elements that share the same classes. + return this.page.locator( + "div.flex.flex-col.items-center.justify-center.bg-selected, div.flex.flex-col.items-center.justify-center.bg-secondary", + ); + } + + /** Only the active (bg-selected) feature toggles. */ + get activeFeatureToggles(): Locator { + // Use div selector to exclude NavItem anchor elements that share the same classes. + return this.page.locator( + "div.flex.flex-col.items-center.justify-center.bg-selected", + ); + } + + /** Open the right-click context menu on a camera card (desktop only). */ + async openContextMenuOn(cameraName: string): Promise { + await this.cameraCard(cameraName).first().click({ button: "right" }); + return this.page + .locator('[role="menu"], [data-radix-menu-content]') + .first(); + } +} diff --git a/web/e2e/pages/review.page.ts b/web/e2e/pages/review.page.ts new file mode 100644 index 0000000000..6d9cfb7c24 --- /dev/null +++ b/web/e2e/pages/review.page.ts @@ -0,0 +1,52 @@ +/** + * Review/events page object. + * + * Encapsulates severity tab, filter bar, calendar, and mobile filter + * drawer selectors. Does NOT own assertions. + */ + +import type { Locator, Page } from "@playwright/test"; +import { BasePage } from "./base.page"; + +export class ReviewPage extends BasePage { + constructor(page: Page, isDesktop: boolean) { + super(page, isDesktop); + } + + get alertsTab(): Locator { + return this.page.getByLabel("Alerts"); + } + + get detectionsTab(): Locator { + return this.page.getByLabel("Detections"); + } + + get motionTab(): Locator { + return this.page.getByRole("radio", { name: "Motion" }); + } + + get camerasFilterTrigger(): Locator { + return this.page.getByRole("button", { name: /cameras/i }).first(); + } + + get calendarTrigger(): Locator { + return this.page.getByRole("button", { name: /24 hours|calendar|date/i }); + } + + get showReviewedToggle(): Locator { + return this.page.getByRole("button", { name: /reviewed/i }); + } + + get reviewItems(): Locator { + return this.page.locator(".review-item"); + } + + /** The filter popover content (desktop) or drawer (mobile). */ + get filterOverlay(): Locator { + return this.page + .locator( + '[data-radix-popper-content-wrapper], [role="dialog"], [data-vaul-drawer]', + ) + .first(); + } +}