테스트 작성과 파일 구성
테스트 작성과 파일 구성 (Writing and Organizing Tests)
Cypress는 **설정보다 관례(convention over configuration)**를 선호해요. 새 프로젝트를 만들면 권장 폴더 구조가 자동으로 생겨서, 파일을 어디에 둘지 고민하거나 빌드 단계를 연결하지 않아도 바로 테스트를 쓸 수 있습니다. 물론 전부 다시 설정할 수 있지만, 기본값만으로도 대부분은 충분히 편리해요. 이 글에서는 Cypress가 프로젝트를 어떻게 구성하는지, 스펙·서포트·픽스처 파일이 각각 무슨 역할을 하는지 살펴볼게요.
출처: Cypress 공식 문서 — Writing and organizing Cypress tests 원본 URL: https://docs.cypress.io/app/core-concepts/writing-and-organizing-tests
기본 폴더 구조
Cypress는 기본적으로 아래 같은 구조를 만들어 줍니다. E2E만 쓰면 cypress/support/e2e.js, 컴포넌트만 쓰면 cypress/support/component.js와 component-index.html이 생기고, 둘 다 쓰면 둘 다 나타나요.
/cypress.config.js
/cypress/fixtures/example.json
/cypress/support/commands.js
/cypress/support/e2e.js # 컴포넌트도 쓰면 component.js 도 생성
/cypress/support/component-index.html
이 위치들은 관례일 뿐 필수는 아니에요. 기존 저장소 구조에 맞추려면 설정 파일에서 테스트·픽스처·서포트 폴더를 다른 곳으로 지정할 수 있습니다. 처음 시작하는 프로젝트라면 공식 문서와 예제에 맞춰 기본값을 유지하는 걸 권장해요.
스펙 파일과 specPattern
스펙 파일은 테스트가 실제로 사는 곳이에요. E2E는 기본적으로 cypress/e2e에, 컴포넌트 테스트는 보통 테스트하는 컴포넌트 옆에 둡니다. 어느 쪽이든 설정으로 위치를 바꿀 수 있어요.
테스트 폴더의 모든 파일이 스펙으로 취급되지는 않습니다. Cypress는 specPattern glob과 일치하는 파일만 로드하는데, 기본값이 파일명에 .cy. 접미사를 요구해요.
- E2E:
cypress/e2e/**/*.cy.{js,jsx,ts,tsx} - 컴포넌트:
**/*.cy.{js,jsx,ts,tsx}
이 관례 덕분에 헬퍼 파일과 스펙을 나란히 둬도 Cypress가 헬퍼를 테스트로 오인해 실행하지 않아요. 대신 cypress/e2e/login.js처럼 .cy.가 없는 파일명은 발견되지 않는다는 뜻이에요. 어떤 테스트가 목록에 안 나타난다면 파일명이 specPattern과 안 맞는 경우가 거의 전부라서, 그걸 먼저 확인해 보세요.
specPattern은 Cypress가 스펙으로 간주하는 전체 집합을 정의하고, excludeSpecPattern은 그 집합에서 파일을 빼는 역할을 해요. --spec 커맨드라인 플래그는 단일 실행을 특정 스펙들로 한정하는데, specPattern에 이미 포함된 것만 좁힐 수 있고 그 밖의 파일은 추가하지 못해요. 요약하면 specPattern이 마스터 목록, excludeSpecPattern이 빼기, --spec이 이번에 실행할 것을 고르는 단계예요.
서포트 파일 (supportFile)
서포트 파일은 모든 스펙에 대한 훅이에요. 매 스펙 파일 앞서 실행되기 때문에, 어디에서든 쓰고 싶은 설정이나 동작을 스펙마다 임포트하지 않아도 되는 자연스러운 장소입니다. 커스텀 커맨드(custom commands)와 전역 오버라이드의 권장 위치이기도 해요. 기본위치는 E2E가 cypress/support/e2e.{js,jsx,ts,tsx}, 컴포넌트가 cypress/support/component.{js,jsx,ts,tsx}예요. cypress run이나 cypress open으로 스펙을 실행하면 Cypress는 서포트 파일을 먼저, 그다음 스펙 파일을 로드합니다.
주의할 점은 서포트 파일을 가볍게 유지하라는 거예요. Cypress는 서포트 파일과 그 파일이 임포트하는 모든 것을 번들링한 뒤 매 스펙 실행 전에 로드하므로, 그 안에서 임포트하는 것의 비용이 매 스펙마다 지불됩니다. 큰 모듈이나 테스트에 꼭 필요하지 않은 것(브라우저에서 실행할 수 없는 Node.js 전용 코드인 DB 드라이버나 fs 같은 것)은 피하고, 무겁거나 스펙 특화된 코드는 필요한 스펙에서 직접 임포트하는 게 좋아요.
beforeEach(() => {
cy.log('I run before every test in every spec file!')
})
픽스처(Fixtures)
픽스처는 테스트가 필요할 때 불러오는 외부 정적 데이터예요. 테스트가 실행되는 '캔 데이터'라고 생각하면 됩니다. 데이터를 테스트 안에 인라인으로 두는 대신 별도 파일로 분리하면 스펙이 읽기 쉬워지고 여러 테스트에서 재사용할 수 있어요. 기본 위치는 cypress/fixtures이고 설정으로 옮길 수 있습니다.
픽스처를 쓰는 방법은 여러 가지예요. cy.fixture()로 파일 내용을 직접 로드하거나(주로 네트워크 요청을 스텁할 때), import user from '../fixtures/user.json'처럼 빌드 시점에 정적 임포트하고, cy.intercept('GET', '/users', { fixture: 'users.json' })처럼 인터셉트가 응답을 픽스처에서 바로 주도록 하거나, 업로드 테스트에서 .selectFile()로 파일 입력에 붙일 수 있어요.
Node.js 쪽 코드 — setupNodeEvents와 cy.task
테스트는 브라우저에서 실행되지만, 파일 시스템을 만지거나 DB에 접속하거나 스펙 번들링을 제어하는 일은 Node.js에서만 가능해요. Cypress는 이런 Node.js 쪽 코드를 설정 파일의 setupNodeEvents 함수로 실행할 수 있게 해주고, 테스트는 cy.task() 커맨드로 그 함수에 접근합니다. preprocessor로 스펙을 번들링하거나, 브라우저 실행 API, OS 접근이 필요한 작업을 여기서 처리할 수 있어요.
실행 산출물과 .gitignore
실행하면 생성되는 산출물(다운로드 파일, 스크린샷, 비디오)은 전용 폴더에 저장되고 매 실행마다 재생성되기 때문에 소스 관리에서 제외하는 게 일반적이에요. 기본 폴더 위치를 그대로 쓰면 아래처럼 .gitignore에 추가하면 됩니다.
# Cypress asset folders to exclude from source control
cypress/downloads/
cypress/screenshots/
cypress/videos/
다운로드는 downloadsFolder(기본 cypress/downloads), 스크린샷은 screenshotsFolder(기본 cypress/screenshots), 비디오는 videosFolder(기본 cypress/videos)에 저장됩니다.
테스트 상태 네 가지
Cypress는 테스트 상태를 네 가지로 구분해요. **passed(통과)**는 모든 훅과 커맨드가 단언 실패 없이 마무리된 상태예요. **failed(실패)**는 단언이 통과하지 못했거나 커맨드가 오류를 낸 상태로, 테스트가 그 일을 다한 것이죠.
**pending(대기)**은 Cypress가 의도적으로 실행하지 않은 테스트예요. 아직 본문이 없어서 it('is not written yet')처럼 작성되지 않은 자리 표시거나, it.skip()/xit()으로 명시적으로 건너뛰었거나, 현재 쓰지 않는 브라우저에서만 실행되도록 browser 옵션으로 제한된 경우에 해당해요. 대기와 달리 **skipped(건너뜀)**는 Cypress가 실행하려 했지만 공유 훅이 실패해서 실행하지 못한 테스트입니다. 예를 들어 beforeEach 훅이 실패하면 첫 테스트는 failed로 표시되고, 같은 훅을 공유하는 나머지 테스트는 반복 실행하지 않고 skipped로 표시돼요. 요약하면 before/beforeEach/afterEach 훅이 실패해서 그에 의존하는 테스트가 실행되지 못할 때 skipped가 됩니다.