E2E 테스트 (Cypress)
Cypress는 현대적인 웹 애플리케이션을 위한 강력한 End-to-End (E2E) 테스팅 도구입니다.
TypeScript와 함께 사용하면 타입 안정성과 개발자 경험을 크게 향상시킬 수 있습니다.
이 절에서는 Cypress를 TypeScript 프로젝트에 통합하고 효과적으로 사용하는 방법을 살펴보겠습니다.
Cypress와 TypeScript 설정
- 필요한 패키지 설치
npm install --save-dev cypress @cypress/typescript-preprocessor typescript
cypress/tsconfig.json
파일 생성
{
"compilerOptions": {
"target": "es5",
"lib": ["es5", "dom"],
"types": ["cypress"]
},
"include": ["**/*.ts"]
}
cypress/plugins/index.js
파일 수정
const wp = require('@cypress/webpack-preprocessor')
module.exports = (on) => {
const options = {
webpackOptions: {
resolve: {
extensions: [".ts", ".js"]
},
module: {
rules: [
{
test: /\.ts$/,
exclude: [/node_modules/],
use: [
{
loader: "ts-loader"
}
]
}
]
}
},
}
on('file:preprocessor', wp(options))
}
TypeScript로 Cypress 테스트 작성
Cypress 명령어와 선택자를 TypeScript로 작성하면 자동완성과 타입 검사의 이점을 누릴 수 있습니다.
describe('Home Page', () => {
it('should display the correct title', () => {
cy.visit('/');
cy.get('h1').should('contain.text', 'Welcome to My App');
});
it('should navigate to the about page', () => {
cy.get('[data-cy="nav-about"]').click();
cy.url().should('include', '/about');
});
});
페이지 객체 모델 (POM) 구현
TypeScript를 사용하여 페이지 객체 모델을 구현하면 테스트 코드의 재사용성과 유지보수성이 향상됩니다.
// pages/HomePage.ts
export class HomePage {
visit() {
cy.visit('/');
}
getTitle() {
return cy.get('h1');
}
navigateToAbout() {
cy.get('[data-cy="nav-about"]').click();
}
}
// tests/home.spec.ts
import { HomePage } from '../pages/HomePage';
describe('Home Page', () => {
const homePage = new HomePage();
it('should display the correct title', () => {
homePage.visit();
homePage.getTitle().should('contain.text', 'Welcome to My App');
});
it('should navigate to the about page', () => {
homePage.navigateToAbout();
cy.url().should('include', '/about');
});
});
커스텀 명령어 정의 및 사용
TypeScript로 Cypress 커스텀 명령어를 정의하고 사용하면 코드 재사용성이 향상됩니다.
// cypress/support/commands.ts
declare global {
namespace Cypress {
interface Chainable {
login(email: string, password: string): Chainable<void>
}
}
}
Cypress.Commands.add('login', (email: string, password: string) => {
cy.get('#email').type(email);
cy.get('#password').type(password);
cy.get('#login-button').click();
});
// 사용 예
cy.login('[email protected]', 'password123');
API 요청 모킹 및 스터빙
TypeScript 환경에서 Cypress를 사용하여 API 요청을 모킹하고 스터빙하는 방법
interface User {
id: number;
name: string;
}
cy.intercept('GET', '/api/users', (req) => {
req.reply({
statusCode: 200,
body: {
users: [
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'Jane Doe' }
] as User[]
}
});
}).as('getUsers');
cy.visit('/users');
cy.wait('@getUsers');
cy.get('.user-list').should('have.length', 2);
비동기 패턴 다루기
Cypress의 비동기 특성과 TypeScript의 비동기 패턴을 조화롭게 사용하는 전략
cy.get('.loader').should('not.exist').then(() => {
return new Cypress.Promise(resolve => {
// 비동기 작업 수행
setTimeout(() => {
resolve('Data loaded');
}, 1000);
});
}).then((result: string) => {
expect(result).to.eq('Data loaded');
cy.get('.data-container').should('be.visible');
});
타입 관련 문제 해결
Cypress 테스트에서 발생할 수 있는 타입 관련 문제들과 해결 방법
cy.stub()
사용 시 타입 정의
interface MyObject {
myMethod: (arg: string) => number;
}
const stub = cy.stub().as('myStub');
(stub as unknown as MyObject['myMethod'])('test');
cy.wrap()
사용 시 타입 단언
const wrappedValue = cy.wrap('Hello') as unknown as Cypress.Chainable<string>;
wrappedValue.should('eq', 'Hello');
Cypress 대시보드 및 CI/CD 통합
- Cypress 대시보드 설정
npx cypress run --record --key your-project-key
- CI/CD 파이프라인 (예: GitHub Actions) 설정
name: Cypress Tests
on: [push]
jobs:
cypress-run:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Cypress run
uses: cypress-io/github-action@v2
with:
command: npm run test:e2e
record: true
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
Best Practices
- 데이터 독립성 : 각 테스트가 독립적으로 실행될 수 있도록 테스트 데이터 관리
- 선택자 관리 : 데이터 속성 사용 (
data-cy
)을 통한 안정적인 선택자 관리 - 네트워크 요청 처리 :
cy.intercept()
를 사용하여 네트워크 요청 제어 및 응답 시뮬레이션 - 타입 안정성 활용 : TypeScript의 타입 시스템을 최대한 활용하여 오류 사전 방지
- 페이지 객체 모델 사용 : 테스트 코드의 구조화 및 재사용성 향상
- 병렬 실행 : Cypress의 병렬 실행 기능을 활용하여 테스트 실행 시간 단축
- 시각적 회귀 테스트 : Cypress의 이미지 스냅샷 기능을 활용한 UI 변경 감지
- 성능 모니터링 : Cypress의 성능 측정 기능을 활용하여 애플리케이션 성능 모니터링
- 지속적인 통합 : CI/CD 파이프라인에 Cypress 테스트 통합
- 문서화 : 테스트 케이스에 대한 명확한 설명과 주석 추가