프론트엔드

Cypress 기초 문법 및 설치 방법

도우 2025. 5. 26. 09:44
728x90

전통적인 테스트 도구들은 브라우저 외부에서 원격으로 명령을 전송하는 방식이었다면, Cypress는 브라우저 내부에서 직접 실행됩니다. Cypress를 실행하면 실제 브라우저 창이 열리고, 테스트가 실행되는 모든 과정을 실시간으로 시각적으로 확인할 수 있습니다.

타임 트래블 기능도 지원합니다. 테스트의 각 단계를 클릭하면 그 시점의 상태로 되돌아가서 DOM의 상태, 네트워크 요청, 콘솔 로그 등을 자세히 살펴볼 수 있습니다.

 

설치 과정

1. 프로젝트 루트 디렉토리에서 다음 명령어를 실행합니다.

npm install cypress --save-dev

 

2. package.json에 스크립트를 추가합니다.

{
  "scripts": {
    "cy:open": "cypress open",
    "cy:run": "cypress run"
  }
}

 

3. 초기 실행과 설정

npm run cy:open

이 명령어를 처음 실행하면 Cypress가 프로젝트를 분석하고 필요한 설정 파일들을 자동으로 생성합니다. cypress 폴더가 생성되고, 그 안에 여러 하위 폴더들이 만들어집니다.

 

 

Cypress 핵심 명령어

1) 페이지 탐색 명령어

  • cy.visit(url) : 페이지에 접속합니다. 모든 E2E 테스트의 시작점입니다.
cy.visit('/') // 기본 URL로 이동
cy.visit('/login') // 로그인 경로로 이동
cy.visit('<https://example.com>') // 절대 URL로 이동

 

  • cy.go(direction) : 브라우저 히스토리를 조작합니다.
cy.go('back') // 뒤로 가기
cy.go('forward') // 앞으로 가기
cy.go(-1) // 한 페이지 뒤로

 

2) 요소 선택 명령어

  • cy.get(selector) : CSS 선택자로 DOM 요소를 찾습니다.
cy.get('button') // 모든 button 태그
cy.get('.btn-primary') // class가 btn-primary인 요소
cy.get('#submit-btn') // id가 submit-btn인 요소
cy.get('input[type="text"]') // text 타입의 Input
cy.get('[data-cy="tagName"]') // data-cy 속성 -> 가장 권장되는 방식
cy.get('ul li:first-child') // 첫 번째 li 요소

 

  • cy.contains(content) : 텍스트 내용으로 요소를 찾습니다.
cy.contains('로그인') // "로그인" 텍스트를 포함한 요소
cy.contains('button', '확인') // button 태그 중 "확인" 텍스트가 존재하는 것
cy.contains(/정규표현식/) // 정규표현식으로 매칭

 

  • cy.find(selector) : 이미 선택된 요소의 하위 요소를 찾습니다.
  • cy.get() 은 전체 문서에서 찾고, cy.find() 는 이미 선택된 요소 내에서만 찾습니다.
cy.get('.todo-list').find('li') // todoList 클래스 안의 li 모두
cy.get('[data-cy="form"]').find('input') // 폼 안의 input 모두

 

3) 사용자 상호작용 명령어

  • cy.type(text) : 텍스트를 입력합니다.
  • 특수키 :
  • {enter}, {tab}, {esc}, {backspace}
  • {selectall}, {del}, {home}, {end}
  • {ctrl + a}, {shift + tab}
cy.get('input').type('안녕하세요')
cy.get('input').type('텍스트{enter}') // Enter키도 함께 입력
cy.get('input').type('{selectall}새텍스트') // 전체선택(Ctrl+A) 후 입력 -> 기존 텍스트 삭제
cy.get('input').type('test@email.com')

 

  • cy.click() : 요소를 클릭합니다.
cy.get('button').click()
cy.contains('제출').click()
cy.get('input[type="checkbox"]').click() // 체크박스 토글
cy.get('.item').click( { multiple : true }) // 여러 요소 클릭

cy.get('button').click({ force : true }) // 숨겨진 요소도 강제 클릭
cy.get('button').click({ position : 'top' }) // 특정 위치 클릭

 

  • cy.clear() : 입력 필드의 내용을 지웁니다.
cy.get('input').clear()
cy.get('input').clear().type('새로운 내용') // 지우고 새로 입력

 

  • cy.select(value) : select 박스에서 옵션을 선택합니다.
cy.get('select').select('option1') // value로 선택
cy.get('select').select('한국어') // 텍스트로 선택
cy.get('select').select(['otp1', 'otp2']) // 다중 선택

 

  • cy.check() / cy.uncheck() : 체크박스나 라디오 버튼을 조작합니다.
cy.get('[type="checkbox"]').check()       // 체크
cy.get('[type="checkbox"]').uncheck()     // 체크 해제
cy.get('[type="radio"]').check('value')   // 특정 라디오 선택

 

4) 검증(Assertion) 명령어

  • cy.should(assertion : 요소의 상태를 검증합니다. 테스트의 핵심입니다.
// 존재와 가시성
cy.get('button').should('exist')        // 요소가 DOM에 존재
cy.get('button').should('be.visible')   // 요소가 화면에 보임
cy.get('button').should('not.exist')    // 요소가 존재하지 않음
cy.get('button').should('be.hidden')    // 요소가 숨겨져 있음

// 텍스트와 내용
cy.get('h1').should('contain.text', 'Todo List')     // 텍스트 포함
cy.get('h1').should('have.text', 'Todo List')        // 정확한 텍스트
cy.get('input').should('have.value', '입력된 값')     // input의 value
cy.get('div').should('be.empty')

// 상태와 속성
cy.get('button').should('be.disabled') // 비활성화됨
cy.get('button').should('be.enabled') // 활성화됨
cy.get('input').should('be.focused') // 포커스됨
cy.get('input').should('have.attr', 'placeholder', '입력하세요')
cy.get('div').should('have.class', 'active') // CSS 클래스 확인

// 개수와 길이
cy.get('li').should('have.length', 3) // 요소 개수
cy.get('li').should('have.length.greaterThan', 0) // 0개보다 많음
cy.get('ul').should('contain', 'list item') // 내용 포함

 

  • cy.then(callback) : 요소를 가져와서 추가 작업을 수행합니다.
cy.get('li').then($elements => {
  expect($elements).to.have.length(3)
  // jQuery 객체로 추가 조작 가능
})

// 텍스트 내용을 변수에 저장
cy.get('.count').then($el => {
  const count = $el.text()
  cy.wrap(count).should('equal', '5')
})

 

5) 대기 명령어

  • cy.wait(time) : 지정된 시간만큼 대기합니다. (일반적으로 권장하지 않음)
cy.wait(1000)  // 1초 대기 - 가능하면 피하세요!
// 더 나은 방법: 요소가 나타날 때까지 자동으로 대기하는 should() 사용

 

  • cy.intercept() : 네트워크 요청을 가로채고 모킹합니다.
// API 응답 모킹
cy.intercept('GET', '/api/todos', { fixture: 'todos.json' })

// 요청 완료까지 대기
cy.intercept('POST', '/api/todos').as('createTodo')
cy.get('button').click()
cy.wait('@createTodo')  // 이때는 wait() 사용이 적절

 

6) 페이지 상태 조작

  • cy.url() : 현재 URL을 검증합니다.
cy.url().should('include', '/dashboard')
cy.url().should('eq', '<http://localhost:3000/login>') // 가져온 URL과 일치하는지 검증

 

  • cy.title() : 페이지 제목을 검증합니다.
cy.title().should('contain', 'Todo List')

 

  • cy.viewport(width, height) : 화면 크기를 변경합니다.
cy.viewport(375, 667)     // iPhone 크기
cy.viewport(1280, 720)    // 데스크톱 크기
cy.viewport('iphone-6')   // 프리셋 사용

 

7) 고급 명령어

  • cy.wrap(object) : Javascript 객체를 Cypress 체인에 포함시킵니다.
const obj = { name: 'test' }
cy.wrap(obj).should('have.property', 'name', 'test')

 

  • cy.window() : 브라우저 window 객체에 접근합니다.
cy.window().its('localStorage').invoke('getItem', 'token')
cy.window().its('location.pathname').should('eq', '/dashboard')

 

  • cy.document() : document 객체에 접근합니다.
cy.document().its('readyState').should('eq', 'complete')

 

8) 자주 사용하는 패턴들

  • 조건부 테스트
cy.get('body').then($body => {
	if ($body.find('.error-message').lenght > 0){
		// 에러 메세지가 있으면 처리
		cy.get('.error-message').should('be.visible')
	} else{
		//없으면 다른 처리
		cy.get('.success-message').should('be.visible')
	}
})

 

  • 체이닝 활용
cy.get('input')
  .clear()                    // 기존 내용 지우기
  .type('새로운 할 일')        // 텍스트 입력
  .should('have.value', '새로운 할 일')  // 검증
  .parent()                   // 부모 요소로 이동
  .find('button')             // 버튼 찾기
  .click()                    // 클릭

 

  • 재사용 가능한 패턴
// 자주 사용하는 동작을 함수로 추출
const addTodo = (text) => {
  cy.get('input[placeholder*="할 일"]').clear().type(text)
  cy.contains('추가').click()
}

// 사용
addTodo('Cypress 공부하기')

 

9) 선택자 우선순위

  1. data-cy 속성 (가장 안정적)
  2. data-test 속성
  3. id 속성
  4. CSS 클래스 (변경 가능성 있음)
  5. 태그명 (가장 불안정)

 

728x90

'프론트엔드' 카테고리의 다른 글

프론트엔드 테스트 기본기와 Cypress  (0) 2025.05.23
CSS의 레이아웃  (1) 2025.01.22
CSS 기본 개념  (1) 2025.01.19
HTML 기본 태그 정리 및 주요 기능  (2) 2025.01.17