프런트엔드 E2E 테스트(Cypress 사용)


프런트엔드 E2E 테스트(Cypress 사용) 1

소개


프런트엔드 E2E 테스트(Cypress 사용) 2

작년 12월 기준으로 3개월 정도 항공웹을 개발했는데 생각보다 동선이 달라서 힘들었던 기억이 납니다.

더군다나 제 작업(웹 허브 개통, TF v12 전환)이 전반적인 항공사 움직임에 적용되어야 했기 때문에 더욱 그랬던 것 같아요.

아직 E2E 테스트를 작성해보지 못해서 이번 기회에 공부해보려고 합니다,

국제선 예약 라인의 E2E 테스트를 보강하면 좋을 것 같아서 준비했습니다.

E2E 테스트란?

먼저 E2E 테스트가 무엇인지 간단히 살펴보겠습니다.

일반적인 종단 간(E2E) 테스트는 사용자가 브라우저 환경에서 사용할 것이라는 가정을 기반으로 합니다.

응용 프로그램의 전반적인 동작을 확인하는 것을 의미합니다.

단위 테스트와 통합 테스트를 통해 각 모듈의 무결성을 검증할 수 있다면,

E2E에서는 이러한 모듈이 잘 혼합되어 필요한 기능을 쉽게 제공하는지 확인할 수 있습니다.


프런트엔드 E2E 테스트(Cypress 사용) 3
출처: https://www.headspin.io/blog/the-testing-pyramid-simplified-for-one-and-all

대신 많은 수의 시나리오가 검증되기 때문에 테스트 노력이 다른 방법보다 높습니다.

그러나 다른 트래픽 경로를 확인해야 하는 경우(예: B. E2E 테스트에 의한 무선 네트워크, 기능 회귀

새로운 기능을 개발하거나 버그를 수정할 때 안정감을 줍니다.

비행 노선 정리

테스트를 작성하기 전에 먼저 현재 항공 교통 웹 트래픽을 알아보자.

우선 가장 기본적인 예약 흐름은 다음과 같습니다.

국내선

  • 웹, 앱, 메타(b2c – 스카이스캐너, 네이버)

국제선

  • 웹, 앱, 메타(b2c – 스카이스캐너)

그리고 모든 흐름은 다음 흐름으로 이어집니다.

허브 → 항공편 검색 목록 → 항공편 상세 → 예약하기 → 결제하기 → 발권완료 → (내 예약상세 || 허브)

또한 상세한 여행자 보험, PLCC 등등 다양한 루트가 있습니다.

이 라인은 국내선/국제선 일반적으로 뒷면에 녹일 수 있습니다.

보다 직관적인 테스트 코드 관리를 위한 경로는 다음과 같습니다.

메인 루트와 동일한 계층 구조를 고려하여 테스트 코드 추가를 진행하였습니다.

integration
 ㄴ intl
 ㄴ domestic
 ㄴ b2c
        ㄴ naver
        ㄴ skyscanner
 ㄴ plcc
 ㄴ ... 그외 cross-sub-domain 기능들

국내선은 이미 eeyore에서 처리가 되었기 때문에 이번에는 국제선 예약 라인의 e2e 테스트를 구성하기로 했습니다.

싸이프레스의 특징 알아보기

Cypress의 대표적인 기능 몇 가지를 살펴보겠습니다.

1⃣ 기능 테스트 러너

사이프러스는 functional 이것은 테스트 러너입니다.

앱이 사용자 관점에서 의도한 대로 작동하는지 확인하는 데 사용됩니다.

2⃣ 비동기 요소 검색 방법

상황에 따라 아이템을 바로 로드할 수 없는 경우가 있습니다.

Cypress는 요소 쿼리를 비동기적으로 수행하므로 내부적으로는 시간이 초과될 때까지 재시도합니다.

3⃣ 반복성

최신 웹 앱은 비동기 작업이 많지만 Cypress의 반복성 덕분에 별도의 동기화 없이 직관적인 테스트 코드 작성이 가능합니다.

본질적으로 항목을 찾는 쿼리를 포함하여 특정 작업을 수행하는 작업(예: 클릭)

요청이 지정된 시간까지 반복되기 때문에 이러한 처리에 대한 걱정 없이 테스트 코드 작성에 집중할 수 있습니다.

(물론 잘못 사용하면 디버깅에 문제가 생길 수 있습니다.

)

4⃣ 약속 기반 체이닝 방법

읽기 쉬운 테스트 코드를 작성할 수 있지만 동기식 로직을 작성할 때는 주의해야 합니다.

5⃣ 녹화 및 스크린샷

Cypress는 테스트 결과를 비디오 또는 스크린샷 형태로 저장하는 기능을 제공합니다.

이러한 출력은 헤드리스 환경에서 테스트 실패의 원인을 찾는 데 도움이 됩니다.

현재 Aviation Web은 GitHub 작업의 아티팩트를 통해 테스트 결과를 유지합니다.

테스트 코드 작성 방법

1⃣ 기획서를 바탕으로 시나리오 작성

E2E 테스트를 통해 반복적인 메인 동작 검증이 가능하며,

이것은 프로젝트를 설명하는 한 단어입니다.

문서 비슷한 역할을 하는 것 같아요.

따라서 가장 정확하고 합리적인 방법은 명단을 기반으로 흐름을 구성하는 것이라고 믿었습니다.

국제선 흐름 정리

약 3개월간의 항공사이트 개발 과정에서 파악한 주요 루트를 중심으로 대략적인 과정을 정리했습니다.

세부적으로는 정말 다양한 경로가 있지만 여기서는 핵심 경로만 요약했습니다.

1. 허브
국제선 검색 조건을 입력하고 "항공권 검색" 을 클릭하면 국제선 (항공편 검색 페이지) 로 이동한다.

2. 항공편 검색 - 필터를 통한 재검색이 되어야한다.

- 항공편 선택 시 <카드 프로모션 액션시트> 가 노출한다.

ㄴ 선택한 프로모션으로 (항공편 상세페이지) 로 이동한다.

3. 항공편 상세 - "상세요금" 선택 시 <요금 상세 정보 팝업> 이 노출된다.

- "항공편 변경" 선택 시 이전 (항공편 검색목록 페이지) 로 이동한다.

- 인원변경 버튼 클릭 시 <인원 선택 팝업> 이 노출된다.

ㄴ 새로운 인원타입이 추가될 경우 해당 조건으로 (항공편 검색 페이지) 로 이동하여 재검색한다.

ㄴ 단순 인원추가 및 제거일 경우 가격 정보만 업데이트된다.

- "운임 및 수하물 규정 자세히보기" 선택 시 <항공사 운임 및 수하물 규정 팝업> 이 노출된다.

- "예약하기" 선택 시 (항공편 예약페이지) 로 이동한다.

4. 항공편 예약 - 예약자 정보와 탑승객 정보를 입력한 뒤에 약관에 전체동의하면 예약이 가능해진다.

- "예약하기" 선택 시 <예약정보 최종확인 팝업> 이 노출된다.

ㄴ"네. 진행합니다.

" 선택 시 (항공편 결제페이지) 로 이동한다.

5. 항공편 결제 - 여정정보 및 탑승객정보 선택 시 <여정정보, 탑승객 정보 팝업>이 노출된다.

- 결제조건 변경 시 <결제 조건 변경 액션시트> 가 노출된다.

ㄴ 결제 조건 선택 후 "선택한 조건으로 변경하기" 선택 시 선택된 조건으로 금액이 재조회된다.

- 카드번호, 유효기간, 비밀번호 앞 두자리, 카드 소유주 생년월일, 할부 개월 수를 입력하고 결제규정에 동의하면 결제가 가능해진다.

- "결제하기" 선택 시 결제가 이루어진다.

6. 발권완료 - "내 예약에서 확인" 선택 시 (국제선 내 예약상세 페이지)로 이동한다.

2⃣ 테스트 형식 및 격리

일반적인 테스트는 세 단계로 구성됩니다.

given
애플리케이션 특정 상태(state)에서

when 
특정 동작(action)을 수행할 때

then
의도대로 동작하는지 검증(assert)한다.

Cypress를 통해 E2E 테스트를 실행할 때 여기에서 더 구체적인 단계 정의가 필요한 것 같습니다.

visit
테스트할 특정 페이지에 방문해서

query & interaction
특정 컴포넌트를 찾아 상호작용을 통해

assertion
의도한대로 동작하는지 검증한다.

위의 3단계에서 수행된 각 독립 테스트 사례를 추가합니다.

기본적으로 Cypress는 각 테스트 사이의 모든 테스트 상태를 재설정합니다.

이를 통해 일관된 테스트 결과를 얻을 수 있습니다.

3⃣ 목 서버로 API 목킹

단순 검색 API의 경우에도 다음과 같은 다양한 경우에 따라 경로가 존재 B. 캐시 키 만료.

조건에 따라 다른 검사 결과를 얻으면 검사의 신뢰도가 떨어집니다.

이 때문에 엄격하게 제어되는 데이터가 필요하며 mocks-server가 그 역할을 돕습니다.


프런트엔드 E2E 테스트(Cypress 사용) 4
모의 서버 개념

모의 서버 통과 및 실패 사례 테스트에 필요한 API를 조롱하여 사용합니다.

Aviation Web은 현재 서버 API 끝점을 환경 변수로 관리하므로 쉽게 위임할 수 있습니다.

다음은 국제선 항공권 검색 API를 Spotting한 예시이다.

// mocks/routes/intl-search.js

const SEL_NYC_RESULTS_FIXTURE = (/** 서울 <-> 뉴욕 검색결과 모킹데이터 */)

module.exports = (
    {
    id: 'search-intl-flights',
    url: '/api/air/intl/search/flights/:key',
    method: 'POST',
    variants: (
      {
        id: 'success',
        response: (req, res) => {
          const sortCriteria = req.body('sort') ?? 'PRICE'
          const airlineCriteria = req.body('filter')('byAirline')

          let contents = SEL_NYC_RESULTS_FIXTURE.contents

          if (airlineCriteria) {
            contents = SEL_NYC_RESULTS_FIXTURE.contents.filter((content) =>
              content.schedules.some((schedule) =>
                airlineCriteria.includes(schedule.carrier.code),
              ),
            )
          }

          /** 가격, 가는날 출발시간 순 정렬만 모킹 */
          if (sortCriteria === 'OUTBOUND_DEPARTURE_TIME') {
            contents.sort((a, b) =>
              moment(a.schedules(0).departureDateTime).isBefore(
                b.schedules(0).departureDateTime,
              )
                ? -1
                : 1,
            )
          } else {
            contents.sort((a, b) => a.totalPrice - b.totalPrice)
          }

          res.send({
            ...SEL_NYC_RESULTS_FIXTURE,
            contents,
            page: {
              currentPage: 1,
              pageSize: 20,
              totalCount: contents.length,
            },
            status: contents.length > 0 ? 'COMPLETE' : 'NO_DATA',
          })
        },
      },
    ),
  }
)

Cypress 사용 시 유용한 팁 및 기능

1⃣ 기본 선택 우선순위

data-cy
data-test
data-testid
data-qa
id
class
tag
attributes
nth-child

테스트할 때 상호 작용할 요소를 찾는 데 사용되는 선택자는 위와 동일한 우선 순위를 갖습니다.

dom 또는 css 속성에 의존하면 UI 변경에 따른 테스트 코드 관리 측면에서 취약합니다.

data- 를 사용하여 사용자 지정 테스트 ID를 지정하는 것이 좋습니다.

국제선용 E2E 테스트 코드에서 data-cy 통해 고유한 테스트 ID를 부여하여 진행했습니다.

하지만 직접 제어할 수 없는 외부 패키지 UI 컴포넌트 요소를 검색해야 하는 경우,

태그 유형 및 클래스 이름과 같은 속성 선택기의 조합을 사용했습니다.


프런트엔드 E2E 테스트(Cypress 사용) 5
예 – 탐색 항목은 배경 이미지로만 처리됩니다.

styled-component 등으로 생성된 내부 컴포넌트의 경우 참고하세요.

프로덕션 빌드 중 최적화 중에 변경되므로 className을 사용하지 않는 것이 좋습니다.

멤버 선택 모범 사례는 공식 문서에 나열되어 있습니다.

모범 사례 | 사이프러스 문서

모범 사례 | 사이프러스 문서

docs.cypress.io

2⃣ 자주 참조되는 요소에 별칭 지정

동일한 컨텍스트에서 자주 참조되는 항목에 대해서는 별칭을 지정하여 쿼리문을 생성할 수 있습니다.

cy.get('.DayPicker-Day--today').as('today')

cy.get('@today').next().click()
cy.get('@today').next().next().click()

3⃣ 기본 시계 재정의

시간 관련 동작을 제어해야 하는 경우가 있습니다.

항공사의 주 공항(허브)에서 돌아오는 항공편을 선택하는 경우 달력에서 출발 및 도착 날짜를 선택해야 합니다.

이 시점에서 현재 타임스탬프는 편리한 테스트를 위해 오늘 날짜로 제공됩니다.

(국제선의 경우 오늘 + 1 중 출발일을 선택하셔야 한다는 조건입니다.

)

cy.clock(new Date(2023, 2, 13), ('Date'))

/** 허브에 진입 */
cy.visit('/')

이렇게 하면 달력 구성 요소에서 날짜 함수가 내부적으로 호출됩니다.

2023-02-13 이렇게 하면 오늘 날짜를 원하는 날짜로 조정할 수 있습니다.

4⃣ 각 테스트에 대해 수행해야 하는 후크 분리

각 테스트는 독립적으로 작성되어야 하지만 각 테스트에 대해 동일한 프로세스를 반복해야 하는 경우 별도의 후크로 나눌 수 있습니다.

사이프러스, 모카 BDD 후크는 다음과 같은 방식으로 정의할 수 있습니다.

여러 갈고리테스트마다 실행할 후크를 정의합니다.

// 페이지 방문 예시 (beforeEach)
describe('국제선 항공편 결제 및 발권완료', () => {
  beforeEach(() => {
    cy.visit(
      '/payment?orderId=3950&id=AMADEUS_AC62G3AC726G3AC8997G3AC61G4&adult=1&child=0&infant=0&from=hub&requestTotalPrice=1067700&originDestination=c%3ASEL-c%3ANYC&inboundDate=2023-03-22&outboundDate=2023-03-15&cabinTypes=ECONOMY&cabinTypes=PREMIUM_ECONOMY&cabinTypes=BUSINESS&cabinTypes=FIRST&detailKey=087d07ff-9c99-4fc5-a166-d65bfcca769d%3A%3AAMADEUS_84e4d118-db54-4447-8aa8-e889af90e798%3A%3A1_1_2&cashRewardDefinitionId=f6938058-e534-4127-89e8-bbf73131635a',
    )
    cy.contains('결제내용 확인', { timeout: 60000 }).should('be.visible')
  })

    it('결제조건 변경 시 선택한 조건으로 결제정보가 재조회된다', () => {
        // ...
    })

    it('카드정보를 입력하고 결제가 완료되면 발권완료 페이지로 이동한다.

', () => { // ... }) }) // 팝업 노출 예시 (afterEach) describe('결제정보 관련 팝업을 노출한다.

', () => { it('여정정보 팝업을 노출한다.

', () => { // ... }) it('탑승객정보 팝업을 노출한다.

', () => { // ... }) afterEach(() => { /** 팝업 닫기 */ cy.get('.-triple-fallback-action').click() }) })

5⃣ 커스텀 커맨드 추가

사이프러스는 custom command 일반적으로 사용되는 로직을 분리하여 인터페이스로 전환하는 기능을 제공합니다.

여기에서 새 명령을 추가하거나 기존 명령을 덮어쓸 수 있습니다.

먼저 사용자 지정 명령을 허용하려면 supportFile 옵션을 추가합니다.

// cypress.config.js

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  e2e: {
    supportFile: 'cypress/support/index.ts',
        // ...
  },
  // ...
})

이제 트리플 로그인 시 설정되는 쿠키 값을 설정하는 간단한 명령어를 추가해 보겠습니다.

command.ts 파일을 생성하여 index 에서 가져오는 경우

분리 import 명령문 없이 테스트가 실행될 때마다 자동으로 호출하여 적절한 명령을 사용할 수 있습니다.

// cypress/support/index.ts

import './command'

// cypress/support/command.ts

Cypress.Commands.add('setupTripleUserCookie', () => {
  cy.setCookie('TP_SE', 'test')
  cy.setCookie('x-soto-session', 'test')
})

명령에 대한 간략한 설명이 있으면 좋을 것입니다.

이를 위해 Cypress 유형을 확장합니다.

// cypress/types/types.d.ts

declare namespace Cypress {
  interface Chainable {
    /**
     * 트리플 로그인 시 설정되는 쿠키값을 모킹합니다.

* @example cy.setupTripleUserCookie() */ setupTripleUserCookie(): void } }

6⃣ API 감시 차단

Cypress에서 제공하는 네트워크 가로채기도 유용한 기능입니다.

국제선의 경우 결제 페이지에서 선택한 카드의 프로모션 정보가 변경된 경우

해당 프로모션 ID로 결제 정보를 확인해야 합니다.

카드액션별로 모킹데이터를 다르게 생성하는데 한계가 있기 때문에

데이터를 확인하는 대신 재조회 API 내가 전화하고 있는지 확인하기 위해 테스트를 작성했습니다.

it('결제조건 변경 시 선택한 조건으로 결제정보가 재조회된다.

', () => { /** 결제조건 변경을 위한 액션시트 선택 */ cy.contains('결제 조건 변경').click() cy.get('div(class^="action-sheet-body")') .contains('결제 조건 변경') .should('be.visible') cy.get('tr(class^=card-promotion-radios)').eq(0).click() cy.intercept({ url: '/api/air/intl/booking/ticketing/ready/orders/*', method: 'GET', query: { cardPromotionPrincipleId: '*', }, }).as('cardPromotionAppliedTicketingRequest') /** 카드 프로모션이 적용된 API 를 호출하는지 확인 */ cy.get('button').contains('선택한 조건으로 변경하기').click() cy.wait('@cardPromotionAppliedTicketingRequest') })

Cypress 테스트 ID 제거 및 배포


프런트엔드 E2E 테스트(Cypress 사용) 6

테스트 중 테스트 ID를 지정하는 문제는 이러한 ID가 운영 환경에 있기 때문에 사용자에게 노출된다는 것입니다.

따라서 빌드 단계에서 제거해야 합니다.

Next 12 바벨 대신 SWC 사용

별도의 플러그인(babel-plugin-react-remove-properties) 없이 환경설정으로만 가능했습니다.

환경 변수와 정규식을 사용하여 앞에서 설명한 Cypress 테스트 ID는 프로덕션 빌드 중에 필터링됩니다.

// next.config.js

module.exports = {
compiler: {
    reactRemoveProperties:
      NODE_ENV === 'production'
        ? {
            properties: ('^data-(cy|test|testid|qa)$'),
          }
        : undefined,
  },
}


프런트엔드 E2E 테스트(Cypress 사용) 7
노출되었던 테스트용 아이디는 이제 사라졌습니다.

병렬 테스트

Cypress에서 병렬 처리를 하려면 Cypress Cloud(유료)를 사용하거나

다른 패키지(sorry-cypress 등)를 함께 사용해야 합니다.

이번 주간지에서는 로컬에서만 간단한 조작을 구현하고 싶었습니다.

node.js child_process를 사용하여 스크립트를 작성했지만 여전히 제대로 작동하지 않습니다.

(테스트가 더 오래 걸리는 경향이 있습니다 )

const CYPRESS_ROOT_PATH = './cypress/integration'
const WORKLOAD = 2
const SPEC_FILE_REGEX = /.*?\.spec\.(js|ts)/

async function main() {
  const testSuitePaths = deriveTestSuitePaths()
  const jobs = allocateJobs(testSuitePaths)

  await runTestGroup(jobs)
}

async function runTestGroup(jobs) {
  const label="🚀 total execution time"

  try {
    console.time(label)
    await Promise.all(jobs)
  } catch (error) {
    console.error(`❌ test failed : ${error.message}`)
  } finally {
    console.timeEnd(label)
  }
}

function allocateJobs(testSuitePaths) {
  const tasks = new Map()

  const groupedJobs = chunk(testSuitePaths, WORKLOAD)
  groupedJobs.forEach((group, idx) => tasks.set(idx, group))

  return (...tasks.entries()).map(((key, task)) => process(key, task))
}

async function process(key, testSuites) {
  const testOption = {
    command: 'cypress:headless',
    option: '--spec',
    specs: testSuites.join(','),
  }

  return new Promise((resolve, reject) => {
    const child = spawn('npm', (
      'run',
      testOption.command,
      '--',
      testOption.option,
      testOption.specs,
    ))

    child.stdout.on('data', (data) => {
      // 현재 수행중인 테스트 케이스 출력
    })

    child.on('exit', (code) => {
      const hasException = code > 0

      if (hasException) {
        reject(new Error(`exception occur at child process with code ${code}`))
      }
      resolve(true)
    })
  })
}

그래도 시간이 나면 조금 해보고 CI 환경에서 사용할 수 있는 패키지 배포까지 해봐야겠습니다.

(올해 안에..?)

테스트 코드 커버리지

Cypress를 사용하여 E2E 테스트 중에 코드 적용 범위를 확인할 수도 있습니다.

이때 싸이프레스에서 별도로 제공하지 않는 코드 인스트루먼트(코드 측정) 과정을 진행해야 하므로 별도로 진행해주셔야 합니다.

가장 유명한 것은 이스탄불 라는 패키지를 사용할 가능성이 있지만 아쉽게도 안정적입니다.

바벨 버전다음 12부터 더 이상 유효하지 않으므로 대신 실험 플러그인사용되어야한다.

(기존 babel-plugin-istanbul의 모든 기능을 제공하지는 않습니다.

)

원래 정식 플러그인에 들어가려고 테스트 단계에 들어갔는데,

실제 사용자가 많지 않아 추후 지원으로 전환되었습니다.

feat(next/swc): kwonoj의 실험적 커버리지 도구 지원 · Pull Request #36692 · vercel/next.js

feat(next/swc): kwonoj의 실험적 커버리지 도구 지원 · Pull Request #36692 · vercel/next.js

관련 #30529 , #30174 이 PR은 실험적인 next.js 구성을 활성화하여 next-swc를 통해 커버리지 계측을 활성화합니다.

현재 구성 자체는 아직 사용되지 않습니다.

github.com

신청방법

> npm i -D swc-plugin-coverage-instrument

npm 스크립트에서 COVERAGE 붓다 true 전달되는 경우에만 intrument 프로세스를 실행할 플러그인을 할당합니다.

// next.config.js

module.exports = {
    experimental:
    process.env.COVERAGE === 'true'
      ? {
          swcPlugins: (('swc-plugin-coverage-instrument', {})),
        }
      : undefined,
}

계측 프로세스가 완료되면 코드 참조 정보가 전역 위젯에 저장됩니다.

__coverage__ 이름으로 추가됩니다

적절한 플러그인을 추가하고 dev 서버를 실행하여 생성된 결과를 확인해보자.


프런트엔드 E2E 테스트(Cypress 사용) 8

외부 모듈의 참조 정보가 앱 코드에 추가된 것을 확인할 수 있습니다.

(babel 플러그인은 외부 모듈을 제외할 가능성이 있지만 swc 플러그인 버전은 제공되는 기능에 제한이 있습니다.

)

테스트 중 코드 커버리지 정보를 추출하기 위해 Cypress @cypress/code-coverage 라는 패키지를 추가해야 합니다.

npm install -D @cypress/code-coverage

cypress.config.js e2e 테스트 중에 로드할 수 있도록 파일에서 패키지를 수정합니다.

// support/e2e.ts
import '@cypress/code-coverage/support'

// support/index.ts
import './e2e'

// cypress.config.js
module.exports = defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      require('@cypress/code-coverage/task')(on, config)
      // NOTE: include any other plugin code

      return config
    },
  },
})

그리고 편백나무를 걷는 동안 coverage 옵션을 함께 전달하면 플러그인 사용 여부를 제어할 수 있습니다.

"cypress:headless:coverage": "cypress run --env coverage=true"

이 패키지를 사용하면 테스트 후 생성되는 코드 커버리지 정보가 HTML 파일로 생성됩니다.

검색을 사용하여 원하는 구성 요소만 찾을 수 있습니다.

다음은 국제선 E2E 테스트 커버리지 결과입니다.


프런트엔드 E2E 테스트(Cypress 사용) 9

각 파일에 대해 테스트 코드에서 추가해야 하는 부분이나 누락된 부분을 시각적으로 검사할 수 있습니다.


프런트엔드 E2E 테스트(Cypress 사용) 10

이 커버리지 정보는 CI 때 Github 아티팩트에 올려주시면 좋을 것 같습니다.

이 플러그인은 현재 적극적으로 유지 관리되지 않으며 보고된 문제 중 다음 13이 있습니다.

/app 디렉토리와 함께 사용하는 경우

앱 사용에 문제가 있다는 제보가 있었으니 안정화 될 때까지 로컬 환경에서만 사용하시는 것이 좋을 것 같습니다.

문제 해결

1⃣ 때때로 테스트가 예기치 않게 실패합니다.

예상치 못한 이유로 테스트가 실패하는 경우가 있습니다(네트워크 문제, API, 렌더링 속도 등).

이러한 변수를 최소화하기 위해 몇 가지 설정을 추가하고 계속 진행했습니다.

1. 다음 빌드 파일로 CI에서 테스트

그러나 개발 서버에서 실행되는 앱으로 로컬에서 테스트됩니다.

CI 환경에서 빌드를 사용하면 최적화된 코드로 실행할 수 있습니다.

"e2e:headless": "start-server-and-test testdev-withmocks http://localhost:3000/air cypress:headless",
"e2e:ci": "start-server-and-test start-withmocks http://localhost:3000/air cypress:headless",

2. 이벤트 로깅 차단

테스트 중 불필요한 네트워크 요청을 방지하기 위해 이벤트 로깅 관련 요청을 차단하는 설정을 추가했습니다.

// cypress.config.js

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  // ...
  blockHosts: '*.google-analytics.com',
})

3. 방문, 위치 변경 시 타임아웃 허용

페이지에 들어가거나 전환할 때 시간이 걸리는 API 호출로 인해 테스트가 실패하는 경우가 가끔 있으므로 기본 시간 초과 값입니다.

4s 더 크게 조정했습니다.

4. 테스트 재실행 설정 추가

기본적으로 실패한 테스트에서는 재시도가 수행되지 않지만 설정을 통해 변경할 수 있습니다.

runMode 그리고 openMode 당신은 무엇이든 설정할 수 있습니다

CI 동안 헤드리스 수행 cypress run 신청을 허용했습니다.

// cypress.config.js

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  // ...
  retries: {
    runMode: 2,
  },
})

2⃣ 회의 처리 방법

항공사에 따르면 별도의 테스트 계정은 없다.

세션과 관련된 동선을 어떻게 할까 고민하다가 테스트를 실행하기 전에 쿠키를 설정하여 우회했습니다.

쿠키를 사용할 때 Cypress는 일관된 상태를 보장하기 위해 각 테스트 사이에 쿠키를 삭제한다는 점에 유의해야 합니다.

테스트 사이에 세션을 유지하려면 cy.session 당신이 사용할 수있는.

더 생각

모의 데이터를 사용하는 한 서버 인터페이스에 대한 모든 변경 사항은 모의 데이터도 변경해야 유지 관리 지점으로 간주될 수 있습니다.

이것을 자동화하는 방법이 있습니까? 당신은 걱정해야합니다.

→ 테스트의 안정성을 위해서는 데이터의 무력함을 보장해야 하지만 부작용이 없는지 검증이 필요해 보인다.

사실 현재 항공사 웹에서 가장 짜증나는 것은 예외 처리의 흐름이다.

(검색키 유효기간, 가격변동, 유효기간 등)

현재는 Happy Path만 추가되었지만 이러한 예외 경로를 테스트 케이스에도 추가하면 좋을 것입니다.

→ 망을 가로챈 후 심하게 실패하면 동선 테스트가 가능할 것 같다.

완료


프런트엔드 E2E 테스트(Cypress 사용) 11

대략적인 E2E 테스팅 방법론을 제시하였고, 이번 국제 E2E 테스팅을 통해 트리플 비즈프론트 개발자들의 반복적인 업무로 인한 피로가 조금이나마 줄어들 수 있기를 바라며 이 글을 마치겠습니다.

긴 글 읽어주셔서 감사합니다