RSpec ile _form.html.erb View testi

Kullandığım sürümler: ruby 3.0.0p0 and Rails 7.0.4 and rspec-rails (6.0.1)

Selamlar,

View ve System testleri konusunda çalışmalar yapıyorum. scaffold ile Product model, controller ve view oluşturdum. Product için model, system, controller ve view testlerini yazdım fakat _form.html.erb testinde best practice konusunda sıkıntı yaşıyorum. _form.html.erb view testini hem Edit hemde New için yazmam gerek. Bu yüzden input alanlarının value değerleri ve submit button textleri değişiklik gösteriyor. Bu durumda testime bakış açım nasıl olmalı ve paylaşacağım kod sizce best practice ne kadar yakın?

views/products/_form.html.erb

<%= form_with(model: product, class: "contents") do |form| %>
  <% if product.errors.any? %>
    <div id="error_explanation" class="bg-red-50 text-red-500 px-3 py-2 font-medium rounded-lg mt-3">
      <h2><%= pluralize(product.errors.count, "error") %> prohibited this product from being saved:</h2>

      <ul>
        <% product.errors.each do |error| %>
          <li><%= error.full_message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <div class="my-5">
    <%= form.label :title %>
    <%= form.text_field :title, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full" %>
  </div>

  <div class="my-5">
    <%= form.label :description %>
    <%= form.text_area :description, rows: 4, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full" %>
  </div>

  <div class="my-5">
    <%= form.label :image_url %>
    <%= form.text_field :image_url, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full" %>
  </div>

  <div class="my-5">
    <%= form.label :price %>
    <%= form.text_field :price, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full" %>
  </div>

  <div class="inline">
    <%= form.submit class: "rounded-lg py-3 px-5 bg-blue-600 text-white inline-block font-medium cursor-pointer" %>
  </div>
<% end %>

Benim Kodum:

spec/views/products/_form.html.erb_spec.rb

Input alanlarında value değerlerini yakalamak için burada Nokogiri'den yararlandım

require "rails_helper"

RSpec.describe "rendering locals in a partial", type: :view do
  subject { Nokogiri::HTML(rendered) }

  it "form for editing the product" do
    product = Product.create!(title: "dicer", description: "Hello World 2", price: 10.1)

    render :partial => "products/form", :locals => { :product => product }

    aggregate_failures do
      expect(subject.at('input[@name="product[title]"]')['value']).to eq(product.title)
      expect(subject.at('textarea[@name="product[description]"]').text.strip).to eq(product.description)
      expect(subject.at('input[@name="product[image_url]"]')['value']).to eq(product.image_url)
      expect(subject.at('input[@name="product[price]"]')['value'].to_f).to eq(product.price.to_f)
      expect(rendered).to have_button('Update Product')
    end
  end

  it "form for creating a  product" do
    product = Product.new

    render :partial => "products/form", :locals => { :product => product }

    aggregate_failures do
      expect(subject.at('input[@name="product[title]"]')['value']).to eq(nil)
      expect(subject.at('textarea[@name="product[description]"]').text.strip).to eq("")
      expect(subject.at('input[@name="product[image_url]"]')['value']).to eq(nil)
      expect(subject.at('input[@name="product[price]"]')['value']).to eq(nil)
      expect(rendered).to have_button('Create Product')
    end
  end
end

Merhabalar,

Öncelikle şunu belirtmek isterim, benim kullandığım yaklaşım genelde bu tür partial veya view’ları integration veya request testleri ile test etmek oluyor. Örneğin “new product” sayfasındaki formda ne görmek istiyorsam bir integration veya request testi ile test ediyorum. _form.html.erbyi test etmek sanki implementation detail’i test etmek gibi geliyor bana, eğer yanılıyorsam da biri düzeltirse sevinirim :slight_smile: .

Bu örneğe gelecek olursa, birinci example’da product’ın persist olul olmamasına bakmadan product attribute’larına bağlı form elemanlarını test ederdim:

let(:product) { build(:product) } # factory-bot kullandığımızı varsayarsak.

it "has correct form fields" do
  expect(subject.at('input[@name="product[title]"]')['value']).to eq(product.title)
  expect(subject.at('textarea[@name="product[description]"]').text.strip).to eq(product.description)
  expect(subject.at('input[@name="product[image_url]"]')['value']).to eq(product.image_url)
  expect(subject.at('input[@name="product[price]"]')['value'].to_f).to eq(product.price.to_f)
end

Sonra, product’ın henüz persist edilmediği durum için bir context açardım, ve onun içinde bir example oluştururdum:

context "when the product is not persisted" do
  it "has the correct label for the submit button" do
    expect(rendered).to have_button('Create Product')
  end
end

Diğer context’i ve example’ı da şu şekilde oluştururdum:

context "when the product is persisted" do
  let(:product) { create(:product) }
  
  it "has the correct label for the submit button" do
    expect(rendered).to have_button('Update Product')
  end
end
2 Beğeni

Güzel bir yaklaşım olmuş cevabın için çok teşekkür ederim :bowing_man: