미션 자료 : Next Step : cypress-basic
우리들의 Jun
이 만들어준 Cypress 입문 자료이다!
학습하는데 오랜 시간이 들어가지 않지만, Cypress의 첫 발로 딛기 아주 좋은 자료인 것 같다 :)
연습하고자한다면 직접 fork를 떠서 과제를 진행해보자!
우선 Cypress를 설치하자.
yarn add cypress
의존성 모듈이 많아서 생각보다 설치에 오랜 시간이 걸릴 수 있다. 너무 오래걸린다고 설치를 중단하지 말고 일단 기다려보자!
11분 가량 걸림..
설치에 성공했다면, 프로젝트의 root 폴더에 cypress 폴더가 생성된다.
이제 다음과 같은 명령어를 작성해보자.
> yarn cypress open
> npx cypress open
그럼..! 짜쟌-
cypress에 첫 발을 내딛은 걸 환영한다.
Jest
의 테스트코드는 다음과 같은 양식으로 관리된다.
Jest를 사용했던 사람이라면 Cypress의 테스트코드 관리방식이 바로 궁금해질 것이다.
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에 아래의 순서대로 경로를 추가해준다.
yarn global bin
시스템 환경 변수 편집 => 환경 변수 => 시스템변수 => 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
입문자를 위한 과제이니 공식문서를 읽고 기능명세서의 TC를 짜는 것에 집중하자!
+
버튼을 클릭 시 count가 1증가한다.-
버튼을 클릭 시 count가 1감소한다.+
버튼을 눌렀을 때 count가 12가 넘는 경우 더이상 증가하지 못한다. (Max 값이 12)-
버튼을 눌렀을 때 count는 8보다 작아지는 경우 감소하지 못한다. (Min 값이 8)우선, TC의 개수가 많지 않으니 재사용성을 크게 고려하지 말고 빠르게 코드를 작성하자.
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);
});
});
테스트 코드도 코드
다.
재사용되는 로직이 있다면, 공통 로직을 분리해 재사용하도록 한다.
현재 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!