프론트 프로젝트 규모가 커질수록 기능을 추가할 때마다 사이드 이펙트가 생기는 일이 빈번해진다. 버그들을 자동으로 잡을 수 있는 테스트 툴을 알아보다가 사수님이 Playwright라는 것을 알려주셔서 새로 도전하는 사이드 프로젝트에 이것을 도입하려 보려고 한다. Playwright에 대해 공부하면서 내용을 정리해본다.
E2E Test
E2E(End to End) Test는 애플리케이션이 예상대로 동작하는지 확인하는 테스트를 말한다.
사용자 사용 시나리오을 시뮬레이션하며 제품의 동작을 테스트 하는 것!
위에서 언급했듯이 프로젝트 규모가 작을 때는 테스트 할 범위가 좁아서 버그들이 눈에 띄지만 그 규모가 커질수록 기능 추가 및 수정으로 발생하는 사이드 이펙트를 발견하기 어려워진다. 또한 운영체제나 브라우저 등 사용 환경에 따라 발생할 수 있는 버그가 있는에 개발을 하면서 이 모든 것들을 체크하기 매우 어렵다. 그래서 테스트 코드를 작성하여 이를 자동화하기 위해 Playwright를 사용한다.
Playwright
Cypress라는 것도 E2E 테스트 기능을 제공하는 툴로 유명하다고 한다. 하지만 별 이유는 없이 Playwright가 더 땡겨서 이걸 써보려고 한다. 기회가 된다면 Cypress도 사용해서 비교해봐야겠다.
지원 브라우저
- Webkit 기반 브라우저
- 크롬
- 파이어폭스
- 사파리
- 모바일 브라우저 (cypress는 안된다고 한다)
테스트 속도
동시에 수행가는 것들은 병렬로 실행된다.
cypress는 기본적으로 직렬로 실행되어 개수가 많아질수록 오래걸리고 돈을 내야 병렬로 실행할 수 있다고 한다 못됐어
Playwright 기본 문법
실행 명령어
굉장히 다양하게 제공한다. 참고
// 1. 모든 테스트 파일 실행
$ npx playwright test
// 2. 단일 테스트 실행
$ npx playwright test tests/todo-page.spec.ts
// 3. 폴더 단위 테스트 실행
$ npx playwright test tests/todo-page/ tests/landing-page/
// 4. 특정 키워드가 파일명에 포함된 테스트 실행
$ npx playwright test my-spec my-spec-2
// 5. 특정 파일의 특정 라인 실행
$ npx playwright test my-spec.ts:42
// 6. 제목과 함께 테스트 실행
// -- 스크립트로 테스트 실행을 자동화해둘 때 제목을 지정해두면 나중에 로그 보기가 더 편할 것 같다.
$ npx playwright test -g "add a todo item"
// 7. 특정 브라우저에서 테스트 실행
$ npx playwright test --browser=<all/firefox/등 지원 브라우저>
테스트 코드 예시
첫번째.
import { test, expect } from '@playwright/test';
const url = '테스트를 수행할 페이지 URL';
test.beforeEach(async ({ page }) => {
await page.goto(url);
});
test('입력창에 값을 입력한 뒤 엔터를 누르면 할일이 추가된다.', async ({ page }) => {
await page.click('.header input');
await page.keyboard.type('todo 1');
await page.keyboard.press('Enter');
await page.keyboard.type('todo 2');
await page.keyboard.press('Enter');
// https://playwright.dev/docs/locators#locate-by-css-or-xpath
const list = page.locator('css=.todo-list li');
await expect(list).toHaveCount(2);
await expect(list.first()).toHaveText('todo 1');
});
출처: https://velog.io/@heelieben/E2E-%ED%85%8C%EC%8A%A4%ED%8A%B8-PlayWright-2eub88ik
playwright에서 제공하는 test라는 메소드의 첫번째 인자로 테스트할 제목을 전달한다. 이때 테스트하는 단위를 기능 명세서의 기능 하나로 생각하면 좋을 것 같다.
playwright는 async, await로 비동기 동작을 지원해서 javascript 문법에 익숙한 사람들에게는 조금 더 편리한 문법이라고 생각한다.
test 함수 내에서 실행되어야 하는 동작들을 정의하고 expect 함수로 동작의 결과를 예측하는 방식인가보다.
두번째.
공식문서에서 제공하는 예제를 가져와봤다.
const REPO = 'test-repo-1';
const USER = 'github-username';
test('should create a bug report', async ({ request }) => {
const newIssue = await request.post(`/repos/${USER}/${REPO}/issues`, {
data: {
title: '[Bug] report 1',
body: 'Bug description',
}
});
expect(newIssue.ok()).toBeTruthy();
const issues = await request.get(`/repos/${USER}/${REPO}/issues`);
expect(issues.ok()).toBeTruthy();
expect(await issues.json()).toContainEqual(expect.objectContaining({
title: '[Bug] report 1',
body: 'Bug description'
}));
});
test('should create a feature request', async ({ request }) => {
const newIssue = await request.post(`/repos/${USER}/${REPO}/issues`, {
data: {
title: '[Feature] request 1',
body: 'Feature description',
}
});
expect(newIssue.ok()).toBeTruthy();
const issues = await request.get(`/repos/${USER}/${REPO}/issues`);
expect(issues.ok()).toBeTruthy();
expect(await issues.json()).toContainEqual(expect.objectContaining({
title: '[Feature] request 1',
body: 'Feature description'
}));
});
출처: https://playwright.dev/docs/test-api-testing
다음과 같이 config 파일에 api endpoint를 baseURL이라는 속성에 설정하고 extraHTTPHeaders라는 속성에 기본 헤더값을 설정할 수 있다.
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
// All requests we send go to this API endpoint.
baseURL: 'https://api.github.com',
extraHTTPHeaders: {
// We set this header per GitHub guidelines.
'Accept': 'application/vnd.github.v3+json',
// Add authorization token to all requests.
// Assuming personal access token available in the environment.
'Authorization': `token ${process.env.API_TOKEN}`,
},
}
});
config 파일이 아니라 테스트 파일 내에 개별적으로 baseURL과 요청 관련 옵션을 설정할 수도 있다.
const { request } = require('@playwright/test');
const REPO = 'test-repo-1';
const USER = 'github-username';
(async () => {
// Create a context that will issue http requests.
const context = await request.newContext({
baseURL: 'https://api.github.com',
});
// Create a repository.
await context.post('/user/repos', {
headers: {
'Accept': 'application/vnd.github.v3+json',
// Add GitHub personal access token.
'Authorization': `token ${process.env.API_TOKEN}`,
},
data: {
name: REPO
}
});
// Delete a repository.
await context.delete(`/repos/${USER}/${REPO}`, {
headers: {
'Accept': 'application/vnd.github.v3+json',
// Add GitHub personal access token.
'Authorization': `token ${process.env.API_TOKEN}`,
}
});
})()
출처: https://playwright.dev/docs/test-api-testing
자세한 사항은 공식 문서를 참고해서 실습을 해봐야할 것 같다. 윽
References
'웹 개발 > Web Development' 카테고리의 다른 글
디자인 패턴) Proxy Pattern (0) | 2023.07.07 |
---|---|
디자인 패턴) Singleton Pattern (0) | 2023.06.25 |
Vuepress란 무엇인가 (0) | 2023.02.06 |
/etc/hosts 로컬에서 ip 주소 호스트네임 등록해 두고 사용하기 (0) | 2021.06.16 |
웹 개발) 브라우저 저장소 Web Storage (0) | 2021.04.09 |