Bagaimana cara menegaskan jumlah elemen menggunakan Kapibara dengan pesan kesalahan yang tepat?

87

Saya tahu bahwa di Kapibara, Anda dapat melakukan sesuatu seperti ini:

page.should have_css("ol li", :count => 2)

Namun, dengan asumsi halaman tersebut misalnya hanya memiliki satu elemen yang cocok, error tersebut tidak terlalu deskriptif:

  1) initial page load shows greetings
 Failure/Error: page.should have_css("ol li", :count => 2)
 expected css "ol li" to return something

Alih-alih pesan kesalahan yang agak tidak jelas ini, apakah ada cara untuk menulis pernyataan sedemikian rupa sehingga keluaran kesalahan akan menjadi sesuatu seperti 'Saat mencocokkan' ol li ', diharapkan: 2, ditemukan: 1'. Jelas saya bisa membuat logika kustom sendiri untuk perilaku seperti itu - saya bertanya apakah ada cara untuk melakukan ini 'di luar kotak'?

Untuk apa nilainya, saya menggunakan driver Selenium dan RSpec.

merryprankster
sumber
Sekadar orang tahu, "page.should have_css (" ol li ",: count => 2)" telah diterapkan di kapibara. Saya pikir ini sangat dapat digunakan dengan cakupan: dalam ("ol.users-list") do page.should have_css ('li',: count => 3) end
rafaelkin
@rafaelkin, hanya untuk memperjelas: apakah capybara sekarang melaporkan misalnya ketidakcocokan dalam elemen dihitung dengan lebih detail? Saya sudah lama tidak mengikuti kapibara, tetapi masalah saat itu ketika saya membuat pertanyaan adalah tentang format pesan kesalahan, bukan itu page.should have_css("ol li", :count => 2)belum diterapkan.
merryprankster
teman-teman, saya merasa bahwa jawaban yang diterima saat ini (= milik saya) bukan lagi yang terbaik, tetapi tidak punya waktu (tidak lagi bekerja dengan Ruby) untuk mengevaluasi solusi mana yang disarankan yang terbaik. Saya akan mengubah jawaban yang diterima menjadi jawaban Richard hanya karena itu mencakup keluaran dari pernyataan yang membahas masalah asli.
merryprankster

Jawaban:

22

Nah, karena sepertinya tidak ada dukungan out-of-the-box, saya menulis custom matcher ini:

RSpec::Matchers.define :match_exactly do |expected_match_count, selector|
    match do |context|
        matching = context.all(selector)
        @matched = matching.size
        @matched == expected_match_count
    end

    failure_message_for_should do
        "expected '#{selector}' to match exactly #{expected_match_count} elements, but matched #{@matched}"
    end

    failure_message_for_should_not do
        "expected '#{selector}' to NOT match exactly #{expected_match_count} elements, but it did"
    end
end

Sekarang, Anda dapat melakukan hal-hal seperti:

describe "initial page load", :type => :request do
    it "has 12 inputs" do
        visit "/"
        page.should match_exactly(12, "input")
    end
end

dan mendapatkan keluaran seperti:

  1) initial page load has 12 inputs
     Failure/Error: page.should match_exactly(12, "input")
       expected 'input' to match exactly 12 elements, but matched 13

Itu melakukan trik untuk saat ini, saya akan melihat ke dalam membuat ini bagian dari Kapibara.

merryprankster
sumber
Sepertinya memperbaiki ini di Kapibara tidak mudah: github.com/jnicklas/capybara/issues/331
merryprankster
14

Menurut saya yang berikut ini lebih sederhana, memberikan keluaran yang cukup jelas dan menghilangkan kebutuhan akan pencocokan khusus.

page.all("ol li").count.should eql(2)

Ini kemudian mencetak kesalahan:

      expected: 2
       got: 3

  (compared using eql?)
  (RSpec::Expectations::ExpectationNotMetError)
Richard
sumber
9
Ini tidak menunggu ekspektasi menjadi kenyataan, misalnya saat masih ada permintaan ajax yang tertunda.
Clemens Helm
9

Edit: Seperti yang ditunjukkan oleh @ThomasWalpole, menggunakan allmenonaktifkan Capybara menunggu / mencoba lagi, jadi jawaban di atas oleh @pandaPower jauh lebih baik.

Bagaimana dengan ini?

  within('ol') do
    expect( all('.opportunity_title_wrap').count ).to eq(2)
  end
Meiring Konstan
sumber
2
Ini benar-benar mengalahkan Capybaras menunggu / mencoba lagi dan seharusnya tidak menjadi solusi yang disarankan.
Thomas Walpole
@ThomasWalpole Saya tidak yakin apa yang Anda bicarakan. Bagaimana mencari elemen dalam elemen lain dengan cara apapun menyentuh menunggu / mencoba lagi di Capybara?
Constant Meiring
2
@ConstantMeiring Ini bukan within, itu memanggil .counthasil allyang menonaktifkan menunggu / mencoba lagi. Dengan memanggil counthasil all(yang "larik kosong" adalah pengembalian yang valid) Anda mengonversi ke bilangan bulat dan membandingkannya. Jika perbandingan itu gagal, harapan gagal. Jika sebaliknya Anda meneruskan opsi penghitungan ke salah satu pencocok Kapibara, kapibara akan menunggu / mencoba lagi menemukan pemilih yang ditentukan hingga opsi penghitungan cocok (atau Capybara.default_max_wait_time kedaluwarsa).
Thomas Walpole
4

Praktik terbaik (9/2/2013) saat ini yang direkomendasikan oleh Kapibara adalah sebagai berikut ( sumber ):

page.assert_selector('p#foo', :count => 4)

acconrad
sumber
-4

Jawaban oleh @pandaPower sangat bagus, tetapi sintaksnya sedikit berbeda untuk saya:

expect(page).to have_selector('.views-row', :count => 30)
Nick
sumber
5
Menggunakan roket hash tidak memenuhi syarat sebagai "sintaks berbeda".
premjg
2
Saya bukan seorang pengembang ruby ​​dan tidak menyadari bahwa kedua sintaks itu setara. TBH Saya tidak yakin itu perlu downvoting. Ini alternatif yang valid. Bagi mereka yang bukan dari latar belakang Ruby, ini mungkin tidak terlihat jelas. Itu bukan untukku.
Nick