【ITニュース解説】Missing Reports in Nightwatch with GGR + Selenoid
2025年09月14日に「Dev.to」が公開したITニュース「Missing Reports in Nightwatch with GGR + Selenoid」について初心者にもわかりやすく解説しています。
ITニュース概要
Nightwatchテストでレポートの一部が欠落。子プロセスから親プロセスへの結果送信とレポート作成のタイミングずれが原因だ。子プロセスが送信後、親プロセスの受信確認を待つ解決策が提案された。
ITニュース解説
自動テストは、ソフトウェア開発において品質を保ち、効率を高めるために非常に重要な工程だ。Webアプリケーションの自動テストでよく使われるツールの一つに「Nightwatch」がある。これは、Webサイトの特定の要素をクリックしたり、文字を入力したり、表示内容を検証したりといった、人間が行う操作をプログラムで自動化してくれる便利なフレームワークだ。そして、このNightwatchのようなテストツールを、より大規模かつ効率的に動かすための環境として「GGR」や「Selenoid」がある。これらは、複数のブラウザを同時に立ち上げ、多くのテストを並行して実行できるようにするもので、テストにかかる時間を大幅に短縮し、開発のサイクルを加速させる役割を担っている。
しかし、今回話題になっているのは、NightwatchとGGR、Selenoidを組み合わせて並行テストを実行した際に、テスト自体は最後まで問題なく完了しているにもかかわらず、その結果をまとめた「レポート」の一部、特に最後の数件が欠落してしまうという奇妙な現象だ。テストが失敗したわけでも、途中で止まったわけでもないのに、肝心のレポートに抜けがあるというのは、エンジニアにとっては困った問題である。なぜなら、レポートはテストが正しく行われたこと、またはどこに問題があったのかを確認する上で不可欠だからだ。
この問題の解決に向けて、まずいくつかの可能性が調査された。最初に考えられたのは、テスト中にJavaScriptの「プロミス」が完全に解決されずに残ってしまい、それが原因でテストプロセスが途中で失われてレポートが生成されない、というケースだ。プロミスとは、非同期処理、つまり時間がかかる処理が完了したときに、その結果を受け取るための仕組みだ。しかし、この調査の結果、未解決のプロミスが原因ではないことが判明した。Nightwatchはプロミスの扱いに優れており、この点は問題なかったのだ。
次に、レポートが到着する前にテストセッションが終了してしまうようなリクエストが送られているのではないか、という可能性も探られた。しかし、Nightwatchには「コマンドキュー」という仕組みがあり、たとえプロミスの完了を明示的に待たなかったとしても、次のコマンドは必ず前のコマンドが完了するまで待機するようになっている。そのため、テストセッションが途中で不意に終了してしまうという心配もなく、これも原因ではないことが分かった。さらに、各テストの終了後に実行される「after」という処理で、あえて時間のかかる処理を強制的に入れてみたが、それでもNightwatchは正常に動作し、レポートの欠落は解消されなかった。これらの初期調査によって、Nightwatch自体が持つ基本的な非同期処理やコマンド実行のメカニズムには問題がないことが確認された。
そこで、より深い原因を探るため、開発者がNightwatchのプログラムコードを自分の手元にコピーし(これを「リポジトリをフォークする」という)、その内部の動作を詳細に解析することになった。そして、いくつもの仮説を検証していくうちに、ついに根本的な問題点が突き止められた。
その問題は、テストを並行して実行する際のプロセス間の連携に潜んでいた。並行テストでは、全体のテストを管理する「親プロセス」と、実際に個々のテストを実行する複数の「子プロセス」が生成される。この子プロセスの一つ一つが、JavaScriptにおけるプロミスのように扱われる。各子プロセスは、担当するテストスイートの実行が終了すると、そのテスト結果のデータなどを「IPCメッセージ(Inter-Process Communicationメッセージ)」という特別な仕組みを使って親プロセスに送信する。IPCメッセージとは、コンピュータ内で実行されている異なるプログラム(プロセス)同士が情報をやり取りするための通信手段のことだ。子プロセスはデータを親プロセスに送った後、「test-endイベント」という、テストが終了したことを示す信号を発行し、そして自身は役割を終えて終了する。一方、親プロセスは、全ての子プロセスが終了したことを確認すると、いよいよ集まったデータをもとにレポートを生成する段階へと進む。
問題は、このIPCメッセージの特性にあった。IPCメッセージは、データを「送信する」ことはできるが、そのメッセージが親プロセスに「確実に届いたこと」を保証したり、届くまで「待機する」機能は備えていないのだ。これによって、「レースコンディション」と呼ばれる、複数の処理が並行して実行される際に、実行されるタイミングや順序によって結果が変わってしまうという状況が発生してしまう。
具体的に何が起こっていたかというと、次のような流れだ。 まず、子プロセスがテスト結果のデータを含むIPCメッセージを親プロセスに送信する。 次に、子プロセスはメッセージの送信を終えると、ほぼ同時に「test-endイベント」を発行し、自身の役目を終えて終了する。 すると親プロセスは、全ての子プロセスの終了(test-endイベントの受信)を確認すると、それ以上待つことなく、すぐにレポート生成のステップへと移行する。 このレポート生成のステップでは、その時点で親プロセスが受け取って利用可能なデータだけを使ってレポートが作成される。 そして、レポートが生成されてしまった「後に」、遅れてしまっていたIPCメッセージの内容が親プロセスに到着することがあったのだ。 つまり、親プロセスがレポートを作成する際に、子プロセスから送られたはずのデータがまだ到着していなかったため、そのデータがレポートに含まれずに欠落してしまったのである。これは、手紙をポストに入れた瞬間に「送った」と判断してしまい、相手が受け取ったかを確認せずに次の行動に移ってしまったために、相手が手紙を読む前に自分が手紙の内容をまとめた資料を作ってしまい、情報が古いままになってしまうような状況に似ている。
この問題の解決策として提案されたのは、子プロセスがIPCメッセージを送信した後、ただちに終了するのではなく、親プロセスからの「メッセージを受信した」という確認応答が返ってくるまで待機する仕組みを導入することだ。これにより、子プロセスは親プロセスがデータを受け取ったことを確実に確認してから終了できるため、親プロセスがレポートを生成する際には、全ての子プロセスからのデータが確実に手元にある状態となる。この変更によって、レポートの欠落という問題は解決される見込みだ。
今回のケースは、システムが並行処理や非同期処理を行う上で、データの連携やタイミングの制御がいかに重要であるかを教えてくれる典型的な事例だ。一見するとシンプルな問題に見えても、その裏にはプロセスの内部動作や通信の特性が深く関わっており、表面的な現象だけでは本当の原因にたどり着けないことがある。このような問題を解決するためには、システムの細部まで深く掘り下げて理解する探求心と、仮説を立てて検証していく論理的な思考力が求められることを示している。