フロント゚ンドの統合テストを䜜成し、リリヌスをスピヌドアップしたす

こんにちは私の名前は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. Cypress — trade-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