💻 Frontend
E2E Test with Cypress - 방 생성 테스트 코드 작성하기
date
Sep 22, 2022
slug
e2e-test-with-cypress
author
status
Public
tags
E2E 테스트
Cypress
summary
방 생성 테스트 코드 작성하기
type
Post
thumbnail
category
💻 Frontend
updatedAt
Nov 22, 2023 01:01 AM
언어
개요
E2E
(end-to-end) 테스트란 사용자 관점에서 기능들이 제대로 수행하는지 확인하는 테스트입니다. 버튼이 제대로 클릭 되는지, 원하는 화면이 잘 렌더링 되었는지 등을 테스트합니다.테스트 코드를 작성하는 이유는 무엇일까요? 만약 단순하게 하나의 페이지만 있는 웹사이트를 만들었다면 필요가 없을 수도 있습니다. 하지만 다양한 시스템을 사용하며 복잡한 workflow를 가지는 어플리케이션 이라면 말은 달라질 것입니다. 어떠한 기능이 '제대로' 동작하는지 확신하기 위해 테스트 코드가 필요합니다. 만약 어떠한 기능에 대한 코드를 수정하거나 리팩토링을 진행할 때에도 다양한 케이스들을 직접 확인할 필요없이 테스트 코드만 돌려 확인한다면 불필요한 시간 낭비를 줄일 수 있습니다. 이처럼 테스트 코드를 작성하는 데에는 많은 장점이 있습니다. 이번 포스팅에서는 cypress를 이용하여 테스트 코드를 어떻게 작성하는지 설명드리겠습니다.
Cypress
설치 과정은 생략하겠습니다.
현재 저의 cypress 폴더 구조는 위와 같습니다.
describe('A는', () => { context('B의 상황일때', () => { it('C가 될거야', () => { ... }); }); });
위 코드는 기본 뼈대를 보여주는 예시 테스트 코드 입니다. 여기서
describe
는 '대상', context
는 '상황', it
은 '예상 결과'를 의미합니다.createRoom.cy.ts
이제 실제로 메인 페이지에 있는 방 생성(createRoom.cy.ts)에 대한 테스트 코드를 작성해보겠습니다.
describe('create room modal in main page', () => { beforeEach(() => { // mock get all rooms cy.intercept( { method: 'GET', url: API.ROOM }, { fixture: 'allRooms.json' }, ); ... });
createRoom.cy.ts
는 방 생성 모달을 열었을 때 테스트를 하는 것이므로 describe
를 위와 같이 해주었습니다. 여기서 중요한 것 중 하나는 beforeEach
입니다. beforeEach
는 모든 it
테스트가 실행되기 이전에 실행됩니다. 이와 비슷하지만 다른 before
는 모든 it
테스트가 아닌 테스트 하기 전 한번만 실행됩니다.cy.intercept
와 fixture
를 이용해 response
를 stubbing하였습니다. 여기서 stub
은 기존 코드를 흉내내거나 아직 개발되지 않은 코드를 임시로 대치하는 역할을 수행합니다. 따라서 위의 코드는 API.ROOM
으로 온 GET
요청의 response
를 fixture
인 allRooms.json
으로 stubbing한다! 라는 의미입니다.beforeEach(() => { // mock get all rooms cy.intercept( { method: 'GET', url: API.ROOM }, { fixture: 'allRooms.json' }, ); // mock get my data cy.intercept({ method: 'GET', url: API.ME }, { fixture: 'me.json' }); cy.intercept( { method: 'GET', url: API.RECORDS }, { fixture: 'records.json' }, ); // mock post new room cy.intercept( { method: 'POST', url: API.ROOM }, { fixture: 'newRoom.json' }, ); // set local storage before start -> auto login localStorage.setItem('access_token', 'mock_access_token'); cy.visit('http://localhost:3000'); cy.viewport(1536, 960); cy.wait(500); // check if room modal is opened cy.get('[data-cy="create-room-modal-open"]').click(); cy.get('[data-cy="create-room-modal"]').should('be.visible'); cy.wait(500); });
저같은 경우
beforeEach
에서 각 테스트코드를 실행하기 전 필요한 요청들을 위와 같이 처리해주었습니다. 로컬 스토리지에 access_token
을 미리 저장해두어야 하기 때문에 임시로 'mock_access_token'으로 set해주었습니다.이렇게
intercept
들을 설정해주고 토큰까지 저장해준 뒤 로컬로 visit합니다.viewport로 테스트코드가 실행되는 화면의 width, height을 설정해줍니다.
아래 사진은 노트북/핸드폰에 대한 width, height입니다.
출처: 공식문서
[data-cy="create-room-modal-open"] 은
selector
입니다. 공식문서에서는 best practice로 data-* 를 사용함으로써 css나 js가 바뀌어도 영향받지 않도록 작성하는 것을 권장하고 있습니다.따라서 위 코드에서는
create-room-modal-open
을 클릭하여 create-room-modal
이 보이는지 확인합니다.beforeEach
를 해준뒤 테스트를 실행합니다.- 모달창이 제대로 닫히는지
// close modal test it('check modal when user clicks close button', () => { // close modal cy.get('[data-cy="create-room-modal-close"]').click(); cy.get('[data-cy="create-room-modal"]').should('not.exist'); cy.wait(500); }); it('check modal when user clicks background', () => { cy.get('[data-cy="create-room-modal-background"]').click('left'); cy.get('[data-cy="create-room-modal"]').should('not.exist'); cy.wait(500); });
- 닫기 버튼을 눌렀을 때 제대로 닫히는지
- 모달의 백그라운드를 눌렀을 때 제대로 닫히는지'닫히는지'에 대한 여부는 not.exist한지로 판별합니다.
- 방생성이 제대로 되는지
// create room test it('check create room when user does not enter all required information', () => { // click create button when user does not enter room name cy.get('[data-cy="create-room-modal-create"]').should('be.disabled'); cy.get('[data-cy="create-room-modal"]').should('be.visible'); cy.get('[data-cy="create-room-modal-title"]').type( '1234567891011121314151617181920', ); cy.wait(500); ...
사용자가 필수로 입력해야 하는 값들을 하나라도 입력하지 않았을 경우 방생성 버튼이 활성화되지 않습니다. 이를 테스트하기 위해
should('be.disabled')
로 확인하였습니다.이후
title
에 '1234567891011121314151617181920'로 입력해준뒤 500ms를 기다려줍니다.// check if title length is not over 14 cy.get('[data-cy="create-room-modal-title"]').should( 'be.not.length.greaterThan', 14, ); cy.wait(500); // check if details length is not over 30 cy.get('[data-cy="create-room-modal-details"]').type( '12345678910111213141516171819202122232425262728', ); cy.get('[data-cy="create-room-modal-details"]').should( 'be.not.length.greaterThan', 30, ); cy.wait(500);
다음은 방 제목이 14글자를 넘지 않는지, 방 상세 설명이 30글자를 넘지 않는지 확인합니다.
// click create button when user does not enter room's total cy.get('[data-cy="create-room-modal-create"]').should('be.disabled'); cy.get('[data-cy="create-room-modal-total"]').click(); cy.get( '[data-cy="create-room-modal-total-dropdown"] > :nth-child(3)', ).click(); cy.wait(500);
여기까지 입력했을 때 방 생성 버튼이
disabled
인지 확인합니다.이후 방 전체 인원수를 클릭한 뒤 dropdown에 있는 3번째 필드를 클릭합니다.
// click create button when user does not enter room's theme cy.get('[data-cy="create-room-modal-create"]').should('be.disabled'); cy.get('[data-cy="create-room-modal-theme"]').click(); cy.get( '[data-cy="create-room-modal-theme-dropdown"] > :nth-child(3)', ).click(); cy.wait(500);
여기까지 입력했을 때 방 생성 버튼이
disabled
인지 확인합니다.이후 방 테마를 클릭한 뒤 dropdown에 있는 3번째 필드를 클릭합니다.
// click create button when user does not enter room's pw (optional) cy.get('[data-cy="create-room-modal-private"]').click(); cy.get('[data-cy="create-room-modal-create"]').should('be.disabled'); cy.get('[data-cy="create-room-modal-pw"]').type('1234'); cy.wait(500);
이후 방에 대해 public방이 아닌 private한 방으로 클릭해줍니다.
여기까지 입력했을 때 방 생성 버튼이 disabled인지 확인합니다.
이후 방에 대한 비밀번호를 타이핑해줍니다.
// click create button when user enters all required information cy.get('[data-cy="create-room-modal-create"]').should('not.be.disabled'); cy.get('[data-cy="create-room-modal-create"]').click(); cy.wait(500);
이렇게 입력했다면 필수 입력값들은 전부 처리해준 상태입니다. 따라서 방생성 버튼이 abled한지 확인하고 방 생성 버튼을 클릭합니다.
마치며
지금까지 cypress를 이용해 간단한 e2e 테스트를 해보았습니다. 더 자세한 내용은 cypress 공식 홈페이지 를 참고하시면 될것 같습니다.