Add #within method for working within a selector scope
This commit is contained in:
parent
4f843d3d01
commit
e746335d47
2
Rakefile
2
Rakefile
@ -56,7 +56,7 @@ end
|
||||
|
||||
require 'spec/rake/verify_rcov'
|
||||
RCov::VerifyTask.new(:verify_rcov => :rcov) do |t|
|
||||
t.threshold = 97.4 # Make sure you have rcov 0.7 or higher!
|
||||
t.threshold = 97.5 # Make sure you have rcov 0.7 or higher!
|
||||
end
|
||||
|
||||
remove_task "default"
|
||||
|
@ -1,9 +1,11 @@
|
||||
require "rubygems"
|
||||
require "hpricot"
|
||||
require "forwardable"
|
||||
require "English"
|
||||
|
||||
module Webrat
|
||||
class Page
|
||||
extend Forwardable
|
||||
include Logging
|
||||
|
||||
attr_reader :session
|
||||
@ -21,97 +23,9 @@ module Webrat
|
||||
session.current_page = self
|
||||
end
|
||||
|
||||
# Verifies an input field or textarea exists on the current page, and stores a value for
|
||||
# it which will be sent when the form is submitted.
|
||||
#
|
||||
# Examples:
|
||||
# fills_in "Email", :with => "user@example.com"
|
||||
# fills_in "user[email]", :with => "user@example.com"
|
||||
#
|
||||
# The field value is required, and must be specified in <tt>options[:with]</tt>.
|
||||
# <tt>field</tt> can be either the value of a name attribute (i.e. <tt>user[email]</tt>)
|
||||
# or the text inside a <tt><label></tt> element that points at the <tt><input></tt> field.
|
||||
def fills_in(id_or_name_or_label, options = {})
|
||||
field = scope.find_field(id_or_name_or_label, TextField, TextareaField, PasswordField)
|
||||
field.set(options[:with])
|
||||
def within(selector)
|
||||
yield Scope.new(self, session.response_body, selector)
|
||||
end
|
||||
|
||||
alias_method :fill_in, :fills_in
|
||||
|
||||
# Verifies that an input checkbox exists on the current page and marks it
|
||||
# as checked, so that the value will be submitted with the form.
|
||||
#
|
||||
# Example:
|
||||
# checks 'Remember Me'
|
||||
def checks(id_or_name_or_label)
|
||||
field = scope.find_field(id_or_name_or_label, CheckboxField)
|
||||
field.check
|
||||
end
|
||||
|
||||
alias_method :check, :checks
|
||||
|
||||
# Verifies that an input checkbox exists on the current page and marks it
|
||||
# as unchecked, so that the value will not be submitted with the form.
|
||||
#
|
||||
# Example:
|
||||
# unchecks 'Remember Me'
|
||||
def unchecks(id_or_name_or_label)
|
||||
field = scope.find_field(id_or_name_or_label, CheckboxField)
|
||||
field.uncheck
|
||||
end
|
||||
|
||||
alias_method :uncheck, :unchecks
|
||||
|
||||
# Verifies that an input radio button exists on the current page and marks it
|
||||
# as checked, so that the value will be submitted with the form.
|
||||
#
|
||||
# Example:
|
||||
# chooses 'First Option'
|
||||
def chooses(label)
|
||||
field = scope.find_field(label, RadioField)
|
||||
field.choose
|
||||
end
|
||||
|
||||
alias_method :choose, :chooses
|
||||
|
||||
# Verifies that a an option element exists on the current page with the specified
|
||||
# text. You can optionally restrict the search to a specific select list by
|
||||
# assigning <tt>options[:from]</tt> the value of the select list's name or
|
||||
# a label. Stores the option's value to be sent when the form is submitted.
|
||||
#
|
||||
# Examples:
|
||||
# selects "January"
|
||||
# selects "February", :from => "event_month"
|
||||
# selects "February", :from => "Event Month"
|
||||
def selects(option_text, options = {})
|
||||
id_or_name_or_label = options[:from]
|
||||
|
||||
if id_or_name_or_label
|
||||
field = scope.find_field(id_or_name_or_label, SelectField)
|
||||
option = field.find_option(option_text)
|
||||
else
|
||||
option = scope.find_select_option(option_text)
|
||||
end
|
||||
|
||||
flunk("Could not find option #{option_text.inspect}") if option.nil?
|
||||
option.choose
|
||||
end
|
||||
|
||||
alias_method :select, :selects
|
||||
|
||||
# Verifies that an input file field exists on the current page and sets
|
||||
# its value to the given +file+, so that the file will be uploaded
|
||||
# along with the form. An optional <tt>content_type</tt> may be given.
|
||||
#
|
||||
# Example:
|
||||
# attaches_file "Resume", "/path/to/the/resume.txt"
|
||||
# attaches_file "Photo", "/path/to/the/image.png", "image/png"
|
||||
def attaches_file(id_or_name_or_label, path, content_type = nil)
|
||||
field = scope.find_field(id_or_name_or_label, FileField)
|
||||
field.set(path, content_type)
|
||||
end
|
||||
|
||||
alias_method :attach_file, :attaches_file
|
||||
|
||||
# Saves the page out to RAILS_ROOT/tmp/ and opens it in the default
|
||||
# web browser if on OS X. Useful for debugging.
|
||||
@ -130,108 +44,6 @@ module Webrat
|
||||
open_in_browser(filename)
|
||||
end
|
||||
|
||||
def open_in_browser(path) # :nodoc
|
||||
`open #{path}`
|
||||
end
|
||||
|
||||
# Issues a request for the URL pointed to by a link on the current page,
|
||||
# follows any redirects, and verifies the final page load was successful.
|
||||
#
|
||||
# clicks_link has very basic support for detecting Rails-generated
|
||||
# JavaScript onclick handlers for PUT, POST and DELETE links, as well as
|
||||
# CSRF authenticity tokens if they are present.
|
||||
#
|
||||
# Javascript imitation can be disabled by passing the option :javascript => false
|
||||
#
|
||||
# Example:
|
||||
# clicks_link "Sign up"
|
||||
#
|
||||
# clicks_link "Sign up", :javascript => false
|
||||
def clicks_link(link_text, options = {})
|
||||
link = scope.find_link(link_text)
|
||||
link.click(nil, options)
|
||||
end
|
||||
|
||||
alias_method :click_link, :clicks_link
|
||||
|
||||
# Works like clicks_link, but only looks for the link text within a given selector
|
||||
#
|
||||
# Example:
|
||||
# clicks_link_within "#user_12", "Vote"
|
||||
def clicks_link_within(selector, link_text)
|
||||
link = scope.find_link(link_text, selector)
|
||||
link.click
|
||||
end
|
||||
|
||||
alias_method :click_link_within, :clicks_link_within
|
||||
|
||||
# Works like clicks_link, but forces a GET request
|
||||
#
|
||||
# Example:
|
||||
# clicks_get_link "Log out"
|
||||
def clicks_get_link(link_text)
|
||||
link = scope.find_link(link_text)
|
||||
link.click(:get)
|
||||
end
|
||||
|
||||
alias_method :click_get_link, :clicks_get_link
|
||||
|
||||
# Works like clicks_link, but issues a DELETE request instead of a GET
|
||||
#
|
||||
# Example:
|
||||
# clicks_delete_link "Log out"
|
||||
def clicks_delete_link(link_text)
|
||||
link = scope.find_link(link_text)
|
||||
link.click(:delete)
|
||||
end
|
||||
|
||||
alias_method :click_delete_link, :clicks_delete_link
|
||||
|
||||
# Works like clicks_link, but issues a POST request instead of a GET
|
||||
#
|
||||
# Example:
|
||||
# clicks_post_link "Vote"
|
||||
def clicks_post_link(link_text)
|
||||
link = scope.find_link(link_text)
|
||||
link.click(:post)
|
||||
end
|
||||
|
||||
alias_method :click_post_link, :clicks_post_link
|
||||
|
||||
# Works like clicks_link, but issues a PUT request instead of a GET
|
||||
#
|
||||
# Example:
|
||||
# clicks_put_link "Update profile"
|
||||
def clicks_put_link(link_text)
|
||||
link = scope.find_link(link_text)
|
||||
link.click(:put)
|
||||
end
|
||||
|
||||
alias_method :click_put_link, :clicks_put_link
|
||||
|
||||
# Verifies that a submit button exists for the form, then submits the form, follows
|
||||
# any redirects, and verifies the final page was successful.
|
||||
#
|
||||
# Example:
|
||||
# clicks_button "Login"
|
||||
# clicks_button
|
||||
#
|
||||
# The URL and HTTP method for the form submission are automatically read from the
|
||||
# <tt>action</tt> and <tt>method</tt> attributes of the <tt><form></tt> element.
|
||||
def clicks_button(value = nil)
|
||||
button = nil
|
||||
|
||||
scope.forms.each do |form|
|
||||
button = form.find_button(value)
|
||||
break if button
|
||||
end
|
||||
|
||||
flunk("Could not find button #{value.inspect}") if button.nil?
|
||||
button.click
|
||||
end
|
||||
|
||||
alias_method :click_button, :clicks_button
|
||||
|
||||
# Reloads the last page requested. Note that this will resubmit forms
|
||||
# and their data.
|
||||
#
|
||||
@ -243,13 +55,26 @@ module Webrat
|
||||
|
||||
alias_method :reload, :reloads
|
||||
|
||||
def submits_form(form_id = nil) # :nodoc:
|
||||
end
|
||||
|
||||
alias_method :submit_form, :submits_form
|
||||
def_delegators :scope, :fill_in, :fills_in
|
||||
def_delegators :scope, :check, :checks
|
||||
def_delegators :scope, :uncheck, :unchecks
|
||||
def_delegators :scope, :choose, :chooses
|
||||
def_delegators :scope, :select, :selects
|
||||
def_delegators :scope, :attach_file, :attaches_file
|
||||
def_delegators :scope, :click_link, :clicks_link
|
||||
def_delegators :scope, :click_link_within, :clicks_link_within
|
||||
def_delegators :scope, :click_get_link, :clicks_get_link
|
||||
def_delegators :scope, :click_delete_link, :clicks_delete_link
|
||||
def_delegators :scope, :click_post_link, :clicks_post_link
|
||||
def_delegators :scope, :click_put_link, :clicks_put_link
|
||||
def_delegators :scope, :click_button, :clicks_button
|
||||
|
||||
protected
|
||||
|
||||
|
||||
def open_in_browser(path) # :nodoc
|
||||
`open #{path}`
|
||||
end
|
||||
|
||||
def load_page
|
||||
session.request_page(@url, @method, @data)
|
||||
|
||||
|
@ -1,18 +1,196 @@
|
||||
module Webrat
|
||||
class Scope
|
||||
|
||||
def initialize(page, html)
|
||||
def initialize(page, html, selector = nil)
|
||||
@page = page
|
||||
@html = html
|
||||
@selector = selector
|
||||
end
|
||||
|
||||
def find_select_option(option_text)
|
||||
# Verifies an input field or textarea exists on the current page, and stores a value for
|
||||
# it which will be sent when the form is submitted.
|
||||
#
|
||||
# Examples:
|
||||
# fills_in "Email", :with => "user@example.com"
|
||||
# fills_in "user[email]", :with => "user@example.com"
|
||||
#
|
||||
# The field value is required, and must be specified in <tt>options[:with]</tt>.
|
||||
# <tt>field</tt> can be either the value of a name attribute (i.e. <tt>user[email]</tt>)
|
||||
# or the text inside a <tt><label></tt> element that points at the <tt><input></tt> field.
|
||||
def fills_in(id_or_name_or_label, options = {})
|
||||
find_field(id_or_name_or_label, TextField, TextareaField, PasswordField).set(options[:with])
|
||||
end
|
||||
|
||||
alias_method :fill_in, :fills_in
|
||||
|
||||
# Verifies that an input checkbox exists on the current page and marks it
|
||||
# as checked, so that the value will be submitted with the form.
|
||||
#
|
||||
# Example:
|
||||
# checks 'Remember Me'
|
||||
def checks(id_or_name_or_label)
|
||||
find_field(id_or_name_or_label, CheckboxField).check
|
||||
end
|
||||
|
||||
alias_method :check, :checks
|
||||
|
||||
# Verifies that an input checkbox exists on the current page and marks it
|
||||
# as unchecked, so that the value will not be submitted with the form.
|
||||
#
|
||||
# Example:
|
||||
# unchecks 'Remember Me'
|
||||
def unchecks(id_or_name_or_label)
|
||||
find_field(id_or_name_or_label, CheckboxField).uncheck
|
||||
end
|
||||
|
||||
alias_method :uncheck, :unchecks
|
||||
|
||||
# Verifies that an input radio button exists on the current page and marks it
|
||||
# as checked, so that the value will be submitted with the form.
|
||||
#
|
||||
# Example:
|
||||
# chooses 'First Option'
|
||||
def chooses(label)
|
||||
find_field(label, RadioField).choose
|
||||
end
|
||||
|
||||
alias_method :choose, :chooses
|
||||
|
||||
# Verifies that a an option element exists on the current page with the specified
|
||||
# text. You can optionally restrict the search to a specific select list by
|
||||
# assigning <tt>options[:from]</tt> the value of the select list's name or
|
||||
# a label. Stores the option's value to be sent when the form is submitted.
|
||||
#
|
||||
# Examples:
|
||||
# selects "January"
|
||||
# selects "February", :from => "event_month"
|
||||
# selects "February", :from => "Event Month"
|
||||
def selects(option_text, options = {})
|
||||
find_select_option(option_text, options[:from]).choose
|
||||
end
|
||||
|
||||
alias_method :select, :selects
|
||||
|
||||
# Verifies that an input file field exists on the current page and sets
|
||||
# its value to the given +file+, so that the file will be uploaded
|
||||
# along with the form. An optional <tt>content_type</tt> may be given.
|
||||
#
|
||||
# Example:
|
||||
# attaches_file "Resume", "/path/to/the/resume.txt"
|
||||
# attaches_file "Photo", "/path/to/the/image.png", "image/png"
|
||||
def attaches_file(id_or_name_or_label, path, content_type = nil)
|
||||
find_field(id_or_name_or_label, FileField).set(path, content_type)
|
||||
end
|
||||
|
||||
alias_method :attach_file, :attaches_file
|
||||
|
||||
# Issues a request for the URL pointed to by a link on the current page,
|
||||
# follows any redirects, and verifies the final page load was successful.
|
||||
#
|
||||
# clicks_link has very basic support for detecting Rails-generated
|
||||
# JavaScript onclick handlers for PUT, POST and DELETE links, as well as
|
||||
# CSRF authenticity tokens if they are present.
|
||||
#
|
||||
# Javascript imitation can be disabled by passing the option :javascript => false
|
||||
#
|
||||
# Example:
|
||||
# clicks_link "Sign up"
|
||||
#
|
||||
# clicks_link "Sign up", :javascript => false
|
||||
def clicks_link(link_text, options = {})
|
||||
find_link(link_text).click(nil, options)
|
||||
end
|
||||
|
||||
alias_method :click_link, :clicks_link
|
||||
|
||||
# Works like clicks_link, but only looks for the link text within a given selector
|
||||
#
|
||||
# Example:
|
||||
# clicks_link_within "#user_12", "Vote"
|
||||
def clicks_link_within(selector, link_text)
|
||||
find_link(link_text, selector).click
|
||||
end
|
||||
|
||||
alias_method :click_link_within, :clicks_link_within
|
||||
|
||||
# Works like clicks_link, but forces a GET request
|
||||
#
|
||||
# Example:
|
||||
# clicks_get_link "Log out"
|
||||
def clicks_get_link(link_text)
|
||||
find_link(link_text).click(:get)
|
||||
end
|
||||
|
||||
alias_method :click_get_link, :clicks_get_link
|
||||
|
||||
# Works like clicks_link, but issues a DELETE request instead of a GET
|
||||
#
|
||||
# Example:
|
||||
# clicks_delete_link "Log out"
|
||||
def clicks_delete_link(link_text)
|
||||
find_link(link_text).click(:delete)
|
||||
end
|
||||
|
||||
alias_method :click_delete_link, :clicks_delete_link
|
||||
|
||||
# Works like clicks_link, but issues a POST request instead of a GET
|
||||
#
|
||||
# Example:
|
||||
# clicks_post_link "Vote"
|
||||
def clicks_post_link(link_text)
|
||||
find_link(link_text).click(:post)
|
||||
end
|
||||
|
||||
alias_method :click_post_link, :clicks_post_link
|
||||
|
||||
# Works like clicks_link, but issues a PUT request instead of a GET
|
||||
#
|
||||
# Example:
|
||||
# clicks_put_link "Update profile"
|
||||
def clicks_put_link(link_text)
|
||||
find_link(link_text).click(:put)
|
||||
end
|
||||
|
||||
alias_method :click_put_link, :clicks_put_link
|
||||
|
||||
# Verifies that a submit button exists for the form, then submits the form, follows
|
||||
# any redirects, and verifies the final page was successful.
|
||||
#
|
||||
# Example:
|
||||
# clicks_button "Login"
|
||||
# clicks_button
|
||||
#
|
||||
# The URL and HTTP method for the form submission are automatically read from the
|
||||
# <tt>action</tt> and <tt>method</tt> attributes of the <tt><form></tt> element.
|
||||
def clicks_button(value = nil)
|
||||
find_button(value).click
|
||||
end
|
||||
|
||||
alias_method :click_button, :clicks_button
|
||||
|
||||
protected
|
||||
|
||||
def find_select_option(option_text, id_or_name_or_label)
|
||||
if id_or_name_or_label
|
||||
field = find_field(id_or_name_or_label, SelectField)
|
||||
return field.find_option(option_text)
|
||||
else
|
||||
forms.each do |form|
|
||||
result = form.find_select_option(option_text)
|
||||
return result if result
|
||||
end
|
||||
end
|
||||
|
||||
flunk("Could not find option #{option_text.inspect}")
|
||||
end
|
||||
|
||||
def find_button(value)
|
||||
forms.each do |form|
|
||||
result = form.find_select_option(option_text)
|
||||
return result if result
|
||||
button = form.find_button(value)
|
||||
return button if button
|
||||
end
|
||||
|
||||
nil
|
||||
flunk("Could not find button #{value.inspect}")
|
||||
end
|
||||
|
||||
def find_link(text, selector = nil)
|
||||
@ -55,6 +233,13 @@ module Webrat
|
||||
def dom # :nodoc:
|
||||
return @dom if defined?(@dom) && @dom
|
||||
@dom = Hpricot(@html)
|
||||
|
||||
if @selector
|
||||
html = (@dom / @selector).first.to_html
|
||||
@dom = Hpricot(html)
|
||||
end
|
||||
|
||||
return @dom
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -44,6 +44,10 @@ module Webrat
|
||||
current_page.save_and_open
|
||||
end
|
||||
|
||||
def within(selector, &block)
|
||||
current_page.within(selector, &block)
|
||||
end
|
||||
|
||||
def method_missing(name, *args)
|
||||
if current_page.respond_to?(name)
|
||||
current_page.send(name, *args)
|
||||
|
@ -19,6 +19,10 @@ module ActionController
|
||||
super || webrat_session.respond_to?(name)
|
||||
end
|
||||
|
||||
def within(selector, &block)
|
||||
webrat_session.within(selector, &block)
|
||||
end
|
||||
|
||||
def method_missing(name, *args)
|
||||
if webrat_session.respond_to?(name)
|
||||
webrat_session.send(name, *args)
|
||||
|
21
spec/api/within_spec.rb
Normal file
21
spec/api/within_spec.rb
Normal file
@ -0,0 +1,21 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
||||
|
||||
describe "within" do
|
||||
before do
|
||||
@session = Webrat::TestSession.new
|
||||
end
|
||||
|
||||
it "should click links within a scope" do
|
||||
@session.response_body = <<-EOS
|
||||
<a href="/page1">Link</a>
|
||||
<div id="container">
|
||||
<a href="/page2">Link</a>
|
||||
</div>
|
||||
EOS
|
||||
|
||||
@session.should_receive(:get).with("/page2", {})
|
||||
@session.within "#container" do |scope|
|
||||
scope.clicks_link "Link"
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user