Docker, Buildkite 및 CICD와 Cypress 테스트 통합 #frontend@twiliosendgrid

게시 됨: 2020-12-30

우리는 웹 애플리케이션이 백엔드에서 여전히 예상대로 작동하는지 검증하기 위해 많은 종단 간(E2E) Cypress 테스트를 작성했습니다. 이러한 브라우저 자동화 테스트를 작성한 후 코드를 병합하고 특정 환경에 배포하기 전에 항상 이러한 Cypress 테스트를 실행하거나 단위 테스트와 같은 방식으로 트리거하고 싶습니다. 이로 인해 우리는 CI(지속적 통합) 공급자 및 이러한 컨테이너를 실행하기 위해 클라우드에서 사용하는 시스템과 통합하기 위해 Docker 컨테이너에서 Cypress 테스트를 실행하기를 원했습니다.

배포 흐름과 관련하여 우리는 Buildkite를 CI 공급자로 사용합니다. 이를 통해 보드 전체에 걸쳐 코드를 이동할 계획일 때 Buildkite 파이프라인에서 애플리케이션에 대한 자동화된 단계 빌드를 생성할 수 있습니다. 더 자세한 설명을 위해 파이프라인은 일반적으로 애플리케이션의 리포지토리에 연결되어 있어 pull 요청을 생성하고, 새로운 코드 변경 사항을 푸시하고, 코드를 마스터에 병합하고, 다른 환경에 배포할 때 실행할 특정 단계로 빌드를 확인하거나 빌드를 트리거할 수 있습니다. . 배포, 트리거된 Cypress 테스트 및 일정에 따라 실행되는 특정 Cypress 테스트와 같은 별도의 목적을 위해 여러 파이프라인을 생성합니다.

이 블로그 게시물은 이전에 이미 Cypress 테스트를 작성했고 일부 테스트를 실행하고 있다고 가정하지만 개발 및 배포 흐름에서 이러한 테스트를 항상 실행하는 방법에 대한 아이디어가 필요합니다. 대신 Cypress 테스트 작성에 대한 개요를 더 보려면 이 이전 블로그 게시물을 확인한 다음 실행할 항목이 있을 때 다시 방문하십시오.

배포 파이프라인에서 Docker Compose 및 Buildkite를 사용하여 수행한 방법을 살펴봄으로써 Docker 컨테이너의 Cypress 테스트를 CI 공급자와 통합하는 방법에 대한 아이디어를 안내하는 것을 목표로 합니다. 이러한 아이디어는 Cypress 테스트를 트리거할 때 적용할 전략, 명령 및 환경 변수에 대해 인프라에서 확장할 수 있습니다.

우리의 표준 CICD 흐름

표준 개발 및 배포 흐름에서 두 개의 파이프라인을 설정합니다.

  1. 첫 번째는 코드를 푸시할 때 배포 단계를 처리합니다.
  2. 두 번째는 Cypress 테스트가 병렬로 실행되고 기록되도록 트리거합니다. 이것의 성공 또는 실패는 배포 파이프라인에 영향을 줍니다.

배포 파이프라인에서 웹 애플리케이션 자산을 구축하고 단위 테스트를 실행하며 각 환경에 배포하기 전에 선택한 Cypress 테스트를 트리거하는 단계가 있습니다. 푸시 버튼 배포 기능을 해제하기 전에 통과했는지 확인합니다. 두 번째 파이프라인에서 트리거된 이러한 Cypress 테스트는 Docker 컨테이너에서도 실행되며 녹화 키를 통해 유료 Cypress 대시보드에 연결되므로 해당 Cypress 테스트의 비디오, 스크린샷 및 콘솔 출력을 되돌아보고 문제를 디버깅할 수 있습니다.

Buildkite의 선택 입력 을 사용하여 사용자가 "예" 또는 "아니요"를 선택하여 더 많은 코드를 푸시할 때 실행할 Cypress 사양 폴더를 결정하고 확인할 수 있도록 동적 선택을 고안했습니다. 기본 대답은 모든 옵션에 대해 "아니오"이지만 "예" 값은 Cypress 사양 폴더에 대한 glob 경로가 됩니다.

때때로 코드 변경이 다른 페이지에 영향을 미치지 않는 경우 모든 Cypress 테스트를 실행하고 싶지 않습니다. 대신 영향을 받을 것으로 예상되는 테스트만 트리거하려고 합니다. 또한 우리가 트리거하는 테스트 수에 따라 0분에서 10분 정도 걸릴 수 있는 Cypress 테스트를 실행하지 않을 만큼 자신이 있기 때문에 긴급한 버그 문제에 대해 프로덕션에 빠른 수정 사항을 배포해야 할 수도 있습니다. 이 부분에 대해 시각적으로 그리고 YML 단계에서 예제를 제공합니다.

다음으로 runCypress.sh 라는 자체 Bash 스크립트를 구현하여 선택한 "Yes" 또는 "No" 값을 구문 분석한 후 해당 선택 단계를 실행했습니다. 트리거된 파이프라인의 Docker 컨테이너에서 실행되는 최종 Cypress 명령에 --spec 실행 및 추가할 쉼표로 구분된 사양 경로 목록을 형성하기 위해 이 작업을 수행합니다. "CYPRESS_SPECS"의 형성된 사양 목록과 "CYPRESS_TEST_ENV"의 현재 테스트 환경과 같은 환경 변수를 내보냅니다. buildkite-agent pipeline upload "$DIRNAME"/triggerCypress.yml 를 사용하여 스크립트 끝에서 트리거하는 파이프라인에서 사용할 수 있습니다. buildkite-agent pipeline upload "$DIRNAME"/triggerCypress.yml .

"ASYNC" 환경 변수도 내보내는 방법을 보셨을 것입니다. Buildkite에서 트리거된 빌드 단계가 성공 또는 실패 측면에서 차단 또는 비차단이 되도록 선택할 수 있습니다. "ASYNC"를 true로 설정하면 기본 배포 파이프라인 단계가 계속 실행되고 다른 파이프라인에서 트리거된 Cypress 테스트가 완료될 때까지 기다리지 않습니다. 파이프라인의 성공 또는 실패는 배포 파이프라인의 성공 또는 실패에 영향을 주지 않습니다.

"ASYNC"를 false로 설정하면 다른 파이프라인에서 트리거된 Cypress 테스트가 완료될 때까지 기본 배포 파이프라인 단계가 차단됩니다. 트리거된 빌드의 성공 또는 실패는 이후 선택되는 배포 파이프라인의 전반적인 성공 또는 실패로 이어집니다.

우리 코드가 아직 풀 리퀘스트가 열려 있는 기능 브랜치에 있을 때, 더 많은 변경 사항을 푸시하고 일부 Cypress 테스트를 트리거하고 작동 방식을 확인하는 것을 좋아합니다. 그러나 트리거된 테스트가 실패할 경우 나머지 배포 파이프라인 단계가 실행되는 동안 잠재적으로 더 많은 변경 사항이 있을 수 있으므로 실행을 항상 차단하고 싶지는 않습니다. 이 시나리오에서는 Cypress 테스트가 실패할 경우 차단하지 않도록 "ASYNC"를 false로 설정합니다. 이미 풀 요청을 마스터에 병합하고 스테이징에 배포했지만 프로덕션에 배포하기 전에 Cypress 테스트를 트리거하려는 경우 Cypress 테스트가 프로덕션으로 이동하기 전에 항상 통과하기를 원하기 때문에 "ASYNC"를 true로 설정합니다. .

runCypress.sh 로 돌아가서 스크립트가 환경 변수 값이 할당된 triggerCypress.yml 파일을 호출하여 실행하도록 두 번째 파이프라인을 트리거한다는 것을 기억합니다. triggerCypress.yml 파일은 다음과 같습니다. "트리거" 단계와 빌드 메시지로 값의 보간이 디버깅 및 동적 단계 이름에 도움이 된다는 것을 알 수 있습니다.

배포 파이프라인에서 별도의 트리거 파이프라인으로 실행하도록 Cypress 테스트를 트리거하거나 전용 파이프라인에서 일정에 따라 Cypress 테스트를 실행하는 경우 환경 변수 값만 변경하면서 동일한 단계를 따르고 재사용합니다.

이러한 단계에는 다음이 포함됩니다.

  1. 최신 태그 및 고유 버전 태그로 Docker 이미지 빌드
  2. Docker 이미지를 개인 레지스트리에 푸시
  3. 동일한 이미지를 풀다운하여 Docker 컨테이너의 환경 변수 값을 기반으로 Cypress 테스트를 실행합니다.

이러한 단계는 다음과 같이 pipeline.cypress.yml 파일에 요약되어 있습니다.

Cypress 테스트를 실행하도록 트리거하면 Cypress 트리거 파이프라인에서 별도의 빌드가 시작됩니다. 빌드의 성공 또는 실패에 따라 Cypress 테스트 실행은 마스터 브랜치 빌드를 위해 스테이징에서 프로덕션으로 이동할 때 프로덕션에 배포하는 것을 차단하거나 허용합니다.

"트리거된 cypress/integration/..." 단계를 클릭하면 테스트가 어떻게 진행되었는지 볼 수 있는 이와 같은 보기가 있는 트리거된 파이프라인의 빌드로 이동합니다.

Docker 부분이 모두 어떻게 연결되어 있는지 궁금한 경우 Dockerfile.cypressdocker-compose.cypress.yml 은 파이프라인에서 내보낸 환경 변수를 사용하여 오른쪽을 가리키는 애플리케이션의 package.json 에서 적절한 Cypress 명령을 사용합니다. 테스트 환경 및 선택한 사양 파일을 실행합니다. 아래 스니펫은 확장하고 더 유연하게 개선할 수 있는 일반적인 접근 방식을 보여줍니다.


일반적인 통합 및 배포 주기 동안 실행되는 테스트 외에 전용 Buildkite 파이프라인을 만들었습니다. 이러한 파이프라인은 프론트엔드 및 백엔드 서비스가 올바르게 작동하는지 확인하기 위해 스테이징 환경에 대한 중요한 테스트 일정에 따라 실행됩니다. 유사한 파이프라인 단계를 재사용하고 Buildkite 파이프라인 설정에서 특정 환경 변수 값을 조정하고 예약된 시간에 실행되도록 cron 일정을 설정했습니다. 이는 테스트가 얼마나 잘 수행되고 있는지, 다운스트림이나 자체 코드 푸시로 인해 테스트가 실패했을 수 있는지 계속 모니터링하면서 스테이징 환경에서 많은 버그와 문제를 포착하는 데 도움이 됩니다.

병렬화

또한 병렬화 플래그를 활용하여 Ops 팀이 설정한 빌드 에이전트 대기열에서 스핀업할 수 있는 AWS 머신의 수를 활용합니다. 이 병렬화 플래그를 사용하여 Cypress는 Buildkite의 "병렬화" 속성에 설정한 수를 기반으로 특정 수의 시스템을 자동으로 마술처럼 불러옵니다.

애플리케이션 저장소 중 하나에 대해 약 5분 만에 200개 이상의 테스트를 실행할 수 있었습니다.

그런 다음 특정 빌드 실행에 대한 각 테스트의 기록을 유지하면서 모든 Cypress 테스트를 해당 머신에서 병렬로 실행합니다. 이것은 우리의 테스트 실행 시간을 극적으로 향상시켰습니다!

다음은 Cypress 테스트를 병렬화할 때의 몇 가지 팁입니다.

  • 최적의 머신 수에 대한 대시보드 서비스의 제안을 따르고 파이프라인의 유연성을 위해 환경 변수에 머신 수를 설정하십시오.
  • 더 작은 테스트 파일로 분할합니다. 특히 더 오래 실행되는 테스트를 여러 시스템에서 더 잘 병렬화할 수 있는 청크로 분할합니다.
  • Cypress 테스트가 격리되어 있고 서로 영향을 미치거나 서로 의존하지 않는지 확인하십시오. 업데이트, 생성 또는 삭제 관련 흐름을 처리할 때 별도의 사용자 및 데이터 리소스를 사용하여 테스트가 서로를 짓밟고 경쟁 조건이 발생하지 않도록 합니다. 테스트 파일은 어떤 순서로든 실행할 수 있으므로 모든 테스트를 실행할 때 문제가 되지 않는지 확인하십시오.
  • Buildkite의 경우 Buildkite 빌드 ID 환경 변수 값을 parallel 옵션과 함께 --ci-build-id 옵션에 전달하여 머신 간에 테스트를 병렬화할 때 연결할 고유 빌드 실행을 알 수 있도록 합니다.

검토:

Buildkite와 같은 CI 공급자에 Cypress 테스트를 연결하려면 다음을 수행해야 합니다.

  1. 특정 브라우저에 대해 노드 환경에서 테스트를 실행하는 데 필요한 Cypress 기본 이미지와 종속성을 사용하여 애플리케이션 코드로 Docker 이미지를 빌드합니다.
  2. 특정 태그가 있는 레지스트리로 Docker 이미지 푸시
  3. 이후 단계에서 동일한 이미지를 아래로 당깁니다.
  4. Cypress 대시보드 서비스를 사용하는 경우 헤드리스 모드 및 녹음 키를 사용하여 Cypress 테스트를 실행합니다.
  5. 다른 환경 변수 값을 설정하고 해당 Docker 컨테이너의 특정 테스트 환경에 대해 선택된 Cypress 테스트를 트리거하도록 Cypress에 대해 실행하는 명령에 연결합니다.

이러한 일반 단계는 일정에 따라 실행되는 Cypress 테스트 및 배포 파이프라인 외에 선택한 브라우저에 대해 실행되는 테스트 트리거와 같은 기타 사용 사례에 재사용 및 적용할 수 있습니다. 핵심은 CI 제공자의 기능을 활용하고 환경 변수 값을 기반으로 유연하고 구성 가능한 명령을 설정하는 것입니다.

환경 변수 값에 따라 유연하고 구성 가능하도록 명령을 설정합니다.

CI 공급자와 함께 Docker에서 테스트를 실행하고(대시보드 서비스에 대한 비용을 지불하는 경우) 여러 컴퓨터에서 테스트를 병렬화하는 이점을 누릴 수 있습니다. 테스트가 서로를 짓밟는 것을 방지하기 위해 다른 테스트와 리소스에 의존하지 않도록 기존 테스트와 리소스를 수정해야 할 수도 있습니다.

또한 백엔드 API를 검증하기 위한 테스트 스위트를 생성하거나 선택한 브라우저에 대해 실행할 테스트를 트리거하는 것과 같이 스스로 시도할 수 있는 아이디어에 대해서도 논의했습니다. 또한 여기 Cypress 문서에서 지속적 통합을 설정하는 더 많은 방법이 있습니다 .

또한 개발 환경이 항상 예상대로 작동하는지 확인하려면 배포 흐름 또는 예약된 간격 동안 이러한 Cypress 테스트를 실행하는 것이 중요합니다. Cypress 테스트에서 다운스트림 백엔드 서비스와 관련된 문제를 포착한 적이 수없이 많았습니다. 이 문제는 프론트엔드 애플리케이션 오류로 나타나거나 어떤 식으로든 중단되었습니다. 그들은 특히 우리가 새로운 React 코드 변경 사항을 발표한 후 웹 페이지의 예기치 않은 버그로부터 우리를 구해주었습니다.

테스트 환경에서 통과한 테스트를 유지 관리하고 실패한 테스트 실행을 부지런히 모니터링하면 지원 티켓이 줄어들고 프로덕션 환경에서 고객 만족도가 높아집니다. 새로운 코드 변경 사항을 푸시할 때 Cypress 테스트의 건강하고 안정적인 제품군을 계속 실행하면 모든 것이 잘 작동하고 있다는 확신을 더 많이 갖게 되며 귀하와 귀하의 팀이 Cypress 테스트에서 동일한 작업을 수행하는 것이 좋습니다.

Cypress 테스트에 대한 추가 리소스는 다음 문서를 확인하십시오.

  • E2E 테스트를 작성할 때 고려해야 할 사항
  • Cypress 테스트 작성에 대한 1,000피트 개요
  • Cypress 테스트의 모든 것을 TypeScript
  • Cypress 테스트에서 이메일 흐름 다루기
  • Cypress 테스트 구성, 구성 및 통합을 위한 아이디어