turnip-extra_steps 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +3 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/Guardfile +77 -0
- data/LICENSE +21 -0
- data/README.md +39 -0
- data/Rakefile +8 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/config.ru +16 -0
- data/lib/turnip/extra_steps.rb +8 -0
- data/lib/turnip/extra_steps/all_steps.rb +8 -0
- data/lib/turnip/extra_steps/development_steps.rb +32 -0
- data/lib/turnip/extra_steps/email_steps.rb +148 -0
- data/lib/turnip/extra_steps/file_attachment_steps.rb +43 -0
- data/lib/turnip/extra_steps/support.rb +2 -0
- data/lib/turnip/extra_steps/support/custom_matchers.rb +30 -0
- data/lib/turnip/extra_steps/support/mail_finder.rb +59 -0
- data/lib/turnip/extra_steps/support/path_selector_fallbacks.rb +38 -0
- data/lib/turnip/extra_steps/support/step_fallback.rb +13 -0
- data/lib/turnip/extra_steps/support/tolerance_for_selenium_sync_issues.rb +42 -0
- data/lib/turnip/extra_steps/support/version.rb +3 -0
- data/lib/turnip/extra_steps/support/web_steps_helpers.rb +114 -0
- data/lib/turnip/extra_steps/table_steps.rb +187 -0
- data/lib/turnip/extra_steps/timecop_steps.rb +79 -0
- data/lib/turnip/extra_steps/version.rb +5 -0
- data/lib/turnip/extra_steps/web_steps.rb +760 -0
- data/turnip-extra_steps.gemspec +42 -0
- metadata +354 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
|
3
|
+
|
4
|
+
# Steps to travel through time using [Timecop](https://github.com/jtrupiano/timecop).
|
5
|
+
#
|
6
|
+
# See [this article](https://makandracards.com/makandra/1222-useful-cucumber-steps-to-travel-through-time-with-timecop) for details.
|
7
|
+
# FILE_COMMENT_END
|
8
|
+
|
9
|
+
|
10
|
+
if defined?(Timecop)
|
11
|
+
|
12
|
+
module TimecopHarness
|
13
|
+
|
14
|
+
# When you have to make your rails app time zone aware you have to go 100%
|
15
|
+
# otherwise you are better off ignoring time zones at all.
|
16
|
+
# https://makandracards.com/makandra/8723-guide-to-localizing-a-rails-application
|
17
|
+
|
18
|
+
def use_timezones?
|
19
|
+
active_record_loaded = defined?(ActiveRecord::Base)
|
20
|
+
(!active_record_loaded || ActiveRecord::Base.default_timezone != :local) && Time.zone
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse_time(str)
|
24
|
+
if use_timezones?
|
25
|
+
Time.zone.parse(str)
|
26
|
+
else
|
27
|
+
Time.parse(str)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def current_time
|
32
|
+
if use_timezones?
|
33
|
+
Time.current
|
34
|
+
else
|
35
|
+
Time.now
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
World(TimecopHarness)
|
42
|
+
|
43
|
+
# Example:
|
44
|
+
#
|
45
|
+
# Given the date is 2012-02-10
|
46
|
+
# Given the time is 2012-02-10 13:40
|
47
|
+
When /^the (?:date|time) is "?(\d{4}-\d{2}-\d{2}(?: \d{1,2}:\d{2})?)"?$/ do |time|
|
48
|
+
Timecop.travel(parse_time(time))
|
49
|
+
end
|
50
|
+
|
51
|
+
# Example:
|
52
|
+
#
|
53
|
+
# Given the time is 13:40
|
54
|
+
When /^the time is "?(\d{1,2}:\d{2})"?$/ do |time_without_date|
|
55
|
+
Timecop.travel(parse_time(time_without_date)) # date will be today
|
56
|
+
end
|
57
|
+
|
58
|
+
# Example:
|
59
|
+
#
|
60
|
+
# When it is 10 minutes later
|
61
|
+
# When it is a few hours earlier
|
62
|
+
When /^it is (\d+|a|some|a few) (seconds?|minutes?|hours?|days?|weeks?|months?|years?) (later|earlier)$/ do |amount, unit, direction|
|
63
|
+
amount = case amount
|
64
|
+
when 'a'
|
65
|
+
1
|
66
|
+
when 'some', 'a few'
|
67
|
+
10
|
68
|
+
else
|
69
|
+
amount.to_i
|
70
|
+
end
|
71
|
+
amount = -amount if direction == 'earlier'
|
72
|
+
Timecop.travel(current_time + amount.send(unit))
|
73
|
+
end
|
74
|
+
|
75
|
+
After do
|
76
|
+
Timecop.return
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,760 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
|
3
|
+
# Most of cucumber-rails' original web steps plus a few of our own.
|
4
|
+
#
|
5
|
+
# Note that cucumber-rails deprecated all its steps quite a while ago with the following
|
6
|
+
# deprecation notice. Decide for yourself whether you want to use them:
|
7
|
+
#
|
8
|
+
# > This file was generated by Cucumber-Rails and is only here to get you a head start
|
9
|
+
# > These step definitions are thin wrappers around the Capybara/Webrat API that lets you
|
10
|
+
# > visit pages, interact with widgets and make assertions about page content.
|
11
|
+
#
|
12
|
+
# > If you use these step definitions as basis for your features you will quickly end up
|
13
|
+
# > with features that are:
|
14
|
+
#
|
15
|
+
# > * Hard to maintain
|
16
|
+
# > * Verbose to read
|
17
|
+
#
|
18
|
+
# > A much better approach is to write your own higher level step definitions, following
|
19
|
+
# > the advice in the following blog posts:
|
20
|
+
#
|
21
|
+
# > * http://benmabey.com/2008/05/19/imperative-vs-declarative-scenarios-in-user-stories.html
|
22
|
+
# > * http://dannorth.net/2011/01/31/whose-domain-is-it-anyway/
|
23
|
+
# > * http://elabs.se/blog/15-you-re-cuking-it-wrong
|
24
|
+
#
|
25
|
+
# FILE_COMMENT_END
|
26
|
+
|
27
|
+
require 'turnip/extra_steps/support/tolerance_for_selenium_sync_issues'
|
28
|
+
require 'turnip/extra_steps/support/path_selector_fallbacks'
|
29
|
+
require 'turnip/extra_steps/support/step_fallback'
|
30
|
+
require 'turnip/extra_steps/support/custom_matchers'
|
31
|
+
require 'turnip/extra_steps/support/web_steps_helpers'
|
32
|
+
require 'uri'
|
33
|
+
require 'cgi'
|
34
|
+
|
35
|
+
|
36
|
+
# You can append `within [selector]` to any other web step
|
37
|
+
#
|
38
|
+
# Example:
|
39
|
+
#
|
40
|
+
# Then I should see "some text" within ".page_body"
|
41
|
+
#When /^(.*) within (.*[^:])$/ do |nested_step, parent|
|
42
|
+
step "Then I should see :text within :parent" do |text, parent|
|
43
|
+
with_scope(parent) { step(nested_step) }
|
44
|
+
end
|
45
|
+
|
46
|
+
# nodoc
|
47
|
+
#When /^(.*) within (.*[^:]):$/ do |nested_step, parent, table_or_string|
|
48
|
+
#with_scope(parent) { step("#{nested_step}:", table_or_string) }
|
49
|
+
#end
|
50
|
+
|
51
|
+
#Given /^(?:|I )am on (.+)$/ do |page_name|
|
52
|
+
step "I am on :page_name" do |page_name|
|
53
|
+
visit _path_to(page_name)
|
54
|
+
end
|
55
|
+
|
56
|
+
#When /^(?:|I )go to (.+)$/ do |page_name|
|
57
|
+
step "I go to :page_name" do |page_name|
|
58
|
+
visit _path_to(page_name)
|
59
|
+
end
|
60
|
+
|
61
|
+
#Then /^(?:|I )should be on (.+)$/ do |page_name|
|
62
|
+
step "I should be on :page_name" do |page_name|
|
63
|
+
patiently do
|
64
|
+
fragment = URI.parse(current_url).fragment
|
65
|
+
fragment.sub!(/[#?].*/, '') if fragment # most js frameworks will usually use ? and # for params, we dont care about those
|
66
|
+
current_path = URI.parse(current_url).path
|
67
|
+
current_path << "##{fragment}" if fragment.present?
|
68
|
+
expected_path = _path_to(page_name)
|
69
|
+
|
70
|
+
# Consider two pages equal if they only differ by a trailing slash.
|
71
|
+
current_path = expected_path if current_path.chomp("/") == expected_path.chomp("/")
|
72
|
+
current_path = expected_path if current_path.gsub("/#", "#") == expected_path.gsub("/#", "#")
|
73
|
+
|
74
|
+
expect(current_path).to eq(expected_path)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
#When /^(?:|I )press "([^"]*)"$/ do |button|
|
79
|
+
step "I press on :button" do |button|
|
80
|
+
patiently do
|
81
|
+
click_button(button)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
#When /^(?:|I )follow "([^"]*)"$/ do |link|
|
86
|
+
step "I follow :link" do |link|
|
87
|
+
patiently do
|
88
|
+
click_link(link)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Fill in text field
|
93
|
+
#When /^(?:|I )fill in "([^"]*)" (?:with|for) "([^"]*)"$/ do |field, value|
|
94
|
+
step "I fill in :field with :value" do |field, value|
|
95
|
+
patiently do
|
96
|
+
fill_in(field, :with => value)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Fill in text field with multi-line block
|
101
|
+
# You can use a doc string to supply multi-line text
|
102
|
+
#
|
103
|
+
# Example:
|
104
|
+
#
|
105
|
+
# When I fill in "some field" with:
|
106
|
+
# """
|
107
|
+
# Apple
|
108
|
+
# Banana
|
109
|
+
# Pear
|
110
|
+
# """
|
111
|
+
#When /^(?:|I )fill in "([^"]*)" (?:with|for):$/ do |field, value|
|
112
|
+
step "I fill in :field with:" do |field, value|
|
113
|
+
patiently do
|
114
|
+
fill_in(field, :with => value)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Fill in text field
|
119
|
+
#When /^(?:|I )fill in "([^"]*)" (?:with|for) '(.*)'$/ do |field, value|
|
120
|
+
#step "I fill in :field with :value" do |field, value|
|
121
|
+
#patiently do
|
122
|
+
#fill_in(field, :with => value)
|
123
|
+
#end
|
124
|
+
#end
|
125
|
+
|
126
|
+
# Select from select box
|
127
|
+
#When /^(?:|I )select "([^"]*)" from "([^"]*)"$/ do |value, field|
|
128
|
+
step "I select :value from :field" do |value, field|
|
129
|
+
patiently do
|
130
|
+
select(value, :from => field)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Check a checkbox
|
135
|
+
#When /^(?:|I )check "([^"]*)"$/ do |field|
|
136
|
+
step "I check :field" do |field|
|
137
|
+
patiently do
|
138
|
+
check(field)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Uncheck a checkbox
|
143
|
+
#When /^(?:|I )uncheck "([^"]*)"$/ do |field|
|
144
|
+
step "I uncheck :field" do |field|
|
145
|
+
patiently do
|
146
|
+
uncheck(field)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Select a radio button
|
151
|
+
#When /^(?:|I )choose "([^"]*)"$/ do |field|
|
152
|
+
step "I choose :field" do |field|
|
153
|
+
patiently do
|
154
|
+
choose(field)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Attach a file to a file upload form field
|
159
|
+
#When /^(?:|I )attach the file "([^"]*)" to "([^"]*)"$/ do |path, field|
|
160
|
+
step "I attach the file :path to :field" do |path, field|
|
161
|
+
patiently do
|
162
|
+
attach_file(field, File.expand_path(path))
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# Checks that some text appears on the page
|
167
|
+
#
|
168
|
+
# Note that this does not detect if the text might be hidden via CSS
|
169
|
+
#Then /^(?:|I )should see "([^"]*)"$/ do |text|
|
170
|
+
step "I should see :text" do |text|
|
171
|
+
patiently do
|
172
|
+
page.should have_content(text)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# Checks that a regexp appears on the page
|
177
|
+
#
|
178
|
+
# Note that this does not detect if the text might be hidden via CSS
|
179
|
+
#Then /^(?:|I )should see \/([^\/]*)\/$/ do |regexp|
|
180
|
+
step "I should see :regexp regexp" do |regexp|
|
181
|
+
regexp = Regexp.new(regexp)
|
182
|
+
patiently do
|
183
|
+
page.should have_xpath('//*', :text => regexp)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
#Then /^(?:|I )should not see "([^"]*)"$/ do |text|
|
188
|
+
step "I should not see :text" do |text|
|
189
|
+
patiently do
|
190
|
+
page.should have_no_content(text)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
#Then /^(?:|I )should not see \/([^\/]*)\/$/ do |regexp|
|
195
|
+
step "I should not see :regexp regexp" do |regexp|
|
196
|
+
patiently do
|
197
|
+
regexp = Regexp.new(regexp)
|
198
|
+
page.should have_no_xpath('//*', :text => regexp)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
# Checks that an input field contains some value (allowing * as wildcard character)
|
204
|
+
#Then /^the "([^"]*)" field should (not )?contain "([^"]*)"$/ do |label, negate, expected_string|
|
205
|
+
step "the :label field :whether_to contain :expected_string" do |label, positive, expected_string|
|
206
|
+
patiently do
|
207
|
+
field = find_field(label)
|
208
|
+
field_value = case field.tag_name
|
209
|
+
when 'select'
|
210
|
+
options = field.all('option')
|
211
|
+
selected_option = options.detect(&:selected?) || options.first
|
212
|
+
if selected_option && selected_option.text.present?
|
213
|
+
selected_option.text.strip
|
214
|
+
else
|
215
|
+
''
|
216
|
+
end
|
217
|
+
else
|
218
|
+
field.value
|
219
|
+
end
|
220
|
+
if positive
|
221
|
+
expect(field_value).to contain_with_wildcards(expected_string)
|
222
|
+
else
|
223
|
+
expect(field_value).not_to contain_with_wildcards(expected_string)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# Checks that a multiline textarea contains some value (allowing * as wildcard character)
|
229
|
+
#Then(/^the "(.*?)" field should (not )?contain:$/) do |label, negate, expected_string|
|
230
|
+
step "the :label field :whether_to contain:" do |label, positive, expected_string|
|
231
|
+
patiently do
|
232
|
+
field = find_field(label)
|
233
|
+
if positive
|
234
|
+
expect(field.value.chomp).to contain_with_wildcards(expected_string)
|
235
|
+
else
|
236
|
+
expect(field.value.chomp).not_to contain_with_wildcards(expected_string)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
# Checks that a list of label/value pairs are visible as control inputs.
|
242
|
+
#
|
243
|
+
# Example:
|
244
|
+
#
|
245
|
+
# Then I should see a form with the following values:
|
246
|
+
# | E-mail | foo@bar.com |
|
247
|
+
# | Role | Administrator |
|
248
|
+
#
|
249
|
+
#Then /^I should see a form with the following values:$/ do |table|
|
250
|
+
step "I should see a form with the following values:" do |table|
|
251
|
+
expectations = table.raw
|
252
|
+
expectations.each do |label, expected_value|
|
253
|
+
step %(the "#{label}" field should contain "#{expected_value}")
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
# Checks that an input field was wrapped with a validation error
|
258
|
+
#Then /^the "([^"]*)" field should have the error "([^"]*)"$/ do |field, error_message|
|
259
|
+
step "the :field should have the error :error_message" do |field, error_message|
|
260
|
+
patiently do
|
261
|
+
element = find_field(field)
|
262
|
+
classes = element.find(:xpath, '..')[:class].split(' ')
|
263
|
+
|
264
|
+
form_for_input = element.find(:xpath, 'ancestor::form[1]')
|
265
|
+
using_formtastic = form_for_input[:class].include?('formtastic')
|
266
|
+
error_class = using_formtastic ? 'error' : 'field_with_errors'
|
267
|
+
|
268
|
+
classes.should include(error_class)
|
269
|
+
|
270
|
+
if using_formtastic
|
271
|
+
error_paragraph = element.find(:xpath, '../*[@class="inline-errors"][1]')
|
272
|
+
error_paragraph.should have_content(error_message)
|
273
|
+
else
|
274
|
+
page.should have_content("#{field.titlecase} #{error_message}")
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
#Then /^the "([^\"]*)" field should( not)? have an error$/ do |label, negate|
|
280
|
+
step "the :label field :whether_to have an error" do |label, positive|
|
281
|
+
patiently do
|
282
|
+
expectation = positive ? :should : :should_not
|
283
|
+
field = find_field(label)
|
284
|
+
field[:id].should be_present # prevent bad CSS selector if field lacks id
|
285
|
+
page.send(expectation, have_css(".field_with_errors ##{field[:id]}"))
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
#Then /^the "([^"]*)" field should have no error$/ do |field|
|
290
|
+
step "the :field should have no error" do |field|
|
291
|
+
patiently do
|
292
|
+
element = find_field(field)
|
293
|
+
classes = element.find(:xpath, '..')[:class].split(' ')
|
294
|
+
classes.should_not include('field_with_errors')
|
295
|
+
classes.should_not include('error')
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
# nodoc
|
300
|
+
#Then /^the "([^"]*)" checkbox should( not)? be checked$/ do |label, negate|
|
301
|
+
step "the :label checkbox :whether_to be checked" do |label, positive|
|
302
|
+
patiently do
|
303
|
+
field = find_field(label)
|
304
|
+
if positive
|
305
|
+
expect(field).to be_checked
|
306
|
+
else
|
307
|
+
expect(field).not_to be_checked
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
#Then /^the radio button "([^"]*)" should( not)? be (?:checked|selected)$/ do |field, negate|
|
313
|
+
step "the radio button :field :whether_to be checked/selected" do |positive, action|
|
314
|
+
patiently do
|
315
|
+
expectation = positive ? :has_checked_field? : :has_no_checked_field?
|
316
|
+
page.send(expectation, field).should == true
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
# Example:
|
321
|
+
#
|
322
|
+
# I should have the following query string:
|
323
|
+
# | locale | de |
|
324
|
+
# | currency_code | EUR |
|
325
|
+
#
|
326
|
+
# Succeeds when the URL contains the given `locale` and `currency_code` params
|
327
|
+
#Then /^(?:|I )should have the following query string:$/ do |expected_pairs|
|
328
|
+
step "I should have the following query string:" do |expected_pairs|
|
329
|
+
patiently do
|
330
|
+
query = URI.parse(current_url).query
|
331
|
+
actual_params = query ? CGI.parse(query) : {}
|
332
|
+
expected_params = {}
|
333
|
+
expected_pairs.rows_hash.each_pair{|k,v| expected_params[k] = v.split(',')}
|
334
|
+
|
335
|
+
actual_params.should == expected_params
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
# Open the current Capybara page using the `launchy` gem
|
340
|
+
#Then /^show me the page$/ do
|
341
|
+
step "show me the page" do
|
342
|
+
save_and_open_page
|
343
|
+
end
|
344
|
+
|
345
|
+
|
346
|
+
# Checks for the existance of an input field (given its id or label)
|
347
|
+
#Then /^I should( not)? see a field "([^"]*)"$/ do |negate, name|
|
348
|
+
step "I should :whether_to see a field :name" do |positive, name|
|
349
|
+
expectation = positive ? :should : :should_not
|
350
|
+
patiently do
|
351
|
+
begin
|
352
|
+
field = find_field(name)
|
353
|
+
rescue Capybara::ElementNotFound
|
354
|
+
# In Capybara 0.4+ #find_field raises an error instead of returning nil
|
355
|
+
end
|
356
|
+
field.send(expectation, be_present)
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
# Use this step to test for a number or money amount instead of a simple `Then I should see`
|
361
|
+
#
|
362
|
+
# Checks for an unexpected minus sign, correct decimal places etc.
|
363
|
+
#
|
364
|
+
# See [here](https://makandracards.com/makandra/1225-test-that-a-number-or-money-amount-is-shown-with-cucumber) for details
|
365
|
+
#Then /^I should( not)? see the (?:number|amount) ([\-\d,\.]+)(?: (.*?))?$/ do |negate, amount, unit|
|
366
|
+
step "I should :whether_to see the number/amount :amount :unit" do |positive, amount, unit|
|
367
|
+
no_minus = amount.starts_with?('-') ? '' : '[^\\-]'
|
368
|
+
nbsp = " "
|
369
|
+
regexp = Regexp.new(no_minus + "\\b" + Regexp.quote(amount) + (unit ? "( |#{nbsp}| )(#{unit}|#{Regexp.quote(HTMLEntities.new.encode(unit, :named))})" :"\\b"))
|
370
|
+
expectation = positive ? :should : :should_not
|
371
|
+
patiently do
|
372
|
+
page.body.send(expectation, match(regexp))
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
# Checks `Content-Type` HTTP header
|
377
|
+
#Then /^I should get a response with content-type "([^\"]*)"$/ do |expected_content_type|
|
378
|
+
step "I should get a response with context-type :expected_content_type" do |expected_content_type|
|
379
|
+
page.response_headers['Content-Type'].should =~ /\A#{Regexp.quote(expected_content_type)}($|;)/
|
380
|
+
end
|
381
|
+
|
382
|
+
# Checks `Content-Disposition` HTTP header
|
383
|
+
#
|
384
|
+
# Attention: Doesn't work with Selenium, see https://github.com/jnicklas/capybara#gotchas
|
385
|
+
#Then /^I should get a download with filename "([^\"]*)"$/ do |filename|
|
386
|
+
step "I should get a download with filename :filename" do |filename|
|
387
|
+
page.response_headers['Content-Disposition'].should =~ /filename="#{filename}"$/
|
388
|
+
end
|
389
|
+
|
390
|
+
# Checks that a certain option is selected for a text field
|
391
|
+
#Then /^"([^"]*)" should be selected for "([^"]*)"$/ do |value, field|
|
392
|
+
step ":value should be selected for :field" do |value, field|
|
393
|
+
step %(the "#{field}" field should contain "#{value}")
|
394
|
+
end
|
395
|
+
|
396
|
+
#Then /^nothing should be selected for "([^"]*)"?$/ do |field|
|
397
|
+
step "nothing should be selected for :field" do |field|
|
398
|
+
patiently do
|
399
|
+
select = find_field(field)
|
400
|
+
begin
|
401
|
+
select.find(:xpath, ".//option[@selected = 'selected']").should be_blank
|
402
|
+
rescue Capybara::ElementNotFound
|
403
|
+
end
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
# Checks for the presence of an option in a select
|
408
|
+
#Then /^"([^"]*)" should( not)? be an option for "([^"]*)"$/ do |value, negate, field|
|
409
|
+
step ":value :whether_to be an option for :field" do |value, positive, field|
|
410
|
+
patiently do
|
411
|
+
xpath = ".//option[text() = '#{value}']"
|
412
|
+
if positive
|
413
|
+
field_labeled(field).find(:xpath, xpath).should be_present
|
414
|
+
else
|
415
|
+
begin
|
416
|
+
field_labeled(field).find(:xpath, xpath).should_not be_present
|
417
|
+
rescue Capybara::ElementNotFound
|
418
|
+
end
|
419
|
+
end
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
# Like `Then I should see`, but with single instead of double quotes. In case
|
424
|
+
# the expected string contains quotes as well.
|
425
|
+
#Then /^(?:|I )should see '([^']*)'$/ do |text|
|
426
|
+
step "I should see :text" do |text|
|
427
|
+
patiently do
|
428
|
+
page.should have_content(text)
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
432
|
+
# Check that the raw HTML contains a string
|
433
|
+
#Then /^I should see "([^\"]*)" in the HTML$/ do |text|
|
434
|
+
step "I should see :text in the HTML" do |text|
|
435
|
+
patiently do
|
436
|
+
page.body.should include(text)
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
#Then /^I should not see "([^\"]*)" in the HTML$/ do |text|
|
441
|
+
step "I should not see :text in the HTML" do |text|
|
442
|
+
patiently do
|
443
|
+
page.body.should_not include(text)
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
# Checks that status code is 400..599
|
448
|
+
#Then /^I should see an error$/ do
|
449
|
+
step "I should see an error" do
|
450
|
+
(400 .. 599).should include(page.status_code)
|
451
|
+
end
|
452
|
+
|
453
|
+
#nodoc
|
454
|
+
#Then /^the window should be titled "([^"]*)"$/ do |title|
|
455
|
+
step "the window should be title :title" do |title|
|
456
|
+
patiently do
|
457
|
+
page.should have_css('title', :text => title)
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
#When /^I reload the page$/ do
|
462
|
+
step "I reload the page" do
|
463
|
+
case Capybara::current_driver
|
464
|
+
when :selenium
|
465
|
+
page.execute_script(<<-JAVASCRIPT)
|
466
|
+
window.location.reload(true);
|
467
|
+
JAVASCRIPT
|
468
|
+
else
|
469
|
+
visit current_path
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
# Checks that an element is actually present and visible, also considering styles.
|
474
|
+
# Within a selenium test, the browser is asked whether the element is really visible
|
475
|
+
# In a non-selenium test, we only check for `.hidden`, `.invisible` or `style: display:none`
|
476
|
+
#
|
477
|
+
# The step 'Then (the tag )?"..." should **not** be visible' is ambiguous. Please use 'Then (the tag )?"..." should be hidden' or 'Then I should not see "..."' instead.
|
478
|
+
#
|
479
|
+
# More details [here](https://makandracards.com/makandra/1049-capybara-check-that-a-page-element-is-hidden-via-css)
|
480
|
+
#Then /^(the tag )?"([^\"]+)" should( not)? be visible$/ do |tag, selector_or_text, hidden|
|
481
|
+
step "the tag :selector_or_text :whether_to be visible" do |selector_or_text, positive|
|
482
|
+
unless positive
|
483
|
+
warn "The step 'Then ... should not be visible' is ambiguous. Please use 'Then ... should be hidden' or 'Then I should not see ...' instead."
|
484
|
+
end
|
485
|
+
|
486
|
+
options = {}
|
487
|
+
options.store(:selector, selector_or_text)
|
488
|
+
|
489
|
+
positive ? assert_visible(options) : assert_hidden(options)
|
490
|
+
end
|
491
|
+
|
492
|
+
step ":selector_or_text :whether_to be visible" do |selector_or_text, positive|
|
493
|
+
unless positive
|
494
|
+
warn "The step 'Then ... should not be visible' is ambiguous. Please use 'Then ... should be hidden' or 'Then I should not see ...' instead."
|
495
|
+
end
|
496
|
+
|
497
|
+
options = {}
|
498
|
+
options.store(:text, selector_or_text)
|
499
|
+
|
500
|
+
positive ? assert_visible(options) : assert_hidden(options)
|
501
|
+
end
|
502
|
+
|
503
|
+
|
504
|
+
|
505
|
+
# Checks that an element is actually present and hidden, also considering styles.
|
506
|
+
# Within a selenium test, the browser is asked whether the element is really hidden.
|
507
|
+
# In a non-selenium test, we only check for `.hidden`, `.invisible` or `style: display:none`
|
508
|
+
#Then /^(the tag )?"([^\"]+)" should be hidden$/ do |tag, selector_or_text|
|
509
|
+
step "the tag :selector_or_text should be hidden" do |selector_or_text|
|
510
|
+
options = {}
|
511
|
+
options.store(:selector, selector_or_text)
|
512
|
+
|
513
|
+
assert_hidden(options)
|
514
|
+
end
|
515
|
+
|
516
|
+
#Then /^(the tag )?"([^\"]+)" should be hidden$/ do |tag, selector_or_text|
|
517
|
+
step ":selector_or_text should be hidden" do |selector_or_text|
|
518
|
+
options = {}
|
519
|
+
options.store(:text, selector_or_text)
|
520
|
+
|
521
|
+
assert_hidden(options)
|
522
|
+
end
|
523
|
+
|
524
|
+
|
525
|
+
|
526
|
+
# Click on some text that might not be a link
|
527
|
+
#When /^I click on "([^\"]+)"$/ do |text|
|
528
|
+
step "I click on :text" do |text|
|
529
|
+
patiently do
|
530
|
+
contains_text = %{contains(., \"#{text}\")}
|
531
|
+
# find the innermost selector that matches
|
532
|
+
element = page.find(:xpath, ".//*[#{contains_text} and not (./*[#{contains_text}])]")
|
533
|
+
element.click
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
# Use this step to check external links.
|
538
|
+
#
|
539
|
+
# Example:
|
540
|
+
#
|
541
|
+
# Then "Sponsor" should link to "http://makandra.com"
|
542
|
+
#
|
543
|
+
#Then /^"([^"]*)" should link to "([^"]*)"$/ do |link_label, target|
|
544
|
+
step ":link_label should link to :target" do |link_label, target|
|
545
|
+
patiently do
|
546
|
+
link = find_link(link_label)
|
547
|
+
link[:href].should =~ /#{Regexp.escape target}(\?[^\/]*)?$/ # ignore trailing timestamps
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
551
|
+
# Example:
|
552
|
+
#
|
553
|
+
# Then I should see an element ".page .container"
|
554
|
+
#
|
555
|
+
#Then /^I should (not )?see an element "([^"]*)"$/ do |negate, selector|
|
556
|
+
step "I :whether_to see an element :selector" do |positive, selector|
|
557
|
+
expectation = positive ? :should : :should_not
|
558
|
+
patiently do
|
559
|
+
page.send(expectation, have_css(selector))
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
# Checks that the result has content type `text/plain`
|
564
|
+
#Then /^I should get a text response$/ do
|
565
|
+
step "I should get a text response" do
|
566
|
+
step 'I should get a response with content-type "text/plain"'
|
567
|
+
end
|
568
|
+
|
569
|
+
# Click a link within an element matching the given selector. Will try to be clever
|
570
|
+
# and disregard elements that don't contain a matching link.
|
571
|
+
#
|
572
|
+
# Example:
|
573
|
+
#
|
574
|
+
# When I follow "Read more" inside any ".text_snippet"
|
575
|
+
#
|
576
|
+
#When /^I follow "([^"]*)" inside any "([^"]*)"$/ do |label, selector|
|
577
|
+
step "I follow :label inside my :selector" do
|
578
|
+
node = find("#{selector} a", :text => label)
|
579
|
+
node.click
|
580
|
+
end
|
581
|
+
|
582
|
+
#Then /^I should( not)? see "([^"]*)" inside any "([^"]*)"$/ do |negate, text, selector|
|
583
|
+
step "I :whether_to see :text inside my :selector" do |positive, text, selector|
|
584
|
+
expectation = positive ? :should : :should_not
|
585
|
+
page.send(expectation, have_css(selector, :text => text))
|
586
|
+
end
|
587
|
+
|
588
|
+
#When /^I fill in "([^"]*)" with "([^"]*)" inside any "([^"]*)"$/ do |field, value, selector|
|
589
|
+
step "I fill in :field with :value inside any :selector" do |field, value, selector|
|
590
|
+
containers = all(:css, selector)
|
591
|
+
input = nil
|
592
|
+
containers.detect do |container|
|
593
|
+
input = container.first(:xpath, XPath::HTML.fillable_field(field))
|
594
|
+
end
|
595
|
+
if input
|
596
|
+
input.set(value)
|
597
|
+
else
|
598
|
+
raise "Could not find an input field \"#{field}\" inside any \"#{selector}\""
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
#When /^I confirm the browser dialog$/ do
|
603
|
+
step "I confirm the browser dialog" do
|
604
|
+
page.driver.browser.switch_to.alert.accept
|
605
|
+
end
|
606
|
+
|
607
|
+
#When /^I cancel the browser dialog$/ do
|
608
|
+
step "I cancel the browser dialog" do
|
609
|
+
page.driver.browser.switch_to.alert.dismiss
|
610
|
+
end
|
611
|
+
|
612
|
+
#When /^I enter "([^"]*)" into the browser dialog$/ do |text|
|
613
|
+
step "I enter :text into the browser dialog" do
|
614
|
+
alert = page.driver.browser.switch_to.alert
|
615
|
+
alert.send_keys(text)
|
616
|
+
alert.accept
|
617
|
+
end
|
618
|
+
|
619
|
+
#When /^I switch to the new tab$/ do
|
620
|
+
step "I switch to the new tab" do
|
621
|
+
Capybara::current_driver == :selenium or raise("This step works only with selenium")
|
622
|
+
page.driver.browser.switch_to.window(page.driver.browser.window_handles.last)
|
623
|
+
end
|
624
|
+
|
625
|
+
# Checks that these strings are rendered in the given order in a single line or in multiple lines
|
626
|
+
#
|
627
|
+
# Example:
|
628
|
+
#
|
629
|
+
# Then I should see in this order:
|
630
|
+
# | Alpha Group |
|
631
|
+
# | Augsburg |
|
632
|
+
# | Berlin |
|
633
|
+
# | Beta Group |
|
634
|
+
#
|
635
|
+
#Then /^I should see in this order:?$/ do |text|
|
636
|
+
step "I should see in this order:" do |text|
|
637
|
+
if text.is_a?(String)
|
638
|
+
lines = text.split(/\n/)
|
639
|
+
else
|
640
|
+
lines = text.raw.flatten
|
641
|
+
end
|
642
|
+
lines = lines.collect { |line| line.gsub(/\s+/, ' ')}.collect(&:strip).reject(&:blank?)
|
643
|
+
pattern = lines.collect(&Regexp.method(:quote)).join('.*?')
|
644
|
+
pattern = Regexp.compile(pattern)
|
645
|
+
patiently do
|
646
|
+
page.text.gsub(/\s+/, ' ').should =~ pattern
|
647
|
+
end
|
648
|
+
end
|
649
|
+
|
650
|
+
# Tests that an input or button with the given label is disabled.
|
651
|
+
#Then /^the "([^\"]*)" (field|button) should( not)? be disabled$/ do |label, kind, negate|
|
652
|
+
step "the :label :kind :wether_to be disabled" do |label, kind, positive|
|
653
|
+
if kind == 'field'
|
654
|
+
element = find_field(label)
|
655
|
+
else
|
656
|
+
element = find_button(label)
|
657
|
+
end
|
658
|
+
expectation = positive ? :should : :should_not
|
659
|
+
["false", "", nil].send(expectation, include(element[:disabled]))
|
660
|
+
end
|
661
|
+
|
662
|
+
# Tests that a field with the given label is visible.
|
663
|
+
#Then /^the "([^\"]*)" field should( not)? be visible$/ do |label, hidden|
|
664
|
+
step "the :label field :whether_to be visible" do |label, positive|
|
665
|
+
field = find_field(label)
|
666
|
+
|
667
|
+
case Capybara::current_driver
|
668
|
+
when :selenium, :webkit
|
669
|
+
patiently do
|
670
|
+
visibility_detecting_javascript = %[
|
671
|
+
(function(){
|
672
|
+
var field = $('##{field['id']}');
|
673
|
+
return(field.is(':visible'));
|
674
|
+
})();
|
675
|
+
].gsub(/\n/, ' ')
|
676
|
+
page.evaluate_script(visibility_detecting_javascript).should == !hidden
|
677
|
+
end
|
678
|
+
else
|
679
|
+
expectation = positive ? :should : :should_not
|
680
|
+
field.send(expectation, be_visible)
|
681
|
+
end
|
682
|
+
end
|
683
|
+
|
684
|
+
# Waits for the page to finish loading and AJAX requests to finish.
|
685
|
+
#
|
686
|
+
# More details [here](https://makandracards.com/makandra/12139-waiting-for-page-loads-and-ajax-requests-to-finish-with-capybara).
|
687
|
+
#When /^I wait for the page to load$/ do
|
688
|
+
step "I wait for the page to load" do
|
689
|
+
if [:selenium, :webkit, :poltergeist].include?(Capybara.current_driver)
|
690
|
+
patiently do
|
691
|
+
# when no jQuery is loaded, we assume there are no pending AJAX requests
|
692
|
+
page.evaluate_script("typeof jQuery === 'undefined' || $.active == 0").should == true
|
693
|
+
end
|
694
|
+
end
|
695
|
+
page.has_content? ''
|
696
|
+
end
|
697
|
+
|
698
|
+
# Performs HTTP basic authentication with the given credentials and visits the given path.
|
699
|
+
#
|
700
|
+
# More details [here](https://makandracards.com/makandra/971-perform-http-basic-authentication-in-cucumber).
|
701
|
+
#When /^I perform basic authentication as "([^\"]*)\/([^\"]*)" and go to (.*)$/ do |user, password, page_name|
|
702
|
+
step "I perform basic authentication as :user/:password and go to :page_name" do |user, password, page_name|
|
703
|
+
path = _path_to(page_name)
|
704
|
+
if Capybara::current_driver == :selenium
|
705
|
+
visit("http://#{user}:#{password}@#{page.driver.rack_server.host}:#{page.driver.rack_server.port}#{path}")
|
706
|
+
else
|
707
|
+
authorizers = [
|
708
|
+
(page.driver.browser if page.driver.respond_to?(:browser)),
|
709
|
+
(self),
|
710
|
+
(page.driver)
|
711
|
+
].compact
|
712
|
+
authorizer = authorizers.detect { |authorizer| authorizer.respond_to?(:basic_authorize) }
|
713
|
+
authorizer.basic_authorize(user, password)
|
714
|
+
visit path
|
715
|
+
end
|
716
|
+
end
|
717
|
+
|
718
|
+
# Goes to the previously viewed page.
|
719
|
+
#When /^I go back$/ do
|
720
|
+
step "I go back" do
|
721
|
+
case Capybara::current_driver
|
722
|
+
when :selenium, :webkit
|
723
|
+
page.evaluate_script('window.history.back()')
|
724
|
+
else
|
725
|
+
if page.driver.respond_to?(:browser)
|
726
|
+
visit page.driver.browser.last_request.env['HTTP_REFERER']
|
727
|
+
else
|
728
|
+
visit page.driver.last_request.env['HTTP_REFERER']
|
729
|
+
end
|
730
|
+
end
|
731
|
+
end
|
732
|
+
|
733
|
+
# Tests whether a select field is sorted. Uses Array#natural_sort, if defined;
|
734
|
+
# Array#sort else.
|
735
|
+
#Then /^the "(.*?)" select should( not)? be sorted$/ do |label, negate|
|
736
|
+
step "the :label select :whether_to be sorted" do |label, positive|
|
737
|
+
select = find_field(label)
|
738
|
+
options = select.all('option').reject { |o| o.value.blank? }
|
739
|
+
option_texts = options.collect(&:text)
|
740
|
+
|
741
|
+
if positive
|
742
|
+
expect(option_texts).to be_sorted
|
743
|
+
else
|
744
|
+
expect(option_texts).not_to be_sorted
|
745
|
+
end
|
746
|
+
end
|
747
|
+
|
748
|
+
placeholder :whether_to do
|
749
|
+
match /should not/ do
|
750
|
+
false
|
751
|
+
end
|
752
|
+
|
753
|
+
match /should/ do
|
754
|
+
true
|
755
|
+
end
|
756
|
+
end
|
757
|
+
# step 'I :whether_to see :text' do |positive, text|
|
758
|
+
# expectation = positive ? :to : :not_to
|
759
|
+
# expect(page.body).send expectation, eq(text)
|
760
|
+
# end
|