글 목록
- 사용자 동작을 중심으로 Playwright로 E2E 테스트 작성하기 - Part 1
- 사용자 동작을 중심으로 Playwright로 E2E 테스트 작성하기 - Part 2
- 사용자 동작을 중심으로 Playwright로 E2E 테스트 작성하기 - Part 3
Intro.
이번 Part 2에서는 Playwright에 대한 소개와 E2E 테스트 코드 작성 시의 경험과 생각을 공유하고자 합니다.
Playwright 관련 자료
Playwright를 학습하는 동안 여러 가지 자료들을 참고하였습니다. 그중에서도 유용하게 활용한 자료들은 다음과 같습니다.
공식문서
어떤 기술이든 공식 문서가 최우선입니다. Playwright 공식 문서에서 Getting Started 메뉴의 내용을 튜토리얼처럼 따라 하면서, 기본적인 설치 방법, 간단한 테스트 코드 작성, 테스트 실행, HTML 테스트 레포트 등을 실제로 경험할 수 있습니다.
기타 레퍼런스
Microsoft 문서 중 Microsoft Playwright Testing 설명서를 참고하여 다양한 레퍼런스를 얻을 수 있었습니다. 또한 Playwright Github에서는 릴리즈 내용, 버그, 이슈에 대한 정보를 얻을 수 있습니다. 책, 영상, 강의, 블로그 글 등을 통해서도 Playwright를 학습하는 데 도움을 받았습니다.
프로젝트 및 파일 구조
Playwright로 구성된 프로젝트의 구조와 파일의 설명은 다음과 같습니다.
ㄴ .gitlab // gitlab pipeline script가 존재
ㄴ .husky
ㄴ e2e // 테스트 폴더
ㄴ dataAnalysis.spec.ts
ㄴ login.spec.ts
ㄴ trendAnalysis.spec.ts
ㄴ digitalTwin.spec.ts
ㄴ global.setup.ts // 전역 설정 파일
ㄴ global.teardown.ts // 전역 설정해제 파일
ㄴ //...
ㄴ node_modules
ㄴ .env // 전역 변수
ㄴ .eslintrc.json
ㄴ .gitignore
ㄴ playwright.config.ts // playwright 설정 파일
ㄴ tsconfig.json
ㄴ README.md
*.spec.ts 파일
테스트 코드를 작성하는 파일입니다. 각 테스트 파일은 기본적으로 하나의 메뉴 테스트를 담당하고 있습니다. 메뉴 테스트의 일부가 반복되는 경우 중복되는 테스트 함수를 모듈화하였습니다.
전역 설정 파일
global.setup.ts
와 global.teardown.ts
파일은 전역 설정을 등록하거나 해제하는 데 사용됩니다.
전역 설정과 해제에 대한 자세한 내용은 여기에서 확인할 수 있습니다.
playwright.config.ts 파일
playwright.config.ts
파일은 Playwright 테스트를 위한 설정 파일입니다.
기본적인 설정은 여기에서 확인할 수 있습니다.
- 테스트 파일 디렉토리, 테스트 파일 매치, 테스트 병렬 실행, retry, worker 제한 개수, 전역 설정, 전역 해제 설정 등을 설정할 수 있습니다.
- 브라우저 옵션, 전역 timeout 옵션, 에뮬레이션 옵션, 네트워크 옵션, 레코딩(screenshot, trace, video) 옵션, viewport 등을 설정할 수 있습니다.
전역 설정/해제 구성 방식
Playwright 테스트에서 전역 설정과 해제를 구성하는 방식은 크게 두 가지입니다.
- Project Dependencies
- Configure globalSetup, globalTeardown
두 방식 각각에는 장단점이 존재하며, 공식 문서에서는 테스트 독립성, 추적, 레포트 등의 이유로 Project Dependencies 방식을 권장하고 있습니다. 하지만 저는 Configure globalSetup, globalTeardown 방식을 사용하였는데, 그 이유로는 다음과 같습니다.
- 전역 설정이나 해제할 내용이 많지 않고, 거의 모든 테스트에 동일한 전역 설정과 해제를 하는 환경이었습니다.
- 복잡한 디펜던시 설정이 필요하지 않는 단순한 프로젝트 환경이었습니다.
- 전역 설정/해제 파일을 분리하고 해당 파일만 업데이트하는 편리성이 있었습니다.
- Project Dependencies 환경에서는 코드를 새로 작성하거나 수정하고 테스트를 실행할 때마다 매 번 디펜던시 테스트가 실행되는 오버헤드가 존재합니다.
E2E 코드 작성
E2E 테스트 코드를 작성하면서 익힌 노하우와 유용한 팁을 공유하려고 합니다. 기본적으로 메뉴마다 하나의 테스트 파일로 구성하는 규칙을 채택하였습니다.
테스트 그룹화
각 메뉴에는 다양한 사용자 시나리오가 존재합니다. 이러한 사용자 시나리오를 E2E 테스트 코드로 옮겨보면 대부분의 시나리오(또는 코드)에서 반복되는 패턴을 발견할 수 있었습니다.
사용자 시나리오와 매칭되는 E2E 코드 예시
- 사용자는 메인 화면을 볼 수 있다. -> 메인 화면의 특정 요소가 정상적으로 렌더링된다.
- 사용자는 (메인 화면의) 헤더 영역을 볼 수 있다. -> 메인 화면의 특정 요소가 정상적으로 렌더링된다. + 메인 화면의 헤더 영역의 특정 요소가 정상적으로 렌더링된다.
- 사용자는 (메인 화면의 헤더 영역에서) 트레인 뷰 타입을 변경할 수 있다 -> 메인 화면의 특정 요소가 정상적으로 렌더링된다. + 메인 화면의 헤더 영역의 특정 요소가 정상적으로 렌더링된다. + 메인 화면에서 헤더 영역의 트레인 뷰 타입의 요소가 정상적으로 렌더링되며, 뷰 타입을 클릭 이벤트로 변경할 수 있다.
test(), test.describe() 중첩
반복되는 패턴을 관리하기 위해 test(), test.describe() API를 사용하여 중첩된 테스트 구조를 구성하였습니다. 아래 이미지는 중첩된 테스트를 UI 모드에서 본 이미지입니다.
playwright 레포트
화면에 특정 요소가 렌더링되면 해당 화면이 사용자에게 시각적으로 표시된다는 의미입니다. 이 시나리오들은 단순하면서도 하위 시나리오에서 반복되어 사용됩니다.
playwright에서 제공되는 레포트에서는 중첩된 테스트명을 >
특수문자를 사용하여 나열하고 있습니다.
모든 시나리오를 테스트명으로 나열하게 되면 가시성이 낮아지게 됩니다.
이를 개선하기 위해 반복되는 시나리오를 모두 나열하기보다는 어느 영역인지 표시해 주도록 정의하였습니다.
AS-IS] 사용자는 메인 화면을 볼 수 있다. > 사용자는 헤더 영역을 볼 수 있다. > 사용자는 트레인 뷰 타입을 변경할 수 있다.
TO-BE] 메인 화면 > 헤더 영역 > 사용자는 트레인 뷰 타입을 변경할 수 있다.
test.beforeEach(), test.afterEach() 훅
beforeEach(), afterEach() 훅은 실행 코드가 속한 스코프에 있는 모든 하위의 test에 대해 전/후처리를 실행하는 API입니다. 이 훅을 잘 활용하면 반복되는 테스트 코드를 재사용할 수 있습니다.
조건부 테스트
test.skip()
, test.fail()
이나 return
을 활용하면 테스트를 중단할 수 있습니다.
특정 조건이 성립될 경우 테스트를 skip하거나 fail 처리를 할 수 있습니다.
중첩된 구조의 테스트를 실행할 때 상위 테스트가 실패할 경우 하위의 모든 테스트들이 실패하게 됩니다.
그러나 playwright의 기본 설정에 의해 하위의 모든 테스트가 실패하더라도 30초의 timeout 딜레이가 발생하게 됩니다.
이런 딜레이를 막기 위해 상위 테스트가 특정 조건에 의해 skip/fail 할 경우 하위 테스트가 바로 skip/fail 하도록 설정할 때 사용하기 좋습니다.
test.skip([condition]), test.fail([condition])
테스트를 스킵하거나 실패하기 위해 사용되는 API입니다. 파라미터로 boolean 값의 조건부 변수를 넣어 사용할 수 있습니다.
테스트 그룹화
test.step()
을 사용하여 일련의 테스트 하나의 단위로 그룹화하여 테스트 코드의 가독성을 높일 수 있습니다.
test.step()
도 중첩된 형태를 가질 수 있으며, playwright 레포트, UI 모드에서 유용합니다.
Locators를 활용한 요소 찾기
Locators는 playwright에서 제공하는 auto-waiting, retry-ability와 관련된 핵심 기능으로, 언제 어디서나 페이지 내에서 항상 최신 상태의 요소를 찾을 수 있도록 도와주는 강력한 기능입니다. Locators에 대한 자세한 내용은 여기에서 확인할 수 있습니다.
변수 선언
테스트 코드를 작성할 때, Locators의 반환 값을 변수에 할당하고 범위를 좁혀나가는 방식을 사용하였습니다. 범위를 좁히지 않는다면 특정 요소를 찾기 위해 불필요한 작업을 해야 합니다. 적당한 요소를 찾아 변수로 선언하고, 이를 재사용함으로써 코드의 가시성, 재사용성, 유지보수성이 향상됩니다.
Playwright에서 JS의 Execution context, Scope 등의 기본 문법에 대한 이해가 있다면 코드 작성에 도움이 됩니다. 변수를 선언하고 요소를 찾아 참조 값을 할당하는 방법은 무엇일까요? 요소를 어떻게 효율적으로 찾을 수 있을까요?
효과적인 요소 찾기
Playwright의 Locators를 활용하여 요소를 찾을 수 있습니다. 공식 문서에서 추천하는 Locators를 사용해 보며 우선순위와 장단점을 소개해 보고자 합니다.
data-testid
속성과 page.getByTestId()
사용하기
page.getByTestId()
는 data-testid
와 같은 테스트 목적의 속성으로 요소를 찾는 방법입니다.
이 방식은 다음과 같은 장점을 가집니다.
- 테스트 용이성 증가
- CSS나 Xpath를 이용하여 요소를 찾는 방법보다
data-testid
를 사용한다면 DOM이 변경되더라도 테스트가 유연하게 진행될 수 있습니다.
- CSS나 Xpath를 이용하여 요소를 찾는 방법보다
- 코드 가독성 향상
- 요소를 쉽게 찾을 수 있으며, 작성된 코드가 줄어듭니다.
- 관심사의 분리
data-testid
는 DOM 구조나 class명이 변경되는 것보다 테스트 목적의 값이 변경될 가능성이 적습니다.- 사용자 동작과 관련 있는
data-testid
를 만들어 코드 작성에 도움을 줄 수 있습니다.
- 명확한 의미와 규칙
- 공통된
data-testid
를 통해 용어 통일과 문서 작성 시 도움을 줄 수 있습니다. - 각 요소의 목적과 의도된 동작을 이해하기 쉽습니다.
- 공통된
이 방식은 개발자가 요소에 data-testid
를 부여해야 하므로 정확한 규칙이 필요합니다.
또한, E2E 테스트 외에 단위 테스트에서도 테스트 목적의 속성이 사용될 수 있으므로 유의해야 합니다.
권장 Locators 사용하기
Playwright에서는 다양한 Locators를 권장하고 있습니다. 여러 상황에 맞게 선택할 수 있으며, 특히 웹 접근성이 잘 구성된 경우 유용합니다.
page.getByRole()
page.getByText()
page.getByLabel()
page.getByPlaceholder()
page.getByAltText()
page.getByTitle()
page.getByTestId()
이 API들은 page.getBy-*
형태를 가지고 있으며, 정해진 규칙을 통해 요소를 찾습니다.
특히, page.getByText()
나 page.getPlaceholder()
등은 다국어 처리 시에 주의가 필요합니다.
playwright에 다국어와 타임존 설정에 대한 설명은 여기에서 확인할 수 있습니다.
page.locator(selector[, options])
사용하기
일반적으로 page.locator()
를 사용하여 요소를 찾을 때는 class명, id, tag명 등을 이용합니다.
그러나 복잡하고 깊은 구조를 가진 웹 페이지에서는 특정 요소를 찾기 어려울 수 있습니다.
이런 경우에는 CSS나 XPath locators를 사용하여 요소에 접근할 수 있습니다.
page.locator()에 대한 설명은 여기에서 확인할 수 있습니다. 다만, DOM이 자주 변경되는 경우에는 테스트가 깨질 확률이 높기 때문에 이러한 방법이 권장되지 않습니다.
애플리케이션이 웹 접근성이 떨어지는 환경이거나, 급한 일정 속에서 테스트를 수행해야 할 경우에는 최후의 수단(?)으로 사용될 수 있습니다. 이런 경우에는 먼저 테스트 코드를 작성하고, 이후에 점진적으로 리팩토링을 진행하는 것이 좋습니다.
그리고...
Part 2에서는 간단한 playwright 설정 방식과 E2E 코드를 작성 시 테스트 그룹화 및 요소를 찾는 방식에 대해 작성하였습니다. 다음 파트에서는 찾은 요소들을 활용하는 방식에 대해 작성해 보고자 합니다.