Cypress 101 -1

dante Yoon·2022년 2월 1일
1

test

목록 보기
1/3
post-thumbnail
post-custom-banner

cypress

cypress 는 웹 자동화 테스트 프레임워크이다.
Chrome, Edge, Firefox의 브라우저 환경에서 테스팅을 할 수 있으며,
비슷한 테스팅 도구인 playwright 보다 별점이 높다.

현업에서 e2e 테스트 도입을 위해 이번 설 연휴 기간을 이용해 공부를 진행했으며 개인적인 치트시트이자 누군가에게 도움이 되고 싶어 cypress 공부 내용을 정리한다.

install

대단히 쉽다. npm을 통해 cypress 모듈을 설치한 이후 npx cypress open 명령어 실행을 하면 실행 위치에 cypress 폴더가 생긴다.

npm install cypress
npx cypress open

Directory

디렉토리를 살펴보자. config, videos 폴더는 첫 설치시 생성되는 폴더는 아니므로 생략한다.

  • fixture: mock api response의 json 파일이 존재한다.
  • integration: npx cypress open을 통해 실행되는 테스트들이 존재하는 폴더이다. 테스트 코드를 작성할 때 intergartion 파일 내부에 있는 *.spec.js 파일을 작성한다고 보면된다.
  • plugins: cypress 실행 환경변수를 설정할 때 사용한다. cypress.json의 env 키 값에 환경변수를 설정해도 무방하나, 동적으로 개발환경, 프로덕션 환경에 따른 다른 환경변수를 적용하려면 이 폴더의 index.js를 사용해야 한다.
  • support: cypress는 기본적으로 cy 모듈 이하에 있는 함수들을 호출하는데, 사용자 편의성을 위해 커스텀 함수들을 정의할 수 있다.

locators

돔 엘리먼트를 선택하는 방법을 알아보자

특정 영역을 조회할 때

예를 들어 다음과 같이 html 구조가 있다고 하자.

<div>Form</div>

다음 명령어를 통해 div 영역을 선택할 수 있다.

cy.contains("Forms")

다음과 같이 동일한 텍스트를 가지고 있는 돔이 여러 개가 있을 경우는 속성 값을 사용해 돔을 특정할 수 있다.

<div status="warning">Form</div>
<div >Form</div>
cy.contains("[status='warning']","Form") 

위의 명령어를 한글로 번역하면, status 속성 값이 warning이고 Form을 텍스트로 가지고 있는 돔을 가져와라는 말이 된다.

비슷한 문법으로 cy.get이 있다.

cy.get("[status='warning']");

예를 들어 다음 처럼 warning을 이용해 버튼 엘리먼트를 가져오고 싶다면, 다음과 같이 chaning 방식을 이용해 엘리먼트를 가져올 수 있다.

<form>
  <div status="warning"></div>
  <div>
    <button>Click</button>
  </div>
</form>
cy.get("[status='warning']")
  .parents("form")
  .find("button")
  .click();

폼이 여러 개라면, 다음과 같이 should 구문을 이용해 특정한다.

cy.get("[status='warning']")
  .parents("form")
  .should('contain', 'Sign in')
  .find("button")
  .click();

then

selenium의 경우 한 로직에서 선택한 엘리먼트를 재사용하고 싶으면, 일반적인 변수 할당을 사용하면 되지만, cypress는 불가능하다.

// 잘못된 방식
const button = cy.contains('button', 'Read Me');
button.click();

// 올바른 방식
cy.contains('button', 'Read Me')
  .then(button => {
    cy.wrap(button).click()
  })

좀더 살펴보자면, cy를 통해 반환되는 객체와 then을 통해 조회할 수 있는 인자는 다른 타입이다. 전자는 cypress의 객체이며, 인자는 JQuery의 객체이다. 따라서 cy 객체에서 체이닝으로 제공하는 메소드를 사용하기 위해서는cy.wrap을 통해 캐스팅 해줘야 한다.

invoke

특정 돔의 텍스트를 확인한다고 할 때 다음과 같이 contains, should를 사용할 수 있다.

cy.get('[for="findMe"]')
  .should('have.text', 'Find Me')

cy.get('[for="findMe"]')
  .then(label => {
    expect(label.text()).to.equal("Find Me")
  })

// invoke 사용
cy.get('[for="findMe"]')
  .invoke('text')
  .then(text => {
    expect(text).to.equal("Find Me");
  })

좀 더 우아하다고 해야 할까..

Radio button / Checkbox

흔히 스타일링을 위해 label과 input 태그를 함께 사용하고, input 태그는 크기를 줄여 눈에 안보이게 만든다. 이렇게 돔 트리에 없는 경우 check 함수를 통해 돔을 가져올 수 없는데, 다음 처럼 추가 옵션을 주어야 한다.

cy.contains("custom-form", "Using Radio")
  .find('[type="radio"]')
  .then(radioButtons => {
    cy.wrap(radioButtons)
      .first()
      .check({force: true})
      .should('be.checked')
  })

위의 예제에서 first 함수를 통해 첫번 째 radio 버튼을 선택했는데, n 번째 인덱스는 다음과 같이 선택한다.

  ... 
  cy.wrap(radioButtons)
    .eq(2)
    .should('be.disabled')

color

벨로그의 다크모드/라이트 모드 버튼 클릭을 통해 실제로 돔의 색이 변경했는지 알아보려면 어떻게 색깔을 가져와야 할까

const colors = {
  black: "#000",
  white: "#fff",
}

cy.get("color-mode")
  .then(button => {
   const buttonLabel = button.text(); // 버튼 글자가 있다고 가정한다.
    cy.wrap(button).click();
   	cy.get('body').should('have.css', 'background-color', colors[buttonLabel])
  })
  

dialog

특정 상황에서 브라우저에서 제공하는 기본 다이얼로그가 띄어진다고 할 때 이 다이얼로그는 돔의 일부가 아니기에 일반적인 방법으로는 가져올 수 없다.

cy.on('window:confirm', confirm => {
  expect(confirm).to.equal('Confirm Text')
})

근데, 위의 방법으로는 cy.on 이전에 특정 동작이 생략되었든, 아니면 잘못된 로직이 작성되었든지 다이얼로그가 뜨지 않는다면 화면에 나올때까지 무한정 기다리기 때문에 우아한 방법은 아니라고 할 수 있다.

const stub = cy.stub();
cy.on('window:confirm', stub);
cy.get('button')
  .click()
  .then(() => {
    expect(stub.getCall(0)).to.be.calledWith("Confirm Text")
  })

취소 버튼을 누르기 위해서는 다음과 같이 한다.

    cy.on('window:confirm', () => false);

https://www.cypress.io/

profile
성장을 향한 작은 몸부림의 흔적들
post-custom-banner

1개의 댓글

comment-user-thumbnail
2022년 2월 2일

연락 부탁 드리겠습니다. sam.joung@thelabs.kr

답글 달기