フォーム欄の<label>と<input>の関係性
フォーム欄のlabelとinputの関係性
下記のようなフォーム欄があるviewファイルでテスト1のようなコードでテストを行なった場合、エラー1のように表示される場合。
[app/viewa ファイル] <%= form_with model: board, local: true do |f| %> <%= render 'shared/error_messages', { object: f.object } %> <div class="form-group"> <%= f.label :title %> <%= f.text_field :title, class: "form-control" %> </div> <div class="form-group"> <%= f.label :body %> <%= f.text_area :body, class: "form-control", rows: "10" %> </div> <div class="form-group"> <%= f.label :image %> <%= f.file_field :image, id: :board_img, class: "form-control mb-3", accept: 'image/*' %> <%= f.hidden_field :image_cache %> </div> <div class="form-group"> <%= image_tag board.image.url, id: :img_prev %> <script type="text/javascript"> $(function() { function readURL(input) { if (input.files && input.files[0]) { var reader = new FileReader(); reader.onload = function (e) { $('#img_prev').attr('src', e.target.result); } reader.readAsDataURL(input.files[0]); } } $("#board_img").change(function(){ readURL(this); }); }); </script> </div> <%= f.submit (t 'defaults.create'), class: "btn btn-primary" %> <% end %>
[テスト1 ファイル] it '掲示板が作成できること' do fill_in 'タイトル', with: 'テストタイトル' fill_in '本文', with: 'テスト本文' file_path = Rails.root.join('spec', 'fixtures', 'example.jpg') attach_file "サムネイル", file_path click_button '登録する' expect(current_path).to eq boards_path expect(page).to have_content('掲示板を作成しました'), 'フラッシュメッセージ「掲示板を作成しました」が表示されていません' expect(page).to have_content('テストタイトル'), '作成した掲示板のタイトルが表示されていません' expect(page).to have_content('テスト本文'), '作成した掲示板の本文が表示されていません' end
[エラー1] Capybara::ElementNotFound: Unable to find file field "サムネイル" that is not disabled 0) 掲示板 掲示板のCRUD 掲示板の作成 ログインしている場合 掲示板が作成できること Failure/Error: attach_file "サムネイル", file_path # サムネイルというlebelがあるフィールドにfile_pathを挿入したらエラーが起きた Capybara::ElementNotFound: # Capybara::ElementNotFoundという例外クラス Unable to find file field "サムネイル" that is not disabled # サムネイルというフィールドが無い [Screenshot]: tmp/screenshots/failures_r_spec_example_groups_nested_crud_nested_2_nested_2_掲示板が作成できること_490.png # ./spec/system/boards/board_spec.rb:103:in `block (5 levels) in <top (required)>'
viewファイルにも実際にサーバーを起動した時のブラウザにも画像挿入のフィールドが存在し、動作に問題がないのにテストでエラーが起きてしまう。
これは、テストで利用している[Capybara Gem]が見ているのは、viewファイルではなくブラウザで表示されるhtmlの為。
Capybaraの動作順序は以下のようになる。
ブラウザのhtmlで[サムネイル]というlabelを探す。
↓
[サムネイル]というlabelに関連したフィールドに、[file_path]という画像を挿入する。
今回発生しているエラーの原因は、labelとフィールドに関連性がないことが原因。([サムネイルというlabelを探せるがそれに関連しているフィールドが存在しない。])
htmlでlabelとinputに関連性をもたらすには、inputにid属性、labelにfor属性(inputのid属性と同じもの)を付与しなければならない。
今回のviewファイルでは、以下のようになっている。(labelとinputでforの属性名とidの属性名が違う)
[app/views ファイル] <div class="form-group"> <%= f.label :image %> <%= f.file_field :image, id: :board_img, class: "form-control mb-3", accept: 'image/*' %> <%= f.hidden_field :image_cache %> </div>
下記のように修正することでテストエラーを解消できる。
[app/views ファイル] <div class="form-group"> <%= f.label :image, for: :board_img %> <%= f.file_field :image, id: :board_img, class: "form-control mb-3", accept: 'image/*' %> <%= f.hidden_field :image_cache %> </div>
[補足]
以下のようにlabelにfor属性、inputにid属性を付与しない場合は、for属性名もid属性名も[board_board_image]になる。
<%= form_with model: board do |f| %> <%= f.label :board_image %> <%= f.file_field :board_image %> <% end %>
参考記事: