피그마 UI를 보다가, 기능정의서로 돌아가서 어디로 이동시켜야하는지, 어디서 모달이 열려야하는지 확인하고, 다시 피그마 UI로 돌아가면서 코드를 작성했다. 초반에는 이게 당연한 것이기 때문에 번거로워도 감당해야하는 부분이라고 생각했다.
하지만 UT 테스트를 진행하면서 UI와 기능이 생각보다 많이 바뀌었다. 그러다보니 변경된 기능과 기존의 기능이 헷갈려서 전부 다시 확인해야하는 일이 있었다. 애초에 해커톤 때 기능을 반영하지 못한 부분도 많아서 업보긴 했지만, 기존의 기능을 만날 때마다 불편함이 있었다. 그러다 유닛 테스트처럼 케이스를 명시해보자는 마음으로 PlayWright를 도입했다. 사실 최근 인기있는 라이브러리라는 말+스토리북을 이김에 한번 사용해본 것도있다..
도입한 이유
기능정의서가 초반에 엑셀로 명시되고, UI가 완성된 이후에는 화면 명세서가 만들어졌다. 해커톤때는 구현하는데 바빠서 일단 보이는 기능들을 하나씩 해치워나갔다. 그러다보니 디벨롭 과정에서 반영되지 않은 기능들과 새로 추가된 기능들이 뒤섞이면서 하나씩 파악하는게 조금 힘들었다..
따라서 기능의 구현여부를 테스트코드를 통해서 알아보고자 하였다. 그중 다양한 브라우저를 지원하고 나중에 다른 언어로도 사용할 수 있어서 최근 인기를 얻고 있는 PlayWright를 채택하여 도입하였다.
Playwright
Microsoft에서 개발한 오픈 소스 테스트 자동화 프레임워크
주로 웹 애플리케이션의 자동화 테스트에 사용
다양한 브라우저와 플랫폼에서 동작하는 테스트를 작성하고 실행가능
- Chromium, Firefox, WebKit을 포함한 주요 브라우저를 모두 지원
- JavaScript, TypeScript, Python, C#, Java 등의 언어를 지원
- 자동으로 페이지 로딩, 요소 렌더링, 네트워크 활동 등의 이벤트를 감지하여 필요한 시점에 테스트를 진행하도록 대기
적용해보자
import { expect, test } from '@playwright/test';
test.describe('레이아웃 컴포넌트를 테스트한다', () => {
let page;
test.beforeAll(async ({ browser, contextOptions }) => {
const browserContext = await browser.newContext(contextOptions);
page = await browserContext.newPage();
await page.goto('https://www.startupvalley.site/');
});
test('document title이 올바르다', async () => {
await expect(page).toHaveTitle('Startup Valley');
});
test('footer의 copyright가 올바르다', async () => {
const copyrightFooter = await page.locator('body > footer > div > div > p.copyright');
const validCopyright = '@2024 startupvalley.all rights reserved';
await expect(copyrightFooter).toHaveText(validCopyright);
});
test('accessToken이 없을 때 로그인 버튼을 누르면 로그인 페이지로 이동한다', async () => {
await page.click('body > header > div > nav > div > a:nth-child(3)');
await expect(page).toHaveURL('https://www.startupvalley.site/login');
});
test('accessToken이 있을 때 팀 변경 버튼을 누르면 모달이 뜬다', async () => {
await page.click('body > header > div > nav > div > a:nth-child(3)');
await expect(page).toHaveId('portal-modal');
});
});
처음에 어색한 문법에 익숙해지다보면 생각보다 쉽게 테스트 코드를 작성할 수 있다.
import { expect, test } from '@playwright/test';
test.describe('랜딩 페이지(LD)를 테스트한다', () => {
let page;
test.beforeAll(async ({ browser, contextOptions }) => {
const browserContext = await browser.newContext(contextOptions);
page = await browserContext.newPage();
await page.goto('https://www.startupvalley.site/');
});
test('LD-2. 디스코드 봇 추가하기 버튼을 누르면 디스코드봇 연결 페이지가 나온다', async () => {
await page.click('body > header > div > nav > div > a:nth-child(3)');
await expect(page).toHaveURL(
'https://discord.com/oauth2/authorize?client_id=1214574551820800040&permissions=8&scope=bot',
);
});
test('LD-3. footer의 노션 텍스트를 클릭하면 노션 페이지로 이동한다', async () => {
await page.click('body > footer > div > nav > div');
await expect(page).toHaveURL('https://www.startupvalley.site/login');
});
});
처음에는 이런 기능까지 테스트 코드로 작성해야하나 싶었는데, 중간에 놓친 기능들을 추가할 수 있어서 생각보다 만족스러웠다.
npx playwright test
테스트를 실행하면 다음과 같은 결과가 CLI와 UI로 나온다.
사실 생각보다 작성이 금방 끝나서 이렇게 하는게 맞나 싶지만, 어쨌든 기능들을 좀 더 명확히 구성할 수 있었다. 다른 사람들이 확실히 구현하였는지도 테스트 코드를 통해서 이해할 수 있어 보인다. 그러나 작은 프로젝트에는 도입하지 않는게 맞는것으로 보인다. 사실 아직 모든 기능을 다 명시하지도 못했다. 결론적으로 만족도는 4.0점이다. 일단 프론트 같은 경우 api 연결을 하다보면 어디까지 했는지 말하기가 굉장히 모호한데, 기능 구현 여부를 제시할 수 있어서 편했다. 그리고 어쨌든 1년 간 서비스를 운영하기로 했기 때문에, 추후 디벨롭 과정에서 편할 것이라는게 보인다.
장점
기능명세서의 요구사항이 코드화된다
브라우저를 켜서 사용자 액션을 해보지 않아도 된다
기능정의서가 버전업되었을 때 버전업을 기록해놓을 수 있다
변경된 기능들을 하나씩 해보지 않아도 기존의 기능과 추가된 변경 명시를 비교하여 확인할 수 있다.
UI 변경을 다른 분께 요청했을때, 기능도 같이 유지된다는 것을 자동으로 확인할 수 있다
구현 완료된 기능들과 남은 기능들을 말이 아닌 결과로 보여줄 수 있다
단점
보일러플레이트가 엄청 큰건 아니지만, 비용이 든다.
해당 노드의 위치를 직접 파악하고 코드에 반영해야한다.
'트러블이슈' 카테고리의 다른 글
XSS 공격을 막아보자 (0) | 2024.08.08 |
---|---|
테스트 코드 도입기 (0) | 2024.07.17 |
시도를 해보자 (0) | 2024.07.08 |
프로젝트 구조 변경하기 (0) | 2024.07.06 |
Lighthouse로 성능 개선하기 (0) | 2024.07.04 |