From c94e24fbe7bcdf605cafcfabdf97454d1e1e0685 Mon Sep 17 00:00:00 2001 From: Timm Date: Wed, 12 Jun 2013 15:59:34 +0200 Subject: Added Loofah as a dependency in actionview.gemspec. Implemented ActionView: FullSanitizer, LinkSanitizer and WhiteListSanitizer in sanitizers.rb. Deprecated protocol_separator and bad_tags. Added new tests in sanitizers_test.rb and reimplemented assert_dom_equal with Loofah. --- .../lib/action_dispatch/testing/assertions/dom.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/dom.rb b/actionpack/lib/action_dispatch/testing/assertions/dom.rb index 241a39393a..d929e4b400 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/dom.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/dom.rb @@ -1,4 +1,4 @@ -require 'action_view/vendor/html-scanner' +require 'loofah' module ActionDispatch module Assertions @@ -7,20 +7,20 @@ module ActionDispatch # # # 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 = HTML::Document.new(expected).root - actual_dom = HTML::Document.new(actual).root - assert_equal expected_dom, actual_dom, message + def assert_dom_equal(expected, actual, message = "") + expected_dom = Loofah.fragment(expected).to_s + actual_dom = Loofah.fragment(actual).to_s + assert_equal expected_dom, actual_dom end # The negated form of +assert_dom_equivalent+. # # # 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 = HTML::Document.new(expected).root - actual_dom = HTML::Document.new(actual).root - assert_not_equal expected_dom, actual_dom, message + def assert_dom_not_equal(expected, actual, message = "") + expected_dom = Loofah.fragment(expected).to_s + actual_dom = Loofah.fragment(actual).to_s + assert_not_equal expected_dom, actual_dom end end end -- cgit v1.2.3 From 8f5547f489a6559bf2a133d2441deb34f0815c36 Mon Sep 17 00:00:00 2001 From: Timm Date: Mon, 15 Jul 2013 22:40:46 +0200 Subject: Corrected documentation bug. --- .../lib/action_dispatch/testing/assertions/dom.rb | 67 ++++++++++++++++++---- 1 file changed, 57 insertions(+), 10 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/dom.rb b/actionpack/lib/action_dispatch/testing/assertions/dom.rb index d929e4b400..4a05e4aee3 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/dom.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/dom.rb @@ -3,25 +3,72 @@ require 'loofah' module ActionDispatch module Assertions module DomAssertions - # \Test two HTML strings for equivalency (e.g., identical up to reordering of attributes) + # \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 = "") - expected_dom = Loofah.fragment(expected).to_s - actual_dom = Loofah.fragment(actual).to_s - assert_equal expected_dom, actual_dom + def assert_dom_equal(expected, actual, message = nil) + expected_dom, actual_dom = doms_from_strings(expected, actual) + message ||= "Expected: #{expected_dom}\nActual: #{actual_dom}" + assert compare_doms(expected_dom, actual_dom), message end - # The negated form of +assert_dom_equivalent+. + # 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 = "") - expected_dom = Loofah.fragment(expected).to_s - actual_dom = Loofah.fragment(actual).to_s - assert_not_equal expected_dom, actual_dom + def assert_dom_not_equal(expected, actual, message = nil) + expected_dom, actual_dom = doms_from_strings(expected, actual) + message ||= "Expected: #{expected_dom}\nActual: #{actual_dom}" + assert_not compare_doms(expected_dom, actual_dom), message end + + protected + # +doms_from_strings+ creates a Loofah::HTML::DocumentFragment for every string in strings + def doms_from_strings(*strings) + strings.map { |str| Loofah.fragment(str) } + end + + # +compare_doms+ takes two doms loops over all their children and compares each child via +equal_children?+ + def compare_doms(expected, actual) + expected.children.each_with_index do |child, i| + return false unless equal_children?(child, actual.children[i]) + end + true + end + + # +equal_children?+ compares children according to their type + # Determines further comparison via said type + # i.e. element node children with equal names has their attributes compared using +attributes_are_equal?+ + def equal_children?(child, other_child) + return false unless child.type == other_child.type + + case child.type + when Nokogiri::XML::Node::ELEMENT_NODE + child.name == other_child.name && attributes_are_equal?(child, other_child) + else + child.to_s == other_child.to_s + end + end + + # +attributes_are_equal?+ sorts elements attributes by name and compares + # each attribute by calling +equal_attribute?+ + # If those are +true+ the attributes are considered equal + def attributes_are_equal?(element, other_element) + first_nodes = element.attribute_nodes.sort_by { |a| a.name } + other_nodes = other_element.attribute_nodes.sort_by { |a| a.name } + + return false unless first_nodes.size == other_nodes.size + first_nodes.each_with_index do |attr, i| + return false unless equal_attribute?(attr, other_nodes[i]) + end + true + end + + # +equal_attribute?+ compares attributes by their name and value + def equal_attribute?(attr, other_attr) + attr.name == other_attr.name && attr.value == other_attr.value + end end end end -- cgit v1.2.3 From 2ff60e86486141b5a5aae6e1a0a7521fbd85a269 Mon Sep 17 00:00:00 2001 From: Timm Date: Wed, 17 Jul 2013 18:27:00 +0200 Subject: Removed tag.rb since it has been deprecated. --- .../lib/action_dispatch/testing/assertions.rb | 2 - .../lib/action_dispatch/testing/assertions/tag.rb | 135 --------------------- 2 files changed, 137 deletions(-) delete mode 100644 actionpack/lib/action_dispatch/testing/assertions/tag.rb (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions.rb b/actionpack/lib/action_dispatch/testing/assertions.rb index 226baf9ad0..8e6b93ba67 100644 --- a/actionpack/lib/action_dispatch/testing/assertions.rb +++ b/actionpack/lib/action_dispatch/testing/assertions.rb @@ -4,7 +4,6 @@ module ActionDispatch autoload :ResponseAssertions, 'action_dispatch/testing/assertions/response' autoload :RoutingAssertions, 'action_dispatch/testing/assertions/routing' autoload :SelectorAssertions, 'action_dispatch/testing/assertions/selector' - autoload :TagAssertions, 'action_dispatch/testing/assertions/tag' extend ActiveSupport::Concern @@ -12,7 +11,6 @@ module ActionDispatch include ResponseAssertions include RoutingAssertions include SelectorAssertions - include TagAssertions end end diff --git a/actionpack/lib/action_dispatch/testing/assertions/tag.rb b/actionpack/lib/action_dispatch/testing/assertions/tag.rb deleted file mode 100644 index e5fe30ba82..0000000000 --- a/actionpack/lib/action_dispatch/testing/assertions/tag.rb +++ /dev/null @@ -1,135 +0,0 @@ -require 'action_view/vendor/html-scanner' - -module ActionDispatch - module Assertions - # Pair of assertions to testing elements in the HTML output of the response. - module TagAssertions - # Asserts that there is a tag/node/element in the body of the response - # that meets all of the given conditions. The +conditions+ parameter must - # be a hash of any of the following keys (all are optional): - # - # * :tag: the node type must match the corresponding value - # * :attributes: a hash. The node's attributes must match the - # corresponding values in the hash. - # * :parent: a hash. The node's parent must match the - # corresponding hash. - # * :child: a hash. At least one of the node's immediate children - # must meet the criteria described by the hash. - # * :ancestor: a hash. At least one of the node's ancestors must - # meet the criteria described by the hash. - # * :descendant: a hash. At least one of the node's descendants - # must meet the criteria described by the hash. - # * :sibling: a hash. At least one of the node's siblings must - # meet the criteria described by the hash. - # * :after: a hash. The node must be after any sibling meeting - # the criteria described by the hash, and at least one sibling must match. - # * :before: a hash. The node must be before any sibling meeting - # the criteria described by the hash, and at least one sibling must match. - # * :children: a hash, for counting children of a node. Accepts - # the keys: - # * :count: either a number or a range which must equal (or - # include) the number of children that match. - # * :less_than: the number of matching children must be less - # than this number. - # * :greater_than: the number of matching children must be - # greater than this number. - # * :only: another hash consisting of the keys to use - # to match on the children, and only matching children will be - # counted. - # * :content: the textual content of the node must match the - # given value. This will not match HTML tags in the body of a - # tag--only text. - # - # Conditions are matched using the following algorithm: - # - # * if the condition is a string, it must be a substring of the value. - # * if the condition is a regexp, it must match the value. - # * if the condition is a number, the value must match number.to_s. - # * if the condition is +true+, the value must not be +nil+. - # * if the condition is +false+ or +nil+, the value must be +nil+. - # - # # Assert that there is a "span" tag - # assert_tag tag: "span" - # - # # Assert that there is a "span" tag with id="x" - # assert_tag tag: "span", attributes: { id: "x" } - # - # # Assert that there is a "span" tag using the short-hand - # assert_tag :span - # - # # Assert that there is a "span" tag with id="x" using the short-hand - # assert_tag :span, attributes: { id: "x" } - # - # # Assert that there is a "span" inside of a "div" - # assert_tag tag: "span", parent: { tag: "div" } - # - # # Assert that there is a "span" somewhere inside a table - # assert_tag tag: "span", ancestor: { tag: "table" } - # - # # Assert that there is a "span" with at least one "em" child - # assert_tag tag: "span", child: { tag: "em" } - # - # # Assert that there is a "span" containing a (possibly nested) - # # "strong" tag. - # assert_tag tag: "span", descendant: { tag: "strong" } - # - # # Assert that there is a "span" containing between 2 and 4 "em" tags - # # as immediate children - # assert_tag tag: "span", - # children: { count: 2..4, only: { tag: "em" } } - # - # # Get funky: assert that there is a "div", with an "ul" ancestor - # # and an "li" parent (with "class" = "enum"), and containing a - # # "span" descendant that contains text matching /hello world/ - # assert_tag tag: "div", - # ancestor: { tag: "ul" }, - # parent: { tag: "li", - # attributes: { class: "enum" } }, - # descendant: { tag: "span", - # child: /hello world/ } - # - # Please note: +assert_tag+ and +assert_no_tag+ only work - # with well-formed XHTML. They recognize a few tags as implicitly self-closing - # (like br and hr and such) but will not work correctly with tags - # that allow optional closing tags (p, li, td). You must explicitly - # close all of your tags to use these assertions. - def assert_tag(*opts) - opts = opts.size > 1 ? opts.last.merge({ :tag => opts.first.to_s }) : opts.first - tag = find_tag(opts) - assert tag, "expected tag, but no tag found matching #{opts.inspect} in:\n#{@response.body.inspect}" - end - - # Identical to +assert_tag+, but asserts that a matching tag does _not_ - # exist. (See +assert_tag+ for a full discussion of the syntax.) - # - # # Assert that there is not a "div" containing a "p" - # assert_no_tag tag: "div", descendant: { tag: "p" } - # - # # Assert that an unordered list is empty - # assert_no_tag tag: "ul", descendant: { tag: "li" } - # - # # Assert that there is not a "p" tag with between 1 to 3 "img" tags - # # as immediate children - # assert_no_tag tag: "p", - # children: { count: 1..3, only: { tag: "img" } } - def assert_no_tag(*opts) - opts = opts.size > 1 ? opts.last.merge({ :tag => opts.first.to_s }) : opts.first - tag = find_tag(opts) - assert !tag, "expected no tag, but found tag matching #{opts.inspect} in:\n#{@response.body.inspect}" - end - - def find_tag(conditions) - html_document.find(conditions) - end - - def find_all_tag(conditions) - html_document.find_all(conditions) - end - - def html_document - xml = @response.content_type =~ /xml$/ - @html_document ||= HTML::Document.new(@response.body, false, xml) - end - end - end -end -- cgit v1.2.3 From 8c0536c997f7037b2160807168b6fc2aa6dab800 Mon Sep 17 00:00:00 2001 From: Timm Date: Fri, 19 Jul 2013 19:19:13 +0200 Subject: The first attempt at abstracting argument parsing from selection methods. --- .../action_dispatch/testing/assertions/selector.rb | 195 ++++++++++++--------- 1 file changed, 114 insertions(+), 81 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 12023e6f77..aeebfbe1f4 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -59,39 +59,21 @@ module ActionDispatch # end def css_select(*args) # See assert_select to understand what's going on here. - arg = args.shift - - if arg.is_a?(HTML::Node) - root = arg - arg = args.shift - elsif arg == 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 defined?(@selected) && @selected - matches = [] + parser = ArgumentsParser.new(self, args, Proc.new do |arg, args| + # will only be called if we're a nested select, i.e. @selected is set + # the elements to match has already been selected, so we return the matches here + matches = [] @selected.each do |selected| subset = css_select(selected, HTML::Selector.new(arg.dup, args.dup)) subset.each do |match| - matches << match unless matches.any? { |m| m.equal?(match) } + matches << match unless matches.include?(match) end end - return matches - else - root = response_from_page - end - - case arg - when String - selector = HTML::Selector.new(arg, args) - when Array - selector = HTML::Selector.new(*arg) - when HTML::Selector - selector = arg - else raise ArgumentError, "Expecting a selector as the first argument" - end + end) - selector.select(root) + parser.selector.select(parser.root) end # An assertion that selects elements and makes one or more equality tests. @@ -182,72 +164,26 @@ module ActionDispatch # assert_select "[name=?]", /.+/ # Not empty # end def assert_select(*args, &block) - # Start with optional element followed by mandatory selector. - arg = args.shift @selected ||= nil - if arg.is_a?(HTML::Node) - # First argument is a node (tag or text, but also HTML root), - # so we know what we're selecting from. - root = arg - arg = args.shift - elsif arg == nil - # This usually happens when passing a node/element that - # happens to be 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 @selected + parser = ArgumentsParser.new(self, args, Proc.new do |_, _| root = HTML::Node.new(nil) root.children.concat @selected - else - # Otherwise just operate on the response document. - root = response_from_page - end + root + end) - # First or second argument is the selector: string and we pass - # all remaining arguments. Array and we pass the argument. Also - # accepts selector itself. - case arg - when String - selector = HTML::Selector.new(arg, args) - when Array - selector = HTML::Selector.new(*arg) - when HTML::Selector - selector = arg - else raise ArgumentError, "Expecting a selector as the first argument" - end + # Start with optional element followed by mandatory selector. + root = parser.root - # Next argument is used for equality tests. - equals = {} - case arg = args.shift - when Hash - equals = arg - when String, Regexp - equals[:text] = arg - when Integer - equals[:count] = arg - when Range - equals[:minimum] = arg.begin - equals[:maximum] = arg.end - when FalseClass - equals[:count] = 0 - when NilClass, TrueClass - equals[:minimum] = 1 - else raise ArgumentError, "I don't understand what you're trying to match" - end + # First or second argument is the selector + selector = parser.selector - # By default we're looking for at least one match. - if equals[:count] - equals[:minimum] = equals[:maximum] = equals[:count] - else - equals[:minimum] = 1 unless equals[:minimum] - end + # Next argument is used for equality tests. + equals = parser.equals # Last argument is the message we use if the assertion fails. - message = args.shift + message = parser.message #- message = "No match made with selector #{selector.inspect}" unless message - if args.shift - raise ArgumentError, "Not expecting that last argument, you either have too many arguments, or they're the wrong type" - end matches = selector.select(root) # If text/html, narrow down to those elements that match it. @@ -421,10 +357,107 @@ module ActionDispatch end protected + attr_accessor :root_for_nested_select_proc # +assert_select+ and +css_select+ call this to obtain the content in the HTML page. def response_from_page html_document.root end + + def nested_call? + defined(@selected) && @selected + end + + class ArgumentsParser #:nodoc: + attr_accessor :root, :selector + + def initialize(initiator, *args, &root_for_nested_call_proc) + raise ArgumentError, "ArgumentsParser expects a block for parsing a nested call's arguments" unless block_given? + + @initiator = initiator + @args = args + + # see +determine_root_from+ + @selector_is_second_argument = false + @root = determine_root_from(@args.shift) + + arg = @selector_is_second_argument ? @args.shift : @args.first + @selector = selector_from(arg, @args) + end + + def determine_root_from(possible_root) + if possible_root.is_a?(HTML::Node) + # First argument is a node (tag or text, but also HTML root), + # so we know what we're selecting from, + # we also know that the second argument is the selector + @selector_is_second_argument = true + + possible_root + elsif possible_root == nil + # This usually happens when passing a node/element that + # happens to be 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 @initiator.nested_call? + # Nesting selects + root_for_nested_select_proc.call(possible_root, @args) + else + # Otherwise just operate on the response document. + @initiator.response_from_page + end + end + + def selector_from(arg, args) + case arg + when String + HTML::Selector.new(arg, args) # pass all remaining arguments. + when Array + HTML::Selector.new(*arg) # pass the argument. + when HTML::Selector + arg # also accepts selector itself. + else raise ArgumentError, "Expecting a selector as the first argument" + end + end + + class HTMLArgumentsParser < ArgumentsParser + attr_accessor :equals, :message + def initialize(*) + super + @equals = assign_equals_from(@args.shift) + @message = @args.shift + + if @args.shift + raise ArgumentError, "Not expecting that last argument, you either have too many arguments, or they're the wrong type" + end + end + + def assign_equals_from(comparator) + equals = {} + case comparator + when Hash + equals = comparator + when String, Regexp + equals[:text] = comparator + when Integer + equals[:count] = comparator + when Range + equals[:minimum] = comparator.begin + equals[:maximum] = comparator.end + when FalseClass + equals[:count] = 0 + when NilClass, TrueClass + equals[: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 equals[:count] + equals[:minimum] = equals[:maximum] = equals[:count] + else + equals[:minimum] ||= 1 + end + equals + end + end + end end end end -- cgit v1.2.3 From a38c759819012470638005795d5affd6bf305ebc Mon Sep 17 00:00:00 2001 From: Timm Date: Fri, 19 Jul 2013 21:31:47 +0200 Subject: Changed name to selector. And a bunch of other things. --- .../action_dispatch/testing/assertions/selector.rb | 111 ++++++++++----------- 1 file changed, 51 insertions(+), 60 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index aeebfbe1f4..5ce541e178 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -1,5 +1,6 @@ require 'action_view/vendor/html-scanner' require 'active_support/core_ext/object/inclusion' +require 'loofah' #-- # Copyright (c) 2006 Assaf Arkin (http://labnotes.org) @@ -60,12 +61,11 @@ module ActionDispatch def css_select(*args) # See assert_select to understand what's going on here. - parser = ArgumentsParser.new(self, args, Proc.new do |arg, args| + parser = Selector.new(@selected, args, Proc.new do |css_selector| # will only be called if we're a nested select, i.e. @selected is set - # the elements to match has already been selected, so we return the matches here matches = [] @selected.each do |selected| - subset = css_select(selected, HTML::Selector.new(arg.dup, args.dup)) + subset = css_select(selected, css_selector) subset.each do |match| matches << match unless matches.include?(match) end @@ -73,7 +73,7 @@ module ActionDispatch return matches end) - parser.selector.select(parser.root) + parser.root.css(parser.css_selector) end # An assertion that selects elements and makes one or more equality tests. @@ -166,9 +166,9 @@ module ActionDispatch def assert_select(*args, &block) @selected ||= nil - parser = ArgumentsParser.new(self, args, Proc.new do |_, _| - root = HTML::Node.new(nil) - root.children.concat @selected + parser = HTMLSelector.new(@selected, args, Proc.new do |_| + root = Loofah.fragment('') + root.add_child @selected root end) @@ -176,7 +176,7 @@ module ActionDispatch root = parser.root # First or second argument is the selector - selector = parser.selector + selector = parser.css_selector # Next argument is used for equality tests. equals = parser.equals @@ -185,7 +185,7 @@ module ActionDispatch message = parser.message #- message = "No match made with selector #{selector.inspect}" unless message - matches = selector.select(root) + matches = root.css(selector) # If text/html, narrow down to those elements that match it. content_mismatch = nil if match_with = equals[:text] @@ -357,67 +357,59 @@ module ActionDispatch end protected - attr_accessor :root_for_nested_select_proc - # +assert_select+ and +css_select+ call this to obtain the content in the HTML page. - def response_from_page - html_document.root - end - - def nested_call? - defined(@selected) && @selected - end + class Selector #:nodoc: + attr_accessor :root, :css_selector - class ArgumentsParser #:nodoc: - attr_accessor :root, :selector + def initialize(selected, *args, &root_for_nested_call_proc) + raise ArgumentError, "ArgumentsParser expects a block for parsing a nested call's arguments" unless block_given? + @nested_call = selected - def initialize(initiator, *args, &root_for_nested_call_proc) - raise ArgumentError, "ArgumentsParser expects a block for parsing a nested call's arguments" unless block_given? + @args = args - @initiator = initiator - @args = args + # see +determine_root_from+ + @css_selector_is_second_argument = false + @root = determine_root_from(@args.shift) - # see +determine_root_from+ - @selector_is_second_argument = false - @root = determine_root_from(@args.shift) + arg = @css_selector_is_second_argument ? @args.shift : @args.first + @css_selector = css_selector(arg) + end - arg = @selector_is_second_argument ? @args.shift : @args.first - @selector = selector_from(arg, @args) - end + def response_from_page + @html_document ||= if @response.content_type =~ /xml$/ + Loofah.xml_fragment(@response.body) + else + Loofah.fragment(@response.body) + end + @html_document.root + end - def determine_root_from(possible_root) - if possible_root.is_a?(HTML::Node) - # First argument is a node (tag or text, but also HTML root), - # so we know what we're selecting from, - # we also know that the second argument is the selector - @selector_is_second_argument = true - - possible_root - elsif possible_root == nil - # This usually happens when passing a node/element that - # happens to be 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 @initiator.nested_call? - # Nesting selects - root_for_nested_select_proc.call(possible_root, @args) - else - # Otherwise just operate on the response document. - @initiator.response_from_page + def determine_root_from(root_or_selector) + if root_or_selector.is_a?(Nokogiri::XML::Node) + # First argument is a node (tag or text, but also HTML root), + # so we know what we're selecting from, + # we also know that the second argument is the selector + @css_selector_is_second_argument = true + + root_or_selector + elsif root_or_selector == 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 @nested_call + # root_or_selector is a selector since the first call failed + root_for_nested_select_proc.call(root_or_selector) + else + response_from_page + end end - end - def selector_from(arg, args) - case arg - when String - HTML::Selector.new(arg, args) # pass all remaining arguments. - when Array - HTML::Selector.new(*arg) # pass the argument. - when HTML::Selector - arg # also accepts selector itself. - else raise ArgumentError, "Expecting a selector as the first argument" + def css_selector_from(arg) + unless arg.is_a? String + raise ArgumentError, "Expecting a selector as the first argument" + end + arg end end - class HTMLArgumentsParser < ArgumentsParser + class HTMLSelector < Selector attr_accessor :equals, :message def initialize(*) super @@ -457,7 +449,6 @@ module ActionDispatch equals end end - end end end end -- cgit v1.2.3 From 328512ea5f30dd2e408bfb002fab9ed0e1b391ce Mon Sep 17 00:00:00 2001 From: Timm Date: Sat, 20 Jul 2013 12:25:13 +0200 Subject: Removed argument and root variable in assert_select proc. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 5ce541e178..c63dd1ca8a 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -166,10 +166,8 @@ module ActionDispatch def assert_select(*args, &block) @selected ||= nil - parser = HTMLSelector.new(@selected, args, Proc.new do |_| - root = Loofah.fragment('') - root.add_child @selected - root + parser = HTMLSelector.new(@selected, args, Proc.new do + Loofah.fragment('').tap { |fragment| fragment.add_child @selected } end) # Start with optional element followed by mandatory selector. -- cgit v1.2.3 From cb215c9f7d9e4a9d469abdbd87c0dd909161db95 Mon Sep 17 00:00:00 2001 From: Timm Date: Sat, 20 Jul 2013 12:47:10 +0200 Subject: Simplified the first delete_if loop in assert_select to use Loofah's text method. --- .../action_dispatch/testing/assertions/selector.rb | 27 +++++++++++----------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index c63dd1ca8a..43eb899348 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -188,20 +188,11 @@ module ActionDispatch content_mismatch = nil if match_with = equals[:text] matches.delete_if do |match| - text = "" - stack = match.children.reverse - while node = stack.pop - if node.tag? - stack.concat node.children.reverse - else - content = node.content - text << content - end - end + text = match.text text.strip! unless NO_STRIP.include?(match.name) text.sub!(/\A\n/, '') if match.name == "textarea" - unless match_with.is_a?(Regexp) ? (text =~ match_with) : (text == match_with.to_s) - content_mismatch ||= sprintf("<%s> expected but was\n<%s>", match_with, text) + unless content_matches?(match_with, text) + content_mismatch ||= sprintf("<%s> expected but was\n<%s>.", match_with, text) true end end @@ -209,8 +200,8 @@ module ActionDispatch matches.delete_if do |match| html = match.children.map(&:to_s).join html.strip! unless NO_STRIP.include?(match.name) - unless match_with.is_a?(Regexp) ? (html =~ match_with) : (html == match_with.to_s) - content_mismatch ||= sprintf("<%s> expected but was\n<%s>", match_with, html) + unless content_matches?(match_with, html) + content_mismatch ||= sprintf("<%s> expected but was\n<%s>.", match_with, html) true end end @@ -355,6 +346,14 @@ module ActionDispatch end protected + def content_matches?(match_with, content) + if match_with.is_a?(Regexp) + content =~ match_with + else + content == match_with.to_s + end + end + class Selector #:nodoc: attr_accessor :root, :css_selector -- cgit v1.2.3 From 6fa3af8876a12b21871bf6e5fa45ca041d8ae235 Mon Sep 17 00:00:00 2001 From: Timm Date: Sat, 20 Jul 2013 13:00:36 +0200 Subject: Removed more lines of code in assert_select. --- .../lib/action_dispatch/testing/assertions/selector.rb | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 43eb899348..6aa4fea4f2 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -191,18 +191,16 @@ module ActionDispatch text = match.text text.strip! unless NO_STRIP.include?(match.name) text.sub!(/\A\n/, '') if match.name == "textarea" - unless content_matches?(match_with, text) - content_mismatch ||= sprintf("<%s> expected but was\n<%s>.", match_with, text) - true + content_matches?(match_with, text) do |error_message| + content_mismatch ||= error_message end end elsif match_with = equals[:html] matches.delete_if do |match| - html = match.children.map(&:to_s).join + html = match.to_s html.strip! unless NO_STRIP.include?(match.name) - unless content_matches?(match_with, html) - content_mismatch ||= sprintf("<%s> expected but was\n<%s>.", match_with, html) - true + content_matches?(match_with, html) do |error_message| + content_mismatch ||= error_message end end end @@ -352,6 +350,7 @@ module ActionDispatch else content == match_with.to_s end + yield sprintf("<%s> expected but was\n<%s>.", match_with, content) if block_given? end class Selector #:nodoc: -- cgit v1.2.3 From 3b942d36bcaac364096ebb3248c1fc66dd269677 Mon Sep 17 00:00:00 2001 From: Timm Date: Sat, 20 Jul 2013 13:06:23 +0200 Subject: Removed more redundant lines. Removed fix_content block that circumvented a bug in html-scanner. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 6aa4fea4f2..fe48de11d1 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -295,14 +295,8 @@ module ActionDispatch raise ArgumentError, "Argument is optional, and may be node or array of nodes" end - fix_content = lambda do |node| - # Gets around a bug in the Rails 1.1 HTML parser. - node.content.gsub(/)?/m) { Rack::Utils.escapeHTML($1) } - end - selected = elements.map do |elem| - text = elem.children.select{ |c| not c.tag? }.map{ |c| fix_content[c] }.join - root = HTML::Document.new(CGI.unescapeHTML("#{text}")).root + root = Loofah.fragment(CGI.unescapeHTML("#{elem.text}")).root css_select(root, "encoded:root", &block)[0] end -- cgit v1.2.3 From 0538d26c15bd64a3b0c052a62f4d480e01b914bd Mon Sep 17 00:00:00 2001 From: Timm Date: Sat, 20 Jul 2013 13:14:23 +0200 Subject: Changed comparison from HTML::Node to Nokogiri::XML::Node in assert_select_encoded. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index fe48de11d1..2c1ad76ba9 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -285,7 +285,7 @@ module ActionDispatch case element when Array elements = element - when HTML::Node + when Nokogiri::XML::Node elements = [element] when nil unless elements = @selected -- cgit v1.2.3 From 205bfe9af80ad6bfee323f72e421587e6ad7e26f Mon Sep 17 00:00:00 2001 From: Timm Date: Sat, 20 Jul 2013 13:43:58 +0200 Subject: Changed css_select and pulled out response_from_page from Selector. --- .../action_dispatch/testing/assertions/selector.rb | 40 +++++++++------------- 1 file changed, 17 insertions(+), 23 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 2c1ad76ba9..883073ad3e 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -59,21 +59,15 @@ module ActionDispatch # ... # end def css_select(*args) - # See assert_select to understand what's going on here. - - parser = Selector.new(@selected, args, Proc.new do |css_selector| - # will only be called if we're a nested select, i.e. @selected is set - matches = [] - @selected.each do |selected| - subset = css_select(selected, css_selector) - subset.each do |match| - matches << match unless matches.include?(match) - end - end - return matches - end) + raise ArgumentError, "you at least need a selector" if args.empty? - parser.root.css(parser.css_selector) + if args.first.is_a?(String) # allow nokogiri's ability to use several selectors + root, selectors = response_from_page, args + else + root, selectors = args.shift, args + end + + root.css(selectors) end # An assertion that selects elements and makes one or more equality tests. @@ -347,6 +341,15 @@ module ActionDispatch yield sprintf("<%s> expected but was\n<%s>.", match_with, content) if block_given? end + def response_from_page + @html_document ||= if @response.content_type =~ /xml$/ + Loofah.xml_fragment(@response.body) + else + Loofah.fragment(@response.body) + end + @html_document.root + end + class Selector #:nodoc: attr_accessor :root, :css_selector @@ -364,15 +367,6 @@ module ActionDispatch @css_selector = css_selector(arg) end - def response_from_page - @html_document ||= if @response.content_type =~ /xml$/ - Loofah.xml_fragment(@response.body) - else - Loofah.fragment(@response.body) - end - @html_document.root - end - def determine_root_from(root_or_selector) if root_or_selector.is_a?(Nokogiri::XML::Node) # First argument is a node (tag or text, but also HTML root), -- cgit v1.2.3 From afa4caf2bdd35e959674152d89b49968129e9fc9 Mon Sep 17 00:00:00 2001 From: Timm Date: Sat, 20 Jul 2013 14:09:21 +0200 Subject: Updated selector to not have reponse_from_page. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 883073ad3e..586a6bd1ff 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -61,7 +61,7 @@ module ActionDispatch def css_select(*args) raise ArgumentError, "you at least need a selector" if args.empty? - if args.first.is_a?(String) # allow nokogiri's ability to use several selectors + if args.first.is_a?(String) # allow nokogiri's ability to use more selectors root, selectors = response_from_page, args else root, selectors = args.shift, args @@ -160,8 +160,8 @@ module ActionDispatch def assert_select(*args, &block) @selected ||= nil - parser = HTMLSelector.new(@selected, args, Proc.new do - Loofah.fragment('').tap { |fragment| fragment.add_child @selected } + parser = HTMLSelector.new(@selected, reponse_from_page, args, Proc.new do + Loofah.fragment('').tap { |f| f.add_child @selected } end) # Start with optional element followed by mandatory selector. @@ -353,9 +353,10 @@ module ActionDispatch class Selector #:nodoc: attr_accessor :root, :css_selector - def initialize(selected, *args, &root_for_nested_call_proc) + def initialize(selected, page, *args, &root_for_nested_call_proc) raise ArgumentError, "ArgumentsParser expects a block for parsing a nested call's arguments" unless block_given? @nested_call = selected + @page = page @args = args @@ -381,7 +382,7 @@ module ActionDispatch # root_or_selector is a selector since the first call failed root_for_nested_select_proc.call(root_or_selector) else - response_from_page + @page end end -- cgit v1.2.3 From 744cba7b21ba7fc8717c8aeb50a139c0e5238af3 Mon Sep 17 00:00:00 2001 From: Timm Date: Sat, 20 Jul 2013 14:13:22 +0200 Subject: Removed the custom selected proc. It's no longer needed. --- .../lib/action_dispatch/testing/assertions/selector.rb | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 586a6bd1ff..7092b17042 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -160,9 +160,7 @@ module ActionDispatch def assert_select(*args, &block) @selected ||= nil - parser = HTMLSelector.new(@selected, reponse_from_page, args, Proc.new do - Loofah.fragment('').tap { |f| f.add_child @selected } - end) + parser = HTMLSelector.new(@selected, reponse_from_page, args) # Start with optional element followed by mandatory selector. root = parser.root @@ -353,9 +351,9 @@ module ActionDispatch class Selector #:nodoc: attr_accessor :root, :css_selector - def initialize(selected, page, *args, &root_for_nested_call_proc) + def initialize(selected, page, *args) raise ArgumentError, "ArgumentsParser expects a block for parsing a nested call's arguments" unless block_given? - @nested_call = selected + @selected = selected @page = page @args = args @@ -369,18 +367,18 @@ module ActionDispatch end def determine_root_from(root_or_selector) - if root_or_selector.is_a?(Nokogiri::XML::Node) + if root_or_selector == 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 root_or_selector.is_a?(Nokogiri::XML::Node) # First argument is a node (tag or text, but also HTML root), # so we know what we're selecting from, # we also know that the second argument is the selector @css_selector_is_second_argument = true root_or_selector - elsif root_or_selector == 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 @nested_call + elsif @selected # root_or_selector is a selector since the first call failed - root_for_nested_select_proc.call(root_or_selector) + Loofah.fragment('').tap { |f| f.add_child @selected } else @page end -- cgit v1.2.3 From 63938f670bf74596e09ef6affbd850e4cff3f9e5 Mon Sep 17 00:00:00 2001 From: Timm Date: Sat, 20 Jul 2013 14:19:47 +0200 Subject: Renamed Selector to ArgumentFilter. Put code from HTMLSelector to ArgumentFilter. --- .../action_dispatch/testing/assertions/selector.rb | 98 +++++++++------------- 1 file changed, 39 insertions(+), 59 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 7092b17042..3c19b23fa6 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -160,20 +160,12 @@ module ActionDispatch def assert_select(*args, &block) @selected ||= nil - parser = HTMLSelector.new(@selected, reponse_from_page, args) + filter = ArgumentFilter.new(@selected, response_from_page, args) - # Start with optional element followed by mandatory selector. - root = parser.root - - # First or second argument is the selector - selector = parser.css_selector - - # Next argument is used for equality tests. - equals = parser.equals - - # Last argument is the message we use if the assertion fails. - message = parser.message - #- message = "No match made with selector #{selector.inspect}" unless message + root = filter.root + selector = filter.css_selector + equals = filter.comparisons + message = filter.message matches = root.css(selector) # If text/html, narrow down to those elements that match it. @@ -348,22 +340,31 @@ module ActionDispatch @html_document.root end - class Selector #:nodoc: - attr_accessor :root, :css_selector + class ArgumentFilter #:nodoc: + attr_accessor :root, :css_selector, :comparisons, :message def initialize(selected, page, *args) - raise ArgumentError, "ArgumentsParser expects a block for parsing a nested call's arguments" unless block_given? - @selected = selected - @page = page + @selected, @page = selected, page + + # Start with optional element followed by mandatory selector. + @root = determine_root_from(args.shift) + + # First or second argument is the selector + selector = @css_selector_is_second_argument ? args.shift : args.first + unless selector.is_a? String + raise ArgumentError, "Expecting a selector as the first argument" + end + @css_selector = selector - @args = args + # Next argument is used for equality tests. + @comparisons = comparisons_from(args.shift) - # see +determine_root_from+ - @css_selector_is_second_argument = false - @root = determine_root_from(@args.shift) + # Last argument is the message we use if the assertion fails. + @message = args.shift - arg = @css_selector_is_second_argument ? @args.shift : @args.first - @css_selector = css_selector(arg) + if args.shift + raise ArgumentError, "Not expecting that last argument, you either have too many arguments, or they're the wrong type" + end end def determine_root_from(root_or_selector) @@ -372,64 +373,43 @@ module ActionDispatch elsif root_or_selector.is_a?(Nokogiri::XML::Node) # First argument is a node (tag or text, but also HTML root), # so we know what we're selecting from, - # we also know that the second argument is the selector @css_selector_is_second_argument = true root_or_selector elsif @selected - # root_or_selector is a selector since the first call failed + # nested call - wrap in document fragment Loofah.fragment('').tap { |f| f.add_child @selected } else @page end end - def css_selector_from(arg) - unless arg.is_a? String - raise ArgumentError, "Expecting a selector as the first argument" - end - arg - end - end - - class HTMLSelector < Selector - attr_accessor :equals, :message - def initialize(*) - super - @equals = assign_equals_from(@args.shift) - @message = @args.shift - - if @args.shift - raise ArgumentError, "Not expecting that last argument, you either have too many arguments, or they're the wrong type" - end - end - - def assign_equals_from(comparator) - equals = {} + def comparisons_from(comparator) + comparisons = {} case comparator when Hash - equals = comparator + comparisons = comparator when String, Regexp - equals[:text] = comparator + comparisons[:text] = comparator when Integer - equals[:count] = comparator + comparisons[:count] = comparator when Range - equals[:minimum] = comparator.begin - equals[:maximum] = comparator.end + comparisons[:minimum] = comparator.begin + comparisons[:maximum] = comparator.end when FalseClass - equals[:count] = 0 + comparisons[:count] = 0 when NilClass, TrueClass - equals[:minimum] = 1 + 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 equals[:count] - equals[:minimum] = equals[:maximum] = equals[:count] + if comparisons[:count] + comparisons[:minimum] = comparisons[:maximum] = comparisons[:count] else - equals[:minimum] ||= 1 + comparisons[:minimum] ||= 1 end - equals + comparisons end end end -- cgit v1.2.3 From ff0939a8f47bd64a762e4b5bf0122f7f0edb72e7 Mon Sep 17 00:00:00 2001 From: Timm Date: Sat, 20 Jul 2013 15:11:25 +0200 Subject: Added filter_matches to reduce line count in assert_select. --- .../action_dispatch/testing/assertions/selector.rb | 43 ++++++++++------------ 1 file changed, 19 insertions(+), 24 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 3c19b23fa6..11447b341d 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -161,7 +161,6 @@ module ActionDispatch @selected ||= nil filter = ArgumentFilter.new(@selected, response_from_page, args) - root = filter.root selector = filter.css_selector equals = filter.comparisons @@ -170,24 +169,10 @@ module ActionDispatch matches = root.css(selector) # If text/html, narrow down to those elements that match it. content_mismatch = nil - if match_with = equals[:text] - matches.delete_if do |match| - text = match.text - text.strip! unless NO_STRIP.include?(match.name) - text.sub!(/\A\n/, '') if match.name == "textarea" - content_matches?(match_with, text) do |error_message| - content_mismatch ||= error_message - end - end - elsif match_with = equals[:html] - matches.delete_if do |match| - html = match.to_s - html.strip! unless NO_STRIP.include?(match.name) - content_matches?(match_with, html) do |error_message| - content_mismatch ||= error_message - end - end + filter_matches(matches, equals) do |mismatch| + content_mismatch ||= mismatch end + # Expecting foo found bar element only if found zero, not if # found one but expecting two. message ||= content_mismatch if matches.empty? @@ -322,13 +307,23 @@ module ActionDispatch end protected - def content_matches?(match_with, content) - if match_with.is_a?(Regexp) - content =~ match_with - else - content == match_with.to_s + def filter_matches(matches, options) + match_with = options[:text] || options[:html] + return unless match_with + + text_matches = options.has_key?(:text) + matches.delete_if do |match| + # Preserve html markup with to_s if not matching text elements + content = text_matches ? match.text : match.to_s + + content.strip! unless NO_STRIP.include?(match.name) + content.sub!(/\A\n/, '') if text_matches && match.name == "textarea" + + unless match_with.is_a?(Regexp) ? (content =~ match_with) : (content == match_with.to_s) + yield sprintf("<%s> expected but was\n<%s>.", match_with, content) + true + end end - yield sprintf("<%s> expected but was\n<%s>.", match_with, content) if block_given? end def response_from_page -- cgit v1.2.3 From b4258f8dfa0bc2487277d0a388aed176978eb5af Mon Sep 17 00:00:00 2001 From: Timm Date: Sat, 20 Jul 2013 19:50:32 +0200 Subject: Replaced fragment calls with document, since we assume the responses are complete documents. --- .../lib/action_dispatch/testing/assertions/selector.rb | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 11447b341d..cf87a5bac6 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -161,12 +161,10 @@ module ActionDispatch @selected ||= nil filter = ArgumentFilter.new(@selected, response_from_page, args) - root = filter.root selector = filter.css_selector equals = filter.comparisons - message = filter.message - matches = root.css(selector) + matches = filter.root.css(selector) # If text/html, narrow down to those elements that match it. content_mismatch = nil filter_matches(matches, equals) do |mismatch| @@ -175,6 +173,7 @@ module ActionDispatch # Expecting foo found bar element only if found zero, not if # found one but expecting two. + message = filter.message message ||= content_mismatch if matches.empty? # Test minimum/maximum occurrence. min, max, count = equals[:minimum], equals[:maximum], equals[:count] @@ -265,7 +264,7 @@ module ActionDispatch end selected = elements.map do |elem| - root = Loofah.fragment(CGI.unescapeHTML("#{elem.text}")).root + root = Loofah.document(CGI.unescapeHTML("#{elem.text}")).root css_select(root, "encoded:root", &block)[0] end @@ -299,7 +298,7 @@ module ActionDispatch deliveries.each do |delivery| (delivery.parts.empty? ? [delivery] : delivery.parts).each do |part| if part["Content-Type"].to_s =~ /^text\/html\W/ - root = HTML::Document.new(part.body.to_s).root + root = Loofah.document(part.body.to_s).root assert_select root, ":root", &block end end @@ -328,9 +327,9 @@ module ActionDispatch def response_from_page @html_document ||= if @response.content_type =~ /xml$/ - Loofah.xml_fragment(@response.body) + Loofah.xml_document(@response.body) else - Loofah.fragment(@response.body) + Loofah.document(@response.body) end @html_document.root end @@ -372,8 +371,8 @@ module ActionDispatch root_or_selector elsif @selected - # nested call - wrap in document fragment - Loofah.fragment('').tap { |f| f.add_child @selected } + # nested call - wrap in document + Loofah.document('').tap { |d| d.add_child @selected } else @page end -- cgit v1.2.3 From 95afa79439c4f241e2eb68c6f838c355b9f6535e Mon Sep 17 00:00:00 2001 From: Timm Date: Sat, 20 Jul 2013 19:51:12 +0200 Subject: Changed some documentation for css_select. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index cf87a5bac6..3f2037eaea 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -61,7 +61,7 @@ module ActionDispatch def css_select(*args) raise ArgumentError, "you at least need a selector" if args.empty? - if args.first.is_a?(String) # allow nokogiri's ability to use more selectors + if args.first.is_a?(String) # use nokogiri's ability for more selectors root, selectors = response_from_page, args else root, selectors = args.shift, args -- cgit v1.2.3 From 332ccb35a19987d826ccf000238aa61c1db80de6 Mon Sep 17 00:00:00 2001 From: Timm Date: Sat, 20 Jul 2013 20:07:04 +0200 Subject: Added assert_size_match! with the assertions for assert_select. --- .../action_dispatch/testing/assertions/selector.rb | 32 ++++++++++++---------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 3f2037eaea..2488e761f1 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -175,21 +175,10 @@ module ActionDispatch # found one but expecting two. message = filter.message message ||= content_mismatch if matches.empty? - # Test minimum/maximum occurrence. - min, max, count = equals[:minimum], equals[:maximum], equals[:count] - - # FIXME: minitest provides messaging when we use assert_operator, - # so is this custom message really needed? - message = message || %(Expected #{count_description(min, max, count)} matching "#{selector.to_s}", found #{matches.size}) - if count - assert_equal count, matches.size, message - else - assert_operator matches.size, :>=, min, message if min - assert_operator matches.size, :<=, max, message if max - end + assert_size_match!(matches.size, equals, selector, message) - # If a block is given call that block. Set @selected to allow - # nested assert_select, which can be nested several levels deep. + # Set @selected to allow nested assert_select. + # Can be nested several levels deep. if block_given? && !matches.empty? begin in_scope, @selected = @selected, matches @@ -325,6 +314,21 @@ module ActionDispatch end end + # +equals+ must contain :minimum, :maximum and :count keys + def assert_size_match!(size, equals, selector, message = nil) + min, max, count = equals[:minimum], equals[:maximum], equals[:count] + + # FIXME: minitest provides messaging when we use assert_operator, + # so is this custom message really needed? + message ||= %(Expected #{count_description(min, max, count)} matching "#{selector.to_s}", found #{size}.) + if count + assert_equal size, count, message + else + assert_operator size, :>=, min, message if min + assert_operator size, :<=, max, message if max + end + end + def response_from_page @html_document ||= if @response.content_type =~ /xml$/ Loofah.xml_document(@response.body) -- cgit v1.2.3 From 7ef141a7fc3bd089a9b8c31e69f702596ae91535 Mon Sep 17 00:00:00 2001 From: Timm Date: Sun, 21 Jul 2013 10:28:27 +0200 Subject: Removed redundant comments from assert_select. Cleaned up a comment. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 2488e761f1..47e5c8e0e6 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -165,7 +165,6 @@ module ActionDispatch equals = filter.comparisons matches = filter.root.css(selector) - # If text/html, narrow down to those elements that match it. content_mismatch = nil filter_matches(matches, equals) do |mismatch| content_mismatch ||= mismatch @@ -188,7 +187,6 @@ module ActionDispatch end end - # Returns all matches elements. matches end @@ -370,7 +368,7 @@ module ActionDispatch 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 root_or_selector.is_a?(Nokogiri::XML::Node) # First argument is a node (tag or text, but also HTML root), - # so we know what we're selecting from, + # so we know what we're selecting from. @css_selector_is_second_argument = true root_or_selector -- cgit v1.2.3 From 9893a2896bbde50205e850b616ca0d4d196b924d Mon Sep 17 00:00:00 2001 From: Timm Date: Mon, 22 Jul 2013 22:25:23 +0200 Subject: Changed early return for filter_matches as well as reassigning matches. Meddled with initialize in ArgumentFilter. --- .../lib/action_dispatch/testing/assertions/selector.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 47e5c8e0e6..7a1176485e 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -166,7 +166,7 @@ module ActionDispatch matches = filter.root.css(selector) content_mismatch = nil - filter_matches(matches, equals) do |mismatch| + matches = filter_matches(matches, equals) do |mismatch| content_mismatch ||= mismatch end @@ -295,10 +295,10 @@ module ActionDispatch protected def filter_matches(matches, options) match_with = options[:text] || options[:html] - return unless match_with + return matches unless match_with text_matches = options.has_key?(:text) - matches.delete_if do |match| + matches.reject do |match| # Preserve html markup with to_s if not matching text elements content = text_matches ? match.text : match.to_s @@ -339,14 +339,14 @@ module ActionDispatch class ArgumentFilter #:nodoc: attr_accessor :root, :css_selector, :comparisons, :message - def initialize(selected, page, *args) + def initialize(selected, page, args) @selected, @page = selected, page # Start with optional element followed by mandatory selector. - @root = determine_root_from(args.shift) + @root = determine_root_from(args.first) # First or second argument is the selector - selector = @css_selector_is_second_argument ? args.shift : args.first + selector = @css_selector_is_second_argument ? args.shift(2).last : args.shift unless selector.is_a? String raise ArgumentError, "Expecting a selector as the first argument" end -- cgit v1.2.3 From 11fc26b96f6c51643aced40e4522c74036c7458d Mon Sep 17 00:00:00 2001 From: Timm Date: Tue, 23 Jul 2013 15:20:15 +0200 Subject: Initialized @css_selector_is_second_argument in determine_root_from. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 7a1176485e..02f59e3db3 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -364,6 +364,7 @@ module ActionDispatch end def determine_root_from(root_or_selector) + @css_selector_is_second_argument = false if root_or_selector == 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 root_or_selector.is_a?(Nokogiri::XML::Node) -- cgit v1.2.3 From 6aea3bc149bf7ae265d335601cf9c173d7792d58 Mon Sep 17 00:00:00 2001 From: Timm Date: Tue, 23 Jul 2013 16:36:15 +0200 Subject: Changed filter_matches to return a new NodeSet instead of Array. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 02f59e3db3..ff7b611228 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -298,7 +298,7 @@ module ActionDispatch return matches unless match_with text_matches = options.has_key?(:text) - matches.reject do |match| + remaining = matches.reject do |match| # Preserve html markup with to_s if not matching text elements content = text_matches ? match.text : match.to_s @@ -310,6 +310,7 @@ module ActionDispatch true end end + Nokogiri::XML::NodeSet.new(matches.document, remaining) end # +equals+ must contain :minimum, :maximum and :count keys -- cgit v1.2.3 From 63fc9f1f4f42c962c59ef9068d8542552ce0f887 Mon Sep 17 00:00:00 2001 From: Timm Date: Tue, 23 Jul 2013 19:31:24 +0200 Subject: Readded html_document method since it is used integration tests. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index ff7b611228..5045197415 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -329,12 +329,16 @@ module ActionDispatch end def response_from_page + html_document.root + end + + # +html_document+ is used in testing/integration.rb + def html_document @html_document ||= if @response.content_type =~ /xml$/ Loofah.xml_document(@response.body) else Loofah.document(@response.body) end - @html_document.root end class ArgumentFilter #:nodoc: -- cgit v1.2.3 From bc1363eb561f8dc739d9e9571ebf85c0ea292eee Mon Sep 17 00:00:00 2001 From: Timm Date: Tue, 23 Jul 2013 20:42:08 +0200 Subject: Updated documentation to remove mention of HTML::Selector and clarify what is expected of a selector now. --- .../action_dispatch/testing/assertions/selector.rb | 30 +++++++--------------- 1 file changed, 9 insertions(+), 21 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 5045197415..5338278810 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -23,22 +23,19 @@ module ActionDispatch # # * +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. - # - # Also see HTML::Selector to learn how to use selectors. module SelectorAssertions # Select and return all matching elements. # # If called with a single argument, uses that argument as a selector - # to match all elements of the current page. Returns an empty array - # if no match is found. + # to match all elements of the current page. Returns an empty + # Nokogiri::XML::NodeSet if no match is found. # - # If called with two arguments, uses the first argument as the base + # If called with two arguments, uses the first argument as the root # element and the second argument as the selector. Attempts to match the - # base element and any of its children. Returns an empty array if no - # match is found. + # root element and any of its children. + # Returns empty Nokogiri::XML::NodeSet if no match is found. # - # The selector may be a CSS selector expression (String), an expression - # with substitution values (Array) or an HTML::Selector object. + # The selector may be a CSS selector expression (String). # # # Selects all div tags # divs = css_select("div") @@ -76,7 +73,7 @@ module ActionDispatch # starting from (and including) that element and all its children in # depth-first order. # - # If no element if specified, calling +assert_select+ selects from the + # If no element is specified, calling +assert_select+ selects from the # response HTML unless +assert_select+ is called from within an +assert_select+ block. # # When called with a block +assert_select+ passes an array of selected elements @@ -99,8 +96,7 @@ module ActionDispatch # assert_select "li", 8 # end # - # The selector may be a CSS selector expression (String), an expression - # with substitution values, or an HTML::Selector object. + # The selector may be a CSS selector expression (String). # # === Equality Tests # @@ -149,14 +145,6 @@ module ActionDispatch # # # Test the content and style # assert_select "body div.header ul.menu" - # - # # Use substitution values - # assert_select "ol>li#?", /item-\d+/ - # - # # All input fields in the form have a name - # assert_select "form input" do - # assert_select "[name=?]", /.+/ # Not empty - # end def assert_select(*args, &block) @selected ||= nil @@ -299,7 +287,7 @@ module ActionDispatch text_matches = options.has_key?(:text) remaining = matches.reject do |match| - # Preserve html markup with to_s if not matching text elements + # Preserve markup with to_s for html elements content = text_matches ? match.text : match.to_s content.strip! unless NO_STRIP.include?(match.name) -- cgit v1.2.3 From 9eada2daf812ae95d47a22ebe4ecc058a980a38b Mon Sep 17 00:00:00 2001 From: Timm Date: Wed, 24 Jul 2013 13:12:27 +0200 Subject: Readded some documentation about substitution values. --- .../lib/action_dispatch/testing/assertions/selector.rb | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 5338278810..feb98f7e2b 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -35,7 +35,8 @@ module ActionDispatch # root element and any of its children. # Returns empty Nokogiri::XML::NodeSet if no match is found. # - # The selector may be a CSS selector expression (String). + # The selector may be a CSS selector expression (String) or an expression + # with substitution values (Array). # # # Selects all div tags # divs = css_select("div") @@ -96,7 +97,8 @@ module ActionDispatch # assert_select "li", 8 # end # - # The selector may be a CSS selector expression (String). + # The selector may be a CSS selector expression (String) or an expression + # with substitution values (Array). # # === Equality Tests # @@ -145,6 +147,14 @@ module ActionDispatch # # # Test the content and style # assert_select "body div.header ul.menu" + # + # # Use substitution values + # assert_select "ol>li#?", /item-\d+/ + # + # # All input fields in the form have a name + # assert_select "form input" do + # assert_select "[name=?]", /.+/ # Not empty + # end def assert_select(*args, &block) @selected ||= nil -- cgit v1.2.3 From 1e4f1ab95e8059d899736d6e329f18c6d23b444e Mon Sep 17 00:00:00 2001 From: Timm Date: Wed, 24 Jul 2013 16:01:36 +0200 Subject: Added implementation for substitution values via Nokogiri's custom pseudo classes. --- .../action_dispatch/testing/assertions/selector.rb | 40 +++++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index feb98f7e2b..6151491238 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -162,7 +162,7 @@ module ActionDispatch selector = filter.css_selector equals = filter.comparisons - matches = filter.root.css(selector) + matches = filter.root.css(selector, filter.substitution_context) content_mismatch = nil matches = filter_matches(matches, equals) do |mismatch| content_mismatch ||= mismatch @@ -350,10 +350,7 @@ module ActionDispatch # First or second argument is the selector selector = @css_selector_is_second_argument ? args.shift(2).last : args.shift - unless selector.is_a? String - raise ArgumentError, "Expecting a selector as the first argument" - end - @css_selector = selector + @css_selector = selector_from(selector, args) # Next argument is used for equality tests. @comparisons = comparisons_from(args.shift) @@ -384,6 +381,39 @@ module ActionDispatch end end + def selector_from(selector, substitution_values) + unless selector.is_a? String + raise ArgumentError, "Expecting a selector as the first argument" + end + while selector.index('?') + break if substitution_values.empty? + value = substitution_values.shift + if value.is_a?(Regexp) + value = substitution_context.add_regex value + end + selector.sub!('?', value) + end + selector + end + + # used for regex substitution in selectors + def substitution_context + @substitution_context ||= Class.new do + # +regex+ will be a +String+ + def match(matches, attribute, regex) + matches.find_all { |node| node[attribute] =~ @regexes[regex] } + end + + def add_regex(regex) + @regexes ||= [] + @regexes.push(regex) + id_for(regex) + end + + def id_for(regex); @regexes.index(regex).to_s; end + end.new + end + def comparisons_from(comparator) comparisons = {} case comparator -- cgit v1.2.3 From 8d6c92ceccdd5ea845af678fe87854c4ae6e253f Mon Sep 17 00:00:00 2001 From: Timm Date: Wed, 24 Jul 2013 16:03:14 +0200 Subject: Fixed nested assert_select bug. Trying to create a full document for a nested call that already had a document. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 6151491238..c91b5d5887 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -375,7 +375,7 @@ module ActionDispatch root_or_selector elsif @selected # nested call - wrap in document - Loofah.document('').tap { |d| d.add_child @selected } + Loofah.fragment('').tap { |d| d.add_child @selected } else @page end -- cgit v1.2.3 From 5f756e3ebeaa195dcda8dd516c320ae21d5cafc8 Mon Sep 17 00:00:00 2001 From: Timm Date: Wed, 24 Jul 2013 16:45:58 +0200 Subject: Added a proper substitution context class. Changed ArgumentFilter to be a selector. It is now called HTMLSelector. --- .../action_dispatch/testing/assertions/selector.rb | 81 +++++++++++++--------- 1 file changed, 47 insertions(+), 34 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index c91b5d5887..0ba3fffd5a 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -158,11 +158,10 @@ module ActionDispatch def assert_select(*args, &block) @selected ||= nil - filter = ArgumentFilter.new(@selected, response_from_page, args) - selector = filter.css_selector - equals = filter.comparisons + selector = HTMLSelector.new(@selected, response_from_page, args) - matches = filter.root.css(selector, filter.substitution_context) + matches = selector.select + equals = selector.comparisons content_mismatch = nil matches = filter_matches(matches, equals) do |mismatch| content_mismatch ||= mismatch @@ -170,9 +169,9 @@ module ActionDispatch # Expecting foo found bar element only if found zero, not if # found one but expecting two. - message = filter.message + message = selector.message message ||= content_mismatch if matches.empty? - assert_size_match!(matches.size, equals, selector, message) + assert_size_match!(matches.size, equals, selector.source, message) # Set @selected to allow nested assert_select. # Can be nested several levels deep. @@ -339,7 +338,7 @@ module ActionDispatch end end - class ArgumentFilter #:nodoc: + class HTMLSelector #:nodoc: attr_accessor :root, :css_selector, :comparisons, :message def initialize(selected, page, args) @@ -363,6 +362,12 @@ module ActionDispatch end end + alias :source :css_selector + + def select + root.css(css_selector, context) + end + def determine_root_from(root_or_selector) @css_selector_is_second_argument = false if root_or_selector == nil @@ -385,33 +390,7 @@ module ActionDispatch unless selector.is_a? String raise ArgumentError, "Expecting a selector as the first argument" end - while selector.index('?') - break if substitution_values.empty? - value = substitution_values.shift - if value.is_a?(Regexp) - value = substitution_context.add_regex value - end - selector.sub!('?', value) - end - selector - end - - # used for regex substitution in selectors - def substitution_context - @substitution_context ||= Class.new do - # +regex+ will be a +String+ - def match(matches, attribute, regex) - matches.find_all { |node| node[attribute] =~ @regexes[regex] } - end - - def add_regex(regex) - @regexes ||= [] - @regexes.push(regex) - id_for(regex) - end - - def id_for(regex); @regexes.index(regex).to_s; end - end.new + context.substitute!(selector, substitution_values) end def comparisons_from(comparator) @@ -441,6 +420,40 @@ module ActionDispatch end comparisons end + + def context + @context ||= SubstitutionContext.new + end + + class SubstitutionContext + def initialize(substitute = '?') + @substitute = substitute + @regexes = [] + end + + def add(regex) + @regexes.push(regex) + id_for(regex) + end + + def id_for(regex) + @regexes.index(regex).to_s # to_s to store it in selector string + end + + def match(matches, attribute, id) + matches.find_all { |node| node[attribute] =~ @regexes[id] } + end + + def substitute!(selector, values) + while selector.index(@substitute) + break if values.empty? + value = values.shift + value = add(value) if value.is_a?(Regexp) + selector.sub!(@substitute, value) + end + selector + end + end end end end -- cgit v1.2.3 From 1b0a4b9351c47140cd6ae6336c1eb52159766d9d Mon Sep 17 00:00:00 2001 From: Timm Date: Wed, 24 Jul 2013 18:16:11 +0200 Subject: Changed css_select to not count on multiple selectors. Fixed bug in determine_root_from where @selected was an Array. Changed assert_select_encoded to use a fragment instead of a document. --- .../lib/action_dispatch/testing/assertions/selector.rb | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 0ba3fffd5a..615f68e622 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -59,10 +59,10 @@ module ActionDispatch def css_select(*args) raise ArgumentError, "you at least need a selector" if args.empty? - if args.first.is_a?(String) # use nokogiri's ability for more selectors - root, selectors = response_from_page, args + if args.first.is_a?(String) + root, selectors = response_from_page, args.first else - root, selectors = args.shift, args + root, selectors = args.shift, args.first end root.css(selectors) @@ -248,7 +248,7 @@ module ActionDispatch end selected = elements.map do |elem| - root = Loofah.document(CGI.unescapeHTML("#{elem.text}")).root + root = Loofah.fragment(CGI.unescapeHTML("#{elem.text}")) css_select(root, "encoded:root", &block)[0] end @@ -311,12 +311,10 @@ module ActionDispatch end # +equals+ must contain :minimum, :maximum and :count keys - def assert_size_match!(size, equals, selector, message = nil) + def assert_size_match!(size, equals, css_selector, message = nil) min, max, count = equals[:minimum], equals[:maximum], equals[:count] - # FIXME: minitest provides messaging when we use assert_operator, - # so is this custom message really needed? - message ||= %(Expected #{count_description(min, max, count)} matching "#{selector.to_s}", found #{size}.) + message ||= %(Expected #{count_description(min, max, count)} matching "#{css_selector}", found #{size}.) if count assert_equal size, count, message else @@ -380,6 +378,10 @@ module ActionDispatch root_or_selector elsif @selected # nested call - wrap in document + if @selected.is_a?(Array) + doc = @selected.empty? ? @page.document : @selected[0].document + @selected = Nokogiri::XML::NodeSet.new(doc, @selected) + end Loofah.fragment('').tap { |d| d.add_child @selected } else @page -- cgit v1.2.3 From 5670bbeeb37e55299c85592042fc9170538d8f7b Mon Sep 17 00:00:00 2001 From: Timm Date: Wed, 24 Jul 2013 20:09:06 +0200 Subject: Fixed bug by switching to Loofah fragment instead of document. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 615f68e622..1d72dc1513 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -282,7 +282,7 @@ module ActionDispatch deliveries.each do |delivery| (delivery.parts.empty? ? [delivery] : delivery.parts).each do |part| if part["Content-Type"].to_s =~ /^text\/html\W/ - root = Loofah.document(part.body.to_s).root + root = Loofah.fragment(part.body.to_s) assert_select root, ":root", &block end end @@ -443,7 +443,7 @@ module ActionDispatch end def match(matches, attribute, id) - matches.find_all { |node| node[attribute] =~ @regexes[id] } + matches.find_all { |node| node[attribute] =~ @regexes[id.to_i] } end def substitute!(selector, values) -- cgit v1.2.3 From 2cc4f4258a61dd638da2f72d27b26753a72f886f Mon Sep 17 00:00:00 2001 From: Timm Date: Thu, 25 Jul 2013 20:03:28 +0200 Subject: Changed html_document to use fragments. Changed response_from_page to be an alias of html_document. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 1d72dc1513..53e7675f7c 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -323,18 +323,15 @@ module ActionDispatch end end - def response_from_page - html_document.root - end - # +html_document+ is used in testing/integration.rb def html_document @html_document ||= if @response.content_type =~ /xml$/ - Loofah.xml_document(@response.body) + Loofah.xml_fragment(@response.body) else - Loofah.document(@response.body) + Loofah.fragment(@response.body) end end + alias :response_from_page :html_document class HTMLSelector #:nodoc: attr_accessor :root, :css_selector, :comparisons, :message -- cgit v1.2.3 From 7e7e19132d2206831b824039a362aa378a4ef70e Mon Sep 17 00:00:00 2001 From: Timm Date: Thu, 25 Jul 2013 20:04:27 +0200 Subject: Added NodeSet comparison to possible root element in determine_root_from. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 53e7675f7c..9b03ccce14 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -367,7 +367,7 @@ module ActionDispatch @css_selector_is_second_argument = false if root_or_selector == 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 root_or_selector.is_a?(Nokogiri::XML::Node) + elsif root_or_selector.is_a?(Nokogiri::XML::Node) || root_or_selector.is_a?(Nokogiri::XML::NodeSet) # First argument is a node (tag or text, but also HTML root), # so we know what we're selecting from. @css_selector_is_second_argument = true -- cgit v1.2.3 From 4ed784188d329315c79916242a5961c3c128b06c Mon Sep 17 00:00:00 2001 From: Timm Date: Tue, 30 Jul 2013 12:04:37 +0200 Subject: Fixed: now only compares html of children in filter_matches. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 9b03ccce14..dc18136be2 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -297,7 +297,7 @@ module ActionDispatch text_matches = options.has_key?(:text) remaining = matches.reject do |match| # Preserve markup with to_s for html elements - content = text_matches ? match.text : match.to_s + 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" -- cgit v1.2.3 From 99ac0cdcad5584fb1347866532749355dc597429 Mon Sep 17 00:00:00 2001 From: Timm Date: Tue, 30 Jul 2013 12:31:58 +0200 Subject: Simplified assert_select further by moving match filtering into HTMLSelector select. --- .../action_dispatch/testing/assertions/selector.rb | 61 ++++++++++------------ 1 file changed, 29 insertions(+), 32 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index dc18136be2..59bd6dc3b4 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -161,17 +161,7 @@ module ActionDispatch selector = HTMLSelector.new(@selected, response_from_page, args) matches = selector.select - equals = selector.comparisons - content_mismatch = nil - matches = filter_matches(matches, equals) do |mismatch| - content_mismatch ||= mismatch - end - - # Expecting foo found bar element only if found zero, not if - # found one but expecting two. - message = selector.message - message ||= content_mismatch if matches.empty? - assert_size_match!(matches.size, equals, selector.source, message) + assert_size_match!(matches.size, selector.comparisons, selector.source, message) # Set @selected to allow nested assert_select. # Can be nested several levels deep. @@ -290,26 +280,6 @@ module ActionDispatch end protected - def filter_matches(matches, options) - match_with = options[:text] || options[:html] - return matches unless match_with - - text_matches = options.has_key?(:text) - 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" - - unless match_with.is_a?(Regexp) ? (content =~ match_with) : (content == match_with.to_s) - yield sprintf("<%s> expected but was\n<%s>.", match_with, content) - true - end - end - Nokogiri::XML::NodeSet.new(matches.document, remaining) - 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] @@ -360,7 +330,34 @@ module ActionDispatch alias :source :css_selector def select - root.css(css_selector, context) + filter root.css(css_selector, context) + end + + def filter(matches) + match_with = comparisons[:text] || comparisons[:html] + return matches unless match_with + + content_mismatch = nil + text_matches = comparisons.has_key?(:text) + + 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" + + unless match_with.is_a?(Regexp) ? (content =~ match_with) : (content == match_with.to_s) + content_mismatch ||= sprintf("<%s> expected but was\n<%s>.", match_with, content) + true + end + end + + # Expecting foo found bar element only if found zero, not if + # found one but expecting two. + self.message ||= content_mismatch if remaining.empty? + + Nokogiri::XML::NodeSet.new(matches.document, remaining) end def determine_root_from(root_or_selector) -- cgit v1.2.3 From 22aa73b3ee1491b5a1b4271b4f85b53c40f11ff3 Mon Sep 17 00:00:00 2001 From: Timm Date: Tue, 30 Jul 2013 14:45:12 +0200 Subject: Cleaned up SubstitutionContext class. --- .../lib/action_dispatch/testing/assertions/selector.rb | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 59bd6dc3b4..235934f5f1 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -427,25 +427,23 @@ module ActionDispatch @regexes = [] end - def add(regex) + def add_regex(regex) + return regex unless regex.is_a?(Regexp) @regexes.push(regex) - id_for(regex) + last_id.to_s # avoid implicit conversions of Fixnum to String end - def id_for(regex) - @regexes.index(regex).to_s # to_s to store it in selector string + def last_id + @regexes.count - 1 end def match(matches, attribute, id) - matches.find_all { |node| node[attribute] =~ @regexes[id.to_i] } + matches.find_all { |node| node[attribute] =~ @regexes[id] } end def substitute!(selector, values) - while selector.index(@substitute) - break if values.empty? - value = values.shift - value = add(value) if value.is_a?(Regexp) - selector.sub!(@substitute, value) + while !values.empty? && selector.index(@substitute) + selector.sub!(@substitute, add_regex(values.shift)) end selector end -- cgit v1.2.3 From 3c6ce7403423fc7362ba11c921ab2b5d136aff68 Mon Sep 17 00:00:00 2001 From: Timm Date: Tue, 30 Jul 2013 15:20:46 +0200 Subject: Fixed: inadvertently called message method in MiniTest instead of selector.message. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 235934f5f1..b6b47a6771 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -161,7 +161,7 @@ module ActionDispatch selector = HTMLSelector.new(@selected, response_from_page, args) matches = selector.select - assert_size_match!(matches.size, selector.comparisons, selector.source, message) + assert_size_match!(matches.size, selector.comparisons, selector.source, selector.message) # Set @selected to allow nested assert_select. # Can be nested several levels deep. -- cgit v1.2.3 From a45ee9e5e394f1663bf6d96424f42a3e2a21af80 Mon Sep 17 00:00:00 2001 From: Timm Date: Wed, 31 Jul 2013 16:14:00 +0200 Subject: add_regex returns inspected value for non Regexp objects. Workaround, so users don't have to care about enclosing values in double quotes. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index b6b47a6771..504eccd0a7 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -428,7 +428,8 @@ module ActionDispatch end def add_regex(regex) - return regex unless regex.is_a?(Regexp) + # Nokogiri doesn't like arbitrary values without quotes, hence inspect. + return regex.inspect unless regex.is_a?(Regexp) @regexes.push(regex) last_id.to_s # avoid implicit conversions of Fixnum to String end -- cgit v1.2.3 From f1031225f67fc3ee23b68c068f31d5099d00f11d Mon Sep 17 00:00:00 2001 From: Timm Date: Wed, 31 Jul 2013 19:48:35 +0200 Subject: Reverted to using documents instead of document fragments, since searching via default xml namespaces didn't work. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 504eccd0a7..e551851ed6 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -296,12 +296,15 @@ module ActionDispatch # +html_document+ is used in testing/integration.rb def html_document @html_document ||= if @response.content_type =~ /xml$/ - Loofah.xml_fragment(@response.body) + Loofah.xml_document(@response.body) else - Loofah.fragment(@response.body) + Loofah.document(@response.body) end end - alias :response_from_page :html_document + + def response_from_page + html_document.root + end class HTMLSelector #:nodoc: attr_accessor :root, :css_selector, :comparisons, :message -- cgit v1.2.3 From 91650ddc3a38d46b254e5fd8ab3cc7a5823ed9ce Mon Sep 17 00:00:00 2001 From: Timm Date: Wed, 31 Jul 2013 22:21:22 +0200 Subject: Fixed: no longer wrapped @selected in fragment, since .css works fine without it. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index e551851ed6..c2a5d59577 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -374,12 +374,11 @@ module ActionDispatch root_or_selector elsif @selected - # nested call - wrap in document if @selected.is_a?(Array) doc = @selected.empty? ? @page.document : @selected[0].document @selected = Nokogiri::XML::NodeSet.new(doc, @selected) end - Loofah.fragment('').tap { |d| d.add_child @selected } + @selected else @page end -- cgit v1.2.3 From f2c9734be0e007a2f149b53c291d098d283ac376 Mon Sep 17 00:00:00 2001 From: Timm Date: Thu, 1 Aug 2013 19:26:53 +0200 Subject: Returning from filter if matches are empty. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index c2a5d59577..529db22fff 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -338,7 +338,7 @@ module ActionDispatch def filter(matches) match_with = comparisons[:text] || comparisons[:html] - return matches unless match_with + return matches if matches.empty? || !match_with content_mismatch = nil text_matches = comparisons.has_key?(:text) -- cgit v1.2.3 From ea5f3ba0e24f8f554ff256f1f58e437cc3934bdd Mon Sep 17 00:00:00 2001 From: Timm Date: Thu, 1 Aug 2013 19:36:39 +0200 Subject: Moved around alias line. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 529db22fff..8d2a30ca8d 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -309,6 +309,8 @@ module ActionDispatch class HTMLSelector #:nodoc: attr_accessor :root, :css_selector, :comparisons, :message + alias :source :css_selector + def initialize(selected, page, args) @selected, @page = selected, page @@ -330,8 +332,6 @@ module ActionDispatch end end - alias :source :css_selector - def select filter root.css(css_selector, context) end -- cgit v1.2.3 From 77d0333c08d3124120b604c821196db688ee9722 Mon Sep 17 00:00:00 2001 From: Timm Date: Thu, 1 Aug 2013 21:11:48 +0200 Subject: Wrapped element to search in NodeSet. Changed selectors to selector. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 8d2a30ca8d..04628539e8 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -60,12 +60,14 @@ module ActionDispatch raise ArgumentError, "you at least need a selector" if args.empty? if args.first.is_a?(String) - root, selectors = response_from_page, args.first + root, selector = response_from_page, args.first else - root, selectors = args.shift, args.first + root, selector = args.shift, args.first end - root.css(selectors) + # wrap in NodeSet to avoid this: + # .css('div') => no matches + Nokogiri::XML::NodeSet.new(root.document, [root]).css(selector) end # An assertion that selects elements and makes one or more equality tests. -- cgit v1.2.3 From 9020abe0e92c78085ba2b826d442701921ff88ac Mon Sep 17 00:00:00 2001 From: Timm Date: Thu, 1 Aug 2013 22:22:32 +0200 Subject: Reworked the wrapping root in NodeSet implementation in css_select. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 04628539e8..167c80cd98 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -65,9 +65,11 @@ module ActionDispatch root, selector = args.shift, args.first end - # wrap in NodeSet to avoid this: - # .css('div') => no matches - Nokogiri::XML::NodeSet.new(root.document, [root]).css(selector) + root.css(selector).tap do |matches| + if matches.empty? && root.matches?(selector) + return Nokogiri::XML::NodeSet.new(root.document, [root]) + end + end end # An assertion that selects elements and makes one or more equality tests. -- cgit v1.2.3 From 6fd74dc00e8207b981d982bc8b5842859c2589a6 Mon Sep 17 00:00:00 2001 From: Timm Date: Thu, 1 Aug 2013 22:41:12 +0200 Subject: Updated documentation to state more things about css selectors with substitution values. --- .../lib/action_dispatch/testing/assertions/selector.rb | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 167c80cd98..fea9b8daa0 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -33,10 +33,12 @@ module ActionDispatch # 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 empty Nokogiri::XML::NodeSet if no match is found. + # Returns an empty Nokogiri::XML::NodeSet if no match is found. # # 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. # # # Selects all div tags # divs = css_select("div") @@ -56,6 +58,9 @@ module ActionDispatch # inputs = css_select(form, "input") # ... # end + # + # # Selects div tags with ids matching regex + # css_select "div:match('id', ?)", /\d+/ def css_select(*args) raise ArgumentError, "you at least need a selector" if args.empty? @@ -103,6 +108,9 @@ module ActionDispatch # # 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 "div:match('id', ?)", /\d+/ # # === Equality Tests # @@ -153,11 +161,11 @@ module ActionDispatch # assert_select "body div.header ul.menu" # # # Use substitution values - # assert_select "ol>li#?", /item-\d+/ + # assert_select "ol>li:match('id', ?)", /item-\d+/ # # # All input fields in the form have a name # assert_select "form input" do - # assert_select "[name=?]", /.+/ # Not empty + # assert_select ":match('name', ?)", /.+/ # Not empty # end def assert_select(*args, &block) @selected ||= nil -- cgit v1.2.3 From 1bc0bece5b7f51119905e292e6ff9ffb04d15c43 Mon Sep 17 00:00:00 2001 From: Timm Date: Thu, 1 Aug 2013 23:18:18 +0200 Subject: Removed mention of css_select supporting substitution values. It is not tested anywhere. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index fea9b8daa0..e6561fc5d9 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -35,10 +35,7 @@ module ActionDispatch # 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) 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. + # The selector may be a CSS selector expression (String). # # # Selects all div tags # divs = css_select("div") @@ -58,9 +55,6 @@ module ActionDispatch # inputs = css_select(form, "input") # ... # end - # - # # Selects div tags with ids matching regex - # css_select "div:match('id', ?)", /\d+/ def css_select(*args) raise ArgumentError, "you at least need a selector" if args.empty? -- cgit v1.2.3 From 9f73f9f38cd572cdb7bee42b0ef250c8bbd91cc7 Mon Sep 17 00:00:00 2001 From: Timm Date: Fri, 2 Aug 2013 16:05:55 +0200 Subject: Fixed: assert_select_encoded finds the right content. No longer uses a wrapper. Updated tests to reflect this. --- .../lib/action_dispatch/testing/assertions/selector.rb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index e6561fc5d9..1fda4fb42a 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -243,14 +243,18 @@ module ActionDispatch raise ArgumentError, "Argument is optional, and may be node or array of nodes" end - selected = elements.map do |elem| - root = Loofah.fragment(CGI.unescapeHTML("#{elem.text}")) - css_select(root, "encoded:root", &block)[0] - end + content = elements.map do |elem| + elem.children.select(&:cdata?).map(&:content) + end.join + selected = Loofah.fragment(content) begin old_selected, @selected = @selected, selected - assert_select ":root", &block + if content.empty? + yield selected + else + assert_select ":root", &block + end ensure @selected = old_selected end -- cgit v1.2.3 From 95c517b6d6c13bfff2a020b2a29ec5c9bacfebf3 Mon Sep 17 00:00:00 2001 From: Timm Date: Fri, 2 Aug 2013 17:01:54 +0200 Subject: Moved Dom and Selector assertions from ActionDispatch to ActionView. --- .../lib/action_dispatch/testing/assertions.rb | 4 - .../lib/action_dispatch/testing/assertions/dom.rb | 75 +--- .../action_dispatch/testing/assertions/selector.rb | 468 +-------------------- .../lib/action_dispatch/testing/integration.rb | 3 +- 4 files changed, 6 insertions(+), 544 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions.rb b/actionpack/lib/action_dispatch/testing/assertions.rb index 8e6b93ba67..5f923abbf9 100644 --- a/actionpack/lib/action_dispatch/testing/assertions.rb +++ b/actionpack/lib/action_dispatch/testing/assertions.rb @@ -1,16 +1,12 @@ module ActionDispatch module Assertions - autoload :DomAssertions, 'action_dispatch/testing/assertions/dom' autoload :ResponseAssertions, 'action_dispatch/testing/assertions/response' autoload :RoutingAssertions, 'action_dispatch/testing/assertions/routing' - autoload :SelectorAssertions, 'action_dispatch/testing/assertions/selector' extend ActiveSupport::Concern - include DomAssertions include ResponseAssertions include RoutingAssertions - include SelectorAssertions end end diff --git a/actionpack/lib/action_dispatch/testing/assertions/dom.rb b/actionpack/lib/action_dispatch/testing/assertions/dom.rb index 4a05e4aee3..53d1b198e6 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/dom.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/dom.rb @@ -1,74 +1,3 @@ -require 'loofah' +require 'active_support/deprecation' -module ActionDispatch - 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 = doms_from_strings(expected, actual) - message ||= "Expected: #{expected_dom}\nActual: #{actual_dom}" - 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 = doms_from_strings(expected, actual) - message ||= "Expected: #{expected_dom}\nActual: #{actual_dom}" - assert_not compare_doms(expected_dom, actual_dom), message - end - - protected - # +doms_from_strings+ creates a Loofah::HTML::DocumentFragment for every string in strings - def doms_from_strings(*strings) - strings.map { |str| Loofah.fragment(str) } - end - - # +compare_doms+ takes two doms loops over all their children and compares each child via +equal_children?+ - def compare_doms(expected, actual) - expected.children.each_with_index do |child, i| - return false unless equal_children?(child, actual.children[i]) - end - true - end - - # +equal_children?+ compares children according to their type - # Determines further comparison via said type - # i.e. element node children with equal names has their attributes compared using +attributes_are_equal?+ - def equal_children?(child, other_child) - return false unless child.type == other_child.type - - case child.type - when Nokogiri::XML::Node::ELEMENT_NODE - child.name == other_child.name && attributes_are_equal?(child, other_child) - else - child.to_s == other_child.to_s - end - end - - # +attributes_are_equal?+ sorts elements attributes by name and compares - # each attribute by calling +equal_attribute?+ - # If those are +true+ the attributes are considered equal - def attributes_are_equal?(element, other_element) - first_nodes = element.attribute_nodes.sort_by { |a| a.name } - other_nodes = other_element.attribute_nodes.sort_by { |a| a.name } - - return false unless first_nodes.size == other_nodes.size - first_nodes.each_with_index do |attr, i| - return false unless equal_attribute?(attr, other_nodes[i]) - end - true - end - - # +equal_attribute?+ compares attributes by their name and value - def equal_attribute?(attr, other_attr) - attr.name == other_attr.name && attr.value == other_attr.value - end - end - end -end +ActiveSupport::Deprecation.warn("ActionDispatch::Assertions::DomAssertions has been moved to ActionView. You can find it in action_view/testing/assertions/dom.rb.") \ No newline at end of file diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 1fda4fb42a..588da094d5 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -1,467 +1,3 @@ -require 'action_view/vendor/html-scanner' -require 'active_support/core_ext/object/inclusion' -require 'loofah' +require 'active_support/deprecation' -#-- -# Copyright (c) 2006 Assaf Arkin (http://labnotes.org) -# Under MIT and/or CC By license. -#++ - -module ActionDispatch - module Assertions - NO_STRIP = %w{pre script style textarea} - - # 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 - # to match all elements of the current page. 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). - # - # # 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" if args.empty? - - if args.first.is_a?(String) - root, selector = response_from_page, args.first - else - root, selector = args.shift, args.first - end - - root.css(selector).tap do |matches| - if matches.empty? && root.matches?(selector) - return Nokogiri::XML::NodeSet.new(root.document, [root]) - end - end - 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, calling +assert_select+ selects from the - # response HTML unless +assert_select+ is called from within an +assert_select+ block. - # - # 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 "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(@selected, response_from_page, args) - - matches = selector.select - assert_size_match!(matches.size, selector.comparisons, selector.source, selector.message) - - # Set @selected to allow nested assert_select. - # Can be nested several levels deep. - if block_given? && !matches.empty? - begin - in_scope, @selected = @selected, matches - yield matches - ensure - @selected = in_scope - end - end - - matches - end - - def count_description(min, max, count) #:nodoc: - pluralize = lambda {|word, quantity| word << (quantity == 1 ? '' : 's')} - - 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 - - # 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) - case element - when Array - elements = element - when Nokogiri::XML::Node - elements = [element] - when nil - unless elements = @selected - raise ArgumentError, "First argument is optional, but must be called from a nested assert_select" - end - else - raise ArgumentError, "Argument is optional, and may be node or array of nodes" - end - - content = elements.map do |elem| - elem.children.select(&:cdata?).map(&:content) - end.join - selected = Loofah.fragment(content) - - begin - old_selected, @selected = @selected, selected - if content.empty? - yield selected - else - assert_select ":root", &block - end - ensure - @selected = old_selected - 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 = Loofah.fragment(part.body.to_s) - assert_select root, ":root", &block - end - end - end - end - - protected - # +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 size, count, message - else - assert_operator size, :>=, min, message if min - assert_operator size, :<=, max, message if max - end - end - - # +html_document+ is used in testing/integration.rb - def html_document - @html_document ||= if @response.content_type =~ /xml$/ - Loofah.xml_document(@response.body) - else - Loofah.document(@response.body) - end - end - - def response_from_page - html_document.root - end - - class HTMLSelector #:nodoc: - attr_accessor :root, :css_selector, :comparisons, :message - - alias :source :css_selector - - def initialize(selected, page, args) - @selected, @page = selected, page - - # Start with optional element followed by mandatory selector. - @root = determine_root_from(args.first) - - # First or second argument is the selector - selector = @css_selector_is_second_argument ? args.shift(2).last : args.shift - @css_selector = selector_from(selector, args) - - # Next argument is used for equality tests. - @comparisons = comparisons_from(args.shift) - - # Last argument is the message we use if the assertion fails. - @message = args.shift - - if args.shift - raise ArgumentError, "Not expecting that last argument, you either have too many arguments, or they're the wrong type" - end - end - - def select - filter root.css(css_selector, context) - end - - def filter(matches) - match_with = comparisons[:text] || comparisons[:html] - return matches if matches.empty? || !match_with - - content_mismatch = nil - text_matches = comparisons.has_key?(:text) - - 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" - - unless match_with.is_a?(Regexp) ? (content =~ match_with) : (content == match_with.to_s) - content_mismatch ||= sprintf("<%s> expected but was\n<%s>.", match_with, content) - true - end - end - - # Expecting foo found bar element only if found zero, not if - # found one but expecting two. - self.message ||= content_mismatch if remaining.empty? - - Nokogiri::XML::NodeSet.new(matches.document, remaining) - end - - def determine_root_from(root_or_selector) - @css_selector_is_second_argument = false - if root_or_selector == 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 root_or_selector.is_a?(Nokogiri::XML::Node) || root_or_selector.is_a?(Nokogiri::XML::NodeSet) - # First argument is a node (tag or text, but also HTML root), - # so we know what we're selecting from. - @css_selector_is_second_argument = true - - root_or_selector - elsif @selected - if @selected.is_a?(Array) - doc = @selected.empty? ? @page.document : @selected[0].document - @selected = Nokogiri::XML::NodeSet.new(doc, @selected) - end - @selected - else - @page - end - end - - def selector_from(selector, substitution_values) - unless selector.is_a? String - raise ArgumentError, "Expecting a selector as the first argument" - end - context.substitute!(selector, substitution_values) - end - - def comparisons_from(comparator) - comparisons = {} - case comparator - 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 - - def context - @context ||= SubstitutionContext.new - end - - class SubstitutionContext - def initialize(substitute = '?') - @substitute = substitute - @regexes = [] - end - - def add_regex(regex) - # Nokogiri doesn't like arbitrary values without quotes, hence inspect. - return regex.inspect unless regex.is_a?(Regexp) - @regexes.push(regex) - last_id.to_s # avoid implicit conversions of Fixnum to String - end - - def last_id - @regexes.count - 1 - end - - def match(matches, attribute, id) - matches.find_all { |node| node[attribute] =~ @regexes[id] } - end - - def substitute!(selector, values) - while !values.empty? && selector.index(@substitute) - selector.sub!(@substitute, add_regex(values.shift)) - end - selector - end - end - end - end - end -end +ActiveSupport::Deprecation.warn("ActionDispatch::Assertions::SelectorAssertions has been moved to ActionView. You can find it in action_view/testing/assertions/selector.rb.") \ No newline at end of file diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index af3bc26691..96f12b95a9 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -2,6 +2,7 @@ require 'stringio' require 'uri' require 'active_support/core_ext/kernel/singleton_class' require 'active_support/core_ext/object/try' +require 'action_view/testing/assertions' require 'rack/test' module ActionDispatch @@ -313,7 +314,7 @@ module ActionDispatch end module Runner - include ActionDispatch::Assertions + include ActionDispatch::Assertions, ActionView::Assertions def app @app ||= nil -- cgit v1.2.3 From dddf86a3b75c6fc01be34dd94e7ad0d02fa0829f Mon Sep 17 00:00:00 2001 From: Timm Date: Tue, 13 Aug 2013 10:52:58 +0200 Subject: Trimmed deprecation message for ActionDispatch::Assertions::SelectorAssertions. --- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 588da094d5..bb6aec7415 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -1,3 +1,3 @@ require 'active_support/deprecation' -ActiveSupport::Deprecation.warn("ActionDispatch::Assertions::SelectorAssertions has been moved to ActionView. You can find it in action_view/testing/assertions/selector.rb.") \ No newline at end of file +ActiveSupport::Deprecation.warn("ActionDispatch::Assertions::SelectorAssertions has been moved to Action View in action_view/testing/assertions/selector.rb.") \ No newline at end of file -- cgit v1.2.3 From 4e97d7585a2f4788b9eed98c6cdaf4bb6f2cf5ce Mon Sep 17 00:00:00 2001 From: Timm Date: Tue, 3 Sep 2013 09:30:37 +0200 Subject: Added deprecation warning to ActionDispatch::Assertions::TagAssertions. --- actionpack/lib/action_dispatch/testing/assertions/tag.rb | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 actionpack/lib/action_dispatch/testing/assertions/tag.rb (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/tag.rb b/actionpack/lib/action_dispatch/testing/assertions/tag.rb new file mode 100644 index 0000000000..bbf3e7705b --- /dev/null +++ b/actionpack/lib/action_dispatch/testing/assertions/tag.rb @@ -0,0 +1,3 @@ +require 'active_support/deprecation' + +ActiveSupport::Deprecation.warn("ActionDispatch::Assertions::TagAssertions has been eprecated. Use the assert_select methods from SelectorAssertions in action_view/testing/assertions/selector.rb.") \ No newline at end of file -- cgit v1.2.3 From a766a025e61c6ad43c113c7fbaca0adbb7841564 Mon Sep 17 00:00:00 2001 From: Timm Date: Tue, 24 Sep 2013 19:09:22 +0200 Subject: Moved ActionView::Assertions dependency from Action Pack's lib to abstract_unit.rb. --- actionpack/lib/action_dispatch/testing/integration.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 96f12b95a9..af3bc26691 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -2,7 +2,6 @@ require 'stringio' require 'uri' require 'active_support/core_ext/kernel/singleton_class' require 'active_support/core_ext/object/try' -require 'action_view/testing/assertions' require 'rack/test' module ActionDispatch @@ -314,7 +313,7 @@ module ActionDispatch end module Runner - include ActionDispatch::Assertions, ActionView::Assertions + include ActionDispatch::Assertions def app @app ||= nil -- cgit v1.2.3 From fa916af69626ac405e0f71bd4edf9c64159e61a3 Mon Sep 17 00:00:00 2001 From: Timm Date: Tue, 24 Sep 2013 21:21:01 +0200 Subject: Removed tag.rb, since it is actually removed, not just deprecated. [ci skip] --- actionpack/lib/action_dispatch/testing/assertions/tag.rb | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 actionpack/lib/action_dispatch/testing/assertions/tag.rb (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/tag.rb b/actionpack/lib/action_dispatch/testing/assertions/tag.rb deleted file mode 100644 index bbf3e7705b..0000000000 --- a/actionpack/lib/action_dispatch/testing/assertions/tag.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'active_support/deprecation' - -ActiveSupport::Deprecation.warn("ActionDispatch::Assertions::TagAssertions has been eprecated. Use the assert_select methods from SelectorAssertions in action_view/testing/assertions/selector.rb.") \ No newline at end of file -- cgit v1.2.3 From 6061472b8c310158a2a2e8e9a6b81a1aef6b60fe Mon Sep 17 00:00:00 2001 From: Timm Date: Fri, 11 Oct 2013 12:57:36 +0200 Subject: Changed deprecation message in dom and selector assertions in Action Dispatch. --- actionpack/lib/action_dispatch/testing/assertions/dom.rb | 2 +- actionpack/lib/action_dispatch/testing/assertions/selector.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions/dom.rb b/actionpack/lib/action_dispatch/testing/assertions/dom.rb index 53d1b198e6..fb579b52fe 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/dom.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/dom.rb @@ -1,3 +1,3 @@ require 'active_support/deprecation' -ActiveSupport::Deprecation.warn("ActionDispatch::Assertions::DomAssertions has been moved to ActionView. You can find it in action_view/testing/assertions/dom.rb.") \ No newline at end of file +ActiveSupport::Deprecation.warn("ActionDispatch::Assertions::DomAssertions has been extracted to the rails-dom-testing gem.") \ No newline at end of file diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index bb6aec7415..19eca60f70 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -1,3 +1,3 @@ require 'active_support/deprecation' -ActiveSupport::Deprecation.warn("ActionDispatch::Assertions::SelectorAssertions has been moved to Action View in action_view/testing/assertions/selector.rb.") \ No newline at end of file +ActiveSupport::Deprecation.warn("ActionDispatch::Assertions::SelectorAssertions has been has been extracted to the rails-dom-testing gem.") \ No newline at end of file -- cgit v1.2.3 From 9efdffe437ef5ac7b4416a9b7ad180b1e5888e28 Mon Sep 17 00:00:00 2001 From: Timm Date: Sat, 12 Oct 2013 22:58:51 +0200 Subject: Moved html_document to ActionDispatch::Assertions. Included the Rails::Dom::Testing::Assertions there as well. --- actionpack/lib/action_dispatch/testing/assertions.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/assertions.rb b/actionpack/lib/action_dispatch/testing/assertions.rb index 5f923abbf9..44815a75a8 100644 --- a/actionpack/lib/action_dispatch/testing/assertions.rb +++ b/actionpack/lib/action_dispatch/testing/assertions.rb @@ -1,3 +1,6 @@ +require 'loofah' +require 'rails-dom-testing' + module ActionDispatch module Assertions autoload :ResponseAssertions, 'action_dispatch/testing/assertions/response' @@ -7,6 +10,14 @@ module ActionDispatch include ResponseAssertions include RoutingAssertions + include Rails::Dom::Testing::Assertions + + def html_document + @html_document ||= if @response.content_type =~ /xml$/ + Loofah.xml_document(@response.body) + else + Loofah.document(@response.body) + end + end end end - -- cgit v1.2.3 From 5ffc36d476be7f463e5cc275192181da7b94a56e Mon Sep 17 00:00:00 2001 From: Timm Date: Wed, 28 May 2014 09:51:41 +0200 Subject: Add document_root_element to ActionDispatch::IntegrationTest so assert_select can be called without specifying a root. --- actionpack/lib/action_dispatch/testing/integration.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index af3bc26691..05d74e6a27 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -493,5 +493,9 @@ module ActionDispatch reset! unless integration_session integration_session.url_options end + + def document_root_element + html_document.root + end end end -- cgit v1.2.3