Rspecでsystem specを実行した際にブラウザが起動しなかったときの対処方法

## 発生した問題
RSpecでsystem specを実行すると以下のようなエラーが出る。

具体的には下記2つが発生
```
     Got 0 failures and 2 other errors:

     1.1) Failure/Error: visit root_path

          Selenium::WebDriver::Error::SessionNotCreatedError:
            session not created: Chrome failed to start: exited normally.
              (session not created: DevToolsActivePort file doesn't exist)
              (The process started from chrome location /opt/google/chrome/chrome is no longer running, so ChromeDriver is assuming that Chrome has crashed.)
  ```
  ```
       1.2) Failure/Error: Unable to infer file and line number from backtrace

          Selenium::WebDriver::Error::SessionNotCreatedError:
            session not created: Chrome failed to start: exited normally.
              (session not created: DevToolsActivePort file doesn't exist)
              (The process started from chrome location /opt/google/chrome/chrome is no longer running, so ChromeDriver is assuming that Chrome has crashed.)
  ```

### 開発環境
- Rails 6.0.6.1
- Ruby 2.7.7
- rspec-rails 5.1.2
- webdrivers 5.3.1  
- selenium-webdriver 4.9.0  
- capybara 3.39.2  

## 原因
Google Chromeが起動しなかった
- D-Busを起動していなかった
- Windows環境にxserverをインストールしていなかった
- WSL2を使用する場合、特殊なDISPLAY変数の設定方法をする必要がある場合もある

## 解決方法
- D-Busを起動する

    ```bash
    $ sudo service dbus start
    ```

- xserverをインストール

    下記サイトを参考にVcXsrvをインストールし、起動

    [https://www.kkaneko.jp/tools/win/vcxsrv.html](https://www.kkaneko.jp/tools/win/vcxsrv.html)

- DISPLAY変数の設定

    下記を `.bashrc` に記載

    ```bash
    // .bashrc

    export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2; exit;}'):0.0
    ```

上記で無事動くようになりました！
正しい原因にたどり着くまでかなり紆余曲折してしまったので、以下にデバッグの全過程を記録として残します。



## デバッグの全過程
### やったこと①　chromedriverのインストール
#### ChatGPTを使用して状況確認
以下の回答を得る
> このエラーは、Chromeブラウザが起動できないために発生しています。DevToolsActivePort file doesn't exist というエラーメッセージは、Chromeブラウザが正しく起動しなかったことを示しています。

#### chromedriverのインストール
まずインストールしたGoogle Chromeのバージョンを確認
```
$ /usr/bin/google-chrome --version
Google Chrome 128.0.6613.119
```
次に、chromedriverを確認したところインストールされていないことが発覚。
Google Chromeのバージョンに合わせたDriverを下記で確認しインストールし、/usr/bin/に移動して実行権限を付与
https://googlechromelabs.github.io/chrome-for-testing/#stable
```
$ wget https://storage.googleapis.com/chrome-for-testing-public/128.0.6613.137/linux64/chromedriver-linux64.zip
$ unzip chromedriver-linux64.zip
$ sudo mv chromedriver-linux64/chromedriver /usr/bin/
$ sudo chmod +x /usr/bin/chromedriver
```
念の為バージョン情報を表示して、Google Chromeのバージョンとあっていることを確認
```
~$ /usr/bin/chromedriver --version
ChromeDriver 128.0.6613.119 (6e439cfca4deda5954b0c74cde9b521c03cb31ad-refs/branch-heads/6613@{#1464})
```
#### 再度テストを実行
全く同じエラーが継続

### やったこと②　Google Chromeとchromedriverのダウングレード
#### 下記の記事を確認
[RSpecを実行するとWebdrivers::VersionErrorが発生する場合の対処方法](https://qiita.com/jnchito/items/f994dd3ac2cdc39bff8c)  
エラーメッセージは異なるが、古いバージョンのRubyで不具合が出るという記述から互換性が原因と推測
`webdrivers` のバージョンを確認したところ、5.3.1  だったため、記事記載の内容が正しければ機能しそうだと感じたが、
念の為Google Chromeとchromedriverのダウングレードを試してみることにする

#### 現行バージョンを削除し、旧バージョンのダウンロードとインストール
[Google Chrome Older Versions Download (Windows, Linux & Mac)](https://www.slimjet.com/chrome/google-chrome-old-version.php)  
から旧バージョンのGoogle Chromeをインストール、併せて公式サイトから旧バージョンのchromedriverをインストールした

```
$ wget https://www.slimjet.com/chrome/download-chrome.php?file=files%2F104.0.5112.102%2Fgoogle-chrome-stable_current_amd64.deb
$ sudo apt install ./'download-chrome.php?file=files%2F104.0.5112.102%2Fgoogle-chrome-stable_current_amd64.deb'
$ sudo apt-mark hold google-chrome-stable //自動アップデートを防ぐ設定

$ wget https://chromedriver.storage.googleapis.com/104.0.5112.79/chromedriver_linux64.zip
$ unzip chromedriver-linux64.zip
$ sudo mv chromedriver-linux64/chromedriver /usr/bin/
$ sudo chmod +x /usr/bin/chromedriver
```
※バージョンも確認し、適切にダウングレードできていることを確認

#### 結果
全く同じエラーが継続

#### Google Chromeとdriverを最新バージョンに戻す

### やったこと③　Google Chromeの手動起動調査

手動でGoogle Chromeの起動を試みても起動しない

```
$ google-chrome
[13003:13029:0911/201522.846322:ERROR:bus.cc(407)] Failed to connect to the bus: Failed to connect to socket /run/dbus/system_bus_socket: No such file or directory
[13003:13003:0911/201522.849773:ERROR:ozone_platform_x11.cc(244)] Missing X server or $DISPLAY
[13003:13003:0911/201522.849860:ERROR:env.cc(258)] The platform failed to initialize.  Exiting.
```

#### エラーの解釈
- `/run/dbus/system_bus_socket` が存在しない、あるいはアクセスできない
- `X server or $DISPLAY` が存在しない、あるいはアクセスできない

#### socketについてのデバッグ
- system_bus_socketの存在確認
    - system_bus_socketの存在確認

        ```bash
        $ ls /run/dbus/system_bus_socket
        ls: cannot access '/run/dbus/system_bus_socket': No such file or directory
        ```

        上記からファイルが存在しないか、D-Busが起動していない可能性がある

    - D-Busのステータス確認

        ```bash
        $ sudo service dbus status
         * dbus is not running
        ```

    - D-Busを起動

        ```bash
        $ sudo service dbus start
         * Starting system message bus dbus                            [ OK ]
        ```

    - system_bus_socketの再確認

        ```bash
        $ ls /run/dbus/system_bus_socket
        /run/dbus/system_bus_socket
        ```

        これでsocketは存在していそう！

    - あらためてGoogle Chromeの起動を試みる

        ```bash
        $ google-chrome
        [5817:5817:0912/142950.762496:ERROR:ozone_platform_x11.cc(244)] Missing X server or $DISPLAY
        [5817:5817:0912/142950.762629:ERROR:env.cc(258)] The platform failed to initialize.  Exiting.
        ```

        次はX Serverか＄DISPLAYを何とかする必要がある

#### Xserverについてのデバッグ
- XServerの起動確認

    ```bash
    $ ps aux | grep Xorg
    omi  5876  0.0  0.0   4024  1984 pts/0    S+   14:41   0:00 grep --color=auto Xorg
    ```

    - `ps` はプロセスを取得
    - `a` はすべてのユーザー
    - `u`はユーザーやCPU使用率などの情報も含めて表示
    - `x`はターミナルに関連づいていないプロセスも含めて表示
    - `|` は左の処理を右の処理に渡す意図
    - `grep Xorg` でXサーバーのプロセスをフィルタリング

    表示されているのはこのコマンド自体の情報なので、結論XServerが起動できていなさそう

- XServerのインストール

    WSL上でXServerを使う場合、Windows側にXServerをインストールして、Ubuntu上でDISPLAY環境変数を設定する必要があるらしい。

    そのため、下記のサイトを参照し、VcXsrvをインストールした。

    [https://www.kkaneko.jp/tools/win/vcxsrv.html](https://www.kkaneko.jp/tools/win/vcxsrv.html)

- Ubuntu上で＄DISPLAYの設定

    ```bash
    $ export DISPLAY=localhost:0.0
    ```

- VcXsrvでXserverを起動

    ショートカット作成せず、検索にもなぜか引っかからなかったので地味に探すの手間取った＞＜Programfile/VcXsrvからvcxsrv.exeを起動

    起動時の設定は下記の通り

    - **Display settings**:
        - **"Multiple windows"** を選択
        - **"Display number"** は`0`
    - **Client startup**:
        - **"Start no client"** を選択
    - **Extra settings**:
        - **"Disable access control"** を選択
- Xserverの起動を再確認

    下記の通り、変わらず…

    ```bash
    $ ps aux | grep Xorg
    omi  6171  0.0  0.0   4024  2020 pts/0    S+   22:08   0:00 grep --color=auto Xorg
    ```

    可能性として、下記が挙げられる

    - xserverが起動できていない

        ⇒ステータスバーにアイコンはちゃんと表示されている

    - 起動できているが何かしらのエラーが有る

        ⇒ログを確認したところ、特に問題はなさそう

    - Windows側のxserverとWSL側の連携がうまく取れていない

        ⇒これかも…chatGPTはこれについてはあまり答えてくれないので、Google検索

- Ubuntu google chrome Missing X server or $DISPLAYで検索
    - 有用そうな記事をいくつか見つける
        - [https://github.com/puppeteer/puppeteer/issues/8148](https://github.com/puppeteer/puppeteer/issues/8148)

            ⇒下の2つの記事へのリンクがあった

        - [https://www.gregbrisebois.com/posts/chromedriver-in-wsl2/](https://www.gregbrisebois.com/posts/chromedriver-in-wsl2/)

            ⇒これが解決につながる！

        - [https://stackoverflow.com/questions/61860208/running-graphical-linux-desktop-applications-from-wsl-2-error-e233-cannot-op/66398613#66398613](https://stackoverflow.com/questions/61860208/running-graphical-linux-desktop-applications-from-wsl-2-error-e233-cannot-op/66398613#66398613)

            ⇒解決した理由がよくわかる

- $DISPLAYの設定を変更
    - 下記を `.bashrc` に記載

        ```bash
        // .bashrc

        export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2; exit;}'):0.0
        ```

    - .bashrcを再読み込み

        ```bash
        $ source ~/.bashrc
        ```

    - 正しく読み込まれているか確認

        ```bash
        ~$ echo $DISPLAY
        172.xx.xxx.x:0.0
        ```

    - Google Chromeの起動を試みる

        ```bash
        ~$ google-chrome

        なんだかたくさんのエラー
        ```

        が、その後Google Chromeの画面が立ち上がる…！

        たくさんのエラーはD-Busに関連するもので、$DISPLAYをいじったことが関係していそうな印象だが、いったん動作するので解消まではしないことにする。


## 今回のデバッグで学んだこと
- socket
    - socketとは、クライアントとサーバーのやり取りのための通路のようなもので、どこに情報を送るのか、どこに情報を受け取るのかということを規定する役割がある
        - IPアドレスの指定とポート番号の指定の2つの役割がメイン
    - ソケットファイルの種類
        - UNIXドメインソケットファイル：同じマシン上のプロセス間で通信するためのもの
        - ネットワークソケットファイル：ネットワーク上のプロセス間で通信するためのもの。IPアドレスとポート番号を持つのはこれ
        - 一般的なソケットファイル：アプリケーションやサービスがプロセス間通信をするためのもの
    - `/run/dbus/system_bus_socket`　とは？
        - **D-Bus**（Desktop Bus）というプロセス間通信システムで使われるソケットファイルです。このソケットは、特にLinuxシステム上で動作するプロセス同士がデータをやり取りするための「通信経路」として機能します。
        - 種類としてはUNIXドメインソケット
        - ソケットファイル内になにか具体的なデータが記載されているわけではない。接続ポイントとして機能するらしい。よくわからん。
        - Server起動時に生成され、終了時に消滅する＝＞Serverを起動しないといけない！

- XServer、＄DISPLAYとは
    - XServer
        - GUIを使うためのソフトウェア
        - アプリケーションがグラフィカルな表示をおこなうためのサーバーとして機能する
        - 通常はLinuxログイン時に起動する
    - ＄DISPLAY
        - 環境変数の一つで、X Serverがどこで動作しているかを指定するためのもの
        - 通常はXSERVER起動時に生成される
    - 関係性
        - **X Server**をカフェの店員だとすると、**$DISPLAY**はそのカフェのどのテーブルでコーヒーを出すかの指定です。バリスタ（X Server）がカフェ（コンピュータ）でコーヒー（グラフィカルな表示）を提供し、テーブル番号（`$DISPLAY`）でどのテーブルにコーヒーを運ぶかを決めるイメージです。
- .bashrcとは
    - シェル起動時に自動で読み込まれるファイル
    - コマンドのエイリアスや環境変数を設定などにも使われている