🍲
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では動かないのか
-
TinyMCEはiframe内にエディタを配置している
-
[contenteditable="true"]はiframe内にあるため、直接アクセスが不安定
-
-
CI環境はリソースが限られている
- GitHub Actionsのランナーはローカル環境より遅い
- DOMの準備完了タイミングにズレが生じる
-
fill()メソッドの制約- Playwrightの
fill()は通常のinput要素には強いが、リッチテキストエディタには不向き - contenteditable要素への入力は環境依存性が高い
- Playwrightの
解決策
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)
}
ポイント
-
waitForFunction()でTinyMCEの初期化完了を確認-
window.tinymce.activeEditor.initializedがtrueになるまで待機 - これによりエディタが完全に準備できてから操作を行う
-
-
page.evaluate()でTinyMCEのAPIを直接呼び出す-
setContent()メソッドでHTMLを直接設定 - DOM操作ではなくエディタのAPIを使うことで安定性が向上
-
-
適切な待機時間の確保
- 入力後に
waitForTimeout()で反映を待つ
- 入力後に
まとめ
| 項目 | 元の実装 | 改善後 |
|---|---|---|
| 入力方法 |
fill() + contenteditable |
TinyMCE API (setContent()) |
| 待機方法 | 要素の表示待ち | エディタ初期化完了待ち |
| 安定性 | ローカルのみ成功 | CI環境でも成功 |
教訓:
- リッチテキストエディタはDOM操作ではなく、エディタのAPIを使用する
- CI環境とローカル環境の差異を意識する
- playwright-reportのスナップショットは問題特定に非常に有用
参考リンク
明日はアドカレ9日目 emtsさんの「ライブ配信視聴機能改善の取り組みまとめ」の予定です! んがっ、くっく。
株式会社SKIYAKIのテックブログです。ファンクラブプラットフォームBitfanの開発・運用にまつわる知見や調べたことなどを発信します。主な技術スタックは Ruby on Rails / React / AWS / Swift / Kotlin などです。 recruit.skiyaki.com/
Discussion