kubell Creator's Note

株式会社kubellのエンジニアのブログです。

ビジネスチャット「Chatwork」のエンジニアのブログです。

読者になる

E2Eの課題を、チームを越えて解いた話 ― 10分以上から約3分半へ

こんにちは!フロントエンド開発グループの前田です。

E2Eテストには、以前から「実行時間が長い」「並列で動かすとテストデータが競合する」という課題がありました。

フロントエンドの中だけで閉じず、SRE・認証・QAの各チームに相談しながら進めた結果、E2Eの実行時間を10分以上から約3分半にできました。

振り返ると、kubellのValue「Beyond Boundaries」を体験した話でもあります。

E2Eテストを見直すことになった理由

現在、フロントエンド開発グループでは、大きなリファクタリングに向けた準備を進めています。このリファクタリングではさまざまな部分に変更が入る予定のため、Chatworkの各機能を網羅的に動作保証したいというニーズがありました。

Chatworkでは、jQueryで書かれた古い層とReactの層が混在しています。

リファクタリングでは両方に手が入るため、画面の動きが壊れていないかを、単体テストだけでは確かめきれない箇所があります。

そこで、壊れたらChatworkが使えなくなる主要な操作に絞って、E2Eテストを増やすことにしました。

E2Eテスト、思ったより時間がかかる

E2Eテストを増やしていくと、まず気になったのが1回あたりの実行時間です。完了まで10分以上かかっていました。

最近はAIを使った開発で、複数の開発を並行して進めることが増え、E2Eを実行する回数も増えています。1回ごとに10分以上待つのはつらいので、短縮したいと考えました。

SREに相談してみた

使っていない準備を削る

まず、他にも削れるところがないか、Claude Codeに分析してもらいました。

すると、テスト前の準備として、shard(テストを分割して並列に流す単位)ごとにnode_modules一式とCypress本体(562MB)をキャッシュから取得・展開していることが分かりました。これに1shardあたり約90秒かかっていました。あわせて、node_modulesのビルドも毎回実行していました。既存のワークフローを流用していたため、Playwright以外の分までまとめて持ってきていたようです。

実際に動いている内容を確認すると、Playwrightのテストがnode_modulesから使っているのは@playwright/testだけで、準備のほとんどは不要でした。テストが実際に使うものだけを入れる形にすると、各shardの準備がほぼなくなりました。

これだけでも、実行時間は

10分以上 → 8〜10分程度

まで短縮できました。

ランナーにPlaywrightを事前に入れておく

さらにSREに相談すると、E2Eのジョブは動き始めてからPlaywrightのイメージを取得していることが分かりました。ジョブが終わると環境ごと捨てられるので、shardごとに毎回同じ準備をやり直していました。イメージの取得が詰まって、テストジョブに進めないままrun(ワークフローの1回の実行)ごと失敗することもありました。

ChatworkのE2Eは、接続元IPを制限した環境に対して実行します。GitHubが用意するランナーはIPが固定されないため、IP制限を通過できるセルフホステッドランナー(自社管理のマシンで動くランナー)で動かしていました。そこで、ランナーのイメージにPlaywrightをあらかじめ入れておく構成に変えたことで、ジョブごとのイメージ取得がなくなりました。あわせて、shardごとに行っていたログインを1回にまとめました。ログイン状態はPlaywrightのstorageState(ログイン状態をファイルに保存する機能)に保存し、全shardで共有しています。

すると、

8〜10分程度 → 約3分半

まで短縮できました。

初めて3分台の結果を見たときは、思わず画面を二度見しました。

「E2Eだから時間がかかる」と考えていましたが、実際にはE2Eそのもの以外にも、セットアップやビルドなど時間のかかっている処理がありました。

テストデータが競合する

実行時間とは別に、もう一つ問題がありました。

複数のPRでE2Eテストを並列実行すると、同じテストアカウントやテストデータを使っているため、テスト同士が干渉してしまいます。

例えば、あるテストがデータを更新した直後に、別のテストが同じデータを参照すると、想定していた結果にならないことがあります。

その結果、テストが不安定になることがありました。

また、テストアカウントを共有していたため、E2Eラベル付きのPRが2件以上同時に走るだけで待ちが発生し、PRが集中した朝には待ちが最大16分程度に達したこともあります。

ここについては、フロントエンド開発グループで解決方法を考えました。

テストデータをスロット化する

そこで考えたのが、テストデータをスロットに分ける方法です。

PRごとに利用するスロットを分け、それぞれのPRが異なるテストアカウントやテストデータを使うようにしました。

イメージとしては、こんな感じです。

PR番号 スロット 使うアカウント
#101 Slot 1 テストアカウント(slot 1)
#102 Slot 2 テストアカウント(slot 2)
#103 Slot 3 テストアカウント(slot 3)
#104 Slot 4 テストアカウント(slot 4)
#105 Slot 0 既存の共用アカウント
#106 Slot 1 #101と同じスロット

PR番号を5で割った余りでスロットが決まり、以降も同じ順に巡回します。

GitHub Actions側では、PR番号をスロット数で割った余りをそのままスロット番号にしています。

env:
  ACCOUNT_SLOT_COUNT: 5

steps:
  - name: Pick test account slot
    env:
      SLOT_KEY: ${{ github.event.pull_request.number || github.run_id }}
    run: |
      account_slot=$(( SLOT_KEY % ACCOUNT_SLOT_COUNT ))
      echo "account_slot=${account_slot}" >> "$GITHUB_OUTPUT"

手動実行はPR番号がないので、run_idで散らしています。

各スロットに対応するテストアカウントのログイン情報(メールアドレス・パスワード等)は、以下のように環境変数を動的に切り替えてテスト実行プロセスに引き渡しています。

# スロットに応じた環境変数のマッピング例
echo "TEST_USER_EMAIL=${{ secrets[format('E2E_USER_SLOT_{0}', env.account_slot)] }}" >> "$GITHUB_ENV"

これによって、別のPRのテストデータを触ってしまう問題を避けられるようにしました。E2Eラベル付きのPRが2件以上同時に走るだけで待たされる状態も、解消できました。各スロットのテストデータは、テスト実行後にクリーンアップしています。

「PR #101とPR #106が同時に走ったら、同じスロットになるのでは?」と思うかもしれません。

その場合は、同じスロットを使うrun同士をconcurrency(同じグループの実行を1つずつ流す設定)で直列化しています。後から来たrunは、先に動いているrunが終わるまで待ちます。そのため、テストデータは競合しません。

concurrency:
  group: e2e-playwright-serial-execution-group-slot${{ inputs.account_slot }}

同じPRに続けてpushした場合は、同じスロットに載るので、古いコミットのE2Eをキャンセルして新しい方だけを動かしています。

現状の構成では、テストアカウントを5組(スロット)に分けたことで、最大5PR分のE2Eを同時に実行できます。1PRの実行がランナー4本を使うため、5PR同時でも20本で、セルフホステッドランナーの上限30本の範囲内で運用しています。

ここで認証チームにも相談した

スロット化の仕組み自体は、フロントエンド開発グループで考えました。

ただ、実際に作ろうとすると、テストアカウントをどう作るのか、テストアカウントがbot対策に引っかからないようにするにはどうするのかなど、フロントエンドだけでは分からない部分も出てきました。

そこで認証チームに相談しました。認証の仕組みやテストアカウントについて教えてもらいながら、スロット化を進められました。

フロントエンド側で問題を整理して解決方法を考え、そのうえで専門的な部分を認証チームに相談しました。

E2EのことはQAチームにも聞いてみた

もう一つ、E2Eについて気になっていたことがありました。

「そもそもE2Eテストって、どういうところでハマりやすいんだろう?」

そこで、QAチームにも相談してみました。QAチームのこれまでの経験から、E2Eテストの設計や運用について、次のような話を聞きました。

  • E2Eで起きやすい問題
  • テストデータの扱い
  • 不安定なテストへの対応
  • E2Eとしてどこまで確認するか

自分たちだけで考えていると、どうしても「フロントエンドから見たE2E」になってしまいます。QAチームの知見を聞くことで、E2Eテストそのものについても別の視点を得られました。

振り返ってみると、いろんなチームに助けてもらっていた

それぞれのチームに相談した内容は、こんな感じでした。

問題 対応 効果 関わったチーム
テスト前準備が重い(不要なビルド) 使っていないものを洗い出して削減 1shardあたり約90秒の準備がほぼゼロに。10分以上 → 8〜10分程度 SRE・フロントエンド開発グループ
E2Eの実行時間が長い(イメージ取得) ランナーにPlaywrightを事前インストール 8〜10分程度 → 約3分半。イメージ取得詰まりによるrun失敗も解消 SRE
テストデータの競合 スロット化 待ち最大16分 → 解消。最大5PRを同時実行 フロントエンド開発グループ
テストアカウント・認証 認証の仕組みを確認 スロット別のテストアカウント5組を用意 認証チーム
E2Eの設計・運用 E2Eに関する知見を相談 E2Eを別の視点で見直せた QA

「E2Eは遅い」と決めつけなくてよかった

実際には、セットアップ、ビルド、イメージの取得、テストデータの競合といった問題が重なっていました。

一つずつ見ていくと、それぞれに改善できるポイントがあり、その問題を一番よく知っている人もそれぞれ違いました。ランナーや実行環境ならSRE、認証やアカウントなら認証チーム、E2Eの設計や運用ならQAです。その人たちに相談しながら進めたことで、自分たちだけでは気づけなかった問題にも手を入れられました。

「Beyond Boundaries」を実感した

kubellには、

Beyond Boundaries 「越境し、共に高め合う」

というValueがあります。今回のE2E改善は、このValueを実際の開発で経験した出来事だったと思います。

目の前のE2Eの問題を調べていったら、SREに相談することになり、テストデータの問題からは認証チームにも、E2EそのものについてはQAチームにも話を聞くことになりました。結果として、越境していたというのが実感です。

それぞれのチームに解決してもらったというより、自分たちで問題を考えて、分からないところはその領域に詳しい人に聞きながら、一緒に解決していった感覚に近いです。

問題を分けて、一番詳しい人に聞く

今回の改善を通して、「E2Eだから仕方ない」で止めずに、

「何に時間がかかっているんだろう?」

「この問題を一番よく知っている人は誰だろう?」

と問いかけることが大事だと感じました。

E2Eをこれから導入する方や、実行時間に悩んでいる方の参考になればうれしいです。

最後に、相談に乗ってくれたSRE・認証・QAのみなさん、ありがとうございました。

iOSDC Japan 2026に参加してきました!

こんにちは!株式会社kubellで「Chatwork」のiOSアプリ開発をしている小田です。

2026年9月11日(金)〜9月13日(日)に開催された iOSDC Japan 2026 に参加してきました!

kubellは今年もゴールドスポンサーとして協賛し、スポンサーブースを出展しました。

今回は主にブース運営として参加しました。この記事では、kubellブースの様子や、会場での交流について振り返ります

続きを読む

Jira でチケット化しない作業もグラフで品質担保 — プラグインで始めるグラフエンジニアリング開発

こんにちは。認証チームの今廣(いまひろ)です。

以前、AI自身がJira上にグラフを構築し自走する — チケット駆動開発とグラフエンジニアリング という記事で、Jira のサブタスクをノード、課題リンクをエッジ、ステータスとコメントをステートとして扱い、AI エージェント自身がグラフを組み立て、それを辿りながら自ら進めていく開発フローについて書きました。認証チームでは、チーム専用のプラグインと専用のビューを用意し、現在この形で開発を回しています。

ただ、この開発を行うためには 1 つ必要な前提があります。作業自体をJira のチケットで管理することです。裏を返せば、Jira のチケットにならない作業はこの仕組みの外に置かれてしまいます。

今回は、グラフエンジニアリングによる開発を Jira から切り離して汎用化した Claude Code プラグイン「GraphOps」を使い、その「外側の作業」を埋める運用についてご紹介します。Jira と連動した仕組みをお持ちでない方にも、このプラグイン単体で使えるものになっています。

続きを読む

DroidKaigi 2026 にブース出展&ポスターセッション登壇してきました!

こんにちは! 株式会社kubellでAndroidエンジニアをしている竹内です。

2026年9月1日(火)から9月3日(木)にかけてベルサール渋谷ガーデンで開催された DroidKaigi 2026 にて、株式会社kubellはゴールドスポンサーとして、ブース出展という形で参加してきました。あわせて、今年はポスターセッションにも参加してきました。

本記事では、ブースでの取り組みとポスターセッション、そして参加メンバーによるセッションの感想をお届けします。

続きを読む

iOSDC Japan 2026にゴールドスポンサーとしてブース出展します!

こんにちは!株式会社kubellの田川です。 普段はiOSグループ機能開発チームで「Chatwork」のiOSアプリ開発を担当しています。

今年もiOSDC Japanの季節がやってきました! kubellは「#働くをもっと楽しく、創造的に」をミッションに掲げ、iOSDC Japan 2026にゴールドスポンサーとして参加し、ブースを出展します!

続きを読む

【登壇レポート】「PHP Tech Talk Night」でカンファレンスを100倍楽しむコツを話してきた&ブースアンケート分析発表!

みなさん、こんにちは!kubellでPHPエンジニアをしている、だいすけ(@wp_daisuke)です。 2026年8月27日に開催されたアフターイベント「PHP Tech Talk Night 〜 after phpcon 2026 〜」にて登壇してきました。

共催のviviONさん、BASEさん、ピクシブさん、そしてご参加いただいたPHPコミュニティの皆さん、ありがとうございました!今回の発表では、先日開催された「PHPカンファレンス2026」のkubellブースで実施したシールアンケートの分析結果と、全通PHPerとして感じた「カンファレンスを100倍楽しむコツ」をお話ししました。本記事では、当日の登壇スライドの内容をぎゅっと凝縮して振り返ります!

続きを読む

Jiraの操作主体がAIに — 必要な情報だけを表示するダッシュボードを用意して認知負荷を軽減する

こんにちは。認証チームの今廣(いまひろ)です。

前回、AI自身がJira上にグラフを構築し自走する — チケット駆動開発とグラフエンジニアリング という記事で、Jira のサブタスクをノード、課題リンクをエッジ、ステータスとコメントをステートとして扱い、AI エージェント自身がその場でグラフを組み立て、そのグラフを辿って自ら進めていく開発フローについて書きました。

このフローを何スプリントか回して分かったのは、いつの間にか Jira の操作主体が人から AI へ移っていたということでした。チケットの説明文を整えるのも、コメントを残すのも、ステータスを進めるのも、いまはその大半を AI が行っています。人は、AI が書いたものを読んで判断する側へ回りました。

一方で Jira のボードもバックログも、人が書いて、人が読む前提で作られています。書き手が変わったことで、この前提が少しずつ噛み合わなくなってきました。

今回は、その噛み合わせを直すために作ったダッシュボードの話です。このダッシュボードは AI 側の振る舞いを一切変えていません。 スキルもグラフの組み方もステートの置き場も前回のままで、手を入れたのは人に見せるビューだけです。

続きを読む