본문 바로가기
SPA/React

[React] Cypress로 E2E테스트하기

by J4J 2023. 4. 12.
300x250
반응형

안녕하세요. J4J입니다.

 

이번 포스팅은 cypress를 이용하여 e2e 테스트하는 방법에 대해 적어보는 시간을 가져보려고 합니다.

 

 

 

E2E 테스트란?

 

E2E는 End to End의 약자로 사용자의 관점에서 테스트를 진행하는 것을 의미합니다.

 

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

 

 

 

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

 

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

 

 

 

E2E 테스트는 브라우저를 통해 실제 사용자가 서비스를 사용하는 부분을 테스트하기 때문에 위의 테스트들 중 가장 큰 리소스를 필요로 합니다.

 

즉, 테스트를 진행하는데 상대적으로 많은 비용이 필요하며 무겁기 때문에 속도도 느린 편입니다.

 

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

 

 

 

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

 

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

 

 

 

실행을 하면 다음과 같은 화면이 나오는데 왼쪽에 있는 E2E Testing을 클릭해 주고 Continue를 눌러줍니다.

 

cypress 실행 화면

 

 

 

그러면 아래처럼 실행할 브라우저를 선택하는 화면이 나오고 원하는 브라우저를 선택하여 Start를 해줍니다.

 

브라우저 선택 화면

 

 

 

다음으로는 왼쪽 메뉴에서 Specs를 선택하여 Scaffold example specs를 클릭하여 기본 예제 파일들을 모두 추가해 줄 수 있습니다.

 

기본 예제 파일 추가하기

 

 

 

[ 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)

 

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를 추천하는 편입니다.

 

 

 

 

기본 제공 명령어

 

cypress를 활용하여 테스트 코드를 작성할 때 주로 사용되는 기본 명령어들은 다음과 같습니다.

 

이 외에도 훨씬 더 많은 명령어들이 있기 때문에 추가적으로 필요한 명령어들에 대해서는 공식문서를 참고해주시면 될 것 같습니다.

 

  • 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 탐지

 

 

 

 

테스트 코드 예시

 

cypress를 이용하여 테스트 코드를 구현하는 방법은 jest와 유사하게 describe, it 등을 사용합니다.

 

그리고 내부에 cypress에서 제공해 주는 명령어들을 이용하여 각자 원하는 방식의 테스트를 진행해 줄 수 있습니다.

 

 

 

간단한 테스트 코드를 작성하기 위해 페이지를 구성하는 파일을 다음과 같이 작성해 보겠습니다.

 

import React from 'react';
import { useNavigate } from 'react-router';

const Login = () => {
    /**
     * navigate
     */
    const navigate = useNavigate();

    /**
     * handle
     */
    const handle = {
        login: () => {
            navigate('/home');
        },
    };

    return (
        <div>
            <input data-cy="id-input" type="text" placeholder="ID" />
            <input data-cy="password-input" type="password" placeholder="Password" />
            <button data-cy="login-button" onClick={handle.login}>
                로그인
            </button>
        </div>
    );
};

export default Login;

 

 

 

 

그리고 위의 코드를 기반으로 다음과 같은 테스트 코드를 간단하게 작성해 볼 수 있습니다.

 

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

        // id-input dom 요소 가져오는 것을 idInput으로 alias처리
        cy.get('[data-cy=id-input]').as('idInput');
        // idInput에 해당되는 alias에 '입력한 아이디'값을 입력
        cy.get('@idInput').type('입력한 아이디');
        // password-input dom 요소에 '1234'값을 입력
        cy.get('[data-cy=password-input]').type('1234');

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

        // login-button dom 요소가 존재하는지 확인 후 클릭 이벤트 발생
        cy.get('[data-cy=login-button]').should('exist').click();
        // 페이지가 /home으로 이동되었는지 검증
        cy.url().should('eq', 'http://localhost:8088/home');
    });
});

 

 

 

 

 

 

 

이상으로 cypress를 이용하여 e2e 테스트하는 방법에 대해 간단하게 알아보는 시간이었습니다.

 

읽어주셔서 감사합니다.

 

 

 

728x90
반응형

댓글