Cypress 시작하기 — 사용자처럼 테스트하기
Cypress 시작하기 — 사용자처럼 테스트하기
Cypress로 테스트를 쓸 때 가장 먼저 이해할 것이 "사용자가 앱을 쓰는 것처럼 행동한다"는 원칙이에요. 이 문서는 Cypress 앱을 이해하는 가장 중요한 가이드예요. 쿼리 방법, 커맨드 체인, 비동기 특성, 요소 상호작용과 단언까지, Cypress로 생산적으로 테스트하는 법의 뼈대를 담고 있어요.
간단한 테스트 예제
다음 예제는 새 글을 작성하는 흐름을 테스트해요. 페이지를 방문하고, 인풋에 글을 입력하고, 버튼을 클릭하고, 결과를 확인하는 일련의 동작이 자연스러운 영어 문장처럼 읽혀요.
describe('Post Resource', () => {
it('Creating a New Post', () => {
cy.visit('/posts/new') // 1.
cy.get("input.post-title") // 2.
.type("My First Post") // 3.
cy.get("input.post-body") // 4.
.type("Hello, world!") // 5.
cy.contains("Submit") // 6.
.click() // 7.
cy.get("h1") // 8.
.should("contain", "My First Post")
})
})
이 흐름을 읽어 보면 이렇게 이어져요. /posts/new 페이지를 방문하고, post-title 클래스의 <input>을 찾아 "My First Post"를 입력하고, post-body 인풋에 "Hello, world!"를 입력하고, Submit 텍스트를 가진 요소를 찾아 클릭하고, h1 태그에 "My First Post"가 들어 있는지 확인해요.
이 테스트가 클라이언트와 서버 코드 양쪽에서 얼마나 많은 부분을 커버하는지 생각해 보면 놀랍죠.
요소 쿼리 — jQuery 스타일
Cypress에서 요소를 쿼리하는 방식은 jQuery와 같아요. jQuery에 익숙하다면 $('.my-selector')처럼 쓰던 걸 cy.get('.my-selector')로 쓰는 것뿐이에요.
cy.get('.my-selector')
실제로 Cypress는 jQuery를 번들하고 DOM 순회 메서드도 많이 노출해서, 이미 아는 API로 복잡한 HTML 구조를 쉽게 다룰 수 있어요.
// 각 Cypress 쿼리는 jQuery 대응부와 동일해요.
cy.get('#main-content')
.find('.article')
.children('img[src^="/static"]')
.first()
커맨드 체인과 비동기
Cypress 커맨드는 비동기로 큐에 쌓여 실행돼요. 그래서 cy.get() 같은 커맨드의 반환값을 일반 변수에 담아 쓰면 기대와 다르게 동작해요. 커맨드가 산출하는 값에 접근하려면 .then()을 써요.
cy.get('button').then(($btn) => {
// $btn is the object that the previous command yielded us
})
이는 네이티브 Promise와 비슷하게 동작해서, .then() 안에 더 많은 Cypress 커맨드를 중첩할 수 있어요.
타임아웃
Cypress의 커맨드들은 각자 타임아웃을 가져요. 예를 들어 cy.wait()은 두 가지 타임아웃을 써요 — 라우팅 별칭을 기다릴 때는 매칭 요청을 5000ms, 그리고 서버 응답을 30000ms 동안 기다려요. 그 밖의 대부분의 커맨드(모든 DOM 쿼리 포함)는 기본적으로 4000ms 후 타임아웃돼요.
정리하면, Cypress 테스트는 "사용자처럼 요소를 찾고(cy.get), 조작하고(type·click), 결과를 단언(should)하는" 체인으로 구성돼요. 비동기 커맨드의 산출값은 .then()으로 접근한다는 점을 기억하면 돼요.