フロントエンドの統合テストを作成し、リリースをスピードアップします

こんにちは!私の名前はVovaです。Tinkoffのフロントエンドです。私たちのチームは、法人向けの2つの製品を担当しています。製品のサイズについては図で言うことができます。2人のテスターに​​よる各製品の完全な回帰には3日かかります(外部要因の影響なし)。



時間枠は重要であり、対処するように頼みます。戦う方法はいくつかありますが、主なものは次のとおりです。



  • リリースサイクルを使用して、アプリケーションをより小さな製品に分割しました。

  • テストピラミッドに従って製品をテストでコーティングします



最後の段落は私の記事のトピックでした。



画像



ピラミッドのテスト



ご存知のとおり、テストピラミッドには、単体テスト、統合テスト、e2eテストの3つのレベルがあります。多くの人はユニットやe2eに精通していると思うので、統合テストについて詳しく説明します。



統合テストの一環として、UIとの対話を通じてアプリケーション全体の動作をチェックしますが、e2eテストとの主な違いは、実際にバッキングを要求しないことです。これは、将来のe2eテストの数を減らすために、前面にあるすべてのシステムの相互作用のみをチェックするために行われます。サイプレス



を使用して、統合テストを記述しますこの記事では、他のフレームワークとは比較しません。なぜ私たちがそれで終わったのかを述べるだけです。



  1. 非常に詳細なドキュメント。

  2. テストの簡単なデバッグ(Cypressには、このための特別なGUIがあり、テストのタイムトラベルステップが含まれています)。



統合テストの作成経験がなく、非常に簡単な開始が必要だったため、これらのポイントはチームにとって重要でした。この記事では、私たちがたどってきた道、どのバンプを埋めたかについて話し、実装のレシピを共有したいと思います。



道の始まり



最初は、1つのアプリケーションでAngular Workspaceを使用してコードを整理しました。サイプレスパッケージをインストールした後、構成とテストを含むサイプレスフォルダがアプリケーションのルートに表示されたため、このオプションで停止しました。アプリケーションを実行し、その上でテストを実行するために必要なパッケージをpackage.jsonで準備しようとすると、次の問題が発生しました。



  1. Index.htmlには、統合テストでは不要ないくつかのスクリプトが含まれています。

  2. 統合テストを実行するには、アプリケーションを備えたサーバーが実行されていることを確認する必要がありました。



index.htmlの問題は、カスタムのindex.htmlを指定した別個のアセンブリ構成(cypressと呼ぶことにしましょう)によって解決されました。これを実装する方法?私たちは、angular.jsonでアプリケーションの構成を見つけ、ビルドセクションを開き、そこにサイプレスの個別の構成を追加し、この構成をserve-modeに指定することを忘れないでください。



ビルドの構成例:



"build": {
 ...
 "configurations": {
   … //  
   "cypress": {
     "aot": true,
     "index": "projects/main-app-integrations/src/fixtures/index.html",
     "fileReplacements": [
       {
         "replace": "projects/main-app/src/environments/environment.ts",
         "with": "projects/main-app/src/environments/environment.prod.ts"
       }
     ]
   }
 }
}


サーバーとの統合:



"serve": {
 ...
 "configurations": {
   … //  
   "cypress": {
     "browserTarget": "main-app:build:cypress"
   }
 }
}


メインから:サイプレス構成の場合、aotアセンブリを指定し、ファイルを環境に置き換えます。これは、テスト中にprodのようなアセンブリを作成するために必要です。



したがって、index.htmlを計算しました。アプリケーションを生成し、ビルドが完了するまで待機して、その上でテストを実行します。これを行うには、start-server-and-testライブラリ使用し、それに基づいてスクリプトを記述します。



 "main-app:cy:run": "cypress run",
 "main-app:cy:open": "cypress open",
 "main-app:integrations": "start-server-and-test main-app:serve:cypress http://localhost:8808/app/user/ main-app:cy:run",
 "main-app:integrations:open": "start-server-and-test main-app:serve:cypress http://localhost:8808/app/user/ main-app:cy:open"


ご覧のとおり、スクリプトには、オープンと実行の2種類があります。オープンモードは、サイプレス自体のGUIを開き、テストを切り替えてタイムトラベルを使用できます。実行モードは単なるテスト実行であり、その実行の最終結果であり、CIでの実行に最適です。



行われた作業の結果に基づいて、最初のテストを作成してCIで実行するための開始フレームワークを取得することができました。



単一リポジトリ



説明されているアプローチには非常に顕著な問題があります。リポジトリに2つ以上のアプリケーションがある場合、1つのフォルダーを使用するアプローチは実行できません。そして、それは私たちに起こりました。しかし、それはかなり興味深い方法で起こりました。サイプレスの導入当時、私たちはNXに移行していましたが、このハンサムでサイプレスとの連携が可能になりました。その中での仕事の原則は何ですか:



  1. main-appのようなアプリケーションがあり、その横にmain-app-e2eアプリケーションが作成されます。

  2. main-app-e2eの名前をmain-app-integrationsに変更します-あなたは素晴らしいです。



ng e2e main-app-integrationsという 1つのコマンドで統合テストを実行できるようになりましたNXは自動的にメインアプリを起動し、応答を待ち、テストを実行します。



残念ながら、現在Angular Workspaceを使用している人たちは傍観者のままですが、それでも問題ありません。私にもレシピがあります。NXと同様のファイル構造を使用します。



  1. アプリケーションの横にmain-app-integrationsフォルダーを作成します。

  2. その中にsrcフォルダーを作成し、それにcypressフォルダーの内容を追加します。

  3. cypress.json(最初はルートに表示されます)をmain-app-integrationsフォルダーに移動することを忘れないでください。

  4. テスト、プラグイン、および補助コマンド(パラメーターIntegrationFolder、pluginsFile、およびsupportFile)を使用して、新しいフォルダーへのパスを指定して、cypress.jsonを編集します。

  5. サイプレスは任意のフォルダ内のテストを処理できます。

    プロジェクトパラメータを使用してフォルダを指定するため、コマンドをcypress run / openからcypress run / open -–project ./projects/main-app-integrations/srcに変更します。



Angular Workspaceのソリューションは、フォルダーが手動で作成され、それがモノリポジトリ内のプロジェクトの1つではないことを除いて、NXのソリューションにできるだけ似ています。または、サイプレスのNXビルダーを直接使用することもできますサイプレスを使用したNXリポジトリの例では、nx-cypressビルダーの最終的な使用方法を確認できます-angular.jsonと

cart-e2eおよびproducts-e2eプロジェクトに注目してください)。



視覚回帰



最初の5つのテストの後、実際にはこれにはすべての可能性があるため、スクリーンショットテストについて考えました。 「スクリーンショットテスト」という言葉は、チーム内で多くの苦痛を引き起こすと前もって言っておきます。安定したテストを取得する方法は、最も簡単な方法ではなかったからです。次に、発生した主な問題とその解決策について説明します。cypress-image-snapshot



ライブラリがソリューションとして採用されました。実装にはそれほど時間はかかりませんでした。20分後に、サイズが1000×600ピクセルのアプリケーションの最初のスクリーンショットを受け取りました。統合と使用が単純すぎるため、多くの喜びがありました。



5つの参照スクリーンショットを生成した後、CIでテストを開始した結果、ビルドがバラバラになりました。openコマンドとrunコマンドを使用して作成されたスクリーンショットは異なることがわかりました解決策は非常にシンプルでした:CIモードでのみスクリーンショットを撮るので、たとえば次のように、ローカルモードでスクリーンショットを削除しました。



Cypress.Commands.overwrite(
   'matchImageSnapshot',
   (originalFn, subject, fileName, options) => {
       if (Cypress.env('ci')) {
           return originalFn(subject, fileName, options);
       }

       return subject;
   },
);


このソリューションでは、サイプレスのenvパラメーターを確認します。さまざまな方法で設定できます。



書体



ローカルでは、テストは再起動に合格し始め、CIで再度実行しようとします。結果は以下のよう







になります。diffスクリーンショットでフォントの違いに気づくのは非常に簡単です。参照スクリーンショットがmacOSで生成され、LinuxがCIのエージェントにインストールされました。



間違った決定



ピクセルごとの最小の差分

を与える標準フォント(Ubuntuフォントなど)の1つを選び、このフォントをテキストブロックに適用しました(index.htmlで作成され、サイプレステストのみを目的としています)。次に、全体の差分を0.05%に、ピクセルごとの差分を20%に増やしました。これらのパラメーターを使用して、コンポーネントのテキストを変更する必要があったときまで、1週間を費やしました。その結果、スクリーンショットを更新していませんが、ビルドは緑色のままでした。現在のソリューションは役に立たないことが証明されています。



正しい解決策



元の問題はさまざまな環境にありました。原則として、解決策はそれ自体を示唆しています-Docker。サイプレスはすでにドッキングイメージを準備しています。 Cypressはすでにイメージに含まれており、サイプレスバイナリを毎回ダウンロードして解凍しないため、画像にはさまざまなバリエーションがあります(サイプレスGUIはバイナリファイルを介して実行され、ダウンロードと解凍はダウンロードよりも時間がかかりますDockerイメージ)。

含まれているDockerイメージに基づいて、独自のDockerコンテナーを作成します。これのために、同様の内容のIntegration-tests.Dockerfileファイルを作成しました。



FROM cypress:included:4.3.0
COPY package.json /app/
COPY package-lock.json app/
WORKDIR /app
RUN npm ci
COPY / /app/
ENTRYPOINT []


ENTRYPOINTのゼロ化に注意したいと思います。これは、デフォルトでcypress /含まれているイメージに設定されており、cypress runコマンドをポイントしているため、他のコマンドを使用できないためです。また、dockerfileをレイヤーに分割して、テストを再開するたびにnpm ciを再実行しないようにします。



リポジトリのルートに.dockerignoreファイルを追加し(そうでない場合)、node-modules /および* / node-modules /を指定する必要があります。



Dockerでテストを実行するために、次の内容でbashスクリプトintegration-tests.sh記述します。



docker build -t integrations -f integration-tests.Dockerfile .
docker run --rm -v $PWD/projects/main-app-integrations/src:/app/projects/main-app-integrations/src integrations:latest npm run main-app:integrations


簡単な説明:Integration-tests.Dockerfile Dockerコンテナーを作成し、ボリュームをtestsフォルダーにポイントして、生成されたスクリーンショットをDockerから取得できるようにします。



再びフォント



前の章で説明した問題を解決した後、ビルドに落ち込みがありましたが、約1日後、次の問題が発生しました(左と右-異なる時点で取得された1つのコンポーネントのスクリーンショット):







ポップアップに十分なタイトルがないことに最も注意していたと思います... その理由は非常に単純です-フォントはアセットを介して接続されていなかったため、CDN上にあったため、ロードできませんでした。



間違った決定



CDNからフォントをダウンロードし、サイプレス構成用のアセットにドロップし

、統合テストのためにカスタムindex.htmlでそれらを接続します。この決定により、会社のフォントを変更するまで、私たちはまともな時間を過ごしました。同じ物語をもう一度プレイしたくなかった。



正しい解決策





サイプレス構成用のindex.htmlで テストに必要なすべてのフォントのプリロードを開始することが決定されました。これは次のようになります。



<link	
      rel="preload"
      href="...."	
      as="font"	
      type="font/woff2"	
      crossorigin="anonymous"
/>


ロードする時間がなかったフォントが原因でテストクラッシュの数が最小になりましたが、ゼロにはなりませんでした。それでも、フォントをロードする時間がなかった場合があります。サイプレス自体のKitchenSinkからの解決策が救いになりました-waitForResource。

今回のケースでは、フォントのプリロードがすでに接続されているため、サイプレスで単にvisitコマンドを再定義しました。その結果、ページに移動するだけでなく、指定されたフォントがロードされるまで待機します。また、waitForResourceがフォントだけでなく、ロードされた静的要素(たとえば、画像)の問題も解決することを追加したいと思います(そのため、スクリーンショットも壊れていて、waitForResourceが大いに役立ちました)。このソリューションを適用した後、フォントとロードの静的要素に問題はありませんでした。



アニメーション



私たちの頭痛はアニメーションに関連しており、それは今日まで続いています。ある時点で、要素のスクリーンショットが表示され始めるか、アニメーションが始まる前にスクリーンショットが撮られます。そのようなスクリーンショットは不安定であり、標準との次の比較ごとに違いがあります。では、アニメーションに関連する問題を解決するときに、私たちはどちらに進んだのでしょうか。



最初の解決策



最初の段階で頭に浮かんだ最も簡単なことは、スクリーンショットを作成する前に、ブラウザを一定時間停止して、アニメーションが完了する時間を確保することです。100ms、200ms、500ms、そして結果として1000msのチェーンに沿って進みました。振り返ってみると、この決定は当初ひどいものだったと理解していますが、同じ決定に対してあなたに警告したかっただけです。なぜひどい?アニメーションの時間は異なり、CIのエージェントも時々鈍くなることがあります。そのため、ページが安定するまでの待機時間が時々異なっていました。



第二の解決策



1秒待機しても、ページは常に安定することができませんでした。少し調べたところ、Angular- Testabilityのツールが見つかりました原則は、ZoneJSの安定性の追跡に基づいています。



Cypress.Commands.add('waitStableState', () => {
   return cy.window().then(window => {
       const [testability]: [Testability] = window.getAllAngularTestabilities();

       return new Cypress.Promise(resolve => {
           testability.whenStable(() => {
               resolve();
           }, 3000);
       });
   });
});


したがって、スクリーンショットを作成するときに、cy.wait(1000)とcy.waitStableState()の2つのコマンドを呼び出しました。



それ以来、ランダムにドロップされたスクリーンショットは1つもありませんが、アイドル状態のブラウザーで費やされた時間を合計してみましょう。テストに5つのスクリーンショットがあるとします。それぞれに1秒の安定した待機時間とランダムな時間があります。たとえば、平均1.5秒としましょう(実際には平均を測定していなかったので、自分の感情に応じて頭から取っています)。 ...その結果、テストでスクリーンショットを作成するのにさらに12.5秒かかります。すでに20のテストシナリオを作成していて、各テストに少なくとも5つのスクリーンショットが含まれているとします。安定性のための超過支払いは、利用可能な20のテストで約4分であることがわかります。 



しかし、これも最大の問題ではありません。上記で説明したように、ローカルでテストを実行する場合、スクリーンショットは追跡されませんが、CIでは追跡されます。期待のため、デバウンス時間などのコードのコールバックは、スクリーンショットごとにトリガーされました。これは、CIとローカルですでにランダム化されているためです。さまざまな方法で渡されます。



現在のソリューション



Angularアニメーションから始めましょう。DOM要素のアニメーション中のお気に入りのフレームワークは、ng-animatingクラスをハングさせます。これがソリューションの鍵でした。なぜなら、今は要素にアニメーションクラスがないことを確認する必要があるためです。その結果、次のような関数が作成されました。



export function waitAnimation(element: Chainable<JQuery>): Chainable<JQuery> {
   return element.should('be.visible').should('not.have.class', 'ng-animating');
}


複雑なことはなさそうですが、これが私たちの決定の基礎となったものです。このアプローチで注意したいこと:スクリーンショットを作成するときは、スクリーンショットを不安定にする要素のアニメーションを理解する必要があります。スクリーンショットを作成する前に、要素がアニメーション化されていないことを確認するアサーションを追加します。ただし、アニメーションをCSSに含めることもできます。サイプレス自体が言うように、要素のすべてのアサーションはアニメーションが終了するのを待っています-詳細はここここで。つまり、アプローチの本質は次のとおりです。アニメーション化された要素があり、それにアサーションを追加します-should( 'be.visible')/ should( 'not.be.visible')-そして、サイプレス自体はアニメーションが要素で終了するのを待ちます(おそらく、ng-animatingによるソリューションは必要なく、サイプレスチェックだけで十分ですが、今のところはwaitAnimationユーティリティを使用しています)。



ドキュメント自体に記載されているように、サイプレスはページ上の要素の位置の変更をチェックしますが、位置の変更に関するすべてのアニメーションではなく、fadeIn / fadeOutアニメーションもあります。これらの場合でも、解決の原則は同じです。要素がページに表示されるかどうかが確認されます。 



cy.wait(1000)+ cy.waitStableState()からwaitAnimationとサイプレスアサーションに移動する場合、古いスクリーンショットを安定させるために約2時間を費やす必要がありましたが、結果として、テスト実行時間は+4分ではなく+ 20-30秒になりました。 。現時点では、スクリーンショットのレビューに慎重に取り組んでいます。DOM要素のアニメーション中にスクリーンショットが実行されなかったことを確認し、アニメーションを待つテストにチェックを追加しました。たとえば、データが読み込まれるまで、ページに「スケルトン」表示を追加することがよくあります。したがって、スクリーンショットを作成する場合、フェードアニメーションが存在するため、DOMにスケルトンが存在してはならないという要件がすぐにレビューに届きます。 



このアプローチの問題は1つです。スクリーンショットを作成するときに常にすべてを予測できるとは限らず、CIに分類される可能性があります。これに対処する方法は1つだけです-そのようなスクリーンショットの作成をすぐに編集して、延期することはできません。そうしないと、雪だるまのように蓄積され、最終的には統合テストをオフにします。



スクリーンショットのサイズ



スクリーンショットのデフォルトの解像度は1000×600ピクセルです。残念ながら、Dockerで実行しているときのブラウザーウィンドウのサイズに問題があります。サイプレスでビューポートのサイズを変更しても、役に立ちません。Chromeブラウザーの解決策を見つけました(Electronでは、有効な解決策をすぐに見つけることはできませんでしたが、この問題で提案され解決策は開始しませんでした)。まず、Chromeでテストを実行するようにブラウザを変更する必要があります。



  1. NXではなく、サイプレスのopen / runコマンドを開始するときに--browser chrome引数を使用して実行し、runコマンドには--headlessパラメータを指定します。

  2. NXの場合、テストを含むangular.jsonのプロジェクト構成ではbrowser:chromeパラメーターを指定し、CIで実行される構成にはheadless:trueを指定します。



次に、プラグインを編集して、1440×900ピクセルのサイズのスクリーンショットを取得します。



module.exports = (on, config) => {
   on('before:browser:launch', (browser, launchOptions) => {
       if (browser.name === 'chrome' && browser.isHeadless) {
           launchOptions.args.push('--disable-dev-shm-usage');
           launchOptions.args.push('--window-size=1440,1200');

           return launchOptions;
       }

       return launchOptions;
   });
};


日付



ここではすべてが単純です。現在の日付に関連付けられている日付がどこかに表示されている場合、今日のスクリーンショットは明日になります。Fiximは簡単です:



cy.clock(new Date(2025, 11, 22, 0).getTime(), ['Date']);


今タイマー。スクリーンショットを作成するときに、ブラックアウトオプションを気にせず使用しました。たとえば、



cy.matchImageSnapshot('salary_signing-several-payments', {
   blackout: ['.timer'],
});


不安定なテスト



上記の推奨事項を使用すると、テストはコードだけでなく、テストが実行される環境にも影響を受けるため、100%ではなく最大のテスト安定性を実現できます。



その結果、たとえば、CIでのエージェントのパフォーマンスの低下が原因で、特定の割合のテストが失敗することがあります。まず、テストを安定させます。スクリーンショットを撮る前に必要なアサーションを追加しますが、そのようなテストを修復している間は、cypress-plugin-retriesを使用して失敗したテストを再試行できます



CIをポンプします



前の章では、1つのコマンドでテストを実行する方法と、スクリーンショットテストの操作について学びました。これで、CI最適化の方向を見ることができます。私たちのビルドでは確実に実行されます:



  1. NPM CIチーム
  2. アプリケーションをaotモードで発生させます。
  3. 統合テストの実行。


最初と2番目のポイントを見て、CIの他のビルド(アプリケーションアセンブリを使用したビルド)でも同様の手順が実行されることを理解しましょう。

主な違いは、ng serveを実行するのではなく、ng buildを実行することです。したがって、統合テストを含むビルドで既にアセンブルされたアプリケーションを取得し、それを使用してサーバーを上げることができれば、テストを含むビルドの実行時間を短縮できます。



なぜそれが必要だったのですか?私たちのアプリケーションが大きく、充実しているだけです

CI内のエージェントでnpm ci + npmをaotモードで開始するには、約15分かかりました。これには、原則として、エージェントによる多大な労力が必要であり、これに加えて統合テストが実行されました。すでに20以上のテストを作成していて、19日のテストで、テストが実行されるブラウザーがエージェントの負荷が高いためにクラッシュしたとします。ご理解のとおり、ビルドを再開すると、依存関係のインストールとアプリケーションの起動が再び待機します。



これからは、アプリケーション側のスクリプトについてのみ説明します。タスク間でアーティファクトをCIに自分で転送する問題を解決する必要があるため、統合テストを使用した新しいビルドは、アプリケーションビルドのタスクからアセンブルされたアプリケーションにアクセスできることを覚えておいてください。



静的なサーバー



アプリケーションでサーバーを上げるには、ng serveの代わりが必要です。多くのオプションがありますが、最初の-angular-http-serverから始めます。その構成には複雑なものは何もありません。依存関係をインストールし、スタティックが配置されているフォルダーを示し、アプリケーションを起動するポートを示し、満足しています。



このソリューションは20分間全体で十分でしたが、テスト回路にいくつかの要求をプロキシする必要があることに気付きました。 angular-http-serverのプロキシの接続に失敗しました。最終的な解決策は、サーバーをExpressにアップグレードすることでした。この問題を解決するために、expressおよびexpress-http-proxy自体が使用されました。私たちはstatic.staticを使用して静的変数を配布します。

その結果、次のようなスクリプトが得られます。



const express = require('express');
const appStaticPathFolder = './dist';
const appBaseHref = './my/app';
const port = 4200;
const app = express();

app.use((req, res, next) => {
   const accept = req
       .accepts()
       .join()
       .replace('*/*', '');

   if (accept.includes('text/html')) {
       req.url = baseHref;
   }

   next();
});
app.use(appBaseHref, express.static(appStaticPathFolder));
app.listen(port);


ここで興味深い点は、アプリケーションのbaseHrefルートをリッスンする前に、すべてのリクエストを処理し、index.htmlのリクエストを探すことです。これは、テストがアプリケーションページに移動する場合に行われます。そのパスはbaseHrefとは異なります。このトリックを行わない場合、メインページ以外のアプリケーションのページに移動すると、404エラーが表示されます。次に、プロキシのピンチを追加します。



const proxy = require('express-http-proxy');

app.use(
   '/common',
   proxy('https://qa-stand.ru', {
       proxyReqPathResolver: req => '/common' + req.url,
   }),
);


何が起こっているのかを詳しく見てみましょう。定数があります:



  1. appStaticForlderPath-アプリケーションの静的が配置されているフォルダー。 
  2. appBaseHref-アプリケーションにbaseHrefがある場合があります。ない場合は、「/」を指定できます。


/ commonで始まるすべてのリクエストをプロキシし、プロキシするときは、proxyReqPathResolver設定を使用して、リクエストと同じパスを保存します。使用しない場合、すべてのリクエストはhttps://qa-stand.ruに送信さます。



カスタマイズindex.html



サイプレスモードでアプリケーションを提供するときに使用したカスタムindex.htmlの問題を解決する必要がありました。node.jsで簡単なスクリプトを書いてみましょう。最初のパラメーターとしてindex.modern.htmlがあり、それをindex.htmlに変換し、そこから不要なスクリプトを削除する必要がありました。



const fs = require('fs');
const appStaticPathFolder = './dist';

fs.copyFileSync(appStaticPathFolder + '/index.modern.html', appStaticPathFolder + '/index.html');

fs.readFile(appStaticPathFolder + '/index.html', 'utf-8', (err, data) => {
   const newValue = data
       .replace(
           '<script type="text/javascript" src="/auth.js"></script>',
           '',
       )
       .replace(
           '<script type="text/javascript" src="/analytics.js"></script>',
           '',
       );

   fs.writeFileSync(appStaticPathFolder + '/index.html', newValue, 'utf-8');
});


スクリプト



私は本当にCIでテストを実行するためにすべての依存関係のnpm ciを再度実行したくなかったので(結局、これはアプリケーションビルドのタスクですでに行われています)、独自のpackage.jsonを使用してこれらのすべてのスクリプト用に別のフォルダーを作成するように見えました。たとえば、integration-tests-scriptsのようにフォルダーに名前を付け、そこに3つのファイル(server.js、create-index.js、package.json)を置きます。最初の2つのファイルについては上で説明しましたが、package.jsonの内容を分析しましょう。



{
 "name": "cypress-tests",
 "version": "0.0.0",
 "private": true,
 "scripts": {
   "create-index": "node ./create-index.js",
   "main-app:serve": "node ./server.js",
   "main-app:cy:run": "cypress run --project ./projects/main-app-integrations ",
   "main-app:integrations": "npm run create-index && start-server-and-test main-app:serve http://localhost:4200/my/app/ main-app:cy:run"
 },
 "devDependencies": {
   "@cypress/webpack-preprocessor": "4.1.0",
   "@types/express": "4.17.2",
   "@types/mocha": "5.2.7",
   "@types/node": "8.9.5",
   "cypress": "4.1.0",
   "cypress-image-snapshot": "3.1.1",
   "express": "4.17.1",
   "express-http-proxy": "^1.6.0",
   "start-server-and-test": "1.10.8",
   "ts-loader": "6.2.1",
   "typescript": "3.8.3",
   "webpack": "4.41.6"
 }
}


package.jsonには、統合テスト(typescriptおよびスクリーンショットテストをサポート)を実行するために必要な依存関係と、サーバーを起動し、Angular Workspaceでの統合テストの実行に関する章で知られているindex.htmlおよびstart-server-and-testを作成するためのスクリプトのみが含まれています...



発売



統合テストの実行を新しいDockerfileにラップします-integration-tests-ci.Dockerfile



FROM cypress/included:4.3.0
COPY integration-tests-scripts /app/
WORKDIR /app
RUN npm ci
COPY projects/main-app-integrations /app/projects/main-app-integrations
COPY dist /app/dist
COPY tsconfig.json /app/
ENTRYPOINT []


一番下の行は単純です。integration-tests-scriptsフォルダーをコピーしてアプリケーションのルートに展開し、テストの実行に必要なすべてのものをコピーします(このスイートは異なる場合があります)。前のファイルとの主な違いは、Dockerコンテナー内にアプリケーション全体をコピーするのではなく、CIでのテスト実行時間の最小限の最適化だけです。次の内容で



ファイルIntegration-tests-ci.sh作成します



docker build -t integrations -f integration-tests-ci.Dockerfile .
docker run --rm -v $PWD/projects/main-app-integrations/src:/app/projects/main-app-integrations/src integrations:latest npm run main-app:integrations


テストを含むコマンドを実行すると、integration-tests-scriptsフォルダーのpackage.jsonがルートになり、その中でmain-app:integrationsコマンドが実行されます。したがって、このフォルダーはルートに展開されるため、アプリケーションの静的情報が含まれているフォルダーへのパスは、すべてがIntegration-tests-scriptsフォルダーからではなく、ルートから起動されるという考えで指定する必要があります。



また、ちょっとした発言もしたいと思います。統合テストを実行するための最終的なbashスクリプトを、それが異なる形で進化したときに呼び出しました。これを行う必要はありません。これは、この記事を読むための便宜のためだけに行われました。たとえば、すでに開発中のIntegration-tests.shなど、常に1つのファイルを残しておく必要があります。リポジトリに複数のアプリケーションがあり、それらの準備方法が異なる場合は、bashで変数を使用できます。、またはアプリケーションごとに異なるファイル-必要に応じて。



概要



多くの情報がありました-私は今、上記に基づいて要約する価値があると思います。

簡単なスクリーンショットテストを使用して、ローカルでの書き込みとテストを実行するためのツールを準備します。



  1. サイプレスに依存関係を置きます。
  2. テストでフォルダーを準備します。

    1. Angular Single Application-すべてをcypressフォルダーに残します。
    2. Angular Workspace-テストが追跡するアプリケーションの隣に統合アプリケーションのフォルダー名を作成し、すべてをcypressフォルダーからそれに転送します。
    3. NX-プロジェクトの名前をappname-e2eからappname-integrationsに変更します。


  3. cypress- — build- Cypress, aot, index.html, environment prod- serve- Cypress ( , - prod-, ).
  4. :

    1. Angular Single Application — serve- cypress- , start-server-and-test.
    2. Angular Workspace — Angular Single Application, cypress run/open.
    3. NX — ng e2e.


  5. -:

    1. cypress-image-snapshot.
    2. CI.
    3. テストでは、ランダムにスクリーンショットを撮ることはありません。スクリーンショットの前にアニメーションがある場合は、それを待つようにしてください。たとえば、アニメーション要素にCypressアサーションを追加します。
    4. 日付はcy.clockで濡れているか、スクリーンショットを撮るときにブラックアウトオプションを使用しています。
    5. カスタムのcy.waitForResourceコマンド(画像、フォントなど)を使用して、実行時にロードされたすべての静的要素を期待します。


  6. すべてをDockerでラップします。

    1. Dockerfileを準備しています。
    2. bashファイルを作成します。




 アセンブルされたアプリケーションの上でテストを実行します。



  1. CIでは、ビルド間でアセンブルされたアプリケーションのアーティファクトをスローする方法を学びます(それはユーザーに残ります)。
  2. integration-tests-scriptsフォルダーの準備:

    1. アプリケーションのサーバーを起動するスクリプト。
    2. index.htmlを変更するスクリプト(元のindex.htmlに満足している場合は、スキップできます)。
    3. 必要なスクリプトと依存関係を含むpackage.jsonフォルダーに追加します。
    4. 新しいDockerfileを準備しています。
    5. bashファイルを作成します。


役立つリンク



  1. Angular Workspace + Cypress + CI — Angular Workspace CI , ( typescript).

  2. Cypresstrade-offs.

  3. Start-server-and-test — , .

  4. Cypress-image-snapshot — -.

  5. Cypress recipes — Cypress, .

  6. Flaky Tests — , Google.

  7. Github Action — Cypress GitHub Action, README , — wait-on. docker.




All Articles