e2e test, Cypress

Hoon·2024년 6월 25일
0

FrontEnd

목록 보기
8/10
post-thumbnail

오랜만에 작성하는 e2e test... 오랜만에 해서 까먹기도하고, 복잡한 iframe 구조와 인증구조 때문에 어려움을 겪어 정리해본다

e2e test

e2e test : e2e test는 End-to-End test 의 약자로, 사용자 관점에서 전체적인 시스템의 흐름을 테스트 하는 소프트웨어 테스트이다. 이 테스트의 목적은 실제 생산 환경과 유사한 환경에서 시스템이 전체적인 비즈니스 목표에 충족하는지 확인하기 위해 실제 사용자 시나리오를 시뮬레이션한다.

Cypress

Cypress란 e2e Testing library 중 하나로 e2e test를 위한 도구이다. headless 모드도 제공하지만, GUI 환경도 지원하여 손쉽게 테스트 및 관리할 수 있다는 장점이있다. (단위, 통합테스트도 제공)

$ yarn add cypress

// package.json
"scripts": {
	...
    "cy:open": "cypress open", (GUI)
    "cy:run": "cypress run", (headless)
    ...
 },

install 한 후 위의 script로 Cypress를 실행 할 수 있다.

Cypress folder

기본적으로 아래의 폴더구조를 가진다.

cypress/e2e : e2e 테스트 파일들이 위치 *.cy.js 의 네이밍을 가진다.

cypress/fixture : 테스트에 사용할 정적 데이터 파일들을 보관한다.

cypress/support : 공용으로 사용할 함수를 정의하거나, 테스트 전 사전에 실행할 코드를 작성한 파일들을 보관한다. (보통 commands.js 에 함수를 정의)

이외의 옵션에 따라 videos , screenshots 등이 추가된다.

*.cy.js

// test.cy.js
describe('test 대분류명', () => {
  before(() => {
    // 블록의 모든 테스트 전에 한 번 실행
  })

  beforeEach(() => {
    // 블록의 각 테스트 전에 실행
  })

  afterEach(() => {
    // 블록의 각 테스트 후에 실행
  })

  after(() => {
    // 블록의 모든 테스트 후 한 번 실행
  })
  
  it('테스트 이름', () => {
  	// test code
  });
  
  context('테스트 그룹 이름', () => {  // context -> 가독성을 위해 그룹화 용도로 사용 (optional)
      it('테스트2 이름', () => {
        // test code
      });
    
      it('테스트3 이름', () => {
        // test code
      });
  });
})

*.cy.js 는 기본적으로 위의 구조를 가진다.

function

아래는 기본적인 cy 함수들이다. 아래의 함수들을 활용하여 테스트 코드를 작성한다.

cy.viewport() : 테스트 화면 크기 지정

cy.viewport(1920, 1080);

cy.visit() : 웹 사이트 방문

cy.visit('https://google.com');

cy.wait() : 대기 (단위는 ms)

cy.wait(3000);

cy.get() : 선택자에 해당하는 엘리먼트를 반환 (여러개 가져올수있음)

cy.get('#title');
cy.get('.title');

// Cypress에서는 html element에 data-cy attribute를 추가해 사용할 것을 권장한다.
cy.get('[data-cy="title"]'); 

cy.contains() : text 내용을 포함한 엘리먼트 반환

cy.contains('제목');

cy.find() : 이미 선택된 요소의 자식 요소를 반환

cy.get('#my-form').find('#my-btn');

cy.type() : 텍스트 입력

cy.get('#my-input').type('입력값')

cy.click() : 요소 클릭

cy.get('#my-btn').click();

cy.should() : 특정 조건이 충족되는지 확인

cy.contains('제목').should('exist');
cy.get('#my-btn').should('be.disabled');
cy.get('#my-btn').should('not.be.disabled');
cy.get('#my-input').should('have.value', value);
cy.get('#my-tab').should('have.attr', 'aria-selected', 'true');

// 등등...

cy.intercept : 네트워크 요청을 가로채고 제어함

cy.intercept('GET', '/user').as('getUser');

// api 요청까지 대기
cy.wait('@getUser');

// api 요청 code 확인
cy.wait('@getUser').then((api) => {
  expect(api.response.statusCode).to.eq(200);
});

// post user 요청에 대해 실제 요청을 보내지않고, response를 반환함
cy.intercept('POST', '/user', { statusCode: 200 });

commands.js

commands.js 에 자주 사용하는 테스트 코드를 함수화 하여 작성할 수 있다.

// commands.js
Cypress.Commands.add('initService', (url) => {
  cy.viewport(1920, 1080);
  cy.visit(url, { headers });
});

// test.cy.js
cy.initService('https://google.com');

iframe

지금 내가 테스트하는 환경은 iframe 내에서 동작하고있어 조금 다르게 진행해야했다.
wrapwithin 을 사용하여 테스트코드를 작성하고있다.

여기서 within 은 특정 요소를 선택한 뒤 이후 cy 메소드의 범위를 선택한 요소 내부로 제한한다.

// commands.js
Cypress.Commands.add('getIframe', () => {
  return cy.get('#iframe').then(($iframe) => {
    const $body = $iframe.contents().find('body');
    return cy.wrap($body);
  });
});

// test.cy.js
cy.getIframe().within(() => {
  // 테스트 코드 ...
});

profile
4년차 개발자 Hoon입니다

0개의 댓글

관련 채용 정보