2. FrontEnd/TDD / / 2023. 11. 10. 09:46

[TDD] Cypress를 사용하여 E2E테스트

E2E(End to End) : 사용자의 관점에서 테스트를 진행하는 것

 

사용자가 서비스에 접속했을 때 하는 행동들과 그 행동들에 의해 동작되는 여러 액션들을 테스트할 수 있기 때문에 사용자가 사용하는 관점에서 발생될 수 있는 문제들을 파악하는데 도움을 줍니다.

 

E2E 테스트를 포함하여 React에서 진행되는 테스트들은 다음과 같이 있습니다.

  • 단위 테스트
  • 통합 테스트
  • E2E 테스트

 

E2E 테스트는 브라우저를 통해 실제 사용자가 서비스를 사용하는 부분을 테스트하기 때문에 위의 테스트들 중 가장 큰 리소스를 필요한다 (=즉, 테스트를 진행하는데 상대적으로 많은 비용이 필요하며 무겁기 때문에 속도도 느린 편)

그래서 E2E 테스트는 전체 테스트에서 10% ~ 20% 정도만 차지할 정도로 구성을 하기에 꼭 필요로 하는 테스트에 사용되는 것이 추천

그리고 이런 E2E 테스트를 React에서 수행할 수 있게 도와주는 것이 cypress

 

 

[ 1. 패키지 설치 ]

$ npm install -D cypress
$ npm install -D eslint-plugin-cypress // eslint를 사용하는 경우만 추가

[ 2. eslint 설정 추가 (eslint 사용하는 경우만) ]

{
    "extends": [
        "plugin:cypress/recommended"
    ],
}

[ 3. package.json script 추가 ]

{
  "scripts": {
    "cypress": "npx cypress open"
  },
}

[ 4. 실행 ]

$ npm run cypress
$ yarn cypress

[ 5. baseUrl 설정 ]

프로젝트 폴더에 cypress와 관련된 설정 파일 및 테스트 파일들이 많이 만들어져 있다.

root경로에 있는 cypress.config.ts 파일에 다음과 같이 baseUrl을 설정

import { defineConfig } from 'cypress';

export default defineConfig({
    e2e: {
        baseUrl: 'http://localhost:8088', // baseUrl 설정
    },
});

 

[ 6. tsconfig.json 설정 (typescript 사용하는 경우만) ]

cypress 관련 파일들이 만약 tsconfig.json의 영향을 받지 않고 있다면 다음과 같이 include에 추가.

{
  "include": ["./cypress/**/*"]
}

 


선택자 (Selector)

selector는 dom 요소를 컨트롤하기 위해 사용되는 선택자인데 일반적으로 많이 사용되는 케이스로는 class와 id가 있습니다.

 

cypress를 이용해서 테스트를 할 때도 selector를 이용하여 테스트할 dom 컨트롤을 수행하는데 Cypress 공식문서에 따르면 cypress를 위해 사용되는 selector는 유니크한 값으로 사용되는 것을 추천

 

왜냐하면 테스트를 위해 사용되는 selector가 다른 곳에 의해 영향을 받게 되면 작성된 테스트 코드가 무너져 다시 작성해야 되는 상황이 발생하기 때문

 

cypress에서 추천하는 selector의 우선순위는 다음과 같다.

  • data-cy
  • data-test
  • data-testid
  • data-qa
  • id
  • class
  • tag
  • attributes
  • nth-child

당연히 정답은 없기에 개발하고 있는 프로젝트의 상황에 따라 selector를 선택

cypress를 위한 selector라는 것이 명확하게 확인 가능한 data-cy를 추천

 

기본 제공 명령어

추가적으로 필요한 명령어들에 대해서는 공식문서를 참고.

  • visit(url) → url에 해당되는 경로로 이동
  • get(selector) → selector에 해당되는 dom 요소 가져오기 (이전 dom과 상관없이 전체에서  selector 조회)
  • find(selector) → selector에 해당되는 dom 요소 가져오기 (이전 dom 내부에 있는 selector 조회)
  • type(text) → dom 요소에 text값을 입력
  • click() → dom 요소 click 이벤트 발생
  • should(chainer, type) → chainer의 조건에 type이 해당되는지 검증
  • wrap(element) → element를 cypress object로 덮어쓰기 위해 사용
  • as(alias) → as 이전에 나온 명령어들을 alias 처리
  • wait(alias) → alias가 수행될 때까지 대기
  • invoke(functionName, ...args) → functionName에 해당되는 값을 추출
  • first() → 첫 번째 dom 요소 가져오기
  • last() → 마지막 dom 요소 가져오기
  • children() → dom 요소에 해당되는 children 가져오기
  • parent() → dom 요소에 해당되는 parent 가져오기
  • interceptr(url) → url에 해당되는 request 탐지

 

예시

/* eslint-disable no-undef */
describe('로그인', () => {
  it('아이디와 비밀번호를 입력한 뒤 버튼을 클릭하여 /으로 이동하기', () => {
    // 페이지를 /login으로 이동
    cy.visit('/login');

    // id가 loginInput에 '입력한 아이디'값을 입력
    cy.get('#loginInput').type('입력한 아이디');
    // id가 loginPw에 '1234'값을 입력
    cy.get('#loginPw').type('1234');

    // id가 loginInput에 입력되어 있는 value값을 추출한 뒤 '입력한 아이디'와 같은지 검증
    cy.get('#loginInput').invoke('val').should('eq', '입력한 아이디');
    // id가 loginInput 요소로 만들어진 jquery object를 cypress object로 변환하여 value값이 '1234'인지 검증
    cy.get('#loginPw').then(($passwordInput) => {
      cy.wrap($passwordInput).should('have.value', '1234');
    });

    // id가 loginBtn dom 요소가 존재하는지 확인 후 클릭 이벤트 발생
    cy.get('#loginBtn').should('exist').click();
    // 페이지가 /으로 이동되었는지 검증
    cy.url().should('eq', 'http://localhost:8088/');
  });
});
728x90

'2. FrontEnd > TDD' 카테고리의 다른 글

[TDD] Jest 사용법  (1) 2023.11.07
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유