Rspecでdrag&dropをテストする

# はじめに
Rspecでdrag&dropのテストのやり方についてまとめておきます。

#結論
1.Google Chromeをサーバーにインストール
2.selenium_chrome_headlessを使用する設定を行う
3.drag_toメソッドを使用する
これにより、テストを行うことができました。

#環境構築から、テスト実行まで
今回実行できるか確認した手順です。

DockerでRuby on Railsの環境構築を行うためのステップ【Rails 6対応】@kodai_0122
(https://qiita.com/kodai_0122/items/795438d738386c2c1966) を参考にさせていただき、テスト環境の構築を行います。

詳しくは、上記のリンクの記事にまとまってますので、ご確認ください。

```
$ mkdir spec_test_app
$ cd spec_test_app
```

```text:Dockerfile
FROM ruby:2.6.5
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client

########################################################################
# yarnパッケージ管理ツールをインストール
RUN apt-get update && apt-get install -y curl apt-transport-https wget && \
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
apt-get update && apt-get install -y yarn
# Node.jsをインストール
RUN curl -sL https://deb.nodesource.com/setup_7.x | bash - && \
apt-get install nodejs
#######################################################################

# 1.Google Chromeをサーバーにインストール
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add && \
    echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' | tee /etc/apt/sources.list.d/google-chrome.list && \
    apt-get update && \
    apt-get install -y google-chrome-stable

RUN mkdir /spec_test_app
WORKDIR /spec_test_app
COPY Gemfile /spec_test_app/Gemfile
COPY Gemfile.lock /spec_test_app/Gemfile.lock
RUN bundle install
COPY . /spec_test_app

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]

```

```text:Gemfile
source 'https://rubygems.org'
gem 'rails', '~> 6'
```

```text:Gemfile.lock
# 空
```

```text:entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /spec_test_app/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
```

```text:docker-compose.yml
version: '3'
services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/spec_test_app
    ports:
      - "3000:3000"
    depends_on:
      - db
```

### アプリケーション作成
```
$ docker-compose run web rails new . --force --no-deps --database=postgresql --skip-bundle
```

```text:Gemfile
# 追加
gem 'rspec-rails'
```

```
$ docker-compose run web bundle install
```

```
$ docker-compose build
```

```text:config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password:
  pool: 5

development:
  <<: *default
  database: spec_test_app_development


test:
  <<: *default
  database: spec_test_app
```


### コンテナ立ち上げ

```text
$ docker-compose up
```

```text
$ docker-compose run web bundle exec rails webpacker:install
```


### DB作成

```
$ docker-compose run web rake db:create
```

### コントローラー作成

```
$ docker-compose run web bundle exec rails g controller users index
```

### specファイル作成

```
$ docker-compose run web bundle exec rails generate rspec:install
```

```
$ docker-compose run web bundle exec rails generate rspec:feature users
```

### viewファイル編集

```html:/users/index.html.erb
<ul>
  <li draggable="true" ondragstart="dragStarted(event)" ondragover="draggingOver(event)" ondrop="dropped(event)">鈴木さん</li>
  <li draggable="true" ondragstart="dragStarted(event)" ondragover="draggingOver(event)" ondrop="dropped(event)">高橋さん</li>
  <li draggable="true" ondragstart="dragStarted(event)" ondragover="draggingOver(event)" ondrop="dropped(event)">田中さん</li>
  <li draggable="true" ondragstart="dragStarted(event)" ondragover="draggingOver(event)" ondrop="dropped(event)">小林さん</li>
  <li draggable="true" ondragstart="dragStarted(event)" ondragover="draggingOver(event)" ondrop="dropped(event)">伊藤さん</li>
</ul>

<script>
  function dragStarted(evt) {
    source = evt.target;
    evt.dataTransfer.setData("text/plain", evt.target.innerHTML);
    evt.dataTransfer.effectAllowed = "move";
  }
  
  function draggingOver(evt) {
    evt.preventDefault();
    evt.dataTransfer.dropEffect = "move";
  }
  
  function dropped(evt) {
    evt.preventDefault();
    evt.stopPropagation();
    source.innerHTML = evt.target.innerHTML;
    evt.target.innerHTML = evt.dataTransfer.getData("text/plain");
  }
</script>
```

### テスト関連ファイル編集

```ruby:spec/rails_helper.rb
# 2.selenium_chrome_headlessを使用する設定を行う
Capybara.javascript_driver = :selenium_chrome_headless

Capybara.register_driver :selenium_chrome_headless do |app|
  options = ::Selenium::WebDriver::Chrome::Options.new

  options.add_argument('--headless')
  options.add_argument('--no-sandbox')

  Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
end
```

```ruby:spec/features/users_spec.rb

# 追加
scenario 'ドラッグ&ドロップのテスト', js: true do
  visit users_index_path 
  first_user = all('li')[0]
  second_user = all('li')[1]

  # 3.drag_toメソッドを使用する
  all('li')[0].drag_to all('li')[1]
  expect(all('li')[1].text).to eq '鈴木さん' 
end
```

###テスト実行

```
$ docker-compose run web bundle exec bundle exec rspec spec/features/users_spec.rb 
```

```
1 example, 0 failures
```

# まとめ
drag&dropのテストを行うことができました!
より良い方法等などありましたらご教授ください。