From 8bf63ee8e499cf73b05dbf2cd44ec0ca61f17db5 Mon Sep 17 00:00:00 2001 From: Jonas Nicklas Date: Sat, 10 Jul 2010 02:20:32 +0200 Subject: [PATCH] Split node class into finders, matchers and actions --- lib/capybara/node.rb | 222 ++-------------------------------- lib/capybara/node/actions.rb | 62 ++++++++++ lib/capybara/node/finders.rb | 72 +++++++++++ lib/capybara/node/matchers.rb | 97 +++++++++++++++ 4 files changed, 239 insertions(+), 214 deletions(-) create mode 100644 lib/capybara/node/actions.rb create mode 100644 lib/capybara/node/finders.rb create mode 100644 lib/capybara/node/matchers.rb diff --git a/lib/capybara/node.rb b/lib/capybara/node.rb index 87cab5a1..abc61dee 100644 --- a/lib/capybara/node.rb +++ b/lib/capybara/node.rb @@ -1,230 +1,24 @@ +require 'capybara/node/finders' +require 'capybara/node/actions' +require 'capybara/node/matchers' + module Capybara class Node attr_reader :session, :base + include Capybara::Node::Finders + include Capybara::Node::Actions + include Capybara::Node::Matchers + def initialize(session, base) @session = session @base = base end - def click_link_or_button(locator) - msg = "no link or button '#{locator}' found" - locate(:xpath, XPath.link(locator).button(locator), msg).click - end - - def click_link(locator) - msg = "no link with title, id or text '#{locator}' found" - locate(:xpath, XPath.link(locator), msg).click - end - - def click_button(locator) - msg = "no button with value or id or text '#{locator}' found" - locate(:xpath, XPath.button(locator), msg).click - end - - def drag(source_locator, target_locator) - source = locate(:xpath, source_locator, "drag source '#{source_locator}' not found on page") - target = locate(:xpath, target_locator, "drag target '#{target_locator}' not found on page") - source.drag_to(target) - end - - def fill_in(locator, options={}) - msg = "cannot fill in, no text field, text area or password field with id, name, or label '#{locator}' found" - raise "Must pass a hash containing 'with'" if not options.is_a?(Hash) or not options.has_key?(:with) - locate(:xpath, XPath.fillable_field(locator), msg).set(options[:with]) - end - - def choose(locator) - msg = "cannot choose field, no radio button with id, name, or label '#{locator}' found" - locate(:xpath, XPath.radio_button(locator), msg).set(true) - end - - def check(locator) - msg = "cannot check field, no checkbox with id, name, or label '#{locator}' found" - locate(:xpath, XPath.checkbox(locator), msg).set(true) - end - - def uncheck(locator) - msg = "cannot uncheck field, no checkbox with id, name, or label '#{locator}' found" - locate(:xpath, XPath.checkbox(locator), msg).set(false) - end - - def select(value, options={}) - msg = "cannot select option, no select box with id, name, or label '#{options[:from]}' found" - locate(:xpath, XPath.select(options[:from]), msg).select_option(value) - end - - def unselect(value, options={}) - msg = "cannot unselect option, no select box with id, name, or label '#{options[:from]}' found" - locate(:xpath, XPath.select(options[:from]), msg).unselect_option(value) - end - - def attach_file(locator, path) - msg = "cannot attach file, no file field with id, name, or label '#{locator}' found" - locate(:xpath, XPath.file_field(locator), msg).set(path) - end - - def has_xpath?(path, options={}) - wait_conditionally_until do - results = all(:xpath, path, options) - - if options[:count] - results.size == options[:count] - else - results.size > 0 - end - end - rescue Capybara::TimeoutError - return false - end - - def has_no_xpath?(path, options={}) - wait_conditionally_until do - results = all(:xpath, path, options) - - if options[:count] - results.size != options[:count] - else - results.empty? - end - end - rescue Capybara::TimeoutError - return false - end - - def has_css?(path, options={}) - has_xpath?(XPath.from_css(path), options) - end - - def has_no_css?(path, options={}) - has_no_xpath?(XPath.from_css(path), options) - end - - def has_content?(content) - has_xpath?(XPath.content(content)) - end - - def has_no_content?(content) - has_no_xpath?(XPath.content(content)) - end - - def has_link?(locator) - has_xpath?(XPath.link(locator)) - end - - def has_no_link?(locator) - has_no_xpath?(XPath.link(locator)) - end - - def has_button?(locator) - has_xpath?(XPath.button(locator)) - end - - def has_no_button?(locator) - has_no_xpath?(XPath.button(locator)) - end - - def has_field?(locator, options={}) - has_xpath?(XPath.field(locator, options)) - end - - def has_no_field?(locator, options={}) - has_no_xpath?(XPath.field(locator, options)) - end - - def has_checked_field?(locator) - has_xpath?(XPath.field(locator, :checked => true)) - end - - def has_unchecked_field?(locator) - has_xpath?(XPath.field(locator, :unchecked => true)) - end - - def has_select?(locator, options={}) - has_xpath?(XPath.select(locator, options)) - end - - def has_no_select?(locator, options={}) - has_no_xpath?(XPath.select(locator, options)) - end - - def has_table?(locator, options={}) - has_xpath?(XPath.table(locator, options)) - end - - def has_no_table?(locator, options={}) - has_no_xpath?(XPath.table(locator, options)) - end - - #return node identified by locator or raise ElementNotFound(using desc) - def locate(kind_or_locator, locator=nil, fail_msg = nil) - node = wait_conditionally_until { find(kind_or_locator, locator) } - ensure - raise Capybara::ElementNotFound, fail_msg || "Unable to locate '#{locator || kind_or_locator}'" unless node - return node - end - - def find(*args) - all(*args).first - end - - def find_field(locator) - find(:xpath, XPath.field(locator)) - end - alias_method :field_labeled, :find_field - - def find_link(locator) - find(:xpath, XPath.link(locator)) - end - - def find_button(locator) - find(:xpath, XPath.button(locator)) - end - - def find_by_id(id) - find(:css, "##{id}") - end - - def all(*args) - options = if args.last.is_a?(Hash) then args.pop else {} end - - results = XPath.wrap(normalize_locator(*args)).paths.map do |path| - base.find(path) - end.flatten - - if options[:text] - - if options[:text].kind_of?(Regexp) - regexp = options[:text] - else - regexp = Regexp.escape(options[:text]) - end - - results = results.select { |n| n.text.match(regexp) } - end - - if options[:visible] or Capybara.ignore_hidden_elements - results = results.select { |n| n.visible? } - end - - results.map { |n| Capybara::Element.new(self, n) } - end - protected - def normalize_locator(kind, locator=nil) - kind, locator = Capybara.default_selector, kind if locator.nil? - locator = XPath.from_css(locator) if kind == :css - locator - end - def driver session.driver end - - def wait_conditionally_until - if driver.wait? then wait_until { yield } else yield end - end - end end diff --git a/lib/capybara/node/actions.rb b/lib/capybara/node/actions.rb new file mode 100644 index 00000000..29192469 --- /dev/null +++ b/lib/capybara/node/actions.rb @@ -0,0 +1,62 @@ +module Capybara + class Node + module Actions + def click_link_or_button(locator) + msg = "no link or button '#{locator}' found" + locate(:xpath, XPath.link(locator).button(locator), msg).click + end + + def click_link(locator) + msg = "no link with title, id or text '#{locator}' found" + locate(:xpath, XPath.link(locator), msg).click + end + + def click_button(locator) + msg = "no button with value or id or text '#{locator}' found" + locate(:xpath, XPath.button(locator), msg).click + end + + def fill_in(locator, options={}) + msg = "cannot fill in, no text field, text area or password field with id, name, or label '#{locator}' found" + raise "Must pass a hash containing 'with'" if not options.is_a?(Hash) or not options.has_key?(:with) + locate(:xpath, XPath.fillable_field(locator), msg).set(options[:with]) + end + + def choose(locator) + msg = "cannot choose field, no radio button with id, name, or label '#{locator}' found" + locate(:xpath, XPath.radio_button(locator), msg).set(true) + end + + def check(locator) + msg = "cannot check field, no checkbox with id, name, or label '#{locator}' found" + locate(:xpath, XPath.checkbox(locator), msg).set(true) + end + + def uncheck(locator) + msg = "cannot uncheck field, no checkbox with id, name, or label '#{locator}' found" + locate(:xpath, XPath.checkbox(locator), msg).set(false) + end + + def select(value, options={}) + msg = "cannot select option, no select box with id, name, or label '#{options[:from]}' found" + locate(:xpath, XPath.select(options[:from]), msg).select_option(value) + end + + def unselect(value, options={}) + msg = "cannot unselect option, no select box with id, name, or label '#{options[:from]}' found" + locate(:xpath, XPath.select(options[:from]), msg).unselect_option(value) + end + + def attach_file(locator, path) + msg = "cannot attach file, no file field with id, name, or label '#{locator}' found" + locate(:xpath, XPath.file_field(locator), msg).set(path) + end + + def drag(source_locator, target_locator) + source = locate(:xpath, source_locator, "drag source '#{source_locator}' not found on page") + target = locate(:xpath, target_locator, "drag target '#{target_locator}' not found on page") + source.drag_to(target) + end + end + end +end diff --git a/lib/capybara/node/finders.rb b/lib/capybara/node/finders.rb new file mode 100644 index 00000000..f830e14e --- /dev/null +++ b/lib/capybara/node/finders.rb @@ -0,0 +1,72 @@ +module Capybara + class Node + module Finders + #return node identified by locator or raise ElementNotFound(using desc) + def locate(kind_or_locator, locator=nil, fail_msg = nil) + node = wait_conditionally_until { find(kind_or_locator, locator) } + ensure + raise Capybara::ElementNotFound, fail_msg || "Unable to locate '#{locator || kind_or_locator}'" unless node + return node + end + + def find(*args) + all(*args).first + end + + def find_field(locator) + find(:xpath, XPath.field(locator)) + end + alias_method :field_labeled, :find_field + + def find_link(locator) + find(:xpath, XPath.link(locator)) + end + + def find_button(locator) + find(:xpath, XPath.button(locator)) + end + + def find_by_id(id) + find(:css, "##{id}") + end + + def all(*args) + options = if args.last.is_a?(Hash) then args.pop else {} end + + results = XPath.wrap(normalize_locator(*args)).paths.map do |path| + base.find(path) + end.flatten + + if options[:text] + + if options[:text].kind_of?(Regexp) + regexp = options[:text] + else + regexp = Regexp.escape(options[:text]) + end + + results = results.select { |n| n.text.match(regexp) } + end + + if options[:visible] or Capybara.ignore_hidden_elements + results = results.select { |n| n.visible? } + end + + results.map { |n| Capybara::Element.new(self, n) } + end + + protected + + def normalize_locator(kind, locator=nil) + kind, locator = Capybara.default_selector, kind if locator.nil? + locator = XPath.from_css(locator) if kind == :css + locator + end + + def wait_conditionally_until + if driver.wait? then wait_until { yield } else yield end + end + + end + end +end diff --git a/lib/capybara/node/matchers.rb b/lib/capybara/node/matchers.rb new file mode 100644 index 00000000..6d3b12b3 --- /dev/null +++ b/lib/capybara/node/matchers.rb @@ -0,0 +1,97 @@ +module Capybara + class Node + module Matchers + def has_xpath?(path, options={}) + wait_conditionally_until do + results = all(:xpath, path, options) + + if options[:count] + results.size == options[:count] + else + results.size > 0 + end + end + rescue Capybara::TimeoutError + return false + end + + def has_no_xpath?(path, options={}) + wait_conditionally_until do + results = all(:xpath, path, options) + + if options[:count] + results.size != options[:count] + else + results.empty? + end + end + rescue Capybara::TimeoutError + return false + end + + def has_css?(path, options={}) + has_xpath?(XPath.from_css(path), options) + end + + def has_no_css?(path, options={}) + has_no_xpath?(XPath.from_css(path), options) + end + + def has_content?(content) + has_xpath?(XPath.content(content)) + end + + def has_no_content?(content) + has_no_xpath?(XPath.content(content)) + end + + def has_link?(locator) + has_xpath?(XPath.link(locator)) + end + + def has_no_link?(locator) + has_no_xpath?(XPath.link(locator)) + end + + def has_button?(locator) + has_xpath?(XPath.button(locator)) + end + + def has_no_button?(locator) + has_no_xpath?(XPath.button(locator)) + end + + def has_field?(locator, options={}) + has_xpath?(XPath.field(locator, options)) + end + + def has_no_field?(locator, options={}) + has_no_xpath?(XPath.field(locator, options)) + end + + def has_checked_field?(locator) + has_xpath?(XPath.field(locator, :checked => true)) + end + + def has_unchecked_field?(locator) + has_xpath?(XPath.field(locator, :unchecked => true)) + end + + def has_select?(locator, options={}) + has_xpath?(XPath.select(locator, options)) + end + + def has_no_select?(locator, options={}) + has_no_xpath?(XPath.select(locator, options)) + end + + def has_table?(locator, options={}) + has_xpath?(XPath.table(locator, options)) + end + + def has_no_table?(locator, options={}) + has_no_xpath?(XPath.table(locator, options)) + end + end + end +end