links:: advanced Playwright MOC

Chapter 2 - Dynamic Page Objects and Fixtures

Chapter 2 - Dynamic Page Objects and Fixtures

Dynamic Page Objects

hooks.ts:

import { Page } from '@playwright/test';
import { buildUrl } from './uiUrlBuilder';
import BookPage from '../ui/pages/book-page';
import LoginPage from '../ui/pages/login-page';
import ProfilePage from '../ui/pages/profile-page';

async function beforeEach(
  page: Page,
  PageObjectParam: LoginPage|BookPage|ProfilePage,
  targetPage: string,
  params?: Record<any, any>
) {
  await page.goto(buildUrl(targetPage, params));
  const pageObject = await new PageObjectParam(page);
  return pageObject;
}

export default { beforeEach };

uiUrlBuilder.ts:

import uiPages from '../utils/uiPages';

export function buildUrl(page: string, params?: Record<any, any>) {
  const uiPath = uiPages[page];
    
  const qParams = new URLSearchParams(params);
  
  const url = params
  ? `${uiPath.concat('?')}${qParams.toString()}`
  : uiPath;

  /**
    * page  bookStore
    * uiPath  /books
    * params  { book: '9781449337711' }
    * qParams  URLSearchParams { 'book' => '9781449337711' }
    * url  /books?book=9781449337711
  */

  return url;
}

profile-with-dynamic-pom.spec.ts:

import { test } from '@playwright/test';
import ProfilePage from '../pages/profile-page';
import hooks from '../../utils/hooks';
import pages from '../../utils/pages';

let profilePage: ProfilePage;

test.beforeEach(async ({ page }) => {
    // await page.goto(pages.profile);
    // profilePage = new ProfilePage(page);
    profilePage = await hooks.beforeEach(page, ProfilePage, pages.profile);
});

test.describe('Profile - Dynamic Page Object Model', () => {
    test('Check logged in', async () => {
        await profilePage.checkLoggedIn();
    });
});

Fixtures

// book-store-fixture.ts
import { test as base } from "@playwright/test";
import BookStorePage from "../pages/book-store-page";
import hooks from "../../utils/hooks";
import pages from "../../utils/pages";

type MyFixtures = {
  bookStorePage: BookStorePage;
};

export const test = base.extend<MyFixtures>({
  bookStorePage: async ({ page }, use) => {
    const bookStorePage = await hooks.beforeEach(
      page,
      BookStorePage,
      pages.bookStorePage
    );

    await use(bookStorePage);
  },
});

export { expect } from "@playwright/test";

//book-store-page.ts
import { type Page, type Locator, expect } from "@playwright/test";

class BookStorePage {
  readonly page: Page;
  readonly searchInput: Locator;
  readonly logoutButton: Locator;
  readonly userNameLabel: Locator;
  readonly resultRows: Locator;
  readonly resultCellsImage: Locator;
  readonly resultCellsTitle: Locator;
  readonly header: Locator;

  constructor(page: Page) {
    this.page = page;
    this.searchInput = page.getByPlaceholder(/type to search/i);
    this.userNameLabel = page.locator("#userName-value");
    this.resultRows = page.getByRole("row");
    this.resultCellsTitle = page.getByRole("row").getByRole("link");
    this.header = page.getByText("Book Store", { exact: true }).first();
  }

  async typeToSearch(searchQuery: string) {
    if (searchQuery) {
      await this.searchInput.fill(searchQuery);
    }
  }

  async checkSearchResultsTitles(expectedTitles: string[]) {
    await expect(this.resultCellsTitle as Locator).toHaveText(expectedTitles);

    console.log(await (this.resultCellsTitle as Locator).all());

    (await (this.resultCellsTitle as Locator).all()).map(
      async (title) => await expect(title).not.toBeVisible()
    );
  }
  async checkHeader() {
    await expect(this.header).toHaveText("Book Store");
    await expect(this.header).toBeVisible();
  }
}

export default BookStorePage;

//book-store.spec.ts
import { test } from "../fixtures/books-store-fixture";

test.describe.configure({ mode: "serial" });

const EXPECTED_SEARCH_RESULTS = {
  java: {
    query: "java",
    expectedTitles: [
      "Learning JavaScript Design Patterns",
      "Speaking JavaScript",
      "Programming JavaScript Applications",
      "Eloquent JavaScript, Second Edition",
    ],
  },
};

test.describe("Book store  - Fixture", () => {
  test("Open book store pages", async ({ bookStorePage }) => {
    await bookStorePage.checkHeader();
  });

  test.only("Search java books in Book store", async ({ bookStorePage }) => {
    await bookStorePage.typeToSearch("java");
    await bookStorePage.checkSearchResultsTitles(
      EXPECTED_SEARCH_RESULTS.java.expectedTitles
    );
  });
});