kelp 0.1.9 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/History.md +10 -0
- data/examples/sinatra_app/features/checkbox_fail.feature +11 -0
- data/examples/sinatra_app/features/dropdown.feature +4 -4
- data/examples/sinatra_app/features/dropdown_fail.feature +28 -0
- data/examples/sinatra_app/features/field.feature +57 -0
- data/examples/sinatra_app/features/field_fail.feature +31 -0
- data/examples/sinatra_app/features/visibility.feature +96 -6
- data/examples/sinatra_app/features/visibility_fail.feature +30 -2
- data/examples/sinatra_app/views/form.erb +14 -0
- data/features/kelp_step_definitions.feature +101 -12
- data/features/step_definitions/app_steps.rb +24 -8
- data/kelp.gemspec +1 -1
- data/lib/kelp.rb +0 -15
- data/lib/kelp/attribute.rb +26 -4
- data/lib/kelp/checkbox.rb +33 -8
- data/lib/kelp/dropdown.rb +37 -11
- data/lib/kelp/exceptions.rb +4 -2
- data/lib/kelp/field.rb +80 -41
- data/lib/kelp/helper.rb +8 -1
- data/lib/kelp/navigation.rb +14 -8
- data/lib/kelp/scoping.rb +1 -3
- data/lib/kelp/visibility.rb +152 -167
- data/rails_generators/kelp/templates/web_steps.rb +2 -2
- data/spec/attribute_spec.rb +4 -4
- data/spec/checkbox_spec.rb +4 -4
- data/spec/dropdown_spec.rb +10 -10
- data/spec/field_spec.rb +15 -15
- data/spec/navigation_spec.rb +2 -2
- data/spec/spec_helper.rb +0 -9
- data/spec/visibility_spec.rb +40 -103
- metadata +8 -5
data/lib/kelp/helper.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'kelp/exceptions'
|
2
|
+
|
1
3
|
module Kelp
|
2
4
|
module Helper
|
3
5
|
# Convert a Cucumber::Ast::Table or multiline string into
|
@@ -14,11 +16,16 @@ module Kelp
|
|
14
16
|
# A slightly friendlier version of Capybara's `find_field`, which actually
|
15
17
|
# tells you which locator failed to match (instead of giving a useless
|
16
18
|
# Unable to find '#<XPath::Union:0xXXXXXXX>' message).
|
19
|
+
#
|
20
|
+
# @raise [Kelp::FieldNotFound]
|
21
|
+
# If no field with the given locator could be found
|
22
|
+
#
|
17
23
|
def nice_find_field(locator)
|
18
24
|
begin
|
19
25
|
field = find_field(locator)
|
20
26
|
rescue Capybara::ElementNotFound
|
21
|
-
raise
|
27
|
+
raise Kelp::FieldNotFound,
|
28
|
+
"Could not find field: '#{locator}'"
|
22
29
|
end
|
23
30
|
end
|
24
31
|
|
data/lib/kelp/navigation.rb
CHANGED
@@ -76,6 +76,9 @@ module Kelp
|
|
76
76
|
# Human-readable page name (mapped to a pathname by your `path_to` function),
|
77
77
|
# or an absolute path beginning with `/`.
|
78
78
|
#
|
79
|
+
# @raise [Kelp::Unexpected]
|
80
|
+
# If actual page path doesn't match the expected path
|
81
|
+
#
|
79
82
|
# @since 0.1.9
|
80
83
|
#
|
81
84
|
def should_be_on_page(page_name_or_path)
|
@@ -88,10 +91,10 @@ module Kelp
|
|
88
91
|
expect_path = page_name_or_path
|
89
92
|
end
|
90
93
|
actual_path = URI.parse(current_url).path
|
91
|
-
if actual_path
|
92
|
-
|
93
|
-
|
94
|
-
|
94
|
+
if actual_path != expect_path
|
95
|
+
raise Kelp::Unexpected,
|
96
|
+
"Expected to be on page: '#{expect_path}'" + \
|
97
|
+
"\nActually on page: '#{actual_path}'"
|
95
98
|
end
|
96
99
|
end
|
97
100
|
|
@@ -101,6 +104,9 @@ module Kelp
|
|
101
104
|
# @param [Hash] params
|
102
105
|
# Key => value parameters, as they would appear in the URL
|
103
106
|
#
|
107
|
+
# @raise [Kelp::Unexpected]
|
108
|
+
# If actual query parameters don't match expected parameters
|
109
|
+
#
|
104
110
|
# @since 0.1.9
|
105
111
|
#
|
106
112
|
def should_have_query(params)
|
@@ -110,10 +116,10 @@ module Kelp
|
|
110
116
|
params.each_pair do |k,v|
|
111
117
|
expected_params[k] = v.split(',')
|
112
118
|
end
|
113
|
-
if actual_params
|
114
|
-
|
115
|
-
|
116
|
-
|
119
|
+
if actual_params != expected_params
|
120
|
+
raise Kelp::Unexpected,
|
121
|
+
"Expected query params: '#{expected_params.inspect}'" + \
|
122
|
+
"\nActual query params: '#{actual_params.inspect}'"
|
117
123
|
end
|
118
124
|
end
|
119
125
|
|
data/lib/kelp/scoping.rb
CHANGED
@@ -12,10 +12,8 @@ module Kelp
|
|
12
12
|
# by features/support/selectors.rb, generated by cucumber-rails.
|
13
13
|
if defined? selector_for
|
14
14
|
within(*selector_for(locator)) { yield }
|
15
|
-
# Otherwise,
|
16
|
-
# and fall back on the Capybara locator syntax (CSS or XPath)
|
15
|
+
# Otherwise, fall back on the Capybara locator syntax (CSS or XPath)
|
17
16
|
else
|
18
|
-
locator.gsub!(/^"(.*?)"$/, '\1')
|
19
17
|
if locator =~ /\.?\//
|
20
18
|
within(:xpath, locator) { yield }
|
21
19
|
else
|
data/lib/kelp/visibility.rb
CHANGED
@@ -12,6 +12,28 @@ module Kelp
|
|
12
12
|
include Scoping
|
13
13
|
include XPaths
|
14
14
|
|
15
|
+
# Return `true` if the current page contains the given text or regular expression,
|
16
|
+
# or `false` if it does not.
|
17
|
+
#
|
18
|
+
# @param [String, Regexp] text_or_regexp
|
19
|
+
# Text or regular expression to look for
|
20
|
+
#
|
21
|
+
# @raise [ArgumentError]
|
22
|
+
# If the given argument isn't a String or Regexp
|
23
|
+
#
|
24
|
+
# @since 0.2.0
|
25
|
+
#
|
26
|
+
def page_contains?(text_or_regexp)
|
27
|
+
if text_or_regexp.class == String
|
28
|
+
return page.has_content?(text_or_regexp)
|
29
|
+
elsif text_or_regexp.class == Regexp
|
30
|
+
return page.has_xpath?('.//*', :text => text_or_regexp)
|
31
|
+
else
|
32
|
+
raise ArgumentError, "Expected String or Regexp, got #{text_or_regexp.class}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
|
15
37
|
# Verify the presence of content on the page. Passes when all the given items
|
16
38
|
# are found on the page, and fails if any of them are not found.
|
17
39
|
#
|
@@ -30,20 +52,16 @@ module Kelp
|
|
30
52
|
# If any of the expected text strings are not seen in the given scope
|
31
53
|
#
|
32
54
|
def should_see(texts, scope={})
|
33
|
-
texts = [texts] if (texts.class == String || texts.class == Regexp)
|
34
|
-
unexpected = []
|
35
55
|
in_scope(scope) do
|
36
|
-
texts.
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
56
|
+
texts = [texts] if (texts.class == String || texts.class == Regexp)
|
57
|
+
# Select all expected values that don't appear on the page
|
58
|
+
unexpected = texts.select do |text|
|
59
|
+
!page_contains?(text)
|
60
|
+
end
|
61
|
+
if !unexpected.empty?
|
62
|
+
raise Kelp::Unexpected,
|
63
|
+
"Expected to see: #{texts.inspect}\nDid not see: #{unexpected.inspect}"
|
42
64
|
end
|
43
|
-
end
|
44
|
-
if !unexpected.empty?
|
45
|
-
raise Kelp::Unexpected,
|
46
|
-
"Expected to see: #{texts.inspect}\nDid not see: #{unexpected.inspect}"
|
47
65
|
end
|
48
66
|
end
|
49
67
|
|
@@ -52,7 +70,7 @@ module Kelp
|
|
52
70
|
# items are found on the page, and fails if any of them are found.
|
53
71
|
#
|
54
72
|
# @param [String, Regexp, Array] texts
|
55
|
-
# Text(s) or
|
73
|
+
# Text(s) or Regexp(s) to look for
|
56
74
|
# @param [Hash] scope
|
57
75
|
# Scoping keywords as understood by {#in_scope}
|
58
76
|
#
|
@@ -60,149 +78,16 @@ module Kelp
|
|
60
78
|
# If any of the expected text strings are seen in the given scope
|
61
79
|
#
|
62
80
|
def should_not_see(texts, scope={})
|
63
|
-
texts = [texts] if (texts.class == String || texts.class == Regexp)
|
64
|
-
unexpected = []
|
65
81
|
in_scope(scope) do
|
66
|
-
texts.
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
unexpected << text
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
if !unexpected.empty?
|
75
|
-
raise Kelp::Unexpected,
|
76
|
-
"Expected not to see: #{texts.inspect}\nDid see: #{unexpected.inspect}"
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
|
81
|
-
# Ensure that the current page content includes a String or Regexp.
|
82
|
-
#
|
83
|
-
# @param [String, Regexp] text_or_regexp
|
84
|
-
# Content you expect to be on the page
|
85
|
-
#
|
86
|
-
def page_should_contain(text_or_regexp)
|
87
|
-
if text_or_regexp.class == String
|
88
|
-
page_should_contain_text(text_or_regexp)
|
89
|
-
elsif text_or_regexp.class == Regexp
|
90
|
-
page_should_contain_regexp(text_or_regexp)
|
91
|
-
else
|
92
|
-
raise ArgumentError, "Expected String or Regexp, got #{text_or_regexp.class}"
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
|
97
|
-
# Ensure that the current page content does not include a String or Regexp.
|
98
|
-
#
|
99
|
-
# @param [String, Regexp] text_or_regexp
|
100
|
-
# Content you expect to be missing from the page
|
101
|
-
#
|
102
|
-
def page_should_not_contain(text_or_regexp)
|
103
|
-
if text_or_regexp.class == String
|
104
|
-
page_should_not_contain_text(text_or_regexp)
|
105
|
-
elsif text_or_regexp.class == Regexp
|
106
|
-
page_should_not_contain_regexp(text_or_regexp)
|
107
|
-
else
|
108
|
-
raise ArgumentError, "Expected String or Regexp, got #{text_or_regexp.class}"
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
|
113
|
-
# Ensure that the current page content includes a String.
|
114
|
-
#
|
115
|
-
# @param [String] text
|
116
|
-
# Content you expect to be on the page
|
117
|
-
#
|
118
|
-
def page_should_contain_text(text)
|
119
|
-
if Kelp.driver == :capybara
|
120
|
-
if page.respond_to? :should
|
121
|
-
page.should have_content(text)
|
122
|
-
else
|
123
|
-
assert page.has_content?(text)
|
124
|
-
end
|
125
|
-
elsif Kelp.driver == :webrat
|
126
|
-
if defined?(Spec::Rails::Matchers)
|
127
|
-
response.should contain(text)
|
128
|
-
else
|
129
|
-
assert_contain text
|
130
|
-
end
|
131
|
-
else
|
132
|
-
raise NotImplementedError, "Unsupported driver: #{Kelp.driver}"
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
|
137
|
-
# Ensure that the current page content matches a Regexp.
|
138
|
-
#
|
139
|
-
# @param [Regexp] regexp
|
140
|
-
# Content you expect to match
|
141
|
-
#
|
142
|
-
def page_should_contain_regexp(regexp)
|
143
|
-
if Kelp.driver == :capybara
|
144
|
-
if page.respond_to? :should
|
145
|
-
page.should have_xpath('.//*', :text => regexp)
|
146
|
-
else
|
147
|
-
assert page.has_xpath?('.//*', :text => regexp)
|
148
|
-
end
|
149
|
-
elsif Kelp.driver == :webrat
|
150
|
-
if defined?(Spec::Rails::Matchers)
|
151
|
-
response.should contain(regexp)
|
152
|
-
else
|
153
|
-
assert_match(regexp, response_body)
|
154
|
-
end
|
155
|
-
else
|
156
|
-
raise NotImplementedError, "Unsupported driver: #{Kelp.driver}"
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
|
161
|
-
# Ensure that the current page content does not include a String.
|
162
|
-
#
|
163
|
-
# @param [String] text
|
164
|
-
# Content you expect to be missing from the page
|
165
|
-
#
|
166
|
-
def page_should_not_contain_text(text)
|
167
|
-
if Kelp.driver == :capybara
|
168
|
-
if page.respond_to? :should
|
169
|
-
page.should have_no_content(text)
|
170
|
-
else
|
171
|
-
assert page.has_no_content?(text)
|
172
|
-
end
|
173
|
-
elsif Kelp.driver == :webrat
|
174
|
-
if defined?(Spec::Rails::Matchers)
|
175
|
-
response.should_not contain(text)
|
176
|
-
else
|
177
|
-
hc = Webrat::Matchers::HasContent.new(text)
|
178
|
-
assert !hc.matches?(content), hc.negative_failure_message
|
179
|
-
end
|
180
|
-
else
|
181
|
-
raise NotImplementedError, "Unsupported driver: #{Kelp.driver}"
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
|
186
|
-
# Ensure that the current page content does not match a Regexp.
|
187
|
-
#
|
188
|
-
# @param [Regexp] regexp
|
189
|
-
# Content you expect to fail matching
|
190
|
-
#
|
191
|
-
def page_should_not_contain_regexp(regexp)
|
192
|
-
if Kelp.driver == :capybara
|
193
|
-
if page.respond_to? :should
|
194
|
-
page.should have_no_xpath('.//*', :text => regexp)
|
195
|
-
else
|
196
|
-
assert page.has_no_xpath?('.//*', :text => regexp)
|
82
|
+
texts = [texts] if (texts.class == String || texts.class == Regexp)
|
83
|
+
# Select all unexpected values that do appear on the page
|
84
|
+
unexpected = texts.select do |text|
|
85
|
+
page_contains?(text)
|
197
86
|
end
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
else
|
202
|
-
assert_not_contain(regexp)
|
87
|
+
if !unexpected.empty?
|
88
|
+
raise Kelp::Unexpected,
|
89
|
+
"Expected not to see: #{texts.inspect}\nDid see: #{unexpected.inspect}"
|
203
90
|
end
|
204
|
-
else
|
205
|
-
raise NotImplementedError, "Unsupported driver: #{Kelp.driver}"
|
206
91
|
end
|
207
92
|
end
|
208
93
|
|
@@ -221,12 +106,13 @@ module Kelp
|
|
221
106
|
# @param [Hash] scope
|
222
107
|
# Scoping keywords as understood by {#in_scope}
|
223
108
|
#
|
109
|
+
# @raise [Kelp::Unexpected]
|
110
|
+
# If no row is found containing all strings in `texts`
|
111
|
+
#
|
224
112
|
def should_see_in_same_row(texts, scope={})
|
225
113
|
in_scope(scope) do
|
226
|
-
if
|
227
|
-
|
228
|
-
elsif Kelp.driver == :webrat
|
229
|
-
raise NotImplementedError, "Not implemented yet"
|
114
|
+
if !page.has_xpath?(xpath_row_containing(texts))
|
115
|
+
raise Kelp::Unexpected, "Expected, but did not see: #{texts.inspect} in the same row"
|
230
116
|
end
|
231
117
|
end
|
232
118
|
end
|
@@ -245,12 +131,13 @@ module Kelp
|
|
245
131
|
# @param [Hash] scope
|
246
132
|
# Scoping keywords as understood by {#in_scope}
|
247
133
|
#
|
134
|
+
# @raise [Kelp::Unexpected]
|
135
|
+
# If a row is found containing all strings in `texts`
|
136
|
+
#
|
248
137
|
def should_not_see_in_same_row(texts, scope={})
|
249
138
|
in_scope(scope) do
|
250
|
-
if
|
251
|
-
|
252
|
-
elsif Kelp.driver == :webrat
|
253
|
-
raise NotImplementedError, "Not implemented yet"
|
139
|
+
if page.has_xpath?(xpath_row_containing(texts))
|
140
|
+
raise Kelp::Unexpected, "Did not expect, but did see: #{texts.inspect} in the same row"
|
254
141
|
end
|
255
142
|
end
|
256
143
|
end
|
@@ -276,9 +163,7 @@ module Kelp
|
|
276
163
|
def should_see_button(button_text, scope={})
|
277
164
|
in_scope(scope) do
|
278
165
|
xpath = XPath::HTML.button(button_text)
|
279
|
-
|
280
|
-
page.should have_xpath(xpath)
|
281
|
-
rescue rspec_unexpected
|
166
|
+
if !page.has_xpath?(xpath)
|
282
167
|
raise Kelp::Unexpected, "Expected to see button '#{button_text}', but button does not exist."
|
283
168
|
end
|
284
169
|
end
|
@@ -305,14 +190,114 @@ module Kelp
|
|
305
190
|
def should_not_see_button(button_text, scope={})
|
306
191
|
in_scope(scope) do
|
307
192
|
xpath = XPath::HTML.button(button_text)
|
308
|
-
|
309
|
-
page.should have_no_xpath(xpath)
|
310
|
-
rescue rspec_unexpected
|
193
|
+
if page.has_xpath?(xpath)
|
311
194
|
raise Kelp::Unexpected, "Did not expect to see button '#{button_text}', but button exists."
|
312
195
|
end
|
313
196
|
end
|
314
197
|
end
|
315
198
|
|
199
|
+
|
200
|
+
# -------------------------------------------------------------------
|
201
|
+
# DEPRECATED METHODS
|
202
|
+
# These will be removed in a future release of Kelp. Do not use them.
|
203
|
+
# -------------------------------------------------------------------
|
204
|
+
|
205
|
+
|
206
|
+
# Ensure that the current page content includes a String or Regexp.
|
207
|
+
#
|
208
|
+
# @deprecated
|
209
|
+
# Use {#should_see} instead
|
210
|
+
#
|
211
|
+
# @param [String, Regexp] text_or_regexp
|
212
|
+
# Content you expect to be on the page
|
213
|
+
#
|
214
|
+
def page_should_contain(text_or_regexp)
|
215
|
+
warn "WARNING: page_should_contain is deprecated. Use should_see instead."
|
216
|
+
if !page_contains?(text_or_regexp)
|
217
|
+
raise Kelp::Unexpected
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
|
222
|
+
# Ensure that the current page content does not include a String or Regexp.
|
223
|
+
#
|
224
|
+
# @deprecated
|
225
|
+
# Use {#should_not_see} instead
|
226
|
+
#
|
227
|
+
# @param [String, Regexp] text_or_regexp
|
228
|
+
# Content you expect to be missing from the page
|
229
|
+
#
|
230
|
+
def page_should_not_contain(text_or_regexp)
|
231
|
+
warn "WARNING: page_should_not_contain is deprecated. Use should_not_see instead."
|
232
|
+
if page_contains?(text_or_regexp)
|
233
|
+
raise Kelp::Unexpected
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
|
238
|
+
# Ensure that the current page content includes a String.
|
239
|
+
#
|
240
|
+
# @deprecated
|
241
|
+
# Use {#should_see} instead
|
242
|
+
#
|
243
|
+
# @param [String] text
|
244
|
+
# Content you expect to be on the page
|
245
|
+
#
|
246
|
+
def page_should_contain_text(text)
|
247
|
+
warn "WARNING: page_should_contain_text is deprecated. Use should_see instead."
|
248
|
+
if !page.has_content?(text)
|
249
|
+
raise Kelp::Unexpected
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
|
254
|
+
# Ensure that the current page content matches a Regexp.
|
255
|
+
#
|
256
|
+
# @deprecated
|
257
|
+
# Use {#should_see} instead
|
258
|
+
#
|
259
|
+
# @param [Regexp] regexp
|
260
|
+
# Content you expect to match
|
261
|
+
#
|
262
|
+
def page_should_contain_regexp(regexp)
|
263
|
+
warn "WARNING: page_should_contain_regexp is deprecated. Use should_see instead."
|
264
|
+
if !page.has_xpath?('.//*', :text => regexp)
|
265
|
+
raise Kelp::Unexpected
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
|
270
|
+
# Ensure that the current page content does not include a String.
|
271
|
+
#
|
272
|
+
# @deprecated
|
273
|
+
# Use {#should_not_see} instead
|
274
|
+
#
|
275
|
+
# @param [String] text
|
276
|
+
# Content you expect to be missing from the page
|
277
|
+
#
|
278
|
+
def page_should_not_contain_text(text)
|
279
|
+
warn "WARNING: page_should_not_contain_text is deprecated. Use should_not_see instead."
|
280
|
+
if page.has_content?(text)
|
281
|
+
raise Kelp::Unexpected
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
|
286
|
+
# Ensure that the current page content does not match a Regexp.
|
287
|
+
#
|
288
|
+
# @deprecated
|
289
|
+
# Use {#should_not_see} instead
|
290
|
+
#
|
291
|
+
# @param [Regexp] regexp
|
292
|
+
# Content you expect to fail matching
|
293
|
+
#
|
294
|
+
def page_should_not_contain_regexp(regexp)
|
295
|
+
warn "WARNING: page_should_not_contain_regexp is deprecated. Use should_not_see instead."
|
296
|
+
if page.has_xpath?('.//*', :text => regexp)
|
297
|
+
raise Kelp::Unexpected
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
316
301
|
end
|
317
302
|
end
|
318
303
|
|