기왕 cypress를 설치했으니, 조금 더 잘, 조금 더 깊게 cypress를 활용해보자.
현재 내가 생각하기에 가능한 사용자의 모든 동작들을 시뮬레이션하는 코드를 작성해 볼 것이다.
꽤나 직관적으로 정해져 있기에 큰 어려움 없이 적용할 수 있다.
특정 URL로 이동하여 페이지를 로드한다.
cy.visit('/');
cy.visit('/chart');
cy.visit('/404', { failOnStatusCode: false }); // 4xx, 5xx 시 실패 여부
특정 DOM 요소를 선택한다. 기본적으로 DOM 요소가 나타날 때까지 기다리는 특징이 있다. (기본 4초 대기)
cy.get('#loading').should('exist'); // 기본 4초 동안 기다림
cy.get('#loading').should('not.exist'); // 요소가 사라질 때까지 기다림
선택한 요소에 대한 조건을 확인한다.
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('GET', '/api/bitcoin/assets').as('getCoins');
cy.wait('@getCoins');
특정 이벤트가 완료될 때까지 기다린다.
특정 텍스트가 포함된 DOM 요소를 찾을 수 있다.
cy.contains('다크 모드').click();
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');
});
});
});
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');
});
});
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');
});
});
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');
});
});