Next.js로 이것저것 (6) - cypress로 E2E 흉내내보기

sham·2025년 1월 2일
0

Next.js 제로베이스

목록 보기
9/9
post-thumbnail

개요

기왕 cypress를 설치했으니, 조금 더 잘, 조금 더 깊게 cypress를 활용해보자.

현재 내가 생각하기에 가능한 사용자의 모든 동작들을 시뮬레이션하는 코드를 작성해 볼 것이다.

본문

주요 모듈

꽤나 직관적으로 정해져 있기에 큰 어려움 없이 적용할 수 있다.

cy.visit()

특정 URL로 이동하여 페이지를 로드한다.

cy.visit('/');
cy.visit('/chart');
cy.visit('/404', { failOnStatusCode: false }); // 4xx, 5xx 시 실패 여부

cy.get()

특정 DOM 요소를 선택한다. 기본적으로 DOM 요소가 나타날 때까지 기다리는 특징이 있다. (기본 4초 대기)

cy.get('#loading').should('exist'); // 기본 4초 동안 기다림
cy.get('#loading').should('not.exist'); // 요소가 사라질 때까지 기다림

cy.should()

선택한 요소에 대한 조건을 확인한다.

  • exist: 요소가 존재하는지 확인.
  • not.exist: 요소가 존재하지 않는지 확인.
  • be.enabled: 요소가 활성화되어 있는지 확인.
  • be.disabled: 요소가 비활성화 상태인지 확인.
  • have.attr: 특정 속성이 존재하는지 확인.
  • contain.text: 텍스트가 포함되어 있는지 확인.
cy.get('#loading').should('exist'); // 존재 여부 확인
cy.get('button').should('be.enabled'); // 활성화 상태 확인
cy.get('html').should('have.attr', 'data-theme', 'light'); // 속성 확인

cy.intercept()

네트워크 요청을 가로채고 요청/응답 데이터를 확인한다.

cy.intercept('GET', '/api/bitcoin/assets').as('getCoins');
cy.wait('@getCoins');

cy.wait()

특정 이벤트가 완료될 때까지 기다린다.

cy.contains()

특정 텍스트가 포함된 DOM 요소를 찾을 수 있다.

cy.contains('다크 모드').click();

실제 테스트 코드

rootLayout-themeTest.cy.ts

describe('Dark Mode Toggle', () => {
  beforeEach(() => {
    localStorage.setItem('darkMode', 'false'); // 초기값을 라이트 모드로 설정
    cy.visit('/');
  });

  it('초기 테스트 - data-theme=light', () => {
    // 초기 상태에서 body의 data-theme 속성이 light여야 함
    cy.get('html').should('have.attr', 'data-theme', 'light');
  });

  it('다크 모드 클릭 - light -> dark', () => {
    cy.get('button').click();
    cy.get('html').should('have.attr', 'data-theme', 'dark');
    // localStorage에 darkMode 값이 true로 저장되어야 함
    cy.window().then(win => {
      expect(win.localStorage.getItem('darkMode')).to.equal('true');
    });
  });

  it('다크 모드 2번 클릭 - light -> dark -> light', () => {
    cy.get('button').should('be.enabled').click();
    cy.get('button').should('be.enabled').click();
    cy.get('html').should('have.attr', 'data-theme', 'light');

    // localStorage에 darkMode 값이 false로 저장되어야 함
    cy.window().then(win => {
      expect(win.localStorage.getItem('darkMode')).to.equal('false');
    });
  });
});

chartPage-BasicTest.cy.ts

describe('Chart Page - Basic Test', () => {
  it('Visit the Chart page', () => {
    cy.visit('/chart');
    cy.intercept('GET', 'api/bitcoin/assets/history?coin=bitcoin&interval=m1').as('getCharts');

    // 로딩 확인
    cy.get('#loading').should('exist');

    // API 응답 확인
    cy.wait('@getCharts', { timeout: 5000 });
    cy.get('#loading').should('not.exist');
    cy.get('@getCharts').its('response.statusCode').should('eq', 200); // 응답 코드 확인

    // 차트가 렌더링되었는지 확인
    cy.get('#chart').should('exist');
  });
});

mainPage-BasicTest.cy.ts

describe('Main Page - Basic Test', () => {
  it('Visit the main page', () => {
    cy.visit('/');

    cy.intercept('GET', '/api/bitcoin/assets').as('getCoins');

    // 로딩 확인
    cy.get('#loading').should('exist');

    // API 응답 확인
    cy.wait('@getCoins', { timeout: 5000 });
    cy.get('#loading').should('not.exist');

    cy.get('@getCoins').its('response.statusCode').should('eq', 200); // 응답 코드 확인

    // 테이블이 렌더링되었는지 확인
    cy.get('#table').should('exist');
  });
});

routeTest.cy.ts

describe('Route Test', () => {
  it('Visit the main page', () => {
    cy.visit('/');
    cy.get('#loading').should('exist');
    cy.get('#loading').should('not.exist');
    cy.get('#table').should('exist');
  });

  it('Visit the Chart page', () => {
    cy.visit('/chart');
    cy.get('#loading').should('exist');
    cy.get('#loading').should('not.exist');
    cy.get('#chart').should('exist');
  });

  it('Visit the NotFound page', () => {
    cy.visit('/404', { failOnStatusCode: false });
    cy.get('#not-found').should('exist');
  });

  it('cache the page', () => {
    cy.visit('/');
    cy.get('#loading').should('not.exist');
    cy.get('#table').should('exist');

    cy.visit('/chart');
    cy.get('#loading').should('not.exist');
    cy.get('#chart').should('exist');
  });
});
profile
씨앗 개발자

0개의 댓글