[Cypress] Counter 예제를 이용한 E2E Test 익히기

pengooseDev·2023년 8월 8일
0
post-thumbnail

미션 자료 : Next Step : cypress-basic

우리들의 Jun이 만들어준 Cypress 입문 자료이다!

학습하는데 오랜 시간이 들어가지 않지만, Cypress의 첫 발로 딛기 아주 좋은 자료인 것 같다 :)
연습하고자한다면 직접 fork를 떠서 과제를 진행해보자!


Cypress

우선 Cypress를 설치하자.

yarn add cypress

의존성 모듈이 많아서 생각보다 설치에 오랜 시간이 걸릴 수 있다. 너무 오래걸린다고 설치를 중단하지 말고 일단 기다려보자!

11분 가량 걸림..

설치에 성공했다면, 프로젝트의 root 폴더에 cypress 폴더가 생성된다.

이제 다음과 같은 명령어를 작성해보자.

> yarn cypress open
> npx cypress open

그럼..! 짜쟌-

cypress에 첫 발을 내딛은 걸 환영한다.


Test 코드 관리

Jest의 TestCode 코드 관리

Jest의 테스트코드는 다음과 같은 양식으로 관리된다.

Jest를 사용했던 사람이라면 Cypress의 테스트코드 관리방식이 바로 궁금해질 것이다.

Cypress의 TestCode 관리

Cypress의 테스트코드 관리는 다음과 같은 방식을 따른다.

테스트코드는 /cypress/integration/ 하위에 [name].spec.js의 형태로 작성한다.

root/cypress/integration/[name].spec.js


로컬 서버 띄우기

Cypress는 실제 브라우저에서 동작한다. 따라서, index.html을 작성하고 로컬 서버에서 띄워 결과를 트래킹 해야 한다.

이 글을 쓰는 이유이다.
index.html을 연다면 아무것도 보이지 않는다.

file:// 프로토콜로 직접 파일을 불러오면 일부 브라우저의 기능에 제한이 있다. 또한, CORS 에러로 인해 테스트가 불가능하기에 서버를 띄워 테스트를 진행해야한다.

물론, 직접 서버에 띄워서 확인해도 좋지만, 간단하게 해결하기 위해 http-server를 사용해보도록 하자.

yarn global add http-server

설치가 끝났다면, 환경변수의 PATH에 아래의 순서대로 경로를 추가해준다.

  1. 명령어 입력
yarn global bin
  1. path 복사
  2. 환경변수 추가

시스템 환경 변수 편집 => 환경 변수 => 시스템변수 => Path => 새로 만들기 => 경로 입력

TC에 관련된 글을 볼 사람이라면, 이미 환경변수 편집은 잘 할거라 믿는다. 구글링하면 바로 나오니 위 텍스트로 충분할 것이라 생각한다.

환경 설정에 끝났다면, VSC를 종료했다가 다시 켠 뒤 터미널창에 8000번 포트로 서버를 띄우자.

http-server . -p 8000

주어진 주소로 들어가자.
그렇다면 쟈쟌-

이제 Cypress를 학습할 모든 준비는 끝났다.


잘 작동하는지 확인하기! 😆

우선 로컬에서 잘 접속되는지 테스트를 진행한다.

// counter.spec.js
describe('ui-counter', () => {
  beforeEach(() => {
    cy.visit('http://127.0.0.1:8000/');
  });

  it('생성시 버튼과 초기값(10)을 렌더링 한다', () => {
    cy.get('.counter')
      .find('.count-display')
      .should('have.value', '10');
  });
});

우선 TDD의 원칙에 따라, 실패하는 코드(목표)를 작성하고 cypress를 실행하자.

yarn cypress open

작성한 테스트코드를 실행한다.

잘 돌아간다! 😀

이제 각자 기능 명세서를 작성하고, TDD 원칙에 따라 테스트 코드를 작성하고 구현해보자! 😆

아래의 Docs를 참고하면 좋다.
> Docs
> Cheet sheet


Test Code

입문자를 위한 과제이니 공식문서를 읽고 기능명세서의 TC를 짜는 것에 집중하자!

기능명세서

  • 생성시 버튼과 초기값(10)을 렌더링 한다.
  • + 버튼을 클릭 시 count가 1증가한다.
  • - 버튼을 클릭 시 count가 1감소한다.
  • + 버튼을 눌렀을 때 count가 12가 넘는 경우 더이상 증가하지 못한다. (Max 값이 12)
  • - 버튼을 눌렀을 때 count는 8보다 작아지는 경우 감소하지 못한다. (Min 값이 8)

우선, TC의 개수가 많지 않으니 재사용성을 크게 고려하지 말고 빠르게 코드를 작성하자.


Test Code

describe('ui-counter', () => {
  beforeEach(() => {
    cy.visit('http://127.0.0.1:8000/');
  });
  
  it('생성시 버튼과 초기값(10)을 렌더링 한다', () => {
    cy.get('.counter').find('.count-display').should('have.value', '10');
  });
  
  it('+ 버튼을 클릭 시 count가 1증가한다', () => {
    cy.get('plus-button').click();
    cy.get('.count-display').should('have.value', '11');
  });
  
  it('- 버튼을 클릭 시 count가 1감소한다', () => {
    cy.get('minus-button').click();
    cy.get('.count-display').should('have.value', '9');
  });
  
  it('count의 값은 12를 넘어갈 수 없다', () => {
    const TOTAL_CLICK = 5;
    for (let clickCount = 0; clickCount < TOTAL_CLICK; clickCount++) {
      cy.get('plus-button').click();
    }

    cy.get('.count-display').should('have.value', 12);
  });

  it('count의 값은 8 아래로 떨어질 수 없다', () => {
    const TOTAL_CLICK = 5;
    for (let clickCount = 0; clickCount < TOTAL_CLICK; clickCount++) {
      cy.get('minus-button').click();
    }

    cy.get('.count-display').should('have.value', 8);
  });
});

Refactoring Test Code

테스트 코드도 코드다.
재사용되는 로직이 있다면, 공통 로직을 분리해 재사용하도록 한다.

현재 TestCode에 소프트 코딩이 적용되어있는데, TC의 본질 자체는 프로덕트 코드와 조금은 다르다.
따라서, 과도하게 소프트 코딩을 적용하기보단, 너무 긴 class명이나 매직넘버(숫자만으로는 다른 팀원들이 의미를 추론하기 어려운 부분) 등에만 가볍게 적용하도록 한다.

const SELECTOR = Object.freeze({
  PLUS_BUTTON: '.plus-button',
  MINUS_BUTTON: '.minus-button',
  COUNTER: '.count-display',
});

describe('ui-counter', () => {
  beforeEach(() => {
    cy.visit('http://127.0.0.1:8000/');
  });

  const clickButton = (selector, times = 1) => {
    for (let i = 0; i < times; i++) cy.get(selector).click();
  };

  const counterShouldBe = (expected) =>
    cy.get(SELECTOR.COUNTER).should('have.value', expected);

  it('생성시 버튼과 초기값(10)을 렌더링 한다', () => {
    counterShouldBe('10');
  });

  it('+ 버튼을 클릭 시 count가 1증가한다', () => {
    clickButton(SELECTOR.PLUS_BUTTON);
    counterShouldBe('11');
  });

  it('- 버튼을 클릭 시 count가 1감소한다', () => {
    clickButton(SELECTOR.MINUS_BUTTON);
    counterShouldBe('9');
  });

  it('count의 값은 12를 넘어갈 수 없다', () => {
    const NUMBER_OF_CLICKS = 5;
    clickButton(SELECTOR.PLUS_BUTTON, NUMBER_OF_CLICKS);

    counterShouldBe('12');
  });

  it('count의 값은 8 아래로 떨어질 수 없다', () => {
    const NUMBER_OF_CLICKS = 5;
    clickButton(SELECTOR.MINUS_BUTTON, NUMBER_OF_CLICKS);

    counterShouldBe('8');
  });
});


잘 배웠습니다 준! 그리고 나도 기여하기!

jun이 시간을 들여 작성한 문서 덕분에, cypress를 수월하게 학습할 수 있었다.

Cypress를 학습할 때 해당 저장소를 사용하여 학습하는 사람들을 위해, 로컬 서버에 대한 설명이 추가되면 다른 사람들이 조금 더 편하게 학습하지 않을까? 생각하며, 문서를 정리하고 Next Step에 첫 PR을 날려본다! 😃

감사해요 Jun!

0개의 댓글