forked from rails/jquery-rails
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathassert_select.rb
More file actions
99 lines (90 loc) · 3.28 KB
/
assert_select.rb
File metadata and controls
99 lines (90 loc) · 3.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
module ActionDispatch
module Assertions
module SelectorAssertions
# Selects content from a JQuery response. Patterned loosely on
# assert_select_rjs.
#
# === Narrowing down
#
# With no arguments, asserts that one or more method calls are made.
#
# Use the +method+ argument to narrow down the assertion to only
# statements that call that specific method.
#
# Use the +opt+ argument to narrow down the assertion to only statements
# that pass +opt+ as the first argument.
#
# Use the +id+ argument to narrow down the assertion to only statements
# that invoke methods on the result of using that identifier as a
# selector.
#
# === Using blocks
#
# Without a block, +assert_select_jquery_ merely asserts that the
# response contains one or more statements that match the conditions
# specified above
#
# With a block +assert_select_jquery_ also asserts that the method call
# passes a javascript escaped string containing HTML. All such HTML
# fragments are selected and passed to the block. Nested assertions are
# supported.
#
# === Examples
#
# # asserts that the #notice element is hidden
# assert_select :hide, '#notice'
#
# # asserts that the #cart element is shown with a blind parameter
# assert_select :show, :blind, '#cart'
#
# # asserts that #cart content contains a #current_item
# assert_select :html, '#cart' do
# assert_select '#current_item'
# end
PATTERN_HTML = "\"((\\\\\"|[^\"])*)\""
PATTERN_UNICODE_ESCAPED_CHAR = /\\u([0-9a-zA-Z]{4})/
def assert_select_jquery(*args, &block)
jquery_method = args.first.is_a?(Symbol) ? args.shift : nil
jquery_opt = args.first.is_a?(Symbol) ? args.shift : nil
id = args.first.is_a?(String) ? args.shift : nil
pattern = "\\.#{jquery_method || '\\w+'}\\("
pattern = "#{pattern}['\"]#{jquery_opt}['\"],?\\s*" if jquery_opt
pattern = "#{pattern}#{PATTERN_HTML}"
pattern = "(?:jQuery|\\$)\\(['\"]#{id}['\"]\\)#{pattern}" if id
fragments = []
response.body.scan(Regexp.new(pattern)).each do |match|
doc = HTML::Document.new(unescape_js(match.first))
doc.root.children.each do |child|
fragments.push child if child.tag?
end
end
if fragments.empty?
opts = [jquery_method, jquery_opt, id].compact
flunk "No JQuery call matches #{opts.inspect}"
end
if block
begin
in_scope, @selected = @selected, fragments
yield
ensure
@selected = in_scope
end
end
end
private
# Unescapes a JS string.
def unescape_js(js_string)
# js encodes double quotes and line breaks.
unescaped= js_string.gsub('\"', '"')
unescaped.gsub!('\\\'', "'")
unescaped.gsub!(/\\\//, '/')
unescaped.gsub!('\n', "\n")
unescaped.gsub!('\076', '>')
unescaped.gsub!('\074', '<')
# js encodes non-ascii characters.
unescaped.gsub!(PATTERN_UNICODE_ESCAPED_CHAR) {|u| [$1.hex].pack('U*')}
unescaped
end
end
end
end