Etc

Page Object Models - Playwright

POM?

Playwright에서 제공하는 POM(Page Object Model) 개념은, 테스트 코드 작성의 용이성 및 유지 보수 관리를 최적화하면서 테스트 케이스를 작성할 수 있는 접근 방식중의 하나이다. class를 사용함으로써 중복을 줄이고 장황한 테스트 코드의 추상화를 통해 유지 관리를 단순화한다.



How?

Init

// playwright.dev 기준 작성
import { Locator, Page, expect } from '@playwright/test';

export class InitPage {
  readonly page: Page;
  private getStartedLocator: Locator;

  constructor({ page }: { page: Page }) {
    this.page = page;
    this.getStartedLocator = page.getByRole('heading', {
      name: 'Playwright enables reliable end-to-end testing for modern web apps.',
    });
  }

  async goto(link: string) {
    await this.page.goto(link);
  }

  async initializeToMainPage() {
    await this.goto('https://playwright.dev/');
    await expect(this.getStartedLocator).toBeVisible();
  }
}
  • 위와 같이, 테스트를 하고자 하는 페이지 인스턴스를 생성하는 클래스를 작성함으로써 캡슐화가 가능하다.
import { test, expect } from '@playwright/test';
import { InitPage } from './common/InitPage';

// before
test('test with normal test code', async ({ page }) => {
  const getStartedLocator = await page.getByRole('heading', {
    name: 'Playwright enables reliable end-to-end testing for modern web apps.',
  });

  await page.goto('https://playwright.dev/');
  await expect(getStartedLocator).toBeVisible();
});

// after
test('go to main page', async ({ page }) => {
  const testPage = new InitPage({ page });
  await testPage.initializeToMainPage();
});
  • POM을 적용한 이후의 코드가 가독성 및 유지 보수의 용이성의 측면에서 좋아졌다. 또한 테스트 케이스별 개별적인 인스턴스를 생성하기 때문에 테스트 케이스간의 의존성을 낮출 수 있었다.

Extends

import { Page, Locator, expect } from '@playwright/test';
import { InitPage } from './InitPage';

export class PageObjectModelPage extends InitPage {
  private pageObjectModelPageLocator: Locator;

  constructor({ page }: { page: Page }) {
    super({ page });

    this.pageObjectModelPageLocator = page.getByRole('heading', {
      name: 'Page object models',
    });
  }

  async initPageObjectModelPage() {
    await super.initializeToMainPage();
    await this.page.getByLabel('Search').click();
    await this.page.getByPlaceholder('Search docs').fill('page object');
    await this.page
      .getByRole('link', { name: 'Page object models', exact: true })
      .click();
    await expect(this.pageObjectModelPageLocator).toBeVisible();
  }
}
  • 테스트 케이스별, 기본적으로 필요한 메서드의 중복이 지속될 경우 상속으로 이를 개선할 수 있다.
import { test, expect } from '@playwright/test';
import { PageObjectModelPage } from './common/PageObjectModelPage';

// before
test('test with normal test code', async ({ page }) => {
  // InitPage 클래스에서 사용되던 locator
  const getStartedLocator = await page.getByRole('heading', {
    name: 'Playwright enables reliable end-to-end testing for modern web apps.',
  });

  await page.goto('https://playwright.dev/');
  await expect(getStartedLocator).toBeVisible();

  await page.getByLabel('Search').click();
  await page.getByPlaceholder('Search docs').fill('page object');
  await page
    .getByRole('link', { name: 'Page object models', exact: true })
    .click();
});

// after
test('go to page object models page', async ({ page }) => {
  const pageObjectModelPage = new PageObjectModelPage({ page });
  await pageObjectModelPage.initPageObjectModelPage();
});
  • 11번가의 Tech Talk을 통해 처음 접했을 때와 달리 직접 사용해보니, 사용 경험이 매우 만족스러움을 느꼈다.


Reference

'Etc' 카테고리의 다른 글

소스맵 정리  (0) 2023.09.28
TTF, OTF 폰트별 특징  (0) 2023.07.28
리액트와 함께하는 테스트 격리(번역)  (0) 2023.04.17
TIL | Reflow, Repaint  (0) 2022.08.28
TIL | 패키지 잠금파일  (1) 2022.03.26