Как подтвердить количество элементов с помощью Capybara с правильным сообщением об ошибке?

86

Я знаю, что в Capybara можно сделать что-то вроде этого:

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

Однако если предположить, что на странице есть, например, только один соответствующий элемент, ошибка не очень информативна:

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

Вместо этого довольно непонятного сообщения об ошибке, есть ли способ написать утверждение таким образом, чтобы вывод ошибки был чем-то вроде «При сопоставлении« ol li », ожидалось: 2, найдено: 1». Очевидно, я мог бы сам создать собственную логику для такого поведения - я спрашиваю, есть ли способ сделать это «из коробки»?

Как бы то ни было, я использую драйвер Selenium и RSpec.

веселый шутник
источник
На всякий случай, "page.should have_css (" ol li ",: count => 2)" был реализован в capybara. Я думаю, что это очень удобно с областями действия: внутри ("ol.users-list") do page.should have_css ('li',: count => 3) end
rafaelkin
@rafaelkin, просто чтобы уточнить: теперь капибара сообщает, например, о несоответствии в количестве элементов более подробно? Я уже некоторое время не слежу за капибарой, но тогда, когда я задал вопрос, проблема заключалась в формате сообщения об ошибке, а это page.should have_css("ol li", :count => 2)еще не было реализовано.
merryprankster
ребята, у меня такое чувство, что принятый в настоящее время ответ (= мой собственный) больше не лучший, но у меня нет времени (больше не работать с Ruby), чтобы оценить, какое из предложенных решений является лучшим. Я заменю принятый ответ на ответ Ричарда только потому, что он включает в себя вывод утверждения, которое касается исходной проблемы.
merryprankster

Ответы:

22

Ну, так как кажется, что нет поддержки из коробки, я написал этот пользовательский сопоставитель:

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

Теперь вы можете делать что-то вроде:

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

и получите такой результат:

  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

На данный момент это помогает, я постараюсь сделать эту часть Capybara.

веселый шутник
источник
Похоже, исправить это в
Capybara непросто
14

Я думаю, что следующее проще, дает довольно четкий вывод и устраняет необходимость в настраиваемом сопоставлении.

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

Затем при ошибке выводится:

      expected: 2
       got: 3

  (compared using eql?)
  (RSpec::Expectations::ExpectationNotMetError)
Ричард
источник
9
Это не дожидается, пока ожидания сбудутся, например, когда еще есть ожидающие запросы ajax.
Клеменс Хелм
9

Изменить: как указано @ThomasWalpole, использование allотключает ожидание / повторные попытки Capybara, поэтому ответ @pandaPower выше намного лучше.

Как насчет этого?

  within('ol') do
    expect( all('.opportunity_title_wrap').count ).to eq(2)
  end
Постоянный Мейринг
источник
2
Это полностью предотвращает ожидание / повторные попытки капибар и никогда не должно быть рекомендуемым решением.
Thomas Walpole
@ThomasWalpole Я не понимаю, о чем вы. Как поиск элемента внутри другого элемента каким-либо образом влияет на ожидание / повторную попытку в Capybara?
Constant Meiring 07
2
@ConstantMeiring Это не тот within, он вызывает .countрезультаты, allкоторые отключают ожидание / повторные попытки. Вызывая countрезультаты all(для которых допустимым возвратом является пустой «массив») вы конвертируете их в целое число и сравниваете его. Если это сравнение не оправдывает себя, ожидания не оправдаются. Если вместо этого вы передадите опцию подсчета одному из сопоставителей Capybara, капибара будет ждать / повторять попытки поиска указанного селектора до тех пор, пока опция подсчета не совпадет (или истечет срок действия Capybara.default_max_wait_time).
Thomas Walpole
4

Текущая (2 сентября 2013 г.) передовая практика, рекомендованная Capybara, заключается в следующем ( источник ):

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

Акконрад
источник
-4

Ответ @pandaPower очень хорош, но синтаксис у меня немного отличался:

expect(page).to have_selector('.views-row', :count => 30)
Ник
источник
5
Использование хэш-ракет не квалифицируется как «другой синтаксис».
premjg
2
Я не разработчик Ruby и не осознавал, что эти два синтаксиса эквивалентны. TBH Я не уверен, что это оправдывает голосование против. Это достойная альтернатива. Для тех, кто не знаком с Ruby, это может показаться неочевидным. Это было не для меня.
Ник