테스트 작성하기

테스트 작성하기 (Writing Tests)

Playwright 테스트는 크게 두 가지 동작으로 이루어져요. 어떤 액션을 수행하고, 그 결과로 **상태가 기대와 맞는지 단언(assert)**하는 거죠. 테스트를 직접 작성해 보기 전에, Playwright가 어떤 철학으로 테스트를 단순하게 만드는지 먼저 보면 좋아요. 액션을 수행하기 전에 그 요소가 조작 가능한 상태에 도달할 때까지 Playwright가 자동으로 기다려 줘서, 수동 대기나 경쟁 조건을 신경 쓸 필요가 없어요.

출처: Writing tests — Playwright 공식 문서

첫 테스트

테스트 파일 하나를 예시로 보면서 구조를 익혀 볼게요. testexpect@playwright/test에서 가져와서, 페이지에 접속한 뒤 제목이 특정 문자열을 포함하는지 확인하는 단언을 넣은 모습이에요.

import { test, expect } from '@playwright/test';

test('has title', async ({ page }) => {
  await page.goto('https://playwright.dev/');

  // Expect a title "to contain" a substring.
  await expect(page).toHaveTitle(/Playwright/);
});

test('get started link', async ({ page }) => {
  await page.goto('https://playwright.dev/');

  // Click the get started link.
  await page.getByRole('link', { name: 'Get started' }).click();

  // Expects page to have a heading with the name of Installation.
  await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible();
});

VS Code에서 JavaScript로 작성한다면 각 테스트 파일 맨 위에 // @ts-check를 붙여 주면 자동 타입 체크를 받을 수 있어요.

액션

내비게이션

대부분의 테스트는 URL로 이동하는 것으로 시작해요. 페이지가 load 상태에 도달할 때까지 Playwright가 기다린 뒤 다음 단계로 진행해요.

await page.goto('https://playwright.dev/');
page.goto("https://playwright.dev/")

상호작용

요소를 조작하려면 먼저 그 요소를 찾아야 하는데, Playwright는 이때 Locators API를 사용해요. 로케이터는 페이지에서 요소를 찾아내는 방법 자체를 나타내며, 그 시점의 상태와 무관하게 항상 동작해요. 액션을 수행하기 전에도 요소가 조작 가능한 상태가 될 때까지 Playwright가 기다려 주니, 직접 대기 코드를 넣을 필요가 없어요.

// Create a locator.
const getStarted = page.getByRole('link', { name: 'Get started' });

// Click it.
await getStarted.click();

대부분은 한 줄로 합쳐 써요.

await page.getByRole('link', { name: 'Get started' }).click();

기본 액션

자주 쓰는 액션을 몇 가지 정리하면 이러해요. 전체 목록은 Locator API 문서에서 볼 수 있어요.

액션 설명
Locator.check 체크박스에 체크
Locator.click 요소 클릭
Locator.uncheck 체크박스 체크 해제
Locator.hover 요소에 마우스 호버
Locator.fill 폼 필드에 텍스트 입력
Locator.focus 요소에 포커스
Locator.press 단일 키 누르기
Locator.setInputFiles 업로드할 파일 선택
Locator.selectOption 드롭다운에서 옵션 선택

단언

Playwright는 expect 함수 형태의 테스트 단언을 제공해요. expect(value)를 호출하고 기대를 반영하는 매처(matcher)를 고르면 돼요. async 매처는 기대 조건이 충족될 때까지 대기하기 때문에 테스트가 매끄럽고(flaky) 경쟁 조건에 취약하지 않아요. 예를 들어 이 코드는 페이지 제목에 "Playwright"가 들어갈 때까지 기다려요.

await expect(page).toHaveTitle(/Playwright/);

자주 쓰는 async 단언 몇 가지를 표로 정리했어요.

단언 설명
LocatorAssertions.toBeChecked 체크박스가 체크됨
LocatorAssertions.toBeEnabled 컨트롤이 활성화됨
LocatorAssertions.toBeVisible 요소가 보임
LocatorAssertions.toContainText 요소가 텍스트를 포함
LocatorAssertions.toHaveAttribute 요소가 속성을 가짐
LocatorAssertions.toHaveCount 요소 목록의 길이
LocatorAssertions.toHaveText 요소가 텍스트와 일치
LocatorAssertions.toHaveValue 입력 요소의 값
PageAssertions.toHaveTitle 페이지 제목
PageAssertions.toHaveURL 페이지 URL

toEqual, toContain, toBeTruthy 같은 범용 매처로도 아무 조건이나 단언할 수 있어요. 이들은 이미 값이 준비된 상태에서 즉시 동기적으로 확인하므로 await 키워드를 쓰지 않아요.

expect(success).toBeTruthy();

테스트 격리

Playwright Test는 테스트 픽스처라는 개념에 기반을 두고 있으며, 대표적인 게 테스트에 전달되는 내장 page 픽스처예요. 페이지는 브라우저 콘텍스트 덕분에 테스트 간에 서로 격리돼요 — 마치 완전히 새로운 브라우저 프로필을 쓰는 것과 같죠. 같은 브라우저에서 여러 테스트가 돌아도 각 테스트는 항상 깨끗한 환경을 받아요.

import { test } from '@playwright/test';

test('example test', async ({ page }) => {
  // "page" belongs to an isolated BrowserContext, created for this specific test.
});

test('another test', async ({ page }) => {
  // "page" in this second test is completely isolated from the first test.
});

테스트 훅 사용하기

test.describe로 테스트 그룹을 묶고, test.beforeEach·test.afterEach로 각 테스트 전후에 실행되는 코드를 선언할 수 있어요. test.beforeAll·test.afterAll은 워커 하나당 전체 테스트 앞뒤로 한 번씩만 실행되고요. 아래처럼 describe 안에서 번거로운 준비 코드를 한곳에 모아 두면 각 테스트는 핵심만 남겨요.

import { test, expect } from '@playwright/test';

test.describe('navigation', () => {
  test.beforeEach(async ({ page }) => {
    // Go to the starting url before each test.
    await page.goto('https://playwright.dev/');
  });

  test('main navigation', async ({ page }) => {
    // Assertions use the expect API.
    await expect(page).toHaveURL('https://playwright.dev/');
  });
});

더 알아보기