Cypress 변수와 별칭 — 비동기 값 다루기

Cypress 변수와 별칭 — 비동기 값 다루기

Cypress는 비동기 API라서, 처음에는 커맨드가 산출하는 객체를 어떻게 참조하고 비교하고 활용할지 헷갈리기 쉬워요. 이 가이드는 Cypress로 복잡한 상황을 다루는 흔한 패턴을 여러 개 소개해요. 그중 핵심 원칙 하나는 "Cypress 커맨드의 반환값을 변수에 담아 쓰면 안 된다"는 거예요.

출처: Variables and aliases in Cypress | Cypress Documentation

중요: Cypress 커맨드의 반환값을 변수에 할당하거나 그걸로 작업할 수 없어요. 커맨드는 큐에 쌓여 비동기로 실행되기 때문이에요.

// this won't work the way you think it does
const button = cy.get('button')
const form = cy.get('form')
button.click()

클로저로 값에 접근하기

각 Cypress 커맨드가 산출하는 값에 접근하려면 .then()을 써요.

cy.get('button').then(($btn) => {
  // $btn is the object that the previous command yielded us
})

네이티브 Promise에 익숙하다면 Cypress의 .then()도 비슷하게 동작한다고 보면 돼요. .then() 안에 더 많은 Cypress 커맨드를 중첩할 수 있어요.

cy.get('button').then(($btn) => {
  // store the button's text
  const txt = $btn.text()
  // submit a form
  cy.get('form').submit()
  // compare the two buttons' text and make sure they are different
  cy.get('button').should(($btn2) => {
    expect($btn2.text()).not.to.eq(txt)
  })
})

.then() 밖의 커맨드는 중첩된 커맨드가 모두 끝날 때까지 실행되지 않아요. 콜백 함수를 쓰면서 우리는 **클로저(closure)**를 만들었어요. 클로저 덕분에 이전 커맨드에서 한 작업을 참조하는 참조를 계속 유지할 수 있어요.

디버깅

.then() 함수는 debugger를 쓰기에 좋은 기회예요. 커맨드가 실행되는 순서를 이해하고, 각 커맨드가 산출하는 객체를 검사하는 데 도움이 돼요.

cy.get('button').then(($btn) => {
  // inspect $btn <object>
  debugger
  cy.get('[data-testid="countries"]').select('USA').then(($select) => {
    // inspect $select <object>
    debugger
  })
})

별칭으로 값 공유하기

후크(hook)와 테스트 사이에서 객체를 공유하려면 변수 대신 **별칭(alias)**을 쓰는 게 좋아요. cy.as()로 별칭을 만들고, cy.get('@alias')로 참조해요.

beforeEach(() => {
  cy.wrap('some value').as('exampleValue')
})

it('works in the first test', () => {
  cy.get('@exampleValue').should('equal', 'some value')
})

별칭은 각 테스트가 시작하기 전에 리셋돼요. 그래서 before가 아니라 beforeEach에서 만들어야 각 테스트에서 유효해요. 별칭은 DOM 요소, intercept(네트워크 요청), request 등 여러 대상을 지정할 수 있어요.

정리하면, Cypress 커맨드의 비동기 산출값은 변수에 담지 말고 .then()이나 별칭(cy.as·cy.get('@...'))으로 접근하는 것이 정석이에요. 특히 훅과 테스트 사이에서 값을 공유할 때는 별칭이 필수예요.

더 알아보기