Skip to content

Commit

Permalink
base page object model for proxying locator calls
Browse files Browse the repository at this point in the history
  • Loading branch information
fungairino committed Jun 28, 2024
1 parent c161881 commit 507ed70
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 36 deletions.
56 changes: 26 additions & 30 deletions end-to-end-tests/pageObjects/extensionsShortcutsPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import { expect, type Page } from "@playwright/test";
import { getModifierKey, getModifierSymbol } from "end-to-end-tests/utils";
import BasePageObject from "./pageObject";

function getExtensionShortcutsUrl(chromiumChannel: "chrome" | "msedge") {
switch (chromiumChannel) {
Expand All @@ -42,13 +43,14 @@ async function getShortcut(page: Page): Promise<string> {
return modifierKey === "Meta" ? `${modifierSymbol}M` : "Ctrl + M";
}

export class ExtensionsShortcutsPage {
export class ExtensionsShortcutsPage extends BasePageObject {
private readonly pageUrl: string;

constructor(
private readonly page: Page,
page: Page,
private readonly chromiumChannel: "chrome" | "msedge",
) {
super(page);
this.pageUrl = getExtensionShortcutsUrl(this.chromiumChannel);
}

Expand All @@ -57,88 +59,82 @@ export class ExtensionsShortcutsPage {
}

async goto() {
await this.page.goto(this.pageUrl);
await this.page().goto(this.pageUrl);

if (this.chromiumChannel === "chrome") {
await expect(
this.page.getByRole("heading", { name: /PixieBrix/ }),
this.getByRole("heading", { name: /PixieBrix/ }),
).toBeVisible();
} else {
await expect(this.page.getByText(/PixieBrix/)).toBeVisible();
await expect(this.getByText(/PixieBrix/)).toBeVisible();
}
}

async clearQuickbarShortcut() {
await this.page.bringToFront();
await this.page().bringToFront();

const shortcut = await getShortcut(this.page);
const shortcut = await getShortcut(this.page());

if (this.chromiumChannel === "chrome") {
await expect(this.page.getByPlaceholder(/shortcut set: /i)).toHaveValue(
await expect(this.page().getByPlaceholder(/shortcut set: /i)).toHaveValue(
shortcut,
);

// Clear the shortcut
await this.page.getByLabel("Edit shortcut Toggle Quick").click();
await this.page
.locator("extensions-keyboard-shortcuts #container")
.click();
await this.getByLabel("Edit shortcut Toggle Quick").click();
await this.locator("extensions-keyboard-shortcuts #container").click();

await expect(
this.page.getByLabel(/Shortcut Toggle Quick Bar for PixieBrix/, {
this.getByLabel(/Shortcut Toggle Quick Bar for PixieBrix/, {
exact: true,
}),
).toBeEmpty();
} else {
await expect(
this.page.getByLabel(
this.getByLabel(
/Type a shortcut that will Toggle Quick Bar for PixieBrix/,
),
).toHaveValue(shortcut);

await this.page.getByRole("button", { name: "Clear shortcut" }).click();
await this.getByRole("button", { name: "Clear shortcut" }).click();

await expect(
this.page.getByLabel(
this.getByLabel(
/Type a shortcut that will Toggle Quick Bar for PixieBrix/,
),
).toBeEmpty();
}
}

async setQuickbarShortcut() {
await this.page.bringToFront();
await this.page().bringToFront();

const modifierKey = await getModifierKey(this.page);
const shortcut = await getShortcut(this.page);
const modifierKey = await getModifierKey(this.page());
const shortcut = await getShortcut(this.page());

if (this.chromiumChannel === "chrome") {
await expect(
this.page.getByLabel(/Shortcut Toggle Quick Bar for PixieBrix/),
this.getByLabel(/Shortcut Toggle Quick Bar for PixieBrix/),
).toBeEmpty();

await this.page.getByLabel("Edit shortcut Toggle Quick").click();
await this.page
.getByPlaceholder("Type a shortcut")
.press(`${modifierKey}+m`);
await this.getByLabel("Edit shortcut Toggle Quick").click();
await this.getByPlaceholder("Type a shortcut").press(`${modifierKey}+m`);

await this.page
.locator("extensions-keyboard-shortcuts #container")
.click();
await this.locator("extensions-keyboard-shortcuts #container").click();

await expect(this.page.getByPlaceholder(/shortcut set: /i)).toHaveValue(
await expect(this.getByPlaceholder(/shortcut set: /i)).toHaveValue(
shortcut,
);
} else {
const shortcutLabel = /type a shortcut that will toggle quick bar/i;
const input = this.page.getByLabel(shortcutLabel);
const input = this.getByLabel(shortcutLabel);

await expect(input).toBeEmpty();

await input.click();
await input.press(`${modifierKey}+m`);

await this.page.getByText("Keyboard ShortcutsPixieBrix").click();
await this.getByText("Keyboard ShortcutsPixieBrix").click();

await expect(input).toHaveValue(shortcut);
}
Expand Down
10 changes: 4 additions & 6 deletions end-to-end-tests/pageObjects/floatingActionButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { type Page } from "@playwright/test";

export class FloatingActionButton {
constructor(private readonly page: Page) {}
import BasePageObject from "./pageObject";

export class FloatingActionButton extends BasePageObject {
async getActionButton() {
return this.page.getByRole("button", {
return this.getByRole("button", {
name: "Toggle the PixieBrix Sidebar",
});
}
Expand All @@ -35,7 +33,7 @@ export class FloatingActionButton {
const actionButton = await this.getActionButton();
await actionButton.hover();

const hideButton = this.page.getByRole("button", {
const hideButton = this.getByRole("button", {
name: "Hide Button",
});
await hideButton.click();
Expand Down
49 changes: 49 additions & 0 deletions end-to-end-tests/pageObjects/pageObject.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2024 PixieBrix, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { type Locator, type Page } from "playwright";

class BasePageObject implements Partial<Locator> {
private readonly baseLocator: Locator;
constructor(locatorOrPage: Locator | Page) {
if ("page" in locatorOrPage) {
this.baseLocator = locatorOrPage;
} else {
this.baseLocator = locatorOrPage.locator("body");
}

return new Proxy(this, {

Check failure on line 29 in end-to-end-tests/pageObjects/pageObject.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected return statement in constructor
get: function (target, prop, receiver) {

Check failure on line 30 in end-to-end-tests/pageObjects/pageObject.ts

View workflow job for this annotation

GitHub Actions / lint

Expected method shorthand
if (Reflect.has(target, prop)) {
return Reflect.get(target, prop, receiver);
} else if (Reflect.has(target.baseLocator, prop)) {

Check failure on line 33 in end-to-end-tests/pageObjects/pageObject.ts

View workflow job for this annotation

GitHub Actions / lint

Unnecessary 'else' after 'return'
if (typeof target.baseLocator[prop] === "function") {
return function (...args) {
return target.baseLocator[prop].apply(target.baseLocator, args);

Check failure on line 36 in end-to-end-tests/pageObjects/pageObject.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe return of an `any` typed value

Check failure on line 36 in end-to-end-tests/pageObjects/pageObject.ts

View workflow job for this annotation

GitHub Actions / lint

Use the spread operator instead of '.apply()'

Check failure on line 36 in end-to-end-tests/pageObjects/pageObject.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe call of an `any` typed value
};
} else {

Check failure on line 38 in end-to-end-tests/pageObjects/pageObject.ts

View workflow job for this annotation

GitHub Actions / lint

Unnecessary 'else' after 'return'
return target.baseLocator[prop];

Check failure on line 39 in end-to-end-tests/pageObjects/pageObject.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe return of an `any` typed value
}
}
},
});
}
}

export default BasePageObject as unknown as new (
locatorOrPage: Locator | Page,
) => Locator;

0 comments on commit 507ed70

Please sign in to comment.