学習ノート：システムテスト再入門

## この記事の内容
プロダクトの作成中、設定がいまいちだったためにシステムテストに徐々に不具合が出てくるようになった。リファクタリングをするとともに、システムテストについて今一度しっかり勉強して、ノートにまとめてみた。

対象読者は、今までコピペでテスト周りの設定をしていたけれど、それをしっかり理解しながら自分でやってみたい人。

## システムテストを構成する要素
この記事はいくつかのパートに分かれていますが、前半のこの部分は、主に[こちらの記事](https://techracho.bpsinc.jp/hachi8833/2020_08_06/95282)の内容をまとめたもの。

- [2020年のRailsでブラウザテストを「正しく」行う方法（翻訳）](https://techracho.bpsinc.jp/hachi8833/2020_08_06/95282)

システムテストには、以下の三つの要素が必要とのこと。

- `テストランナー` ... RSpec, Minitest など
- `テストサーバー` ... WEBrick, Puma など
- `ブラウザー` ... 後述

### テスト用のブラウザについて
上記のうちブラウザについては、テスト用のブラウザもいくつか開発された。一方で、「現実のブラウザを使う」という体験に追いつくのは難しかった。

### Seleniumとは
ブラウザの自動化テストで勝ち残ってきたソフトの一つ。ブラウザごとの差異に対応してテストを実施できた。

### 転機とCDP
Chromeが[CDPプロトコル](https://chromedevtools.github.io/devtools-protocol/)を提供して、ブラウザを直接操作できるようになった。

### CDPを利用したプロジェクト代表例
- [Pupetter](https://github.com/puppeteer/puppeteer) ... Node.js用ブラウザ自動化ライブラリ
- [Ferrum](https://github.com/rubycdp/ferrum) ... Ruby向けCDPライブラリ

このうちFerrumについては、以下の利点もある。

- Pupetterとの互換性も保たれている。
- [Cuprite](https://github.com/rubycdp/cuprite)（CupriteはピュアRuby製Capybaraドライバ、CDP使用）も同梱されている。

### WebDriverとは
WebDriverとは本来はプロトコルらしい(ソースは[こちらの記事](https://avdi.codes/rails-6-system-tests-from-top-to-bottom/))。そして、そのプロトコルを使って操作をするのが、WebDriverToolであるとのこと。

主要ブラウザごとに

- Chrome ...chromedriver
- Firefox ... geckodriver
- MS Edge ... edgedriver
- Safari ... safaridriver

があるそう。

`Rails6`では、デフォルトでそれらをまとめて`webdrivers`というGemでDLしてくる。そして、`Capybara`のデフォルトの設定でそれを使うようになっている。

### WebDriverとSelenium-Webdriber
WebDriverはそれが呼び出された時に、`Selenium-Webdliver`を拡張して呼び出す。
ブラウザごとに最新のWebDriverツールをDLしてきて、それらが`Selenium-Webdliver`で使えるようにする。

## システムテスト関連の、設定ファイルの読み方
このように、システムテストには色々なツールが関わっている。
そして、「色々なツールが関わっている」ためにシステムテストの設定ファイルを読み解くのが、当初は少し難しかった。

例えば、こんなコードがあったとする

```ruby
Selenium::WebDriver::Remote::Capabilities.chrome( ... )
Capybara::Selenium::Driver.new( ... )
```

この時、1行目は`Selenium`の設定で、2行目は`Capybara`の設定になる。
上記で、`.chrome`は`Selenium`の下位クラスのメソッドで、や`.new`は`Capybara`の下位クラスのメソッド。

つまり、機能の詳細を知りたいときは一番左に書いてある名前のもののドキュメントを見れば良いのだが、どれも同じような名前なので、最初はとてもわかりにくかった。

ちなみに、参考にしたドキュメントはこちら。

- [Capybara](https://github.com/teamcapybara/capybara) ... GithubのReadme
- [Selenium](https://www.selenium.dev/documentation/en/) ... Seleniumのドキュメントページ

なお、設定ファイル中に、こんな記述もよく出てくると思う。

```ruby
RSpec.configure do |config|
  config.fixture_path = "#{::Rails.root}/spec/fixtures"
  # さまざまな設定が続く ...
end
```
この時の`config`はブロックを囲んでいる`Rspec`の設定で、`fixture_path`はRspecのメソッド。こちらも似たような記述が多いので、今、何の設定をしているのかを見失わないように注意。


### rails_helper と spec_helper
設定ファイルを書く場所には `rails_helper`と`spec_helper`がありますが、基本的には`rails_helper`に書けば良さそう。

- `spec_helper` ... Railsに依存しないSystem Testを書くためのファイル
- `rails_helper` ... RailsにおけるSystem Testの設定を書くためのファイル

らしいのだけど（参考：「[RSpec 3 時代の設定ファイル rails_helper.rb について](https://blog.willnet.in/entry/2014/06/10/142341)」)、あまりRailsに依存しないsystem specを書く人はいないと思うので。。。

`rails_helper`の自動生成されるコードを見ても、上の方に

```ruby:spec/rails_helper
require 'spec_helper'
```
と入っている。`spec_helper`の設定を読み込んでから`rails_helper`を動かしているのがわかる。

そして、それぞれのspecファイルでは

```ruby
require 'rails_helper'

RSpec.describe 'SomeModelSpec', type: :model do
# ...
end
```
というように、`rails_helper`を読み込んでいるので、両者の設定が反映される。

ちなみに、どちらかの設定ファイル(大概`rails_helper`)にこのような記述があれば

```ruby
Dir[Rails.root.join('spec/support/**/*.rb')].sort.each { |f| require f }
```
これは`spec/support`ディレクトリ下にある設定も読み込むということなので、そちらの設定も確認する。


### 余談：Systemテストになって不要だったもの
なお、システムテストに関しては古い記事もたくさんあり、コピペでなんとなく導入していたら、実際には不要になったものもたくさんあった。

system specが導入された当時に、その新機能を紹介した記事はこちら。

- [Rails 5.1以降のシステムテストをRSpecで実行する（翻訳）](https://techracho.bpsinc.jp/hachi8833/2018_01_25/51101)

システムテストでは、「データベースのロールバック」「テストが失敗したときのスクリーンショット自動撮影」など機能が備わっているので、もし、以下の導入を紹介する記事があったら、それらは基本的には不要です。

- capybara-screenshot ... capybaraでscreen shotをとってくれるGem
- database_cleaner ... テスト後、データベースの掃除をしてくれるgem


以上、まとまらない内容ですが、システムテストの設定ファイルをしっかり読みたい人の助けになればと思います。。。