¿Cómo afirmar la cantidad de elementos usando Capybara con el mensaje de error adecuado?

86

Sé que en Capybara, puedes hacer algo como esto:

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

Sin embargo, asumiendo que la página tiene, por ejemplo, un solo elemento coincidente, el error no es muy descriptivo:

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

En lugar de este mensaje de error bastante oscuro, ¿hay alguna manera de escribir la aserción de tal manera que la salida de error sea algo como 'Al coincidir con' ol li ', esperado: 2, encontrado: 1'. Obviamente, yo mismo podría hacer una lógica personalizada para tal comportamiento; me pregunto si hay alguna manera de hacer esto "fuera de la caja".

Por lo que vale, estoy usando el controlador Selenium y RSpec.

merryprankster
fuente
Solo para que la gente sepa, "page.should have_css (" ol li ",: count => 2)" se implementó en carpincho. Creo que es muy útil con ámbitos: dentro de ("ol.users-list") do page.should have_css ('li',: count => 3) end
rafaelkin
@rafaelkin, solo para aclarar: ¿el capibara ahora informa, por ejemplo, la falta de coincidencia en el recuento de elementos con más detalle? No he seguido al capibara desde hace un tiempo, pero el problema en ese entonces cuando hice la pregunta era sobre el formato del mensaje de error, no que page.should have_css("ol li", :count => 2)ya no se hubiera implementado.
merryprankster
Amigos, tengo la sensación de que la respuesta actualmente aceptada (= la mía) ya no es la mejor, pero no tengo tiempo (ya no trabajo con Ruby) para evaluar cuál de las soluciones sugeridas es la mejor. Cambiaré la respuesta aceptada por la de Richard solo porque incluye la salida de la afirmación que aborda el problema original.
merryprankster

Respuestas:

22

Bueno, como parece que no hay soporte fuera de la caja, escribí este comparador personalizado:

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

Ahora puedes hacer cosas como:

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

y obtener resultados como:

  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

Por ahora funciona, buscaré hacer esta parte de Capybara.

merryprankster
fuente
Parece que arreglar esto en Capybara no es sencillo: github.com/jnicklas/capybara/issues/331
merryprankster
14

Creo que lo siguiente es más simple, ofrece un resultado bastante claro y elimina la necesidad de un comparador personalizado.

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

Esto luego se imprime en caso de error:

      expected: 2
       got: 3

  (compared using eql?)
  (RSpec::Expectations::ExpectationNotMetError)
Ricardo
fuente
9
Esto no espera a que la expectativa se haga realidad, por ejemplo, cuando todavía hay solicitudes de ajax pendientes.
Clemens Helm
9

Editar: como lo señaló @ThomasWalpole, el uso alldeshabilita la espera / reintento de Capybara, por lo que la respuesta anterior de @pandaPower es mucho mejor.

¿Qué tal esto?

  within('ol') do
    expect( all('.opportunity_title_wrap').count ).to eq(2)
  end
Meiring constante
fuente
2
Esto derrota por completo a los capibaras en espera / reintento y nunca debería ser una solución recomendada.
Thomas Walpole
@ThomasWalpole No estoy seguro de qué estás hablando. ¿Cómo la búsqueda de un elemento dentro de otro elemento afecta de alguna manera la espera / reintento en Capybara?
Constant Meiring
2
@ConstantMeiring No es el within, está llamando .counta los resultados allque deshabilita la espera / reintento. Al llamar counta los resultados de all(para los cuales una "matriz" vacía es un retorno válido), convierte a un número entero y lo compara. Si esa comparación falla, la expectativa falla. Si, en cambio, pasa la opción de conteo a uno de los comparadores de Capybara, carpincho esperará / volverá a intentar encontrar el selector especificado hasta que coincida la opción de conteo (o Capybara.default_max_wait_time expire).
Thomas Walpole
4

La mejor práctica actual (2/9/2013) recomendada por Capybara es la siguiente ( fuente ):

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

acconrad
fuente
-4

La respuesta de @pandaPower es muy buena, pero la sintaxis fue ligeramente diferente para mí:

expect(page).to have_selector('.views-row', :count => 30)
Mella
fuente
5
El uso de cohetes hash no califica como "sintaxis diferente".
premjg
2
No soy un desarrollador de ruby ​​y no me di cuenta de que las dos sintaxis eran equivalentes. TBH no estoy seguro de que merezca una votación negativa. Es una alternativa válida. Para aquellos que no tienen experiencia en Ruby, puede que no parezca obvio. No fue para mi.
Nick