Added fancy XPath generation class
This commit is contained in:
parent
f22092a214
commit
8d44e8cb74
|
@ -1,17 +1,6 @@
|
|||
module Capybara
|
||||
class Session
|
||||
|
||||
FIELDS_PATHS = {
|
||||
:text_field => proc { |id| "//input[@type='text'][@id='#{id}' or @id=//label[contains(.,'#{id}')]/@for]" },
|
||||
:text_area => proc { |id| "//textarea[@id='#{id}' or @id=//label[contains(.,'#{id}')]/@for]" },
|
||||
:password_field => proc { |id| "//input[@type='password'][@id='#{id}' or @id=//label[contains(.,'#{id}')]/@for]" },
|
||||
:radio => proc { |id| "//input[@type='radio'][@id='#{id}' or @id=//label[contains(.,'#{id}')]/@for]" },
|
||||
:hidden_field => proc { |id| "//input[@type='hidden'][@id='#{id}' or @id=//label[contains(.,'#{id}')]/@for]" },
|
||||
:checkbox => proc { |id| "//input[@type='checkbox'][@id='#{id}' or @id=//label[contains(.,'#{id}')]/@for]" },
|
||||
:select => proc { |id| "//select[@id='#{id}' or @id=//label[contains(.,'#{id}')]/@for]" },
|
||||
:file_field => proc { |id| "//input[@type='file'][@id='#{id}' or @id=//label[contains(.,'#{id}')]/@for]" }
|
||||
}
|
||||
|
||||
attr_reader :mode, :app
|
||||
|
||||
def initialize(mode, app)
|
||||
|
@ -49,37 +38,37 @@ module Capybara
|
|||
end
|
||||
|
||||
def fill_in(locator, options={})
|
||||
field = find_field(locator, :text_field, :text_area, :password_field)
|
||||
field = find(XPath.fillable_field(locator).to_s)
|
||||
raise Capybara::ElementNotFound, "cannot fill in, no text field, text area or password field with id or label '#{locator}' found" unless field
|
||||
field.set(options[:with])
|
||||
end
|
||||
|
||||
def choose(locator)
|
||||
field = find_field(locator, :radio)
|
||||
field = find(XPath.radio_button(locator).to_s)
|
||||
raise Capybara::ElementNotFound, "cannot choose field, no radio button with id or label '#{locator}' found" unless field
|
||||
field.set(true)
|
||||
end
|
||||
|
||||
def check(locator)
|
||||
field = find_field(locator, :checkbox)
|
||||
field = find(XPath.checkbox(locator).to_s)
|
||||
raise Capybara::ElementNotFound, "cannot check field, no checkbox with id or label '#{locator}' found" unless field
|
||||
field.set(true)
|
||||
end
|
||||
|
||||
def uncheck(locator)
|
||||
field = find_field(locator, :checkbox)
|
||||
field = find(XPath.checkbox(locator).to_s)
|
||||
raise Capybara::ElementNotFound, "cannot uncheck field, no checkbox with id or label '#{locator}' found" unless field
|
||||
field.set(false)
|
||||
end
|
||||
|
||||
def select(value, options={})
|
||||
field = find_field(options[:from], :select)
|
||||
field = find(XPath.select(options[:from]).to_s)
|
||||
raise Capybara::ElementNotFound, "cannot select option, no select box with id or label '#{options[:from]}' found" unless field
|
||||
field.select(value)
|
||||
end
|
||||
|
||||
def attach_file(locator, path)
|
||||
field = find_field(locator, :file_field)
|
||||
field = find(XPath.file_field(locator).to_s)
|
||||
raise Capybara::ElementNotFound, "cannot attach file, no file field with id or label '#{locator}' found" unless field
|
||||
field.set(path)
|
||||
end
|
||||
|
@ -143,9 +132,8 @@ module Capybara
|
|||
all(locator).first
|
||||
end
|
||||
|
||||
def find_field(locator, *kinds)
|
||||
kinds = FIELDS_PATHS.keys if kinds.empty?
|
||||
find(kinds.map { |kind| FIELDS_PATHS[kind].call(locator) }.join("|"))
|
||||
def find_field(locator)
|
||||
find(XPath.field(locator).to_s)
|
||||
end
|
||||
alias_method :field_labeled, :find_field
|
||||
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
module Capybara
|
||||
# this is a class for generating XPath queries, use it like this:
|
||||
# Xpath.text_field('foo').link('blah').to_s
|
||||
# this will generate an XPath that matches either a text field or a link
|
||||
class XPath
|
||||
class << self
|
||||
def respond_to?(method)
|
||||
new.respond_to?(method)
|
||||
end
|
||||
|
||||
def method_missing(*args)
|
||||
new.send(*args)
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :paths
|
||||
|
||||
def initialize(*paths)
|
||||
@paths = paths
|
||||
end
|
||||
|
||||
def field(locator)
|
||||
fillable_field(locator).file_field(locator).checkbox(locator).radio_button(locator).select(locator)
|
||||
end
|
||||
|
||||
def fillable_field(locator)
|
||||
text_field(locator).password_field(locator).text_area(locator)
|
||||
end
|
||||
|
||||
def text_field(locator)
|
||||
append("//input[@type='text'][@id='#{locator}' or @id=//label[contains(.,'#{locator}')]/@for]")
|
||||
end
|
||||
|
||||
def password_field(locator)
|
||||
append("//input[@type='password'][@id='#{locator}' or @id=//label[contains(.,'#{locator}')]/@for]")
|
||||
end
|
||||
|
||||
def text_area(locator)
|
||||
append("//textarea[@id='#{locator}' or @id=//label[contains(.,'#{locator}')]/@for]")
|
||||
end
|
||||
|
||||
def radio_button(locator)
|
||||
append("//input[@type='radio'][@id='#{locator}' or @id=//label[contains(.,'#{locator}')]/@for]")
|
||||
end
|
||||
|
||||
def checkbox(locator)
|
||||
append("//input[@type='checkbox'][@id='#{locator}' or @id=//label[contains(.,'#{locator}')]/@for]")
|
||||
end
|
||||
|
||||
def select(locator)
|
||||
append("//select[@id='#{locator}' or @id=//label[contains(.,'#{locator}')]/@for]")
|
||||
end
|
||||
|
||||
def file_field(locator)
|
||||
append("//input[@type='file'][@id='#{locator}' or @id=//label[contains(.,'#{locator}')]/@for]")
|
||||
end
|
||||
|
||||
def to_s
|
||||
@paths.join(' | ')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def append(path)
|
||||
XPath.new(*[@paths, path].flatten)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -552,15 +552,10 @@ shared_examples_for "session" do
|
|||
@session.find_field('Region')[:name].should == 'form[region]'
|
||||
end
|
||||
|
||||
it "should raise an error if the field doesn't exist" do
|
||||
it "should be nil if the field doesn't exist" do
|
||||
@session.find_field('Does not exist').should be_nil
|
||||
end
|
||||
|
||||
it "should find only given kind of field" do
|
||||
@session.find_field('form_description', :text_field, :text_area).text.should == 'Descriptive text goes here'
|
||||
@session.find_field('form_description', :password_field).should be_nil
|
||||
end
|
||||
|
||||
it "should be aliased as 'field_labeled' for webrat compatibility" do
|
||||
@session.field_labeled('Dog').value.should == 'dog'
|
||||
@session.field_labeled('Does not exist').should be_nil
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
||||
|
||||
describe Capybara::XPath do
|
||||
|
||||
before do
|
||||
@driver = Capybara::Driver::RackTest.new(TestApp)
|
||||
@driver.visit('/form')
|
||||
@xpath = Capybara::XPath.new
|
||||
end
|
||||
|
||||
it "should proxy any class method calls to a new instance" do
|
||||
@query = Capybara::XPath.fillable_field('First Name').to_s
|
||||
@driver.find(@query).first.value.should == 'John'
|
||||
end
|
||||
|
||||
it "should respond to instance methods at the class level" do
|
||||
Capybara::XPath.should respond_to(:fillable_field)
|
||||
end
|
||||
|
||||
describe '#field' do
|
||||
it "should find any field by id or label" do
|
||||
@query = @xpath.field('First Name').to_s
|
||||
@driver.find(@query).first.value.should == 'John'
|
||||
@query = @xpath.field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
@query = @xpath.field('Description').to_s
|
||||
@driver.find(@query).first.text.should == 'Descriptive text goes here'
|
||||
@query = @xpath.field('Document').to_s
|
||||
@driver.find(@query).first[:name].should == 'form[document]'
|
||||
@query = @xpath.field('Cat').to_s
|
||||
@driver.find(@query).first.value.should == 'cat'
|
||||
@query = @xpath.field('Male').to_s
|
||||
@driver.find(@query).first.value.should == 'male'
|
||||
@query = @xpath.field('Region').to_s
|
||||
@driver.find(@query).first[:name].should == 'form[region]'
|
||||
end
|
||||
|
||||
it "should be chainable" do
|
||||
@query = @xpath.field('First Name').password_field('First Name').to_s
|
||||
@driver.find(@query).first.value.should == 'John'
|
||||
@query = @xpath.field('Password').password_field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#fillable_field' do
|
||||
it "should find a text field, password field, or text area by id or label" do
|
||||
@query = @xpath.fillable_field('First Name').to_s
|
||||
@driver.find(@query).first.value.should == 'John'
|
||||
@query = @xpath.fillable_field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
@query = @xpath.fillable_field('Description').to_s
|
||||
@driver.find(@query).first.text.should == 'Descriptive text goes here'
|
||||
end
|
||||
|
||||
it "should be chainable" do
|
||||
@query = @xpath.fillable_field('First Name').password_field('First Name').to_s
|
||||
@driver.find(@query).first.value.should == 'John'
|
||||
@query = @xpath.fillable_field('Password').password_field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#text_field' do
|
||||
it "should find a text field by id or label" do
|
||||
@query = @xpath.text_field('form_first_name').to_s
|
||||
@driver.find(@query).first.value.should == 'John'
|
||||
@query = @xpath.text_field('First Name').to_s
|
||||
@driver.find(@query).first.value.should == 'John'
|
||||
end
|
||||
|
||||
it "should be chainable" do
|
||||
@query = @xpath.text_field('First Name').password_field('First Name').to_s
|
||||
@driver.find(@query).first.value.should == 'John'
|
||||
@query = @xpath.text_field('Password').password_field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#password_field' do
|
||||
it "should find a password field by id or label" do
|
||||
@query = @xpath.password_field('form_password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
@query = @xpath.password_field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
end
|
||||
|
||||
it "should be chainable" do
|
||||
@query = @xpath.password_field('First Name').text_field('First Name').to_s
|
||||
@driver.find(@query).first.value.should == 'John'
|
||||
@query = @xpath.password_field('Password').text_field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#text_area' do
|
||||
it "should find a text area by id or label" do
|
||||
@query = @xpath.text_area('form_description').to_s
|
||||
@driver.find(@query).first.text.should == 'Descriptive text goes here'
|
||||
@query = @xpath.text_area('Description').to_s
|
||||
@driver.find(@query).first.text.should == 'Descriptive text goes here'
|
||||
end
|
||||
|
||||
it "should be chainable" do
|
||||
@query = @xpath.text_area('Description').password_field('Description').to_s
|
||||
@driver.find(@query).first.text.should == 'Descriptive text goes here'
|
||||
@query = @xpath.text_area('Password').password_field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#radio_button' do
|
||||
it "should find a radio button by id or label" do
|
||||
@query = @xpath.radio_button('Male').to_s
|
||||
@driver.find(@query).first.value.should == 'male'
|
||||
@query = @xpath.radio_button('gender_male').to_s
|
||||
@driver.find(@query).first.value.should == 'male'
|
||||
end
|
||||
|
||||
it "should be chainable" do
|
||||
@query = @xpath.radio_button('Male').password_field('Male').to_s
|
||||
@driver.find(@query).first.value.should == 'male'
|
||||
@query = @xpath.radio_button('Password').password_field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#checkbox' do
|
||||
it "should find a checkbox by id or label" do
|
||||
@query = @xpath.checkbox('Cat').to_s
|
||||
@driver.find(@query).first.value.should == 'cat'
|
||||
@query = @xpath.checkbox('form_pets_cat').to_s
|
||||
@driver.find(@query).first.value.should == 'cat'
|
||||
end
|
||||
|
||||
it "should be chainable" do
|
||||
@query = @xpath.checkbox('Cat').password_field('Cat').to_s
|
||||
@driver.find(@query).first.value.should == 'cat'
|
||||
@query = @xpath.checkbox('Password').password_field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#select' do
|
||||
it "should find a select by id or label" do
|
||||
@query = @xpath.select('Region').to_s
|
||||
@driver.find(@query).first[:name].should == 'form[region]'
|
||||
@query = @xpath.select('form_region').to_s
|
||||
@driver.find(@query).first[:name].should == 'form[region]'
|
||||
end
|
||||
|
||||
it "should be chainable" do
|
||||
@query = @xpath.select('Region').password_field('Region').to_s
|
||||
@driver.find(@query).first[:name].should == 'form[region]'
|
||||
@query = @xpath.select('Password').password_field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#file_field' do
|
||||
it "should find a file field by id or label" do
|
||||
@query = @xpath.file_field('Document').to_s
|
||||
@driver.find(@query).first[:name].should == 'form[document]'
|
||||
@query = @xpath.file_field('form_document').to_s
|
||||
@driver.find(@query).first[:name].should == 'form[document]'
|
||||
end
|
||||
|
||||
it "should be chainable" do
|
||||
@query = @xpath.file_field('Document').password_field('Document').to_s
|
||||
@driver.find(@query).first[:name].should == 'form[document]'
|
||||
@query = @xpath.file_field('Password').password_field('Password').to_s
|
||||
@driver.find(@query).first.value.should == 'seeekrit'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue