「Rails + Vue」 System spec が実行されなかった際の対処法
問題
「selenium_chrome_headless」を使用してsystem specを実行した際、通るはずの簡単なテストが通りませんでした。しかも、失敗した際のスクショが真っ白という謎の現象に襲われました。
- 検証する画面
# ユーザー登録画面で必須項目が未入力により登録に失敗するというテストです。 require 'rails_helper' RSpec.describe "ユーザー登録", type: :system, js: true do context 'ユーザー情報に不備がある場合' do before do visit '/register' binding.pry click_on 'メールアドレスで登録' end it '新規登録に失敗する' do expect(page).to have_content 'ニックネームは必須項目です' end end end
- 「メールアドレスで登録」というボタンが見つからないとエラーが吐かれる!!
しかも、下記のように真っ白...
原因の究明
① capybaraが実際に動いているか?
application.html.erbでvue.jsを読み込む設定をしていたので、下記のようにbody要素内に適当な文字を設定して表示されるか確認しました。
# views/layouts/application.html.erb <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Arrangy</title> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= javascript_pack_tag 'hello_vue' %> </head> <body> <%= yield %> <p>hoge</p> # <= 表示されるか確認!! </body> </html>
結果は表示された為、capybaraは問題なく実行されているようです。
② webpackerでコンパイルされているのか?
こちらも「public/packs-test」下にコンパイルされたファイルを確認できたので違いました。
③ headlessを使用せずに、ブラウザ上で確認してみる。
めっちゃエラー吐いてる...
// app/frontend/plugins/axios.js import axios from 'axios'; let csrf_token = document.getElementsByName('csrf-token')[0].content; #<= ここでエラーが発生している!! const axiosInstance = axios.create({ baseURL: '/api', headers: { 'X-CSRF-TOKEN': csrf_token }, }); export default axiosInstance;
axiosを使用してリクエストを送る際、csrf-token
をheaderに埋め込む設定をしていました。
しかし、test環境では「csrf-token」が生成されていないにも関わらず、値を取得しに行っていた為にエラーが吐かれていました。
しかし、エラーが発生しているコードがないと開発、本番環境ではRails側から怒られてしまいます...
解決策
メドピアさんの記事を参考にしました。
jsのライブラリとして提供されている「rails-ujs」があるみたいですのでそちらを使用します。
ライブラリ追加後、ファイルを以下のように修正。
import axios from 'axios'; import { csrfToken } from 'rails-ujs'; // <= ここ!! const axiosInstance = axios.create({ baseURL: '/api', headers: { 'X-CSRF-TOKEN': csrfToken() }, }); export default axiosInstance;
これで無事に解決できました!!