public Method

SelectorAssertions.assert_select_rjs(*args) { |matches| ... }

assert_select_rjs(id?) { |elements| ... }
assert_select_rjs(statement, id?) { |elements| ... }
assert_select_rjs(:insert, position, id?) { |elements| ... }

Selects content from the RJS response.

Narrowing down

With no arguments, asserts that one or more elements are updated or inserted by RJS statements.

Use the id argument to narrow down the assertion to only statements that update or insert an element with that identifier.

Use the first argument to narrow down assertions to only statements of that type. Possible values are :replace, :replace_html, :show, :hide, :toggle, :remove and :insert_html.

Use the argument :insert followed by an insertion position to narrow down the assertion to only statements that insert elements in that position. Possible values are :top, :bottom, :before and :after.

Using the :remove statement, you will be able to pass a block, but it will be ignored as there is no HTML passed for this statement.

Using blocks

Without a block, #assert_select_rjs merely asserts that the response contains one or more RJS statements that replace or update content.

With a block, #assert_select_rjs also selects all elements used in these statements and passes them to the block. Nested assertions are supported.

Calling #assert_select_rjs with no arguments and using nested asserts asserts that the HTML content is returned by one or more RJS statements. Using #assert_select directly makes the same assertion on the content, but without distinguishing whether the content is returned in an HTML or JavaScript.

Examples

# Replacing the element foo.
# page.replace 'foo', ...
assert_select_rjs :replace, "foo"

# Replacing with the chained RJS proxy.
# page[:foo].replace ...
assert_select_rjs :chained_replace, 'foo'

# Inserting into the element bar, top position.
assert_select_rjs :insert, :top, "bar"

# Remove the element bar
assert_select_rjs :remove, "bar"

# Changing the element foo, with an image.
assert_select_rjs "foo" do
  assert_select "img[src=/images/logo.gif""
end

# RJS inserts or updates a list with four items.
assert_select_rjs do
  assert_select "ol>li", 4
end

# The same, but shorter.
assert_select "ol>li", 4

Source Code

# File action_controller/assertions/selector_assertions.rb, line 397
def assert_select_rjs(*args, &block)
  rjs_type = nil
  arg      = args.shift

  # If the first argument is a symbol, it's the type of RJS statement we're looking
  # for (update, replace, insertion, etc). Otherwise, we're looking for just about
  # any RJS statement.
  if arg.is_a?(Symbol)
    rjs_type = arg

    if rjs_type == :insert
      arg = args.shift
      insertion = "insert_#{arg}".to_sym
      raise ArgumentError, "Unknown RJS insertion type #{arg}" unless RJS_STATEMENTS[insertion]
      statement = "(#{RJS_STATEMENTS[insertion]})"
    else
      raise ArgumentError, "Unknown RJS statement type #{rjs_type}" unless RJS_STATEMENTS[rjs_type]
      statement = "(#{RJS_STATEMENTS[rjs_type]})"
    end
    arg = args.shift
  else
    statement = "#{RJS_STATEMENTS[:any]}"
  end

  # Next argument we're looking for is the element identifier. If missing, we pick
  # any element.
  if arg.is_a?(String)
    id = Regexp.quote(arg)
    arg = args.shift
  else
    id = "[^\"]*"
  end

  pattern =
    case rjs_type
      when :chained_replace, :chained_replace_html
        Regexp.new("\\$\\(\"#{id}\"\\)#{statement}\\(#{RJS_PATTERN_HTML}\\)", Regexp::MULTILINE)
      when :remove, :show, :hide, :toggle
        Regexp.new("#{statement}\\(\"#{id}\"\\)")
      else
        Regexp.new("#{statement}\\(\"#{id}\", #{RJS_PATTERN_HTML}\\)", Regexp::MULTILINE)
    end

  # Duplicate the body since the next step involves destroying it.
  matches = nil
  case rjs_type
    when :remove, :show, :hide, :toggle
      matches = @response.body.match(pattern)
    else
      @response.body.gsub(pattern) do |match|
        html = unescape_rjs($2)
        matches ||= []
        matches.concat HTML::Document.new(html).root.children.select { |n| n.tag? }
        ""
      end
  end

  if matches
    assert_block("") { true } # to count the assertion
    if block_given? && !([:remove, :show, :hide, :toggle].include? rjs_type)
      begin
        in_scope, @selected = @selected, matches
        yield matches
      ensure
        @selected = in_scope
      end
    end
    matches
  else
    # RJS statement not found.
    flunk args.shift || "No RJS statement that replaces or inserts HTML content."
  end
end
Comments

Have your say
Please use Textile formatting (click here for a cheat sheet). Use <code/> and <pre/> for code samples.
Click here to login with OpenID to to post comments.