web4cucumber 0.0.2
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/COPYING +674 -0
- data/README.md +250 -0
- data/Rakefile +1 -0
- data/examples/testproject/Gemfile +10 -0
- data/examples/testproject/Gemfile.lock +59 -0
- data/examples/testproject/features/example.feature +12 -0
- data/examples/testproject/features/step_definitions/web.rb +23 -0
- data/examples/testproject/features/support/env.rb +20 -0
- data/examples/testproject/lib/log.rb +17 -0
- data/examples/testproject/lib/web.rb +19 -0
- data/examples/testproject/lib/web/check_community_header.yaml +117 -0
- data/examples/testproject/lib/web/login.yaml +26 -0
- data/lib/web4cucumber.rb +641 -0
- data/lib/web4cucumber/version.rb +3 -0
- data/web4cucumber.gemspec +23 -0
- metadata +130 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
:login:
|
2
|
+
:pages:
|
3
|
+
- 'login_page'
|
4
|
+
:final_checkpoints:
|
5
|
+
:a:
|
6
|
+
:type: a
|
7
|
+
:selector:
|
8
|
+
:href: "/app/account"
|
9
|
+
|
10
|
+
:login_page:
|
11
|
+
:url: '/app/login'
|
12
|
+
:sleep: 1
|
13
|
+
:commit:
|
14
|
+
:type: input
|
15
|
+
:selector:
|
16
|
+
:class: 'create'
|
17
|
+
:expected_fields:
|
18
|
+
:login:
|
19
|
+
:type: textfield
|
20
|
+
:selector:
|
21
|
+
:id: 'web_user_rhlogin'
|
22
|
+
:password:
|
23
|
+
:type: textfield
|
24
|
+
:selector:
|
25
|
+
:id: 'web_user_password'
|
26
|
+
|
data/lib/web4cucumber.rb
ADDED
@@ -0,0 +1,641 @@
|
|
1
|
+
# Copyright 2015 Red Hat, Inc. and/or its affiliates.
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require 'watir-webdriver'
|
17
|
+
require 'headless'
|
18
|
+
|
19
|
+
class Web4Cucumber
|
20
|
+
def positive_checkpoint_lookup(checkpoints, result, options=nil)
|
21
|
+
# checkpoints should be a hash
|
22
|
+
checkpoints.each_pair { |key, value|
|
23
|
+
if options
|
24
|
+
begin
|
25
|
+
value[:selector].each_pair do |how, what|
|
26
|
+
options.keys.each do |optkey|
|
27
|
+
if what.match Regexp.new("<#{optkey.to_s}>")
|
28
|
+
what.gsub!("<#{optkey.to_s}>", options[optkey])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
rescue NoMethodError
|
33
|
+
raise "Please provide :selector: keyword in your checkpoint"
|
34
|
+
end
|
35
|
+
else
|
36
|
+
@@logger.info "No options provided to checkpoint lookup"
|
37
|
+
end
|
38
|
+
if value.has_key? :sleep
|
39
|
+
sleep value[:sleep]
|
40
|
+
end
|
41
|
+
secs = 0
|
42
|
+
if value.has_key? :type
|
43
|
+
myhash = {
|
44
|
+
:a => @@b.a(value[:selector]),
|
45
|
+
:text => @@b.element(value[:selector]),
|
46
|
+
:input => @@b.input(value[:selector]),
|
47
|
+
:select => @@b.select(value[:selector])
|
48
|
+
}
|
49
|
+
element = myhash[value[:type].to_sym]
|
50
|
+
else
|
51
|
+
element = @@b.element(value[:selector])
|
52
|
+
end
|
53
|
+
until element.exists? or secs == 10 do
|
54
|
+
sleep 1
|
55
|
+
secs +=1
|
56
|
+
end
|
57
|
+
unless element.exists?
|
58
|
+
@@logger.warn "#{key} with #{value[:selector]} can not found in #{@@b.url}"
|
59
|
+
result[:failed_positive_checkpoints] << value[:selector]
|
60
|
+
result[:result] = false
|
61
|
+
end
|
62
|
+
}
|
63
|
+
return result
|
64
|
+
end
|
65
|
+
|
66
|
+
def negative_checkpoint_lookup(checkpoints, result, options=nil)
|
67
|
+
# checkpoints should be a hash
|
68
|
+
sleep 7
|
69
|
+
checkpoints.each_pair { |key, value|
|
70
|
+
if options
|
71
|
+
value[:selector].each_pair do |how, what|
|
72
|
+
options.keys.each do |optkey|
|
73
|
+
if what.match Regexp.new("<#{optkey.to_s}>")
|
74
|
+
what.gsub!("<#{optkey.to_s}>", options[optkey])
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
else
|
79
|
+
@@logger.info "No options provided to checkpoint lookup"
|
80
|
+
end
|
81
|
+
if @@b.element(value[:selector]).exists?
|
82
|
+
@@logger.warn("#{key} with #{value} should not be display on the #{@@b.url}")
|
83
|
+
result[:result] = false
|
84
|
+
result[:failed_negative_checkpoints] << value[:selector]
|
85
|
+
end
|
86
|
+
}
|
87
|
+
return result
|
88
|
+
end
|
89
|
+
|
90
|
+
def screenshot_save
|
91
|
+
FileUtils.mkdir_p("screenshots")
|
92
|
+
screenshot = File.join("screenshots", "error.png")
|
93
|
+
@@b.driver.save_screenshot(screenshot)
|
94
|
+
File::open("screenshots/output.html", 'w') {
|
95
|
+
|f| f.puts(@@b.html)
|
96
|
+
}
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
def check_iframe(page_rules)
|
101
|
+
if page_rules.has_key? :iframe
|
102
|
+
return @@b.iframe(page_rules[:iframe][:selector])
|
103
|
+
else
|
104
|
+
return @@b
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def wait_for_element(element, may_absent)
|
109
|
+
if @counter == 20
|
110
|
+
screenshot_save
|
111
|
+
unless may_absent # Sometimes not finding an element is OK, by design
|
112
|
+
@result[:failed_positive_checkpoints] << element
|
113
|
+
raise "Failed to find the #{element.to_s} element"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
sleep 1
|
117
|
+
@counter += 1
|
118
|
+
end
|
119
|
+
|
120
|
+
def run_action(key, options)
|
121
|
+
@result = {:result=>true, :failed_positive_checkpoints=>[], :failed_negative_checkpoints=>[], :errors => []}
|
122
|
+
@@rules.freeze
|
123
|
+
rules = Marshal.load(Marshal.dump(@@rules))
|
124
|
+
action_rules = rules[key.to_sym]
|
125
|
+
# loop over all pages...
|
126
|
+
unless action_rules[:pages]
|
127
|
+
@@logger.warn("No pages defined in the #{key} action")
|
128
|
+
end
|
129
|
+
action_rules[:pages].each { |page|
|
130
|
+
# sometimes you need to stop the execution at some point to test whether
|
131
|
+
# partial form data gets into the database, for example. In this case you
|
132
|
+
# can provide :stop_at key with the name of the page for a value and the
|
133
|
+
# action will be aborted once it gets into this page
|
134
|
+
if options.has_key?(:stop_at) and options[:stop_at] == page
|
135
|
+
@result[:result] = false
|
136
|
+
@result[:errors] << "Execution stopped at page #{page}"
|
137
|
+
return @result
|
138
|
+
end
|
139
|
+
# sometimes also it is pretty handy to be able to stick the debugger at
|
140
|
+
# some point to have a human control over the webdriver instance. Then
|
141
|
+
# in the same way stick the :debug_at keyword with the page name as a value
|
142
|
+
# into the options hash. The webdriver is available via @@b clas variable
|
143
|
+
if options.has_key?(:debug_at) and options[:stop_at] == page
|
144
|
+
require "byebug"
|
145
|
+
byebug
|
146
|
+
end
|
147
|
+
page_rules = rules[page.to_sym]
|
148
|
+
unless page_rules
|
149
|
+
@@logger.warn("The page #{page} not found in #{key} yaml file, maybe you have wrong yaml format...")
|
150
|
+
end
|
151
|
+
if page_rules.has_key? :url
|
152
|
+
options.keys.each do |key|
|
153
|
+
if page_rules[:url].match Regexp.new("<#{key.to_s}>")
|
154
|
+
page_rules[:url].gsub!("<#{key.to_s}>", options[key])
|
155
|
+
end
|
156
|
+
end
|
157
|
+
elsif page_rules.has_key? :base_url
|
158
|
+
options.keys.each do |key|
|
159
|
+
if page_rules[:base_url].match Regexp.new("<#{key.to_s}>")
|
160
|
+
page_rules[:base_url].gsub!("<#{key.to_s}>", options[key])
|
161
|
+
end
|
162
|
+
end
|
163
|
+
else
|
164
|
+
@@logger.warn("#{page} has no url, trying default base_url")
|
165
|
+
end
|
166
|
+
if page_rules.has_key?(:url) or page_rules.has_key?(:base_url) or options.has_key?(:base_url)
|
167
|
+
if options.has_key? :base_url
|
168
|
+
url = options[:base_url]
|
169
|
+
elsif page_rules.has_key? :base_url
|
170
|
+
url = page_rules[:base_url]
|
171
|
+
else
|
172
|
+
# extract the host part from the current url. Makes it more flexible
|
173
|
+
# than to use fixed @@base_url
|
174
|
+
url = @@b.url.match(/(https?:\/\/.*?\/)/).captures[0]
|
175
|
+
end
|
176
|
+
if page_rules[:url].match /^\:\d+/
|
177
|
+
if url.match /\:\d+/
|
178
|
+
url.gsub!(/\:\d+\//, "")
|
179
|
+
else
|
180
|
+
url.gsub!(/\/$/, "")
|
181
|
+
end
|
182
|
+
end
|
183
|
+
if page_rules[:url]
|
184
|
+
url = url + page_rules[:url]
|
185
|
+
end
|
186
|
+
@@b.goto url
|
187
|
+
end
|
188
|
+
unless page_rules[:expected_forms]
|
189
|
+
@@logger.warn("No expected_forms defined in the #{page} page")
|
190
|
+
end
|
191
|
+
if page_rules.has_key? :sleep
|
192
|
+
sleep page_rules[:sleep]
|
193
|
+
end
|
194
|
+
driver = check_iframe(page_rules) # substitute browser operating with main html
|
195
|
+
# with the one operating with internal iframe
|
196
|
+
unless page_rules[:expected_fields]
|
197
|
+
@@logger.warn("No expected fields in #{page} page")
|
198
|
+
end
|
199
|
+
if page_rules.has_key? :expected_fields
|
200
|
+
page_rules[:expected_fields].each_pair { |name, prop|
|
201
|
+
# Beginning of page fields
|
202
|
+
possible_elements = {
|
203
|
+
# There could be more than one element with the same
|
204
|
+
# properties and only one would be visible. As an example:
|
205
|
+
# try adding more than one member to the same domain
|
206
|
+
'select' => driver.select_lists(prop[:selector]),
|
207
|
+
'checkbox' => driver.checkboxes(prop[:selector]),
|
208
|
+
'radio' => driver.radios(prop[:selector]),
|
209
|
+
'text_field' => driver.text_fields(prop[:selector]),
|
210
|
+
'textfield' => driver.text_fields(prop[:selector]),
|
211
|
+
'text_area' => driver.textareas(prop[:selector]),
|
212
|
+
'textarea' => driver.textareas(prop[:selector]),
|
213
|
+
'filefield' => driver.file_fields(prop[:selector]),
|
214
|
+
'file_field' => driver.file_fields(prop[:selector]),
|
215
|
+
'a' => driver.as(prop[:selector]),
|
216
|
+
'element' => driver.elements(prop[:selector])
|
217
|
+
}
|
218
|
+
if prop.has_key?(:type) and not possible_elements.keys.include? prop[:type]
|
219
|
+
@@logger.error("Unsupported element #{prop[:type]} for cucushift, so type error?")
|
220
|
+
end
|
221
|
+
result ||= true
|
222
|
+
@counter = 0
|
223
|
+
prop[:type] ||= 'element' # default to 'element' unless declared explicitly
|
224
|
+
if prop[:type] == 'alert'
|
225
|
+
begin
|
226
|
+
@@b.alert.wait_until_present(3)
|
227
|
+
@@b.alert.ok
|
228
|
+
rescue Watir::Wait::TimeoutError => e
|
229
|
+
@result[:result] = false
|
230
|
+
@result[:errors] << "e.message"
|
231
|
+
end
|
232
|
+
end
|
233
|
+
options.each do |key,value|
|
234
|
+
if value.is_a? String and prop[:selector].values[0].match Regexp.new("<#{key.to_s}>")
|
235
|
+
prop[:selector].values[0].gsub!("<#{key.to_s}>", options[key])
|
236
|
+
end
|
237
|
+
end
|
238
|
+
elements = possible_elements[prop[:type]]
|
239
|
+
element = nil
|
240
|
+
elements.each do |elem|
|
241
|
+
if elem.visible?
|
242
|
+
element = elem
|
243
|
+
end
|
244
|
+
end
|
245
|
+
if (options.has_key? name and options[name]) or prop.has_key? :def_value
|
246
|
+
options.keys.each do |key|
|
247
|
+
if prop[:selector].values[0].match Regexp.new("<#{key.to_s}>")
|
248
|
+
prop[:selector].values[0].gsub!("<#{key.to_s}>", options[key])
|
249
|
+
end
|
250
|
+
end
|
251
|
+
if prop[:selector].values[0].size == 0
|
252
|
+
tmphash = prop[:selector].clone
|
253
|
+
# if no default value provided, put the value from options
|
254
|
+
tmphash.each_pair do |key, value|
|
255
|
+
prop[:selector][key] = options[name.to_sym]
|
256
|
+
end
|
257
|
+
end
|
258
|
+
if not element
|
259
|
+
if not prop[:may_absent]
|
260
|
+
@result[:result] = false
|
261
|
+
@result[:errors] << "Unable to find element #{name.to_s} by the following #{prop[:selector].keys[0].to_s}: #{prop[:selector].values[0]}"
|
262
|
+
end
|
263
|
+
else
|
264
|
+
until element.exists? do
|
265
|
+
begin
|
266
|
+
wait_for_element(prop[:selector], prop[:may_absent])
|
267
|
+
rescue Exception => e
|
268
|
+
result = false
|
269
|
+
break
|
270
|
+
end
|
271
|
+
end
|
272
|
+
if result # continue if nothing failed
|
273
|
+
if prop[:type] == 'select'
|
274
|
+
if options[name.to_sym]
|
275
|
+
driver.select_list(prop[:selector]).select_value options[name.to_sym].to_s
|
276
|
+
elsif prop[:def_value]
|
277
|
+
driver.select_list(prop[:selector]).select_value prop[:def_value]
|
278
|
+
else
|
279
|
+
@@logger.error("Please, provide a value for this element: #{prop}")
|
280
|
+
end
|
281
|
+
elsif ['filefield', 'file-field', 'file_field'].include? prop[:type]
|
282
|
+
element.set options[name]
|
283
|
+
elsif ['checkbox', 'radio', 'a', 'element'].include? prop[:type]
|
284
|
+
element.click
|
285
|
+
elsif ['textfield', 'text_field', 'text_area', 'textarea'].include? prop[:type]
|
286
|
+
element.clear
|
287
|
+
if options.has_key? name.to_sym
|
288
|
+
options[name.to_sym].each_char do |c|
|
289
|
+
element.append c
|
290
|
+
end
|
291
|
+
elsif prop.has_key? :def_value
|
292
|
+
element.send_keys prop[:def_value]
|
293
|
+
else
|
294
|
+
@@logger.error("Please provide the value for this element: #{prop}")
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
} # End of page fields
|
301
|
+
end
|
302
|
+
# each form ends with commit button
|
303
|
+
if page_rules.has_key? :checkpoints
|
304
|
+
@result = positive_checkpoint_lookup(page_rules[:checkpoints], @result)
|
305
|
+
else
|
306
|
+
@@logger.info "No positive checkpoints defined..."
|
307
|
+
end
|
308
|
+
if page_rules.has_key? :negative_checkpoints
|
309
|
+
@result = negative_checkpoint_lookup(page_rules[:negative_checkpoints], @result)
|
310
|
+
else
|
311
|
+
@@logger.info "No negative checkpoints defined..."
|
312
|
+
end
|
313
|
+
unless page_rules[:links]
|
314
|
+
@@logger.warn("No links defined in the #{page} page")
|
315
|
+
end
|
316
|
+
if page_rules.has_key? :links
|
317
|
+
page_rules[:links].each_pair do |key, value|
|
318
|
+
@@b.a(value[:selector]).click
|
319
|
+
if value.has_key? :checkpoints
|
320
|
+
@result = positive_checkpoint_lookup(value[:checkpoints], @result)
|
321
|
+
end
|
322
|
+
@@b.back
|
323
|
+
end
|
324
|
+
end
|
325
|
+
if page_rules.has_key? :commit
|
326
|
+
if page_rules[:commit].has_key?(:selector)
|
327
|
+
options.keys.each do |optkey|
|
328
|
+
if page_rules[:commit][:selector].values[0].include? "<#{optkey}>"
|
329
|
+
page_rules[:commit][:selector].values[0].gsub!("<#{optkey}>", options[optkey])
|
330
|
+
end
|
331
|
+
end
|
332
|
+
myhash = {
|
333
|
+
:input => @@b.input(page_rules[:commit][:selector]),
|
334
|
+
:a => @@b.a(page_rules[:commit][:selector]),
|
335
|
+
:button => @@b.button(page_rules[:commit][:selector])
|
336
|
+
}
|
337
|
+
begin
|
338
|
+
if page_rules[:commit].has_key? :type
|
339
|
+
button = myhash[page_rules[:commit][:type].to_sym]
|
340
|
+
else
|
341
|
+
button = @@b.element(page_rules[:commit][:selector])
|
342
|
+
end
|
343
|
+
begin
|
344
|
+
button.exists?
|
345
|
+
rescue Watir::Exception::MissingWayOfFindingObjectException
|
346
|
+
button = @@b.input(page_rules[:commit][:selector])
|
347
|
+
end
|
348
|
+
if options[:scroll] or page_rules[:commit][:scroll]
|
349
|
+
@@b.execute_script('arguments[0].scrollIntoView();', button)
|
350
|
+
sleep 1 # This scroll sometimes takes up to a second
|
351
|
+
end
|
352
|
+
button.click
|
353
|
+
rescue Exception => e
|
354
|
+
@result[:result]=false
|
355
|
+
@result[:error_message] = e.message
|
356
|
+
screenshot_save
|
357
|
+
end
|
358
|
+
elsif page_rules[:commit].has_key?(:type) and page_rules[:commit][:type] == 'alert'
|
359
|
+
@@b.alert.ok
|
360
|
+
else
|
361
|
+
raise "Please provide selector for #{page} page commit"
|
362
|
+
end
|
363
|
+
else
|
364
|
+
@@logger.warn("No commit defined in the #{page} page")
|
365
|
+
end
|
366
|
+
} # end of pages
|
367
|
+
if action_rules.has_key? :final_checkpoints
|
368
|
+
@result = positive_checkpoint_lookup(action_rules[:final_checkpoints], @result, options=options)
|
369
|
+
end
|
370
|
+
if action_rules.has_key? :negative_final_checkpoints
|
371
|
+
@result = negative_checkpoint_lookup(action_rules[:negative_final_checkpoints], @result, options=options)
|
372
|
+
end
|
373
|
+
unless @result[:failed_positive_checkpoints].empty? and @result[:failed_negative_checkpoints].empty?
|
374
|
+
@result[:result] = false
|
375
|
+
end
|
376
|
+
return @result
|
377
|
+
end
|
378
|
+
|
379
|
+
def web_to_load(options)
|
380
|
+
#returns an array of yaml files
|
381
|
+
if options.has_key? :version
|
382
|
+
return Dir.glob(File.join(options[:rules_path], options[:version], "*"))
|
383
|
+
else
|
384
|
+
return Dir.glob(File.join(options[:rules_path], "*"))
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
def initialize(options)
|
389
|
+
# Let's make sure, that we get all necessary options in the proper format
|
390
|
+
obligatory_options = [:base_url, :rules_path, :logger]
|
391
|
+
# :logger should be a Logger class instance with at least the following
|
392
|
+
# methods implemented, taking a string as an argument:
|
393
|
+
# - info
|
394
|
+
# - warn
|
395
|
+
# - error
|
396
|
+
unless options.is_a? Hash
|
397
|
+
raise "Please provide a hash of options. Valid option keys are: :base_url, :browser, rules_path and :version
|
398
|
+
The initialize method needs to know at least the base_url you want to test against and the :rules_path - path
|
399
|
+
to the folder where you store your yaml files with action descriptions. Other keys are optional"
|
400
|
+
end
|
401
|
+
if options.keys & obligatory_options == obligatory_options
|
402
|
+
@@base_url = options[:base_url]
|
403
|
+
@@rules_path = options[:rules_path]
|
404
|
+
@@logger = options[:logger]
|
405
|
+
else
|
406
|
+
raise "Please provide #{obligatory_options.join(', ')} in the passed options"
|
407
|
+
end
|
408
|
+
if options.has_key? :browser
|
409
|
+
browser = options[:browser].to_sym
|
410
|
+
else
|
411
|
+
browser = :firefox
|
412
|
+
end
|
413
|
+
# OK, now all info from the options is processed, let's rock-n-roll!
|
414
|
+
unless ENV.has_key? "DEBUG_WEB"
|
415
|
+
@@headless = Headless.new
|
416
|
+
@@headless.start
|
417
|
+
end
|
418
|
+
file_names = web_to_load(options)
|
419
|
+
@@rules = {}
|
420
|
+
file_names.each do |filename|
|
421
|
+
tmphash = YAML.load_file(filename)
|
422
|
+
tmphash.each_pair do |key, value|
|
423
|
+
if @@rules[key]
|
424
|
+
raise "Duplicate entries detected in yaml file #{filename}: #{key}"
|
425
|
+
else
|
426
|
+
@@rules[key] = value
|
427
|
+
end
|
428
|
+
end
|
429
|
+
end
|
430
|
+
firefox_profile = Selenium::WebDriver::Firefox::Profile.new
|
431
|
+
chrome_profile = Selenium::WebDriver::Remote::Capabilities.chrome()
|
432
|
+
if ENV.has_key? "http_proxy"
|
433
|
+
proxy = ENV["http_proxy"].scan(/[\w\.\d\_\-]+\:\d+/)[0] # to get rid of the heading "http://" that breaks the profile
|
434
|
+
firefox_profile.proxy = chrome_profile.proxy = Selenium::WebDriver::Proxy.new({:http => proxy, :ssl => proxy})
|
435
|
+
firefox_profile['network.proxy.no_proxies_on'] = "localhost, 127.0.0.1"
|
436
|
+
ENV['no_proxy'] = '127.0.0.1'
|
437
|
+
end
|
438
|
+
client = Selenium::WebDriver::Remote::Http::Default.new
|
439
|
+
client.timeout = 180
|
440
|
+
if browser == :firefox
|
441
|
+
@@b = Watir::Browser.new browser, :profile => firefox_profile, :http_client=>client
|
442
|
+
elsif browser == :chrome
|
443
|
+
@@b = Watir::Browser.new browser, desired_capabilities: chrome_profile
|
444
|
+
else
|
445
|
+
raise "Not implemented yet"
|
446
|
+
end
|
447
|
+
# @@b.window.resize_to(1920, 1080)
|
448
|
+
@@b.goto @@base_url
|
449
|
+
end
|
450
|
+
|
451
|
+
def goto(params) # params should be a hash
|
452
|
+
if params[:relative]
|
453
|
+
# if provided relative url and current url contain port nuumbers - take
|
454
|
+
# the explicitly provided one
|
455
|
+
if params[:url].match /^:\d+/
|
456
|
+
base_url.gsub!(/\/$/, "")
|
457
|
+
end
|
458
|
+
@@b.goto base_url + params[:url]
|
459
|
+
else
|
460
|
+
@@b.goto params[:url]
|
461
|
+
end
|
462
|
+
hash = {:result => true, :response => @@b.html}
|
463
|
+
end
|
464
|
+
|
465
|
+
def get_url
|
466
|
+
return @@b.url
|
467
|
+
end
|
468
|
+
|
469
|
+
def cookie_option(cookies,opt = nil)
|
470
|
+
@result = {:result => true, :failed_positive_checkpoints => nil,:message => nil}
|
471
|
+
@cookies= @@b.cookies
|
472
|
+
if opt == 'show'
|
473
|
+
return @cookies.to_a
|
474
|
+
end
|
475
|
+
if opt == 'select'
|
476
|
+
new_cookies = []
|
477
|
+
cookies.each do |cookie|
|
478
|
+
if @cookies[cookie[:name].to_sym]
|
479
|
+
cookie[:value] = @cookies[cookie[:name].to_sym][:value]
|
480
|
+
new_cookies << cookie
|
481
|
+
else
|
482
|
+
@result[:result]=false
|
483
|
+
@result[:falied_negative_checkpoints] =[cookie]
|
484
|
+
return @result
|
485
|
+
end
|
486
|
+
end
|
487
|
+
return new_cookies
|
488
|
+
end
|
489
|
+
if opt == 'delete_all'
|
490
|
+
unless @cookies.clear
|
491
|
+
@result[:result]=false
|
492
|
+
@result[:falied_negative_checkpoints] =[cookie]
|
493
|
+
end
|
494
|
+
end
|
495
|
+
cookies.each do |cookie|
|
496
|
+
if opt == 'add'
|
497
|
+
if @cookies.add cookie[:name],cookie[:value]
|
498
|
+
@result[:result]=true
|
499
|
+
else
|
500
|
+
@result[:result]=false
|
501
|
+
@result[:falied_negative_checkpoints] = [cookie]
|
502
|
+
end
|
503
|
+
end
|
504
|
+
if opt == 'delete'
|
505
|
+
unless @cookies.delete cookie[:name]
|
506
|
+
@result[:result]=false
|
507
|
+
@result[:falied_negative_checkpoints] = [cookie]
|
508
|
+
end
|
509
|
+
end
|
510
|
+
end
|
511
|
+
return @result
|
512
|
+
end
|
513
|
+
|
514
|
+
def check_elements(elements, negate=nil, click=nil)
|
515
|
+
# elements should be an array of hashes, for example:
|
516
|
+
# [{:a=>{:class=>"block"}}, {:a=>{:href=>"/products"}}, {:a=>{:text=>"Log In"}}]
|
517
|
+
@counter = 0
|
518
|
+
@result = {:result=>true, :failed_positive_checkpoints => [], :failed_negative_checkpoints => [], :error_messages => []}
|
519
|
+
elements.each do |element|
|
520
|
+
myhash = {
|
521
|
+
:a=>@@b.a(element.values[0]),
|
522
|
+
:textfield=>@@b.text_field(element.values[0]),
|
523
|
+
:filefield=>@@b.file_field(element.values[0]),
|
524
|
+
:input=>@@b.input(element.values[0]),
|
525
|
+
:element=>@@b.element(element.values[0]),
|
526
|
+
:pre=>@@b.element(element.values[0]),
|
527
|
+
:select=>@@b.select(element.values[0]),
|
528
|
+
:option=>@@b.element(element.values[0])
|
529
|
+
}
|
530
|
+
if negate
|
531
|
+
if myhash[element.keys[0]].exists? and myhash[element.keys[0]].visible?
|
532
|
+
@result[:result] = false
|
533
|
+
@result[:failed_negative_checkpoints] << [element]
|
534
|
+
# must be an array for consistency
|
535
|
+
end
|
536
|
+
else
|
537
|
+
unless myhash[element.keys[0]].exists?
|
538
|
+
@result[:result] = false
|
539
|
+
@result[:failed_positive_checkpoints] << element
|
540
|
+
end
|
541
|
+
if click
|
542
|
+
begin
|
543
|
+
myhash[element.keys[0]].click
|
544
|
+
rescue => e
|
545
|
+
@result[:result] = false
|
546
|
+
@result[:failed_positive_checkpoints] << element
|
547
|
+
@result[:error_messages] << e.message
|
548
|
+
end
|
549
|
+
end
|
550
|
+
end
|
551
|
+
end
|
552
|
+
return @result
|
553
|
+
end
|
554
|
+
|
555
|
+
def element_click(element)
|
556
|
+
check_elements([element], negate = nil, click=true)
|
557
|
+
end
|
558
|
+
|
559
|
+
def value_select(element_selector, value)
|
560
|
+
result = {
|
561
|
+
:result => true,
|
562
|
+
:failed_positive_checkpoints => [],
|
563
|
+
:failed_negative_checkpoints => [],
|
564
|
+
:error_messages => []
|
565
|
+
}
|
566
|
+
until @@b.select_list(element_selector).exists? do
|
567
|
+
begin
|
568
|
+
wait_for_element(element_selector)
|
569
|
+
rescue => e
|
570
|
+
result[:result] = false
|
571
|
+
result[:error_messages] << e.message
|
572
|
+
break
|
573
|
+
end
|
574
|
+
end
|
575
|
+
@@b.select_list(element_selector).select_value(value)
|
576
|
+
return result
|
577
|
+
end
|
578
|
+
|
579
|
+
def finalize
|
580
|
+
@@b.close
|
581
|
+
@@headless.destroy if defined?(@@headless)
|
582
|
+
end
|
583
|
+
|
584
|
+
def is_element_present?(how, what)
|
585
|
+
return @@b.element(how=>what).exists?
|
586
|
+
end
|
587
|
+
|
588
|
+
def browser_title_contains?(string)
|
589
|
+
if @@b.title.match(string)
|
590
|
+
return true
|
591
|
+
else
|
592
|
+
return false
|
593
|
+
end
|
594
|
+
end
|
595
|
+
|
596
|
+
def dropdown_value(selector)
|
597
|
+
return @@b.select(selector).value
|
598
|
+
end
|
599
|
+
|
600
|
+
def element_text(selector)
|
601
|
+
return @@b.element(selector).text
|
602
|
+
end
|
603
|
+
|
604
|
+
def refresh_page
|
605
|
+
@@b.refresh
|
606
|
+
end
|
607
|
+
|
608
|
+
def send_keys(element, text)
|
609
|
+
result = {:result=>true}
|
610
|
+
begin
|
611
|
+
@@b.text_field(element).clear
|
612
|
+
@@b.text_field(element).send_keys text
|
613
|
+
rescue => e
|
614
|
+
result[:result] = false
|
615
|
+
result[:response] = e.message
|
616
|
+
end
|
617
|
+
end
|
618
|
+
|
619
|
+
def check_textfield_content(selector, text=nil)
|
620
|
+
result = {}
|
621
|
+
if @@b.text_field(selector).exists?
|
622
|
+
result[:text] = @@b.text_field(selector).value
|
623
|
+
result[:result] = true
|
624
|
+
else
|
625
|
+
result[:result] = false
|
626
|
+
end
|
627
|
+
return result
|
628
|
+
end
|
629
|
+
|
630
|
+
def page_html
|
631
|
+
return @@b.html
|
632
|
+
end
|
633
|
+
|
634
|
+
def rules
|
635
|
+
return @@rules
|
636
|
+
end
|
637
|
+
|
638
|
+
def action_rules(action)
|
639
|
+
return @@rules[action.to_sym]
|
640
|
+
end
|
641
|
+
end
|