class Dill::Widget
Attributes
Public Class Methods
Defines a new action.
This is a shortcut to help defining a widget and a method that clicks on that widget. You can then send a widget instance the message given by name
.
You can access the underlying widget by appending “_widget” to the action name.
@example
# Consider the widget will encapsulate the following HTML # # <div id="profile"> # <a href="/profiles/1/edit" rel="edit">Edit</a> # </div> class PirateProfile < Dill::Widget root "#profile" # Declare the action action :edit, '[rel = edit]' end pirate_profile = widget(:pirate_profile) # Access the action widget action_widget = pirate_profile.widget(:edit_widget) action_widget = pirate_profile.edit_widget # Click the link pirate_profile.edit
@param name the name of the action @param selector the selector for the widget that will be clicked
# File lib/dill/widgets/widget.rb, line 49 def self.action(name, selector = nil) block = if selector wname = :"#{name}_widget" widget wname, selector -> { widget(wname).click; self } else -> { click; self } end define_method name, &block end
# File lib/dill/widgets/widget.rb, line 183 def self.filter @filter || superclass.filter rescue NoMethodError raise MissingSelector, 'no selector defined' end
# File lib/dill/widgets/widget.rb, line 189 def self.filter? filter rescue false end
# File lib/dill/widgets/widget.rb, line 105 def self.find_all_in(parent, *args) filter.nodes(parent, *args).map { |e| new(e) } end
Finds a single instance of the current widget in node
.
@param node the node we want to search in
@return a new instance of the current widget class.
@raise [Capybara::ElementNotFoundError] if the widget can't be found
# File lib/dill/widgets/widget.rb, line 95 def self.find_in(parent, *args) new(filter.node(parent, *args)) rescue Capybara::Ambiguous => e raise AmbiguousWidget.new(e.message). tap { |x| x.set_backtrace e.backtrace } rescue Capybara::ElementNotFound => e raise MissingWidget.new(e.message). tap { |x| x.set_backtrace e.backtrace } end
# File lib/dill/widgets/widget.rb, line 197 def initialize(root) @root = root end
# File lib/dill/widgets/widget.rb, line 119 def self.not_present_in?(parent, *args) filter.nodeless?(parent, *args) end
Determines if an instance of this widget class exists in parent_node
.
@param parent_node [Capybara::Node] the node we want to search in
@return true
if a widget instance is found, false
otherwise.
# File lib/dill/widgets/widget.rb, line 115 def self.present_in?(parent, *args) filter.node?(parent, *args) end
Sets this widget's default selector.
You can pass more than one argument to it, or a single Array. Any valid Capybara selector accepted by Capybara::Node::Finders#find will work.
Examples¶ ↑
Most of the time, your selectors will be Strings:
class MyWidget < Dill::Widget root '.selector' end
This will match any element with a class of “selector”. For example:
<span class="selector">Pick me!</span>
Composite selectors¶ ↑
If you're using CSS as the query language, it's useful to be able to use +text: 'Some text'+ to zero in on a specific node:
class MySpecificWidget < Dill::Widget root '.selector', text: 'Pick me!' end
This is especially useful, e.g., when you want to create a widget to match a specific error or notification:
class NoFreeSpace < Dill::Widget root '.error', text: 'No free space left!' end
So, given the following HTML:
<body> <div class="error">No free space left!</div> <!-- ... --> </body>
You can test for the error's present using the following code:
document.visible?(:no_free_space) #=> true
Note: When you want to match text, consider using I18n.t
instead of hard-coding the text, so that your tests don't break when the text changes.
Finally, you may want to override the query language:
class MyWidgetUsesXPath < Dill::Widget root :xpath, '//some/node' end
# File lib/dill/widgets/widget.rb, line 176 def self.root(*selector, &block) @filter = NodeFilter.new(block || selector) end
# File lib/dill/widgets/widget.rb, line 193 def self.selector filter.selector end
Creates a delegator for one child widget message.
Since widgets are accessed through {WidgetParts::Container#widget}, we can't use {Forwardable} to delegate messages to widgets.
@param name the name of the receiver child widget @param widget_message the name of the message to be sent to the child widget @param method_name the name of the delegator. If nil
the method will
have the same name as the message it will send.
# File lib/dill/widgets/widget.rb, line 72 def self.widget_delegator(name, widget_message, method_name = nil) method_name = method_name || widget_message class_eval <<-RUBY def #{method_name}(*args) if args.size == 1 widget(:#{name}).#{widget_message} args.first else widget(:#{name}).#{widget_message} *args end end RUBY end
Public Instance Methods
Determines if the widget has a specific class
@param name the name of the class
@return [Boolean] true
if the class is found, false
otherwise
# File lib/dill/widgets/widget.rb, line 352 def class?(name) classes.include?(name) end
# File lib/dill/widgets/widget.rb, line 343 def classes root['class'].split end
Clicks the current widget, or the child widget given by name
.
Usage¶ ↑
Given the following widget definition:
class Container < Dill::Widget root '#container' widget :link, 'a' end
Send click
with no arguments to trigger a click
event on #container
.
widget(:container).click
This is the equivalent of doing the following using Capybara:
find('#container').click
Send +click :link+ to trigger a click
event on a
:
widget(:container).click :link
This is the equivalent of doing the following using Capybara:
find('#container a').click
# File lib/dill/widgets/widget.rb, line 228 def click(*args) if args.empty? root.click else widget(*args).click end end
Double clicks the current widget, or the child widget given by name
.
Usage¶ ↑
Given the following widget definition:
class Container < Dill::Widget root '#container' widget :link, 'a' end
Send double_click
with no arguments to trigger an ondblclick
event on #container
.
widget(:container).double_click
This is the equivalent of doing the following using Capybara:
find('#container').double_click
# File lib/dill/widgets/widget.rb, line 290 def double_click(*args) if args.empty? root.double_click else widget(*args).double_click end end
Determines if the widget underlying an action exists.
@param name the name of the action
@raise Missing
if an action with name
can't be found.
@return [Boolean] true
if the action widget is found, false
otherwise.
# File lib/dill/widgets/widget.rb, line 333 def has_action?(name) raise Missing, "couldn't find `#{name}' action" unless respond_to?(name) visible?(:"#{name}_widget") end
Hovers over the current widget, or the child widget given by name
.
Usage¶ ↑
Given the following widget definition:
class Container < Dill::Widget root '#container' widget :link, 'a' end
Send hover
with no arguments to trigger a hover
event on #container
.
widget(:container).hover
This is the equivalent of doing the following using Capybara:
find('#container').hover
Send +hover :link+ to trigger a hover
event on a
:
widget(:container).hover :link
This is the equivalent of doing the following using Capybara:
find('#container a').hover
# File lib/dill/widgets/widget.rb, line 263 def hover(*args) if args.empty? root.hover else widget(*args).hover end end
# File lib/dill/widgets/widget.rb, line 356 def html xml = Nokogiri::HTML(page.body).at(root.path).to_xml Nokogiri::XML(xml, &:noblanks).to_xhtml.gsub("\n", "") end
# File lib/dill/widgets/widget.rb, line 339 def id root['id'] end
Right clicks the current widget, or the child widget given by name
.
Usage¶ ↑
Given the following widget definition:
class Container < Dill::Widget root '#container' widget :link, 'a' end
Send right_click
with no arguments to trigger an oncontextmenu
event on #container
.
widget(:container).right_click
This is the equivalent of doing the following using Capybara:
find('#container').right_click
# File lib/dill/widgets/widget.rb, line 317 def right_click(*args) if args.empty? root.right_click else widget(*args).right_click end end
# File lib/dill/widgets/widget.rb, line 362 def text StringValue.new(root.text.strip) end
Converts this widget into a string representation suitable to be displayed in a Cucumber table cell. By default calls text
.
This method will be called by methods that build tables or rows (usually to_table or to_row) so, in general, you won't call it directly, but feel free to override it when needed.
Returns a String.
# File lib/dill/widgets/widget.rb, line 374 def to_cell text end
# File lib/dill/widgets/widget.rb, line 378 def to_s text end
# File lib/dill/widgets/widget.rb, line 382 def value text end
Private Instance Methods
# File lib/dill/widgets/widget.rb, line 388 def page Capybara.current_session end