Cypress "Commands"에서 "wait" 프로그래밍


기본적인 사용

cy.get('#myButton').click();
cy.wait(2000); // 2초 동안 기다립니다.
cy.get('#myResult').should('be.visible'); // '#myResult' 요소가 표시되는지 확인합니다.

위 예시에서 cy.wait(2000)#myButton 버튼을 클릭한 후 2초 동안 기다린 후 #myResult 요소가 표시되는지 확인합니다.

조건 기반 대기

wait는 다양한 조건을 사용하여 특정 상황이 발생할 때까지 기다릴 수 있도록 합니다.

  • DOM 요소 확인:

    cy.get('#myInput').type('Hello, world!');
    cy.wait(() => $('#myInput').val() === 'Hello, world!'); // '#myInput' 요소의 값이 'Hello, world!'인지 확인합니다.
    
  • API 응답 확인:

    cy.request('GET', '/api/data');
    cy.wait((response) => response.status === 200); // API 요청이 성공적으로 처리되었는지 확인합니다.
    
  • 사용자 상호 작용 확인:

    cy.get('#myLink').click();
    cy.wait(() => window.location.href === '/new-page'); // '#myLink' 클릭 후 페이지 URL이 '/new-page'로 변경되었는지 확인합니다.
    

타임아웃 설정

wait는 선택적으로 타임아웃 값을 설정할 수 있습니다. 예상되는 결과가 나타나지 않으면 테스트가 실패하게 됩니다.

cy.get('#myButton').click();
cy.wait(2000, { timeout: 1000 }); // 2초 동안 기다렸다가 타임아웃 발생

추가적인 사용법

  • "until" 옵션: 특정 조건이 충족될 때까지 계속 기다립니다.
    cy.get('#mySpinner').should('be.visible');
    cy.wait('until', () => $('#mySpinner').is(':hidden')); // '#mySpinner' 로더가 사라질 때까지 기다립니다.
    
  • "multiple" 옵션: 여러 조건 중 하나라도 충족되면 기다리는 것을 중단합니다.
    cy.get('#myForm').submit();
    cy.wait(['#mySuccessMessage', '#myErrorMessage'], { timeout: 1000 }); // '#mySuccessMessage' 또는 '#myErrorMessage' 중 하나가 나타날 때까지 기다립니다.
    


Cypress "wait" 관련 샘플 코드

DOM 요소 확인

describe('Waiting for DOM elements', () => {
  it('Should wait for an element to be visible', () => {
    cy.visit('/example.html');
    cy.get('#myButton').click();
    cy.wait(() => $('#myResult').is(':visible')); // '#myResult' 요소가 표시될 때까지 기다립니다.
    cy.get('#myResult').should('contain', 'Success!'); // '#myResult' 요소의 내용 확인
  });

  it('Should wait for an element to have a specific value', () => {
    cy.visit('/example.html');
    cy.get('#myInput').type('Hello, world!');
    cy.wait(() => $('#myInput').val() === 'Hello, world!'); // '#myInput' 요소의 값이 'Hello, world!'인지 확인
    cy.get('#myInput').should('have.value', 'Hello, world!'); // '#myInput' 요소의 값 확인
  });
});

API 응답 확인

describe('Waiting for API responses', () => {
  it('Should wait for a successful API request', () => {
    cy.request('GET', '/api/data');
    cy.wait((response) => response.status === 200); // API 요청이 성공적으로 처리되었는지 확인
    cy.get(response.body.data).should('have.length', 10); // 응답 데이터 확인
  });

  it('Should wait for an API request to fail', () => {
    cy.request('GET', '/api/error');
    cy.wait((response) => response.status === 500); // API 요청이 실패했는지 확인
    cy.get(response.body.error).should('equal', 'Internal server error'); // 오류 메시지 확인
  });
});

사용자 상호 작용 확인

describe('Waiting for user interactions', () => {
  it('Should wait for a page to load', () => {
    cy.visit('/example.html');
    cy.get('#myLink').click();
    cy.wait(() => window.location.href === '/new-page'); // 페이지 URL 변경 확인
    cy.get('#newPageTitle').should('contain', 'New Page'); // 새 페이지 제목 확인
  });

  it('Should wait for an alert to be displayed', () => {
    cy.visit('/example.html');
    cy.get('#myAlertButton').click();
    cy.on('window:alert', (text) => {
      expect(text).to.equal('This is an alert!');
    });
  });
});

조건 기반 대기

describe('Conditional waiting', () => {
  it('Should wait using "until" option', () => {
    cy.visit('/example.html');
    cy.get('#mySpinner').should('be.visible');
    cy.wait('until', () => $('#mySpinner').is(':hidden')); // '#mySpinner' 로더가 사라질 때까지 기다립니다.
    cy.get('#myContent').should('be.visible'); // '#myContent' 요소가 표시되는지 확인
  });

  it('Should wait using "multiple" option', () => {
    cy.visit('/example.html');
    cy.get('#myForm').submit();
    cy.wait(['#mySuccessMessage', '#myErrorMessage'], { timeout: 1000 }); // '#mySuccessMessage' 또는 '#myErrorMessage' 중 하나가 나타날 때까지 기다립니다.
    cy.get('#myResult').should('be.visible'); // '#myResult' 요소가 표시되는지 확인
  });
});

타임아웃 설정

describe('Waiting with timeout', () => {
  it('Should wait with a timeout', () => {
    cy.visit('/example.html');
    cy.get('#myButton').click();
    cy.wait(2000, { timeout: 1000 }); // 2초 동안 기다렸다가 타임아웃 발생
    cy.get('#myResult').should('not.exist'); // '#myResult


Cypress "wait"의 대안

다음은 몇 가지 대안과 각각의 장단점입니다.

cy.get().should():

장점:

  • 간단하고 명확한 구문
  • DOM 요소의 상태를 직접 확인하는 데 유용

단점:

  • 특정 조건에만 적합 (예: 요소가 표시되거나 특정 값을 갖는 경우)
  • 비동기 작업 처리에 어려움

예시:

cy.get('#myButton').click();
cy.get('#myResult').should('be.visible'); // '#myResult' 요소가 표시되는지 확인합니다.

cy.request().then():

  • API 요청의 응답을 처리하는 데 유용
  • 응답 데이터를 테스트 코드에서 사용할 수 있음
  • DOM 요소와 직접 상호 작용하는 데는 적합하지 않음
cy.request('GET', '/api/data').then((response) => {
  expect(response.status).to.equal(200);
  expect(response.body.data).to.have.length(10);
});

cy.on():

  • 사용자 상호 작용, DOM 이벤트, 타이머 등 다양한 이벤트를 처리하는 데 유용
  • 복잡한 테스트 시나리오에서 사용하기 어려울 수 있음
cy.get('#myLink').click();
cy.on('window:load', () => {
  expect(window.location.href).to.equal('/new-page');
});

cy.clock():

  • 비동기 작업을 제어하고 테스트 코드 실행 속도를 조절하는 데 유용
  • 테스트 코드의 복잡성을 증가시킬 수 있음
cy.clock();
cy.get('#myButton').click();
cy.tick(1000); // 1초 동안 기다립니다.
cy.get('#myResult').should('be.visible'); // '#myResult' 요소가 표시되는지 확인합니다.
cy.clock.restore();

커스텀 커맨드:

  • 특정 상황에 맞는 재사용 가능한 코드를 만들 수 있음
  • 테스트 코드를 더욱 명확하고 이해하기 쉽게 만들 수 있음
  • 개발 및 유지 관리에 더 많은 노력이 필요함
Cypress.Commands.add('waitForElement', (selector, timeout) => {
  cy.wait(() => cy.get(selector).is(':visible'), { timeout });
});

cy.visit('/example.html');
cy.get('#myButton').click();
cy.waitForElement('#myResult', 2000); // '#myResult' 요소가 2초 동안 표시될 때까지 기다립니다.

결론

Cypress "wait"는 테스트 코드에서 특정 조건이 충족될 때까지 기다리는 데 유용한 도구이지만, 상황에 따라 더 적합한 대안을 사용하는 것이 좋습니다.