Wie kann ich die Anzahl der Elemente mit Capybara mit der richtigen Fehlermeldung bestätigen?

84

Ich weiß, dass Sie in Capybara so etwas tun können:

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

Unter der Annahme, dass die Seite beispielsweise nur ein übereinstimmendes Element enthält, ist der Fehler jedoch nicht sehr beschreibend:

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

Anstelle dieser eher undurchsichtigen Fehlermeldung gibt es eine Möglichkeit, die Behauptung so zu schreiben, dass die Fehlerausgabe etwa "Beim Abgleichen von" ol li ", erwartet: 2, gefunden: 1" lautet. Natürlich könnte ich selbst eine benutzerdefinierte Logik für ein solches Verhalten erstellen - ich frage, gibt es eine Möglichkeit, dies "out of the box" zu tun?

Für das, was es wert ist, benutze ich Selenium-Treiber und RSpec.

Merryprankster
quelle
Nur damit die Leute wissen, wurde "page.should have_css (" ol li ",: count => 2)" in capybara implementiert. Ich denke, es ist sehr nützlich mit Bereichen: innerhalb ("ol.users-list") do page.should have_css ('li' ,: count => 3) end
rafaelkin
@rafaelkin, nur um zu verdeutlichen: Meldet Capybara jetzt zB die Nichtübereinstimmung in der Elementanzahl detaillierter? Ich bin capybara schon eine Weile nicht mehr gefolgt, aber das Problem damals, als ich die Frage stellte, war das Format der Fehlermeldung, nicht das, page.should have_css("ol li", :count => 2)was nicht bereits implementiert worden wäre.
Merryprankster
Leute, ich habe das Gefühl, dass die derzeit akzeptierte Antwort (= meine eigene) nicht mehr die beste ist, aber keine Zeit mehr hat (nicht mehr mit Ruby zusammenarbeiten), um zu bewerten, welche der vorgeschlagenen Lösungen die beste ist. Ich werde die akzeptierte Antwort in die von Richard ändern, nur weil sie die Ausgabe der Behauptung enthält, die das ursprüngliche Problem behandelt.
Merryprankster

Antworten:

22

Nun, da es anscheinend keine sofort einsatzbereite Unterstützung gibt, habe ich diesen benutzerdefinierten Matcher geschrieben:

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

Jetzt können Sie Dinge tun wie:

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

und erhalten Ausgabe wie:

  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

Es macht den Trick für jetzt, ich werde versuchen, diesen Teil von Capybara zu machen.

Merryprankster
quelle
Es
scheint
14

Ich denke, das Folgende ist einfacher, liefert eine ziemlich klare Ausgabe und macht einen benutzerdefinierten Matcher überflüssig.

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

Dies wird dann bei einem Fehler ausgedruckt:

      expected: 2
       got: 3

  (compared using eql?)
  (RSpec::Expectations::ExpectationNotMetError)
Richard
quelle
9
Dies wartet nicht darauf, dass die Erwartung in Erfüllung geht, z. B. wenn noch Ajax-Anforderungen anstehen.
Clemens Helm
9

Bearbeiten: Wie von @ThomasWalpole hervorgehoben, alldeaktiviert die Verwendung von Capybaras Warten / Wiederholen, sodass die obige Antwort von @pandaPower viel besser ist.

Wie wäre es damit?

  within('ol') do
    expect( all('.opportunity_title_wrap').count ).to eq(2)
  end
Ständiges Meiring
quelle
2
Dies besiegt Capybaras Warten / Wiederholen vollständig und sollte niemals eine empfohlene Lösung sein.
Thomas Walpole
@ ThomasWalpole Ich bin mir nicht sicher, wovon du sprichst. Wie berührt die Suche nach einem Element in einem anderen Element in irgendeiner Weise das Warten / Wiederholen in Capybara?
Constant Meiring
2
@ConstantMeiring Es ist nicht das within, es ruft .countdie Ergebnisse auf all, die das Warten / Wiederholen deaktivieren. Durch Aufrufen countder Ergebnisse all(für die ein leeres "Array" eine gültige Rückgabe ist) konvertieren Sie in eine Ganzzahl und vergleichen sie. Wenn dieser Vergleich fehlschlägt, schlägt die Erwartung fehl. Wenn Sie stattdessen die Zähloption an einen der Matcher von Capybara übergeben, wartet capybara / versucht erneut, den angegebenen Selektor zu finden, bis die Zähloption übereinstimmt (oder Capybara.default_max_wait_time abläuft).
Thomas Walpole
4

Die derzeitige (02.09.2013) von Capybara empfohlene Best Practice lautet wie folgt ( Quelle ):

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

acconrad
quelle
-4

Die Antwort von @pandaPower ist sehr gut, aber die Syntax war für mich etwas anders:

expect(page).to have_selector('.views-row', :count => 30)
Nick
quelle
5
Die Verwendung von Hash-Raketen gilt nicht als "andere Syntax".
Premjg
2
Ich bin kein Ruby-Entwickler und habe nicht bemerkt, dass die beiden Syntaxen gleichwertig sind. TBH Ich bin mir nicht sicher, ob es eine Abwertung rechtfertigt. Es ist eine gültige Alternative. Für diejenigen, die keinen Ruby-Hintergrund haben, scheint dies nicht offensichtlich zu sein. Es war nicht für mich.
Nick