Cypressでスループットを計測する時のTips


# はじめに

みなさん、Cypress使ってますか？
CypressはJavascriptベースで動作するE2Eテストを作るフレームワークです。
[cypress.io](https://www.cypress.io/)

CypressはTypescriptでUTテストと同じノリで簡単に書けるのでとても気に入ってます。


CypressはE2Eテストフレームワークですが、
自分の所属するチームではE2Eテストの実行以外に本番環境向けのWebアプリケーションのヘルスチェックにも活用しています。

ヘルスチェックの内容としては以下で、

- 遷移した画面で各情報が適切に表示されているか？
    - websocketは繋がっている？
    - 映像は配信されている？
    - 地図は描画されている？
    - 地図上にマーカーやラインなどが描画されている？
    - etc...

- 初期表示や画面遷移での表示までのスループットが過度に遅くなっていないか？

などです。
その中で、今回はCypress上でのスループットの計測について一工夫必要だったので紹介します。

# 最初の実装（スループット計測）

```tsx:cypress.test.ts
it("スループット計測", () => {

    // NOTE: step1 ブラウザ起動〜画面1表示
    cy.log("ブラウザ起動〜画面1表示 計測開始");
    let start = new Date();

    cy.visit('/helloworld');

    // 画面1
    // 画面1の要素が表示されていること
    cy.get(ATTRIBUTE.DISPLAY1)
      .should("be.visible")
      .then(() => {
        // 計測終了
        cy.log("ブラウザ起動〜画面1表示 計測終了");
        const end = new Date();
        const msTime = end.getTime() - start.getTime();
        const s = msTime / 1000;

        cy.log("ブラウザ起動〜画面1表示 経過時間");
        cy.log(`スループットは ${s.toString()}秒でした`);
      });

    // NOTE: 画面遷移
    cy.get("#go-next-page").click();

    // NOTE: step2 画面1〜画面2
    cy.log("画面1〜画面2表示 計測開始");
    start = new Date();

    // 画面2の要素が表示されていること
    cy.get(ATTRIBUTE.DISPLAY2)
      .should("be.visible")
      .then(() => {
        // 計測終了
        cy.log("画面1〜画面2表示 計測終了");
        const end = new Date();
        const msTime = end.getTime() - start.getTime();
        const s = msTime / 1000;

        cy.log("画面1〜画面2表示 経過時間");
        cy.log(`スループットは ${s.toString()}秒でした`);
      });
});
```

概要としては、
- 最初のページが表示されるまでの時間を計測
- 最初のページが表示された状態から、遷移先のページに移って表示されるまでの時間を計測
というE2Eテストの内容です。

一見良さそうに見えますが、このコードは問題があります。

**「最初のページが表示された状態から、遷移先のページに移って表示されるまでの時間を計測」**
この確認の最初の計測開始時に`start`に`new Date()`を代入し直して開始時間を取り直しています。
しかしここで取得した時間は画面1が表示されているタイミングでの取得時間ではなく、
最初の
`let start = new Date();`
とほぼ同じタイミングでの取得時間が入ります。

よって、`画面1〜画面2表示 計測終了`時に計測した時間は、
**ブラウザ起動〜画面2表示** となってしまっているのです。


# 修正した実装

実は、`cy.log`の後にも`.then`でチェーンさせて任意の処理を実行することができます。
これを使って、
`cy.log("画面1〜画面2表示 計測開始");`が実行された際に開始時間を取り直すようにしていきます。


```diff_tsx:cypress.test.ts
it("正常性確認とスループット計測", () => {

+    let start:Date;
    // NOTE: step1 ブラウザ起動〜画面1表示
    cy.log("ブラウザ起動〜画面1表示 計測開始")
+      .then(()=>{
+        start = new Date();
+      });
-    let start = new Date();

    cy.visit('/helloworld');

    // 画面1
    // 画面1の要素が表示されていること
    cy.get(ATTRIBUTE.DISPLAY1)
      .should("be.visible")
      .then(() => {
        // 計測終了
        cy.log("ブラウザ起動〜画面1表示 計測終了");
        const end = new Date();
        const msTime = end.getTime() - start.getTime();
        const s = msTime / 1000;

        cy.log("ブラウザ起動〜画面1表示 経過時間");
        cy.log(`スループットは ${s.toString()}秒でした`);
      });

    // NOTE: step2 画面遷移
    cy.get("#go-next-page").click();

    // NOTE: step2 画面1〜画面2
    cy.log("画面1〜画面2表示 計測開始")
+      .then(()=>{
+        start = new Date();
+      });
-    start = new Date();

    // 画面2の要素が表示されていること
    cy.get(ATTRIBUTE.DISPLAY2)
      .should("be.visible")
      .then(() => {
        // 計測終了
        cy.log("画面1〜画面2表示 計測終了");
        const end = new Date();
        const msTime = end.getTime() - start.getTime();
        const s = msTime / 1000;

        cy.log("画面1〜画面2表示 経過時間");
        cy.log(`スループットは ${s.toString()}秒でした`);
      });
});
```

# まとめ
以上のように修正を加えることで想定通りの取りたいスループットを計測することができました:v: