rails-dom-testing-2.0.3/ 0000755 0000041 0000041 00000000000 13272036654 015116 5 ustar www-data www-data rails-dom-testing-2.0.3/rails-dom-testing.gemspec 0000644 0000041 0000041 00000005443 13272036654 022033 0 ustar www-data www-data #########################################################
# This file has been automatically generated by gem2tgz #
#########################################################
# -*- encoding: utf-8 -*-
# stub: rails-dom-testing 2.0.3 ruby lib
Gem::Specification.new do |s|
s.name = "rails-dom-testing".freeze
s.version = "2.0.3"
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
s.require_paths = ["lib".freeze]
s.authors = ["Rafael Mendon\u{e7}a Fran\u{e7}a".freeze, "Kasper Timm Hansen".freeze]
s.date = "2017-05-10"
s.description = " This gem can compare doms and assert certain elements exists in doms using Nokogiri. ".freeze
s.email = ["rafaelmfranca@gmail.com".freeze, "kaspth@gmail.com".freeze]
s.files = ["MIT-LICENSE".freeze, "README.md".freeze, "lib/rails-dom-testing.rb".freeze, "lib/rails/dom/testing/assertions.rb".freeze, "lib/rails/dom/testing/assertions/dom_assertions.rb".freeze, "lib/rails/dom/testing/assertions/selector_assertions.rb".freeze, "lib/rails/dom/testing/assertions/selector_assertions/count_describable.rb".freeze, "lib/rails/dom/testing/assertions/selector_assertions/html_selector.rb".freeze, "lib/rails/dom/testing/assertions/selector_assertions/substitution_context.rb".freeze, "lib/rails/dom/testing/version.rb".freeze, "test/dom_assertions_test.rb".freeze, "test/selector_assertions_test.rb".freeze, "test/test_helper.rb".freeze]
s.homepage = "https://github.com/rails/rails-dom-testing".freeze
s.licenses = ["MIT".freeze]
s.rubygems_version = "2.5.2.1".freeze
s.summary = "Dom and Selector assertions for Rails applications".freeze
s.test_files = ["test/dom_assertions_test.rb".freeze, "test/selector_assertions_test.rb".freeze, "test/test_helper.rb".freeze]
if s.respond_to? :specification_version then
s.specification_version = 4
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
s.add_runtime_dependency(%q.freeze, [">= 4.2.0"])
s.add_development_dependency(%q.freeze, [">= 1.3"])
s.add_development_dependency(%q.freeze, [">= 0"])
s.add_runtime_dependency(%q.freeze, [">= 1.6"])
s.add_development_dependency(%q.freeze, [">= 0"])
else
s.add_dependency(%q.freeze, [">= 4.2.0"])
s.add_dependency(%q.freeze, [">= 1.3"])
s.add_dependency(%q.freeze, [">= 0"])
s.add_dependency(%q.freeze, [">= 1.6"])
s.add_dependency(%q.freeze, [">= 0"])
end
else
s.add_dependency(%q.freeze, [">= 4.2.0"])
s.add_dependency(%q.freeze, [">= 1.3"])
s.add_dependency(%q.freeze, [">= 0"])
s.add_dependency(%q.freeze, [">= 1.6"])
s.add_dependency(%q.freeze, [">= 0"])
end
end
rails-dom-testing-2.0.3/test/ 0000755 0000041 0000041 00000000000 13272036654 016075 5 ustar www-data www-data rails-dom-testing-2.0.3/test/dom_assertions_test.rb 0000644 0000041 0000041 00000002422 13272036654 022512 0 ustar www-data www-data require 'test_helper'
require 'rails/dom/testing/assertions/dom_assertions'
class DomAssertionsTest < ActiveSupport::TestCase
Assertion = Minitest::Assertion
include Rails::Dom::Testing::Assertions::DomAssertions
def test_responds_to_assert_dom_equal
assert respond_to?(:assert_dom_equal)
end
def test_dom_equal
html = ''
assert_dom_equal(html, html.dup)
end
def test_equal_doms_with_different_order_attributes
attributes = %{}
reverse_attributes = %{}
assert_dom_equal(attributes, reverse_attributes)
end
def test_dom_not_equal
assert_dom_not_equal('', '')
end
def test_unequal_doms_attributes_with_different_order_and_values
attributes = %{}
reverse_attributes = %{}
assert_dom_not_equal(attributes, reverse_attributes)
end
def test_custom_message_is_used_in_failures
message = "This is my message."
e = assert_raises(Assertion) do
assert_dom_equal('', '', message)
end
assert_equal e.message, message
end
def test_unequal_dom_attributes_in_children
assert_dom_not_equal(
%{},
%{}
)
end
end rails-dom-testing-2.0.3/test/selector_assertions_test.rb 0000644 0000041 0000041 00000024754 13272036654 023567 0 ustar www-data www-data # encoding: utf-8
require 'test_helper'
require 'rails/dom/testing/assertions/selector_assertions'
class AssertSelectTest < ActiveSupport::TestCase
Assertion = Minitest::Assertion
include Rails::Dom::Testing::Assertions::SelectorAssertions
def assert_failure(message, &block)
e = assert_raises(Assertion, &block)
assert_match(message, e.message) if Regexp === message
assert_equal(message, e.message) if String === message
end
#
# Test assert select.
#
def test_assert_select
render_html %Q{}
assert_select "div", 2
assert_failure(/Expected at least 1 element matching \"p\", found 0/) { assert_select "p" }
end
def test_equality_integer
render_html %Q{}
assert_failure(/Expected exactly 3 elements matching \"div\", found 2/) { assert_select "div", 3 }
assert_failure(/Expected exactly 0 elements matching \"div\", found 2/) { assert_select "div", 0 }
end
def test_equality_true_false
render_html %Q{}
assert_nothing_raised { assert_select "div" }
assert_raise(Assertion) { assert_select "p" }
assert_nothing_raised { assert_select "div", true }
assert_raise(Assertion) { assert_select "p", true }
assert_raise(Assertion) { assert_select "div", false }
assert_nothing_raised { assert_select "p", false }
end
def test_equality_false_with_substitution
render_html %{}
assert_nothing_raised do
assert_select %{a[href="http://example.org?query=value"]}, false
end
end
def test_equality_false_message
render_html %Q{}
assert_failure(/Expected exactly 0 elements matching \"div\", found 2/) { assert_select "div", false }
end
def test_equality_string_and_regexp
render_html %Q{foo
foo
}
assert_nothing_raised { assert_select "div", "foo" }
assert_raise(Assertion) { assert_select "div", "bar" }
assert_nothing_raised { assert_select "div", :text=>"foo" }
assert_raise(Assertion) { assert_select "div", :text=>"bar" }
assert_nothing_raised { assert_select "div", /(foo|bar)/ }
assert_raise(Assertion) { assert_select "div", /foobar/ }
assert_nothing_raised { assert_select "div", :text=>/(foo|bar)/ }
assert_raise(Assertion) { assert_select "div", :text=>/foobar/ }
assert_raise(Assertion) { assert_select "p", :text=>/foobar/ }
end
def test_equality_of_html
render_html %Q{\n"This is not a big problem," he said.\n
}
text = "\"This is not a big problem,\" he said."
html = "\"This is not a big problem,\" he said."
assert_nothing_raised { assert_select "p", text }
assert_raise(Assertion) { assert_select "p", html }
assert_nothing_raised { assert_select "p", :html=>html }
assert_raise(Assertion) { assert_select "p", :html=>text }
# No stripping for pre.
render_html %Q{\n"This is not a big problem," he said.\n
}
text = "\n\"This is not a big problem,\" he said.\n"
html = "\n\"This is not a big problem,\" he said.\n"
assert_nothing_raised { assert_select "pre", text }
assert_raise(Assertion) { assert_select "pre", html }
assert_nothing_raised { assert_select "pre", :html=>html }
assert_raise(Assertion) { assert_select "pre", :html=>text }
end
def test_strip_textarea
render_html %Q{}
assert_select "textarea", "\nfoo\n"
render_html %Q{}
assert_select "textarea", "foo"
end
def test_counts
render_html %Q{foo
foo
}
assert_nothing_raised { assert_select "div", 2 }
assert_failure(/Expected exactly 3 elements matching \"div\", found 2/) do
assert_select "div", 3
end
assert_nothing_raised { assert_select "div", 1..2 }
assert_failure(/Expected between 3 and 4 elements matching \"div\", found 2/) do
assert_select "div", 3..4
end
assert_nothing_raised { assert_select "div", :count=>2 }
assert_failure(/Expected exactly 3 elements matching \"div\", found 2/) do
assert_select "div", :count=>3
end
assert_nothing_raised { assert_select "div", :minimum=>1 }
assert_nothing_raised { assert_select "div", :minimum=>2 }
assert_failure(/Expected at least 3 elements matching \"div\", found 2/) do
assert_select "div", :minimum=>3
end
assert_nothing_raised { assert_select "div", :maximum=>2 }
assert_nothing_raised { assert_select "div", :maximum=>3 }
assert_failure(/Expected at most 1 element matching \"div\", found 2/) do
assert_select "div", :maximum=>1
end
assert_nothing_raised { assert_select "div", :minimum=>1, :maximum=>2 }
assert_failure(/Expected between 3 and 4 elements matching \"div\", found 2/) do
assert_select "div", :minimum=>3, :maximum=>4
end
end
def test_substitution_values
render_html %Q{foo
foo
}
assert_select "div:match('id', ?)", /\d+/ do |elements|
assert_equal 2, elements.size
end
assert_select "div" do
assert_select ":match('id', ?)", /\d+/ do |elements|
assert_equal 2, elements.size
assert_select "#1"
assert_select "#2"
end
end
end
def test_assert_select_root_html
render_html ''
assert_select 'a'
end
def test_assert_select_root_xml
render_xml ''
assert_select 'rss'
end
def test_nested_assert_select
render_html %Q{foo
foo
}
assert_select "div" do |elements|
assert_equal 2, elements.size
assert_select elements, "#1"
assert_select elements, "#2"
end
assert_select "div" do
assert_select "div" do |elements|
assert_equal 2, elements.size
# Testing in a group is one thing
assert_select "#1,#2"
# Testing individually is another.
assert_select "#1"
assert_select "#2"
assert_select "#3", false
end
end
assert_failure(/Expected at least 1 element matching \"#4\", found 0\./) do
assert_select "div" do
assert_select "#4"
end
end
end
def test_assert_select_text_match
render_html %Q{foo
bar
}
assert_select "div" do
assert_nothing_raised { assert_select "div", "foo" }
assert_nothing_raised { assert_select "div", "bar" }
assert_nothing_raised { assert_select "div", /\w*/ }
assert_nothing_raised { assert_select "div", :text => /\w*/, :count=>2 }
assert_raise(Assertion) { assert_select "div", :text=>"foo", :count=>2 }
assert_nothing_raised { assert_select "div", :html=>"bar" }
assert_nothing_raised { assert_select "div", :html=>"bar" }
assert_nothing_raised { assert_select "div", :html=>/\w*/ }
assert_nothing_raised { assert_select "div", :html=>/\w*/, :count=>2 }
assert_raise(Assertion) { assert_select "div", :html=>"foo", :count=>2 }
end
end
#
# Test css_select.
#
def test_css_select
render_html %Q{}
assert_equal 2, css_select("div").size
assert_equal 0, css_select("p").size
end
def test_nested_css_select
render_html %Q{foo
foo
}
assert_select "div:match('id', ?)", /\d+/ do |elements|
assert_equal 1, css_select(elements[0], "div").size
assert_equal 1, css_select(elements[1], "div").size
end
assert_select "div" do
assert_equal 2, css_select("div").size
css_select("div").each do |element|
# Testing as a group is one thing
assert !css_select("#1,#2").empty?
# Testing individually is another
assert !css_select("#1").empty?
assert !css_select("#2").empty?
end
end
end
# testing invalid selectors
def test_assert_select_with_invalid_selector
render_html 'hello'
assert_raises Nokogiri::CSS::SyntaxError do
assert_select("[href=http://example.com]")
end
end
def test_css_select_with_invalid_selector
render_html 'hello'
assert_raises Nokogiri::CSS::SyntaxError do
css_select("[href=http://example.com]")
end
end
def test_nested_assert_select_with_match_failure_shows_nice_regex
render_html %Q{foo
}
error = assert_raises Minitest::Assertion do
assert_select "div:match('id', ?)", /wups/
end
assert_match %Q{div:match('id', /wups/)}, error.message
end
def test_feed_item_encoded
render_xml <<-EOF
-
Test 1
]]>
-
<p>Test 2</p>
EOF
assert_select "channel item description" do
assert_select_encoded do
assert_select "p", :count=>2, :text=>/Test/
end
# Test individually.
assert_select "description" do |elements|
assert_select_encoded elements[0] do
assert_select "p", "Test 1"
end
assert_select_encoded elements[1] do
assert_select "p", "Test 2"
end
end
end
# Test that we only un-encode element itself.
assert_select "channel item" do
assert_select_encoded do
assert_select "p", 0
end
end
end
def test_body_not_present_in_empty_document
render_html ''
assert_select 'body', 0
end
def test_body_class_can_be_tested
render_html ''
assert_select '.foo'
end
def test_body_class_can_be_tested_with_html
render_html ''
assert_select '.foo'
end
protected
def render_html(html)
fake_render(:html, html)
end
def render_xml(xml)
fake_render(:xml, xml)
end
def fake_render(content_type, content)
@html_document = if content_type == :xml
Nokogiri::XML::Document.parse(content)
else
Nokogiri::HTML::Document.parse(content)
end
end
def document_root_element
@html_document.root
end
end
rails-dom-testing-2.0.3/test/test_helper.rb 0000644 0000041 0000041 00000000230 13272036654 020733 0 ustar www-data www-data require 'nokogiri'
require 'active_support'
require 'active_support/test_case'
require 'minitest/autorun'
ActiveSupport::TestCase.test_order = :random
rails-dom-testing-2.0.3/README.md 0000644 0000041 0000041 00000004712 13272036654 016401 0 ustar www-data www-data # Rails::Dom::Testing
This gem is responsible for comparing HTML doms and asserting that DOM elements are present in Rails applications.
Doms are compared via `assert_dom_equal` and `assert_dom_not_equal`.
Elements are asserted via `assert_select`, `assert_select_encoded`, `assert_select_email` and a subset of the dom can be selected with `css_select`.
The gem is developed for Rails 4.2 and above, and will not work on previous versions.
## Nokogiri::CSS::SyntaxError exceptions when upgrading to Rails 4.2:
Nokogiri is slightly stricter about the format of CSS selectors than the previous implementation.
Check the 4.2 release notes [section on `assert_select`](http://edgeguides.rubyonrails.org/4_2_release_notes.html#assert-select) for help.
## Installation
Add this line to your application's Gemfile:
gem 'rails-dom-testing'
And then execute:
$ bundle
Or install it yourself as:
$ gem install rails-dom-testing
## Usage
### Dom Assertions
```ruby
assert_dom_equal 'Lingua França
', 'Lingua França
'
assert_dom_not_equal 'Portuguese
', 'Danish
'
```
### Selector Assertions
```ruby
# implicitly selects from the document_root_element
css_select '.hello' # => Nokogiri::XML::NodeSet of elements with hello class
# select from a supplied node. assert_select asserts elements exist.
assert_select document_root_element.at('.hello'), '.goodbye'
# elements in CDATA encoded sections can also be selected
assert_select_encoded '#out-of-your-element'
# assert elements within an html email exists
assert_select_email '#you-got-mail'
```
The documentation in [selector_assertions.rb](https://github.com/rails/rails-dom-testing/blob/master/lib/rails/dom/testing/assertions/selector_assertions.rb) goes into a lot more detail of how selector assertions can be used.
## Read more
Under the hood the doms are parsed with Nokogiri and you'll generally be working with these two classes:
- [`Nokogiri::XML::Node`](http://www.rubydoc.info/github/sparklemotion/nokogiri/Nokogiri/XML/Node)
- [`Nokogiri::XML::NodeSet`](http://www.rubydoc.info/github/sparklemotion/nokogiri/Nokogiri/XML/NodeSet)
Read more about Nokogiri:
- [Nokogiri](http://nokogiri.org)
## Contributing to Rails::Dom::Testing
Rails::Dom::Testing is work of many contributors. You're encouraged to submit pull requests, propose
features and discuss issues.
See [CONTRIBUTING](CONTRIBUTING.md).
## License
Rails::Dom::Testing is released under the [MIT License](MIT-LICENSE).
rails-dom-testing-2.0.3/lib/ 0000755 0000041 0000041 00000000000 13272036654 015664 5 ustar www-data www-data rails-dom-testing-2.0.3/lib/rails/ 0000755 0000041 0000041 00000000000 13272036654 016776 5 ustar www-data www-data rails-dom-testing-2.0.3/lib/rails/dom/ 0000755 0000041 0000041 00000000000 13272036654 017555 5 ustar www-data www-data rails-dom-testing-2.0.3/lib/rails/dom/testing/ 0000755 0000041 0000041 00000000000 13272036654 021232 5 ustar www-data www-data rails-dom-testing-2.0.3/lib/rails/dom/testing/version.rb 0000644 0000041 0000041 00000000127 13272036654 023244 0 ustar www-data www-data module Rails
module Dom
module Testing
VERSION = "2.0.3"
end
end
end
rails-dom-testing-2.0.3/lib/rails/dom/testing/assertions/ 0000755 0000041 0000041 00000000000 13272036654 023424 5 ustar www-data www-data rails-dom-testing-2.0.3/lib/rails/dom/testing/assertions/selector_assertions/ 0000755 0000041 0000041 00000000000 13272036654 027516 5 ustar www-data www-data rails-dom-testing-2.0.3/lib/rails/dom/testing/assertions/selector_assertions/count_describable.rb 0000644 0000041 0000041 00000001642 13272036654 033515 0 ustar www-data www-data require 'active_support/concern'
module Rails
module Dom
module Testing
module Assertions
module SelectorAssertions
module CountDescribable
extend ActiveSupport::Concern
private
def count_description(min, max, count) #:nodoc:
if min && max && (max != min)
"between #{min} and #{max} elements"
elsif min && max && max == min && count
"exactly #{count} #{pluralize_element(min)}"
elsif min && !(min == 1 && max == 1)
"at least #{min} #{pluralize_element(min)}"
elsif max
"at most #{max} #{pluralize_element(max)}"
end
end
def pluralize_element(quantity)
quantity == 1 ? 'element' : 'elements'
end
end
end
end
end
end
end
rails-dom-testing-2.0.3/lib/rails/dom/testing/assertions/selector_assertions/html_selector.rb 0000644 0000041 0000041 00000006615 13272036654 032717 0 ustar www-data www-data require 'active_support/core_ext/module/attribute_accessors'
require_relative 'substitution_context'
class HTMLSelector #:nodoc:
attr_reader :css_selector, :tests, :message
def initialize(values, previous_selection = nil, &root_fallback)
@values = values
@root = extract_root(previous_selection, root_fallback)
extract_selectors
@tests = extract_equality_tests
@message = @values.shift
if @values.shift
raise ArgumentError, "Not expecting that last argument, you either have too many arguments, or they're the wrong type"
end
end
def selecting_no_body? #:nodoc:
# Nokogiri gives the document a body element. Which means we can't
# run an assertion expecting there to not be a body.
@selector == 'body' && @tests[:count] == 0
end
def select
filter @root.css(@selector, context)
end
private
NO_STRIP = %w{pre script style textarea}
mattr_reader(:context) { SubstitutionContext.new }
def filter(matches)
match_with = tests[:text] || tests[:html]
return matches if matches.empty? || !match_with
content_mismatch = nil
text_matches = tests.has_key?(:text)
regex_matching = match_with.is_a?(Regexp)
remaining = matches.reject do |match|
# Preserve markup with to_s for html elements
content = text_matches ? match.text : match.children.to_s
content.strip! unless NO_STRIP.include?(match.name)
content.sub!(/\A\n/, '') if text_matches && match.name == "textarea"
next if regex_matching ? (content =~ match_with) : (content == match_with)
content_mismatch ||= sprintf("<%s> expected but was\n<%s>.", match_with, content)
true
end
@message ||= content_mismatch if remaining.empty?
Nokogiri::XML::NodeSet.new(matches.document, remaining)
end
def extract_root(previous_selection, root_fallback)
possible_root = @values.first
if possible_root == nil
raise ArgumentError, 'First argument is either selector or element ' \
'to select, but nil found. Perhaps you called assert_select with ' \
'an element that does not exist?'
elsif possible_root.respond_to?(:css)
@values.shift # remove the root, so selector is the first argument
possible_root
elsif previous_selection
previous_selection
else
root_fallback.call
end
end
def extract_selectors
selector = @values.shift
unless selector.is_a? String
raise ArgumentError, "Expecting a selector as the first argument"
end
@css_selector = context.substitute!(selector, @values.dup, true)
@selector = context.substitute!(selector, @values)
end
def extract_equality_tests
comparisons = {}
case comparator = @values.shift
when Hash
comparisons = comparator
when String, Regexp
comparisons[:text] = comparator
when Integer
comparisons[:count] = comparator
when Range
comparisons[:minimum] = comparator.begin
comparisons[:maximum] = comparator.end
when FalseClass
comparisons[:count] = 0
when NilClass, TrueClass
comparisons[:minimum] = 1
else raise ArgumentError, "I don't understand what you're trying to match"
end
# By default we're looking for at least one match.
if comparisons[:count]
comparisons[:minimum] = comparisons[:maximum] = comparisons[:count]
else
comparisons[:minimum] ||= 1
end
comparisons
end
end
rails-dom-testing-2.0.3/lib/rails/dom/testing/assertions/selector_assertions/substitution_context.rb0000644 0000041 0000041 00000001557 13272036654 034373 0 ustar www-data www-data class SubstitutionContext
def initialize
@substitute = '?'
end
def substitute!(selector, values, format_for_presentation = false)
selector = selector.dup
while !values.empty? && substitutable?(values.first) && selector.index(@substitute)
selector.sub! @substitute, matcher_for(values.shift, format_for_presentation)
end
selector
end
def match(matches, attribute, matcher)
matches.find_all { |node| node[attribute] =~ Regexp.new(matcher) }
end
private
def matcher_for(value, format_for_presentation)
# Nokogiri doesn't like arbitrary values without quotes, hence inspect.
if format_for_presentation
value.inspect # Avoid to_s so Regexps aren't put in quotes.
else
value.to_s.inspect
end
end
def substitutable?(value)
value.is_a?(String) || value.is_a?(Regexp)
end
end
rails-dom-testing-2.0.3/lib/rails/dom/testing/assertions/dom_assertions.rb 0000644 0000041 0000041 00000005373 13272036654 027012 0 ustar www-data www-data module Rails
module Dom
module Testing
module Assertions
module DomAssertions
# \Test two HTML strings for equivalency (e.g., equal even when attributes are in another order)
#
# # assert that the referenced method generates the appropriate HTML string
# assert_dom_equal 'Apples', link_to("Apples", "http://www.example.com")
def assert_dom_equal(expected, actual, message = nil)
expected_dom, actual_dom = fragment(expected), fragment(actual)
message ||= "Expected: #{expected}\nActual: #{actual}"
assert compare_doms(expected_dom, actual_dom), message
end
# The negated form of +assert_dom_equal+.
#
# # assert that the referenced method does not generate the specified HTML string
# assert_dom_not_equal 'Apples', link_to("Oranges", "http://www.example.com")
def assert_dom_not_equal(expected, actual, message = nil)
expected_dom, actual_dom = fragment(expected), fragment(actual)
message ||= "Expected: #{expected}\nActual: #{actual}"
assert_not compare_doms(expected_dom, actual_dom), message
end
protected
def compare_doms(expected, actual)
return false unless expected.children.size == actual.children.size
expected.children.each_with_index do |child, i|
return false unless equal_children?(child, actual.children[i])
end
true
end
def equal_children?(child, other_child)
return false unless child.type == other_child.type
if child.element?
child.name == other_child.name &&
equal_attribute_nodes?(child.attribute_nodes, other_child.attribute_nodes) &&
compare_doms(child, other_child)
else
child.to_s == other_child.to_s
end
end
def equal_attribute_nodes?(nodes, other_nodes)
return false unless nodes.size == other_nodes.size
nodes = nodes.sort_by(&:name)
other_nodes = other_nodes.sort_by(&:name)
nodes.each_with_index do |attr, i|
return false unless equal_attribute?(attr, other_nodes[i])
end
true
end
def equal_attribute?(attr, other_attr)
attr.name == other_attr.name && attr.value == other_attr.value
end
private
def fragment(text)
Nokogiri::HTML::DocumentFragment.parse(text)
end
end
end
end
end
end
rails-dom-testing-2.0.3/lib/rails/dom/testing/assertions/selector_assertions.rb 0000644 0000041 0000041 00000030320 13272036654 030041 0 ustar www-data www-data require 'active_support/deprecation'
require_relative 'selector_assertions/count_describable'
require_relative 'selector_assertions/html_selector'
module Rails
module Dom
module Testing
module Assertions
# Adds the +assert_select+ method for use in Rails functional
# test cases, which can be used to make assertions on the response HTML of a controller
# action. You can also call +assert_select+ within another +assert_select+ to
# make assertions on elements selected by the enclosing assertion.
#
# Use +css_select+ to select elements without making an assertions, either
# from the response HTML or elements selected by the enclosing assertion.
#
# In addition to HTML responses, you can make the following assertions:
#
# * +assert_select_encoded+ - Assertions on HTML encoded inside XML, for example for dealing with feed item descriptions.
# * +assert_select_email+ - Assertions on the HTML body of an e-mail.
module SelectorAssertions
# Select and return all matching elements.
#
# If called with a single argument, uses that argument as a selector.
# Called without an element +css_select+ selects from
# the element returned in +document_root_element+
#
# The default implementation of +document_root_element+ raises an exception explaining this.
#
# Returns an empty Nokogiri::XML::NodeSet if no match is found.
#
# If called with two arguments, uses the first argument as the root
# element and the second argument as the selector. Attempts to match the
# root element and any of its children.
# Returns an empty Nokogiri::XML::NodeSet if no match is found.
#
# The selector may be a CSS selector expression (String).
# css_select returns nil if called with an invalid css selector.
#
# # Selects all div tags
# divs = css_select("div")
#
# # Selects all paragraph tags and does something interesting
# pars = css_select("p")
# pars.each do |par|
# # Do something fun with paragraphs here...
# end
#
# # Selects all list items in unordered lists
# items = css_select("ul>li")
#
# # Selects all form tags and then all inputs inside the form
# forms = css_select("form")
# forms.each do |form|
# inputs = css_select(form, "input")
# ...
# end
def css_select(*args)
raise ArgumentError, "you at least need a selector argument" if args.empty?
root = args.size == 1 ? document_root_element : args.shift
nodeset(root).css(args.first)
end
# An assertion that selects elements and makes one or more equality tests.
#
# If the first argument is an element, selects all matching elements
# starting from (and including) that element and all its children in
# depth-first order.
#
# If no element is specified +assert_select+ selects from
# the element returned in +document_root_element+
# unless +assert_select+ is called from within an +assert_select+ block.
# Override +document_root_element+ to tell +assert_select+ what to select from.
# The default implementation raises an exception explaining this.
#
# When called with a block +assert_select+ passes an array of selected elements
# to the block. Calling +assert_select+ from the block, with no element specified,
# runs the assertion on the complete set of elements selected by the enclosing assertion.
# Alternatively the array may be iterated through so that +assert_select+ can be called
# separately for each element.
#
#
# ==== Example
# If the response contains two ordered lists, each with four list elements then:
# assert_select "ol" do |elements|
# elements.each do |element|
# assert_select element, "li", 4
# end
# end
#
# will pass, as will:
# assert_select "ol" do
# assert_select "li", 8
# end
#
# The selector may be a CSS selector expression (String) or an expression
# with substitution values (Array).
# Substitution uses a custom pseudo class match. Pass in whatever attribute you want to match (enclosed in quotes) and a ? for the substitution.
# assert_select returns nil if called with an invalid css selector.
#
# assert_select "div:match('id', ?)", /\d+/
#
# === Equality Tests
#
# The equality test may be one of the following:
# * true - Assertion is true if at least one element selected.
# * false - Assertion is true if no element selected.
# * String/Regexp - Assertion is true if the text value of at least
# one element matches the string or regular expression.
# * Integer - Assertion is true if exactly that number of
# elements are selected.
# * Range - Assertion is true if the number of selected
# elements fit the range.
# If no equality test specified, the assertion is true if at least one
# element selected.
#
# To perform more than one equality tests, use a hash with the following keys:
# * :text - Narrow the selection to elements that have this text
# value (string or regexp).
# * :html - Narrow the selection to elements that have this HTML
# content (string or regexp).
# * :count - Assertion is true if the number of selected elements
# is equal to this value.
# * :minimum - Assertion is true if the number of selected
# elements is at least this value.
# * :maximum - Assertion is true if the number of selected
# elements is at most this value.
#
# If the method is called with a block, once all equality tests are
# evaluated the block is called with an array of all matched elements.
#
# # At least one form element
# assert_select "form"
#
# # Form element includes four input fields
# assert_select "form input", 4
#
# # Page title is "Welcome"
# assert_select "title", "Welcome"
#
# # Page title is "Welcome" and there is only one title element
# assert_select "title", {count: 1, text: "Welcome"},
# "Wrong title or more than one title element"
#
# # Page contains no forms
# assert_select "form", false, "This page must contain no forms"
#
# # Test the content and style
# assert_select "body div.header ul.menu"
#
# # Use substitution values
# assert_select "ol>li:match('id', ?)", /item-\d+/
#
# # All input fields in the form have a name
# assert_select "form input" do
# assert_select ":match('name', ?)", /.+/ # Not empty
# end
def assert_select(*args, &block)
@selected ||= nil
selector = HTMLSelector.new(args, @selected) { nodeset document_root_element }
if selector.selecting_no_body?
assert true
return
end
selector.select.tap do |matches|
assert_size_match!(matches.size, selector.tests,
selector.css_selector, selector.message)
nest_selection(matches, &block) if block_given? && !matches.empty?
end
end
# Extracts the content of an element, treats it as encoded HTML and runs
# nested assertion on it.
#
# You typically call this method within another assertion to operate on
# all currently selected elements. You can also pass an element or array
# of elements.
#
# The content of each element is un-encoded, and wrapped in the root
# element +encoded+. It then calls the block with all un-encoded elements.
#
# # Selects all bold tags from within the title of an Atom feed's entries (perhaps to nab a section name prefix)
# assert_select "feed[xmlns='http://www.w3.org/2005/Atom']" do
# # Select each entry item and then the title item
# assert_select "entry>title" do
# # Run assertions on the encoded title elements
# assert_select_encoded do
# assert_select "b"
# end
# end
# end
#
#
# # Selects all paragraph tags from within the description of an RSS feed
# assert_select "rss[version=2.0]" do
# # Select description element of each feed item.
# assert_select "channel>item>description" do
# # Run assertions on the encoded elements.
# assert_select_encoded do
# assert_select "p"
# end
# end
# end
def assert_select_encoded(element = nil, &block)
if !element && !@selected
raise ArgumentError, "Element is required when called from a nonnested assert_select"
end
content = nodeset(element || @selected).map do |elem|
elem.children.select do |child|
child.cdata? || (child.text? && !child.blank?)
end.map(&:content)
end.join
selected = Nokogiri::HTML::DocumentFragment.parse(content)
nest_selection(selected) do
if content.empty?
yield selected
else
assert_select ":root", &block
end
end
end
# Extracts the body of an email and runs nested assertions on it.
#
# You must enable deliveries for this assertion to work, use:
# ActionMailer::Base.perform_deliveries = true
#
# assert_select_email do
# assert_select "h1", "Email alert"
# end
#
# assert_select_email do
# items = assert_select "ol>li"
# items.each do
# # Work with items here...
# end
# end
def assert_select_email(&block)
deliveries = ActionMailer::Base.deliveries
assert !deliveries.empty?, "No e-mail in delivery list"
deliveries.each do |delivery|
(delivery.parts.empty? ? [delivery] : delivery.parts).each do |part|
if part["Content-Type"].to_s =~ /^text\/html\W/
root = Nokogiri::HTML::DocumentFragment.parse(part.body.to_s)
assert_select root, ":root", &block
end
end
end
end
private
include CountDescribable
def document_root_element
raise NotImplementedError, 'Implementing document_root_element makes ' \
'assert_select work without needing to specify an element to select from.'
end
# +equals+ must contain :minimum, :maximum and :count keys
def assert_size_match!(size, equals, css_selector, message = nil)
min, max, count = equals[:minimum], equals[:maximum], equals[:count]
message ||= %(Expected #{count_description(min, max, count)} matching "#{css_selector}", found #{size}.)
if count
assert_equal count, size, message
else
assert_operator size, :>=, min, message if min
assert_operator size, :<=, max, message if max
end
end
def nest_selection(selection)
# Set @selected to allow nested assert_select.
# Can be nested several levels deep.
old_selected, @selected = @selected, selection
yield @selected
ensure
@selected = old_selected
end
def nodeset(node)
if node.is_a?(Nokogiri::XML::NodeSet)
node
else
Nokogiri::XML::NodeSet.new(node.document, [node])
end
end
end
end
end
end
end
rails-dom-testing-2.0.3/lib/rails/dom/testing/assertions.rb 0000644 0000041 0000041 00000000646 13272036654 023757 0 ustar www-data www-data require 'active_support/concern'
require 'nokogiri'
module Rails
module Dom
module Testing
module Assertions
autoload :DomAssertions, 'rails/dom/testing/assertions/dom_assertions'
autoload :SelectorAssertions, 'rails/dom/testing/assertions/selector_assertions'
extend ActiveSupport::Concern
include DomAssertions
include SelectorAssertions
end
end
end
end rails-dom-testing-2.0.3/lib/rails-dom-testing.rb 0000644 0000041 0000041 00000000046 13272036654 021553 0 ustar www-data www-data require 'rails/dom/testing/assertions' rails-dom-testing-2.0.3/MIT-LICENSE 0000644 0000041 0000041 00000002071 13272036654 016552 0 ustar www-data www-data Copyright (c) 2013-2015 Kasper Timm Hansen
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.