Cypress는 assertion이 실패할 경우 연결되어 있는 모든 커맨드 체인을 통과할 때까지 계속하여 재실행한다.
예를 들어 다음과 같이 DOM li
요소 하나를 get하여 그 개수를 조사하는 테스트를 짠다고 해 보자.
cy.get('.todoapp') // query
.find('.todo-list li') // query
.should('have.length', 1) // assertion
위의 코드를 곧이곧대로 보면 한 가지 문제가 있다. 이 테스트가 DOM 요소가 모두 마운트되지 않은 상태에서 실행되면 늘 실패할 수 있다는 것이다. 웹 페이지는 늘 비동기적으로 화면에 그려지므로 애초에 테스트 코드에서 요구하는 DOM 요소를 가져올 수 없는 경우가 충분히 일어날 수 있다.
그렇기 때문에 Cypress는 해당 체인에서 assertion이 실패한 경우 연결되어 있는 .get()
이나 .find()
와 같은 쿼리들을 포함한 전체 커맨드 체인을 맨 처음부터 재실행한다. 만약 그럼에도 계속 실패한다면? 그렇다면 정해진 타임아웃 시간(default 값은 4초)이 될 때까지 연달아 시도한다.
그렇다면 어느 상황에서 assertion을 사용하는 것이 좋을까? 정답은 최대한 사용하지 않는 것이다(참고). 왜냐하면 이미 대부분의 Cypress 커맨드들은 자체적인 assertion을 갖고 있기 때문이다. 따라서 명시적(explicit)인 assertion을 사용하지 않아도 암시적(implicit)인 assertion을 통해서도 충분히 테스트를 진행할 수 있다.
아래는 assertion 커맨드가 없는 테스트 코드의 예시이다. 비록 assertion이 없지만 이 테스트는 나름 견고한 테스트라 볼 수 있는데,
cy.visit()
에서 페이지를 갖고 오지 못함cy.get()
에서 DOM 요소가 없음.type()
으로 텍스트를 입력하려 하나 disable 처리가 되어 있음등등 이미 각 커맨드에서 assertion을 자체적으로 진행하고 있기 때문이다.
cy.visit('/home')
cy.get('.main-menu').contains('New Project').click()
cy.get('.title').type('My Awesome Project')
cy.get('form').submit()
또한 assertion이 존재하는 커맨드 체인에서 assertion이 실패하면 다시 해당 체인을 처음부터 재실행하는 것처럼, 각각의 커맨드들의 implicit assertion 역시 이와 같다. 예를 들어 action 커맨드들은 해당 요소가 상호작용이 가능할 때(actionable)까지 기다리기도 하고 페이지가 업데이트될 때를 대비하여 쿼리 체인을 재실행하기도 하며 테스트의 신뢰성을 높인다.