1599 Words 7 min

AngularプロジェクトでPlaywrightを導入しTypeScriptで自動E2Eテストを実行するで詰まったことを調べてみた雑記帳のようなもの。

テストケースを動画で撮影し、ダウンロードする

テストした結果を動画で残して起きたかったので、撮影しダウンロードする方法を調べてみた。

test('テストケースを動画で撮影し、ダウンロードする', async ({ browser }) => {

  // ブラウザ名を取得(小文字に変換)
  const browserName = browser.browserType().name();

 // テスト名(スペースをアンダースコアに変換)
  const testName = 'test_name';

  // 動画保存用のディレクトリパスを生成
  const videoDir = path.join('videos', `${browserName}_${testName}_${今日の日付取得関数}`);

  // コンテキストを作成する際にビデオ録画を設定
  const context = await browser.newContext({
    recordVideo: {
      dir: videoDir, // 録画ファイルを保存するディレクトリ
      size: { width: 1280, height: 720 } // ビデオサイズを設定(オプション)
    }

    // ここで必要なテストを実行する


   // テスト終了時にコンテキストをクローズ(これによりビデオ録画も終了)
  await context.close();
});

複数のテストファイルを順次実行する

デフォルトではPlaywrightは並列実行するらしいので、直列実行するためのコマンドを叩くようにする。

npx playwright test --workers=1

そのうえで、テストファイルがアルファベット順で実行される仕様らしいので、

1_test_login
2_test_acoount_change

認証情報を保持する

順次実行したいのも、ログインしたうえで処理を実行したいからであり、そのためにテストファイルをまたぎ認証情報を保持しておく必要がある。

ログイン処理実行後に認証情報を保存する処理を行い、

test('ログインページが正しく動いている確認テスト', async ({ browser }) => {

    ...テスト実施

    // 認証情報を保存
    const storageStatePath = path.resolve('./storageState.json');
    await page.context().storageState({ path: storageStatePath });
});

認証情報を使用したいファイルで

test.use({
  storageState: path.resolve("./storageState.json"), // 保存した認証情報を使用
});

test("認証情報を使うテスト", async ({ page }) => {});

上記のように使用する。

APIのレスポンスを使用する

// API レスポンスを待つ
const [response] = await Promise.all([
  page.waitForResponse(
    (response) =>
      response.url().includes("/api/endpoint") && response.status() === 200,
  ),
]);

// レスポンスの内容を取得
const responseData = await response.json();

特別変わった書き方ではない。

ちなみに中の値にアクセスする前に、

expect(response.value).not.toBeUndefined();

上記のようにUndefinedチェックをすることができる。

SignalRのテストをする

// ページにアクセス
await page.goto("http://localhost:4200/#/dummy");

// SignalRライブラリを動的にロード
await page.evaluate(async () => {
  return new Promise((resolve, reject) => {
    const script = document.createElement("script");
    script.src =
      "https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/7.0.0/signalr.min.js";
    script.onload = resolve;
    script.onerror = reject;
    document.head.appendChild(script);
  });
});

// SignalRライブラリがグローバルに利用可能か確認
await page.waitForFunction(() => "signalR" in window);

// SignalR接続の開始
const signalRConnection = await page.evaluate(async () => {
  try {
    const connection = new window.signalR.HubConnectionBuilder()
      .withUrl("http://xxx.xx.xxx.xxx:xxxx/SignalR", {
        skipNegotiation: true,
        transport: window.signalR.HttpTransportType.WebSockets,
      })
      .withAutomaticReconnect([0, 1000, 5000])
      .build();

    let connectionState: string | null = null;

    // 再接続処理
    connection.onreconnecting((error) => {
      connectionState = "reconnecting";
      console.log("再接続中:", error?.message || "No error message");
    });

    // 再接続成功時
    connection.onreconnected((connectionId) => {
      connectionState = "reconnected";
      console.log("再接続成功。ID:", connectionId);
    });

    // 接続終了時
    connection.onclose((error) => {
      connectionState = "closed";
      console.log("接続終了:", error?.message || "No error message");
    });

    // 接続の開始
    console.log("SignalR接続開始...");
    await connection.start();
    connectionState = "connected";
    console.log("SignalR接続完了。ID:", connection.connectionId);

    connection.on("Message", async (response) => {
      console.log("ResidentProgramDataAdded メッセージを受信:", response);

      // SignalRで受信したデータについてのテストをする
      console.log(response);
      expect(response === "xxx").toBe(true);

      // テストクリア
      expect(true).toBe(true);
    });

    return {
      success: true,
      connectionId: connection.connectionId,
      state: connectionState,
    };
  } catch (err: any) {
    console.error("SignalR接続エラー:", err);
    return {
      success: false,
      error: err.message,
      state: "setup_failed",
    };
  }
});
console.log("SignalR接続結果:", signalRConnection);

if (!signalRConnection.success) {
  console.error("接続失敗:", signalRConnection.error);
  throw new Error(`SignalR接続失敗: ${signalRConnection.error}`);
}

expect(signalRConnection.success).toBe(true);

どうやってSignalRと接続すればいいかわからなかった。 CDNで接続すればうまくいったので、正解かわからないけどそのように実装した。

これも認証のようにグローバルに受信できるようにしたいけど、いまは接続確認するまで。