Next.js 블로그에 Cypress를 통한 E2E 테스트 적용해보기 Ver.2
# 테스트 시나리오를 작성해보고, 해당 시나리오를 통해 테스트 코드를 작성 및 실행해봅시다.
2024년 07월 06일
Cypress란 무엇인가
Cypress는 JavaScript로 작성된 End-to-End(E2E) 테스트 프레임워크로 다양한 기능을 제공하면서도 사용하기 편리하여 웹 애플리케이션의 전체 시스템을 테스트하고 검증하는데 도움을 준다. 특히 사용자 경험을 중시하는 테스트 환경을 구성하기에 최적화된 도구 중 하나다.
Cypress의 주요 특징
- 실제 환경과 유사한 브라우저 테스트: Cypress는 Chrome, Firefox, Edge와 같은 실제 브라우저에서 테스트를 수행한다. 이는 실제 사용자가 경험하는 환경과 동일한 조건에서 테스트를 진행할 수 있게 한다.
- 강력한 디버깅 도구 & 실시간 리로딩: 테스트 실행 중 발생한 문제를 시각적으로 식별하고 디버그할 수 있는 기능을 제공하며, 코드 변경 시 실시간으로 리로딩되어 빠른 피드백을 받을 수 있다.
- 다양한 선택자 및 명령어: Cypress는 CSS 선택자 등 다양한 선택자와 명령어를 제공한다. 이를 통해 개발자는 더 편리하게 원하는 요소를 찾고 조작할 수 있다.
- 실시간 시각화: 애플리케이션의 상태를 실시간으로 시각화하여 디버깅을 용이하게 한다. 테스트가 실행되는 동안 각 단계에서 무엇이 일어나는지 명확하게 확인할 수 있다.
- 병렬 실행 및 분산 테스트 지원: 병렬 실행과 분산 테스트를 지원하여 여러 테스트를 동시에 실행하고 빠르게 결과를 얻을 수 있다.
- E2E, 단위 및 통합 테스트 지원: Cypress는 단순히 E2E 테스트을 위한것이 아니며, 단위 테스트와 통합 테스트도 모두 지원한다.
Cypress 기본 문법
Cypress의 기본적인 문법은 describe
와 it
을 사용하여 테스트 케이스를 정의한다.
- describe: 테스트 정의
- it: 개별 테스트 케이스를 정의
- cy.visit: 애플리케이션의 특정 URL을 방문
- cy.get: DOM 요소를 선택하는 데 사용. 선택한 요소에 대해 chain을 통해 다양한 동작을 수행
Cypress Query
Cypress는 DOM 요소를 선택하는 다양한 메서드를 제공하며, 이를 통해 특정 요소를 찾고 조작할 수 있다.
as 메서드
선택한 요소에 별칭을 부여하여 나중에 손쉽게 재사용할 수 있다.
Cypress Query 메서드
메서드 | 설명 |
---|---|
closest | 특정 조건에 가장 가까운 부모 요소를 찾는다. cy.get('.element').closest('.parent-container') |
contains | 특정 텍스트를 포함하는 요소를 찾는다.cy.contains('Submit').click() |
eq | 특정 인덱스에 있는 요소를 선택 cy.get('ul li').eq(2).should('have.text', 'Third item') |
find | 특정 자식 요소를 찾는다.cy.get('.parent-element').find('.child-element') |
first, last | 선택된 요소 집합에서 첫 번째/마지막 요소를 선택 |
parent, children | 특정 요소의 부모/자식 요소를 선택 |
not | 주어진 선택자와 일치하지 않는 요소를 선택 cy.get('ul li').not('.special-item').should('have.length', 2) |
next, prev | 특정 요소의 다음/이전 형제 요소를 선택 |
Cypress Assertion
Assertion은 테스트 중에 특정 조건이 만족되는지 확인하며,
and
와should
메서드를 사용하여 다양한 조건을 확인할 수 있다.
Cypress Actions
Actions는 사용자 인터랙션을 시뮬레이션하는 메서드로, 실제 사용자의 행동을 모방하여 E2E 테스트를 작성하는 데 매우 유용하다.
메서드 | 설명 |
---|---|
check | 체크박스나 라디오 버튼을 선택cy.get('#checkbox').check() |
clear | 텍스트 입력 필드를 비움cy.get('input[name=username]').clear() |
click | 특정 요소를 클릭cy.get('#submitButton').click() |
trigger | DOM 이벤트를 강제로 발생cy.get('#targetElement').trigger('mouseover') |
type | 텍스트 입력 필드에 값을 입력cy.get('input[name=username]').type('hello') |
E2E 테스트 시나리오 작성해보기
본격적으로 테스트 코드를 작성하기 전에 테스트 시나리오를 작성해야 한다. 테스트 시나리오를 작성하면, 현재 Next.js 블로그 프로젝트의 로직을 점검할 수 있고, 더 정확하고 효과적인 테스트 코드를 작성하는 데 도움이 된다. 또한, 모든 가능한 경로와 예외 상황을 미리 계획하여 테스트의 완성도를 높일 수 있다.
간단하게 현재 Next.js 블로그 트리를 그려봤다.
위 트리를 바탕으로 상세 시나리오를 작성해본다면
메인 페이지 테스트 시나리오 플로우
---------------------
| 호진방 블로그 |
| About |
| HJ Bang |
| 환영 메시지 |
| ---------------- |
| 검색 아이콘 |
| ---------------- |
| 태그 목록 |
| 글 목록 |
| ---------------- |
| Footer |
---------------------
- 시작 화면
- 웹 애플리케이션 메인 페이지를 방문한다.
- 다양한 텍스트 요소가 화면에 표시된다: '호진방 블로그', 'About', 'HJ Bang', '환영 메시지' 등.
- 각 항목 확인
- 각 텍스트 요소가 잘 렌더링 되나 확인
[About 클릭 -> About 페이지]
---------------------
| About 페이지 |
| 환영 메시지 |
---------------------
About 페이지 이동
- 'About' 링크를 클릭한다.
- About 페이지로 이동한 후, 해당 페이지의 콘텐츠가 올바르게 표시되는지 확인한다.
[검색 아이콘 클릭 -> 검색 모달 열림]
---------------------
| 검색 모달 |
| [검색 입력창] |
| 'not found' 입력 |
| 'No Posts found.' |
| 'Next.js 블로그 ...' 입력 |
| 검색 결과 클릭 |
[검색 모달 닫음 -> 글 상세 페이지]
---------------------
- 검색 아이콘을 클릭하여 검색 모달을 오픈한다.
- 'not found'를 입력하고 'No Posts found.' 출력 확인.
- 입력을 지우고 'Next.js 블로그 모달 관리 개선하기'를 검색.
- 검색 결과를 클릭하고 올바른 페이지로 이동 확인.
- 배경을 클릭하여 검색 모달을 닫음. (모달 close 확인)
[태그 선택 -> 글 필터링]
---------------------
| 태그 필터링된 글 목록 |
| 'Next.js 블로그 만들기 Ver.1' |
| 클릭 -> 글 상세 페이지 이동 |
---------------------
태그 선택과 글 목록
- 'tag'를 클릭하여 태그 목록을 표시한다
- 다양한 태그('학습', '기술', '생각', '경험')를 클릭하여 순서대로 필터링 되는지 확인
- 'Next.js 블로그 만들기 Ver.1' 글 선택 후 해당 콘텐츠 페이지로 이동.
[Footer]
---------------------
| banhogu 링크 클릭 |
| Source 링크 확인(GitHub) |
---------------------
Footer 링크 확인
- 인스타그램 링크가 올바르게 작동하는지 확인.
- 'Source' 링크가 올바른 GitHub URL을 가리키는지 확인.
글 상세 페이지 시나리오 플로우
---------------------
| 경험 |
| Next.js 블로그... |
| On This Page |
| AI Bot 버튼 |
| To Top 버튼 |
---------------------
- 시작 화면
- 특정 글 상세 페이지 방문한다.
- 다양한 텍스트 요소가 화면에 표시된다 '경험', 'Next.js 블로그 만들기 Ver.1', 'On This Page'. 등
- 기타 UI 요소 확인
- AI Bot 버튼과 To Top 버튼이 존재하는지 확인한다.
- 페이지를 하단까지 스크롤하고, 하단 컴포넌트 또한 확인
[사이드바 항목 클릭]
---------------------
| #블로그를-직접-만드는-이유 클릭 |
| #기능-정리 클릭 |
---------------------
사이드바 항목 선택
- '#블로그를-직접-만드는-이유' 링크를 클릭하여 링크가 올바르게 동작하는지 확인.
- '#기능-정리' 링크를 클릭하여링크가 올바르게 동작하는지 확인. + (text-pink 속성확인)
[To Top 버튼]
---------------------
| To Top 버튼 클릭 -> 최상단 이동 |
---------------------
[AI Bot 버튼]
---------------------
| AI Bot 버튼 클릭 -> 요약 모달 표시 |
| 모달 닫기 버튼 클릭 |
---------------------
- To Top 버튼에 호버하여 툴팁 텍스트 표시 확인.
- To Top 버튼 클릭 후 페이지 최상단으로 이동하는지 확인.
- AI Bot 버튼에 호버하여 툴팁 텍스트 표시 확인.
- AI Bot 버튼 클릭 후 요약 모달 표시 확인.
- 요약 모달을 닫기 버튼으로 닫고 확인
테스트 코드 작성
상세 테스트 시나리오를 바탕으로 테스트 코드를 작성한다.
Hydration 작업을 실패하였습니다. 그 원인은 첫 번째 UI가 서버에서 render된 것과 매칭되지 않았기 때문입니다.
드디어 테스트 코드를 작성하겠구나 들뜬 마음에 visit(’/’)
를 통해 메인페이지에 접속하자 마자 위와
같은 오류가 발생했다. 관련 오류 내용을 찾아보니 cypress 공식 문서에는 관련 내용이 전혀 적혀져 있지
않았다. 멘붕 상태로 열심히 구글링 한 결과,
https://github.com/cypress-io/cypress/issues/27204#issuecomment-1894217901
나와 같은 문제를 겪고 있는 사람들이 많았고 해당 issues에서 해결 코드를 찾을 수 있었다. 모든 issues 글들을 번역해서 읽어본 결과, 무엇이 문제고 저 코드가 어떤 역할의 코드인지 설명하는 글이 없었다.
혹시나 해서 stack overflow로도 검색해봤지만 역시 오류가 발생한 이유나, 해당 코드의 역할이 적혀져 있지 않았다. 이유는 알려줘야죠
어쨋든 해당 코드를 e2e.ts 파일에 추가해주면, 거짓말처럼 오류가 사라진다. 공식문서에도 없는 코드를 어떻게 찾아내신거지 궁금하다.
테스트 코드작성
테스트 결과
테스트 시나리오대로 테스트 코드를 작성했고, 모든 테스트 케이스에 대해 통과한 모습이다.