본문으로 건너뛰기

11.2 Todo 핵심 Journey

Capstone Todo journey의 학습용 실행 화면

Page object는 의미 있는 action만 노출한다

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

export class TodoPage {
constructor(private readonly page: Page) {}

async goto() {
await this.page.goto('/');
await expect(this.page.getByRole('heading', { name: 'Todo Lab' })).toBeVisible();
}

async add(title: string) {
await test.step(`Todo 추가: ${title}`, async () => {
await this.page.getByLabel('할 일', { exact: true }).fill(title);
await this.page.getByRole('button', { name: '추가' }).click();
}, { box: true });
}

item(title: string) {
return this.page.getByRole('listitem').filter({ hasText: title });
}
}

clickAddButton()처럼 UI detail을 그대로 노출하면 test가 business story를 설명하지 못합니다.

Journey test

test('CAP-TODO-001 Todo를 만들고 완료한다 @smoke', async ({ page }) => {
const todos = new TodoPage(page);
await todos.goto();
await todos.add('Playwright capstone');

const item = todos.item('Playwright capstone');
await expect(item).toBeVisible();
await item.getByRole('checkbox').check();
await expect(item.getByRole('checkbox')).toBeChecked();
});

Boundary cases

  • 공백 title
  • 매우 긴 title
  • 같은 title 중복
  • Unicode와 emoji
  • 빠른 double submit
  • Re-render 중 checkbox action

E2E에는 대표 경계만 두고 나머지 data 조합은 component/unit test로 내립니다.

Fixture로 기본 상태 제공

export const test = base.extend<{ todoPage: TodoPage }>({
todoPage: async ({ page }, use) => {
const todoPage = new TodoPage(page);
await todoPage.goto();
await use(todoPage);
},
});

Fixture가 test가 필요하지 않은 data를 무조건 생성하지 않게 lazy하고 composable하게 유지합니다.

진단 연습

  1. Button label을 바꾸어 locator failure를 만듭니다.
  2. Summary API를 2초 늦추고 manual sleep 없이 통과하는지 확인합니다.
  3. Checkbox 위에 overlay를 표시해 actionability log를 읽습니다.
  4. 실패 trace에서 before/after DOM snapshot을 비교합니다.

실행 파일: todo.spec.ts, todo-page.ts

참고: Page object models, Fixtures, Best Practices