Capybara está construido sobre un conjunto de bloques básicos. Estos bloques básicos consisten en expresiones XPath que se usan para encontrar cosas en la página para a continuación delegar la acción correspondiente en el driver subyacente.
La mayor parte del tiempo usaremos los métodos de alto nivel, pero hay ocasiones en las que debemos recurrir a estos finders para lograr nuestro propósito.
Consideremos esta página web:
[~/sinatra/sinatra-selenium/intro(gh-pages)]$ cat click.html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Click Examples</title> <script> window.onload = function() { var myanchor = document.getElementById("myanchor"); var mydiv = document.getElementById("mydiv"); var mybutton = document.getElementById("mybutton"); myanchor.onclick = function() { alert("anchor has been clicked"); }; mydiv.onclick = function() { alert("div has been clicked"); }; mybutton.onclick = function() { alert("button has been clicked"); }; }; </script> </head> <body> <div id="main"> <div class="section"> <a id="myanchor" title="myanchortitle" href="#">Click this Anchor</a> <div id="mydiv" title="mydivtitle">Click This Div</div> <input id="mybutton" type="button" value="Click This Button" title="mybuttontitle"/> </div> </div> </body> </html>
Cuando se cliquea en el div
<div id="mydiv" title="mydivtitle">Click This Div</div>se emite un mensaje de alerta.
Para automatizar este click haremos uso del método find
.
[~/sinatra/sinatra-selenium/intro(gh-pages)]$ cat find_and_click.rb visit '/' find('#mydiv').click accept_alert
find('#mydiv')
retorna un
Capybara::Node::Element
sobre el cual se invoca la acción.
Un Element
representa un elemento de la página.
Es posible interactuar con los contenidos de este elelemnto
en la misma forma que con un documento:
session = Capybara::Session.new(:rack_test, my_app) bar = session.find('#bar') # from Capybara::Node::Finders bar.select('Baz', :from => 'Quox') # from Capybara::Node::ActionsLos
Element
también tienen atributos HTML:
bar.value bar.text bar[:title]
Para probar este HTML vamos a usar nuestro script genérico testinglocals.rb
:
[~/sinatra/sinatra-selenium/intro(gh-pages)]$ ./testinglocalhtml.rb click.html find_and_click.rb
Casi todo el resto de métodos de busqueda se construyen a partir de este (Véase la clase Capybara::Node::Finders ):
find_field
: This finder searches for form fields by the related label
element, or the name/id attribute
# File 'lib/capybara/node/finders.rb' def find_field(locator, options={}) find(:field, locator, options) end
field_labeled
: This finder is the same as find_field
find_link
: This finder finds an anchor or an image link using the text, id, or img alt attribute
find_button
: This finder finds a button by the id, name, or value attribute
find_by_id
: This finder finds any element by the id attribute
first([kind], locator, options)
:
Find the first element on the page matching the given selector and options, or nil if no element matches.
# File 'lib/capybara/node/finders.rb' def first(*args) all(*args).first end
Supongamos que estamos comprobando algunas búsquedas de resultados que son añadidos dinámicamente a la página:
[~/sinatra/sinatra-selenium/intro(gh-pages)]$ cat multiple.html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Multiple Match Examples</title> <style> .result { height: 30px; width: 100px; background-color: green; margin-bottom: 10px; } </style> </head> <body> <div id="main"> <h1>Search Results</h1> <ul class="section"> <li id="res1" class="result">Match 1</li> <li id="res2" class="result">Match 2</li> <li id="res3" class="result">Match 3</li> <li id="res4" class="result">Match 4</li> <li id="res5" class="result">Match 5</li> </ul> </div> </body> </html>
Una posible solución es iterar sobre los elementos de la clase .result
usando el método all
:
$ cat multiple.rb RSpec.configure do |config| # avoid warning config.expect_with :rspec do |c| c.syntax = [:should, :expect] end end visit '/' all('.result').each_with_index do |elem, idx| elem.text.should == "Match #{idx + 1}" endCuando se ejecuta
$ ./testinglocalhtml.rb multiple.html multiple.rb p $no produce fallos.
display: none
o visibility: hidden
:
Capybara.ignore_hidden_elements = trueel valor por defecto es
true
.
Capybara provee el método within
que permite
consultas con ámbito.
#within(*find_args) ⇒ Object #within(a_node) ⇒ ObjectExecutes the given block within the context of a node.
within
takes the same options as find
, as well as a block. For the duration of the block, any command to Capybara will be handled as though it were scoped to the given element.
within(:xpath, '//div[@id="delivery-address"]') do fill_in('Street', :with => '12 Main Street') endJust as with
find
, if multiple elements match the selector given to within
, an error will be raised, and just as with find
, this behaviour can be controlled through the :match
and :exact
options.
It is possible to omit the first parameter, in that case, the selector is assumed to be of the type set in Capybara.default_selector
.
within('div#delivery-address') do fill_in('Street', :with => '12 Main Street') endNote that a lot of uses of
within
can be replaced more succinctly with chaining:
find('div#delivery-address').fill_in('Street', :with => '12 Main Street')Raises: (
Capybara::ElementNotFound
) — If the scope can't be found before time expires