Frontend/Cypress

Cypress, React Testing Library에서 제공하는 비동기 쿼리 메서드 체인 안되는 부분 해결 방법

wam 2024. 11. 25. 17:37

 

Cypress testing libray를 설치 후 Form 가져오기

describe("로그인", () => {
  it("홈페이지로 이동해야 합니다.", () => {
    cy.visit("/").title().should("eq", "로그인 | Nuber Eats");
  });

  it("Form에 내용을 입력해야 합니다.", () => {
    cy.visit("/")
      .findByPlaceholderText("이메일")
      .type("test@mail.com")
      .findByPlaceholderText("비밀번호")
      .type("123123")
      .findByRole("button")
      .should("not.have.class", "pointer-events-none");
  });
});

 

 

 

Cypress 실행하여 테스트

npx cypress open

 

 

테스트 결과 : 에러 - 체인으로 연결되지 않았음

  • react tesing library - 계속 연결하는 걸 허용하지 않음 - 분리가 필요
    • findBy로 시작하는 커스텀 쿼리 함수는 체인 방식으로 작동하지 않음
    • findByPlaceholderText와 같은 findBy 메서드는 React Testing Library에서 제공하는 비동기 쿼리 메서드이다.
    • 이유는 Cypress의 findBy 메서드가 기본적으로 Promise 객체를 반환한다.
    • Cypress는 비동기 방식으로 DOM을 조회하고 상태를 확인하는 특성을 가지고 있기 때문이다.
    • findByPlaceholderText를 사용할 때, 또 다른 cy로 분리해야 한다.

 

 

에러 해결 방법 01 : cy 분리하여 작성

describe("로그인", () => {
  it("홈페이지로 이동해야 합니다.", () => {
    cy.visit("/").title().should("eq", "로그인 | Nuber Eats");
  });

  it("Form에 내용을 입력해야 합니다.", () => {
    cy.visit("/");
    cy.findByPlaceholderText("이메일").type("test@mail.com");
    cy.findByPlaceholderText("비밀번호").type("123123");
    cy.findByRole("button").should("not.have.class", "pointer-events-none");
  });

  it("이메일, 비밀번호 검증의 오류를 표시해야 합니다.", () => {
    cy.visit("/");
    cy.findByPlaceholderText("이메일").type("bad@email");
    cy.findByRole("alert").should("have.text", "잘못된 이메일 형식입니다.");
  });
});
  • .type은 체인 가능

 

 

cy를 변수명으로 교체

describe("로그인", () => {
  const user = cy;
  
  it("홈페이지로 이동해야 합니다.", () => {
    user.visit("/").title().should("eq", "로그인 | Nuber Eats");
  });

  it("Form에 내용을 입력해야 합니다.", () => {
    user.visit("/");
    user.findByPlaceholderText("이메일").type("test@mail.com");
    user.findByPlaceholderText("비밀번호").type("123123");
    user.findByRole("button").should("not.have.class", "pointer-events-none");
  });

  it("이메일, 비밀번호 검증의 오류를 표시해야 합니다.", () => {
    user.visit("/");
    user.findByPlaceholderText("이메일").type("bad@email");
    user.findByRole("alert").should("have.text", "잘못된 이메일 형식입니다.");
  });
});

보기 좋게 하려는 의도

 

 

해결방법 02 : 체인으로 사용하고 싶다면 findBy를 쓰는 대신 get 사용

describe("로그인", () => {
  const user = cy;

  it("홈페이지로 이동해야 합니다.", () => {
    user.visit("/").title().should("eq", "로그인 | Nuber Eats");
  });

  it("Form에 내용을 입력해야 합니다.", () => {
    user
      .visit("/")
      .get("input[placeholder='이메일']")
      .type("test@mail.com")
      .get("input[placeholder='비밀번호']")
      .type("123123")
      .get("button")
      .should("not.have.class", "pointer-events-none");
  });

  it("이메일, 비밀번호 검증의 오류를 표시해야 합니다.", () => {
    user
      .visit("/")
      .get("input[placeholder='이메일']")
      .type("bad@email")
      .get('[role="alert"]')
      .should("have.text", "잘못된 이메일 형식입니다.");
  });
});
  • Cypress 기본 메서드 cy.get()을사용하는 것이 좋다.
  • 비동기적인 메서드들에 대해 .then() 을 사용하여 후속 작업을 수행할 수 있다.
  • Cypress 기본 메서드 cy.get()은 DOM을 찾아 해당 요소에 대한 명령어를 체인 방식으로 사용할 수 있게 해 준다.
  • 이 경우, CSS 선택자나 텍스트를 기반으로 요소를 찾는다.