Domino 
View abstraction for integration testing
Usage
To create a basic Domino class, inherit from Domino and
define a selector and attributes:
module Dom
class Post < Domino
selector '#posts .post'
attribute :title
attribute :author_name
attribute :body, '.post-body'
attribute :comments do |text|
text.to_i
end
attribute :posted_at do |text|
Date.parse(text)
end
attribute :active, "&.active"
attribute :rating, "&[data-rating]", &:to_i
attribute :blah, "&[data-blah]" do |a|
!a.nil?
end
end
end
Now in your integration test you can use some of Domino's methods:
assert_equal 4, Dom::Post.count
refute_nil Dom::Post.find_by_title('First Post')
assert_equal Dom::Post.find_by_title { |node| node.text == "First Post" && node.tag_name == 'p' }
refute_nil Dom::Post.find_by(title: 'First Post', author: 'Jane Doe')
refute_nil Dom::Post.find_by!(title: 'First Post', author: 'Jane Doe')
assert_equal ["12/06/2014", "12/01/2014"], Dom::Post.where(author: 'Jane Doe').map(&:posted_on)
What makes it really powerful is defining scoped actions:
module Dom
class Post < Domino
def delete
within(id) { click_button 'Delete' }
end
end
end
refute_nil Dom::Post.find_by_title('First Post')
Dom::Post.find_by_title('First Post').delete
assert_nil Dom::Post.find_by_title('First Post')
Domino::Form
Domino makes it easy to model your forms for testing with Domino::Form
.
To create a basic form, simply inherit from Domino::Form
and define a
selector, a key (optional), and a set of fields.
module Dom
class PersonForm < Domino::Form
selector 'form.person'
key 'person'
submit_with "input[type='submit']"
field :first_name, 'First Name'
field :last_name
field :biography, 'person[bio]'
field :favorite_color, 'Favorite Color', as: :select, &:text
field :allergies, as: :select
field :age, 'person_age', &:to_i
field :vehicles, '.input.vehicles', as: CheckBoxesField
field :is_human, 'is_human', as: :boolean
attribute :action, "&[action]"
attribute :submit_method, "&[method]"
end
end
In the above example, you can define a field to get a reader and writer
method for the field. A form will also provide a mass-assignment writer
and a save method to submit the form.
person = Dom::PersonForm.find!
person.age
person.vehicles
person.is_human
person.favorite_color
person.age = 35
person.age
person.set(vehicles: ["Car", "Van"], first_name: "Jessica", last_name: "Jones")
person.attributes
Domino::Form
provides basic field types for text inputs and textareas,
single-selects, and boolean fields. You can create custom field types
for more complex form inputs by subclassing Domino::Form::Field
and
overriding the read
and write
methods. For example, if you have a
collection of check boxes, this might suit your needs:
class CheckBoxesField < Domino::Form::Field
def read(node)
node.find(locator).all('input[type=checkbox]').select(&:checked?).map(&:value)
end
def write(node, value)
value = Array(value)
node.find(locator).all('input[type=checkbox]').each do |box|
box.set(value.include?(box.value))
end
end
end
Provide your custom class using the :as
option when defining your field,
as shown in the example above.
Accessing the Attribute/Field Node
The named accessor method for any field or attribute will yield the Capybara
node of the attribute if you pass a block. You can use this to check
certain properties of the node without having to break out of your Dominos.
Example: Checking available options in a select field
person = Dom::PersonForm.find!
expected_options = ["- Select a Color -", "Red", "Blue", "Green"]
assert_equal expected_options, person.favorite_color { |n| n.all('option').map(&:text) }
Example: Checking the tag of the node containing the attribute value
person = Dom::Person.find_by!(uuid: "e94bb2d3-71d2-4efb-abd4-ebc0cb58d19f")
assert_equal "h2", person.name { |n| n.tag_name }
Integration with capybara
Domino uses capybara internally to search html for nodes and
attributes. If you need to do something special, you can have direct
access to the capybara node.
module Dom
class Account < Domino
selector "#accounts li"
def text
node.text
end
end
end
For more information about using Capybara nodes, check Capybara Documentation.
Dealing with Asynchronous Behavior
When working with Capybara drivers that support JavaScript, it may be
necessary to wait for elements to appear. Note that the following code
simply collects all Account
dominos currently on the page and
returns the first:
Dom::Account.first
When you are waiting for a unique domino to appear, you can instead
use the find!
method:
Dom::Account.find!
If no matching element appears, Capybara will raise an error telling
you about the expected selector. Depending on the
Capybara.match
option,
this will also raise an error if the selector matches multiple nodes.
Integration with Cucumber
Add a features/support/dominos.rb file, in which you define your dominos.
Use them in your steps.
Integration with Test::Unit
Include "domino" in your Gemfile if using bundler, or simply
require 'domino'
If you're not using Bundler.
Now, define your Dominos anywhere you want. The easiest place to start is
in your test_helper.rb (doesn't have to be inside a Rails test class).
Example
Check out Domino Example for an
example of using Test::Unit and Cucumber with Domino.
Copyright
Copyright (c) 2011 Nick Gauthier, released under the MIT license