🍲

PlaywrightでTinyMCEエディタへの入力がCI環境で失敗する問題と解決策

に公開

SKIYAKI Tech Blog Advent Calendar 2025 の8日目記事です!

概要

PlaywrightでTinyMCEリッチテキストエディタを含むフォームのE2Eテストを作成した際、ローカル環境では成功するがCI環境(GitHub Actions)では失敗するという問題に遭遇しました。本記事ではその原因と解決策を紹介します。

環境

  • Playwright
  • TinyMCE
  • CI: GitHub Actions (環境はubuntu-latest)
  • テスト対象: React + Redux-Formで構築されたフォーム

問題の症状

ローカル環境

テストは問題なく成功する。

CI環境

以下のようなエラーが発生:

Error: expect.toHaveURL: Target page, context or browser has been closed

実際に起きていたこと: TinyMCEエディタへの本文入力が反映されなかった。

原因の特定

playwright-reportの確認

GitHub Actionsのアーティファクトからplaywright-reportをダウンロードし、data/ フォルダ内のスナップショット(.mdファイル)を確認したところ、重要な発見がありました。

# スナップショットの抜粋
- textbox: テスト投稿_XXXXXXXX  # タイトル等、通常の入力箇所は入力されている
- paragraph                      # 本文(TinyMCEを使っている箇所)が空!

本文が入力されていないことが判明。これによりバリデーションエラーが発生し、保存が失敗していました。

元のコード

async fillBody(body) {
  const editor = this.page.locator('[contenteditable="true"]').first()
  await editor.waitFor({ state: 'visible', timeout: 15000 })
  await editor.click()
  await editor.fill(body)
}

なぜローカルでは動くのにCIでは動かないのか

  1. TinyMCEはiframe内にエディタを配置している
    • [contenteditable="true"] はiframe内にあるため、直接アクセスが不安定
  2. CI環境はリソースが限られている
    • GitHub Actionsのランナーはローカル環境より遅い
    • DOMの準備完了タイミングにズレが生じる
  3. fill() メソッドの制約
    • Playwrightの fill() は通常のinput要素には強いが、リッチテキストエディタには不向き
    • contenteditable要素への入力は環境依存性が高い

解決策

TinyMCEのJavaScript APIを直接使用してコンテンツを設定する方法に変更しました。

修正後のコード

async fillBody(body) {
  // TinyMCEが初期化されるまで待機
  await this.page.waitForFunction(() => {
    return window.tinymce &&
           window.tinymce.activeEditor &&
           window.tinymce.activeEditor.initialized
  }, { timeout: 15000 })

  // TinyMCEのAPIを使って直接コンテンツを設定
  await this.page.evaluate((text) => {
    window.tinymce.activeEditor.setContent(`<p>${text}</p>`)
  }, body)

  // 入力が反映されるまで待機
  await this.page.waitForTimeout(500)
}

ポイント

  1. waitForFunction() でTinyMCEの初期化完了を確認
    • window.tinymce.activeEditor.initializedtrue になるまで待機
    • これによりエディタが完全に準備できてから操作を行う
  2. page.evaluate() でTinyMCEのAPIを直接呼び出す
    • setContent() メソッドでHTMLを直接設定
    • DOM操作ではなくエディタのAPIを使うことで安定性が向上
  3. 適切な待機時間の確保
    • 入力後に waitForTimeout() で反映を待つ

まとめ

項目 元の実装 改善後
入力方法 fill() + contenteditable TinyMCE API (setContent())
待機方法 要素の表示待ち エディタ初期化完了待ち
安定性 ローカルのみ成功 CI環境でも成功

教訓:

  • リッチテキストエディタはDOM操作ではなく、エディタのAPIを使用する
  • CI環境とローカル環境の差異を意識する
  • playwright-reportのスナップショットは問題特定に非常に有用

参考リンク

明日はアドカレ9日目 emtsさんの「ライブ配信視聴機能改善の取り組みまとめ」の予定です! んがっ、くっく。

SKIYAKI Tech Blog

Discussion