본문으로 건너뛰기

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