awetestlib 0.1.28 → 0.1.29pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. data/.gitattributes +22 -22
  2. data/.gitignore +69 -69
  3. data/.yardopts +7 -7
  4. data/README.md +108 -108
  5. data/awetestlib.gemspec +57 -57
  6. data/awetestlib.windows.gemspec +41 -41
  7. data/awetestlib_notes.txt +4 -4
  8. data/awetestlib_osx.gemspec +47 -48
  9. data/bin/awetestlib +99 -99
  10. data/bin/awetestlib-android-setup.rb +26 -26
  11. data/bin/awetestlib-cucumber-setup.rb +28 -28
  12. data/bin/awetestlib-driver-setup.rb +21 -21
  13. data/bin/awetestlib-helpers.rb +41 -41
  14. data/bin/awetestlib-mobile-app-setup.rb +31 -31
  15. data/bin/awetestlib-netbeans-setup.rb +58 -58
  16. data/bin/awetestlib-regression-setup.rb +15 -15
  17. data/bin/awetestlib-rubymine-setup.rb +39 -39
  18. data/drivers/chromedriver.exe +0 -0
  19. data/ext/Rakefile +1 -1
  20. data/ext/mkrf_conf.rb +27 -27
  21. data/lib/awetestlib/html_report.rb +142 -142
  22. data/lib/awetestlib/logging.rb +366 -366
  23. data/lib/awetestlib/regression/browser.rb +1380 -1375
  24. data/lib/awetestlib/regression/drag_and_drop.rb +421 -420
  25. data/lib/awetestlib/regression/find.rb +345 -345
  26. data/lib/awetestlib/regression/legacy.rb +1187 -1187
  27. data/lib/awetestlib/regression/page_data.rb +191 -191
  28. data/lib/awetestlib/regression/runner.rb +307 -307
  29. data/lib/awetestlib/regression/tables.rb +627 -619
  30. data/lib/awetestlib/regression/user_input.rb +576 -576
  31. data/lib/awetestlib/regression/utilities.rb +1046 -988
  32. data/lib/awetestlib/regression/validations.rb +1093 -1074
  33. data/lib/awetestlib/regression/waits.rb +470 -470
  34. data/lib/awetestlib/runner.rb +18 -18
  35. data/lib/awetestlib.rb +41 -41
  36. data/lib/patches/README +2 -2
  37. data/lib/patches/firewatir.rb +106 -106
  38. data/lib/patches/watir.rb +175 -175
  39. data/lib/version.rb +2 -2
  40. data/license.txt +13 -13
  41. data/netbeans_setup.md +29 -29
  42. data/rdoc_test.bat +1 -1
  43. data/rubymine_setup.md +23 -23
  44. data/setup_samples/sample_android/features/dk.mejer.hansen.control.FlyingColorsPlayerAidActivity.apk +0 -0
  45. data/setup_samples/sample_android/features/sample_android.feature +5 -5
  46. data/setup_samples/sample_android/features/step_definitions/calabash_steps.rb +1 -1
  47. data/setup_samples/sample_android/features/support/app_installation_hooks.rb +36 -36
  48. data/setup_samples/sample_android/features/support/app_life_cycle_hooks.rb +14 -14
  49. data/setup_samples/sample_android/features/test_servers/8ba795a0288381ae346b67867b586881_0.3.2.apk +0 -0
  50. data/setup_samples/sample_cucumber/features/step_definitions/predefined_steps.rb +76 -76
  51. data/setup_samples/sample_cucumber/features/yahoo_mail.feature +11 -11
  52. data/setup_samples/sample_mobile_app/features/my_first.feature +14 -14
  53. data/setup_samples/sample_mobile_app/features/step_definitions/predefined_webview_steps.rb +80 -80
  54. data/setup_samples/sample_mobile_app/features/support/env.rb +2 -2
  55. data/setup_samples/sample_netbeans/demo.rb +86 -86
  56. data/setup_samples/sample_netbeans/nbproject/configs/Demo.properties +2 -2
  57. data/setup_samples/sample_netbeans/nbproject/private/config.properties +1 -1
  58. data/setup_samples/sample_netbeans/nbproject/private/configs/Demo.properties +2 -2
  59. data/setup_samples/sample_netbeans/nbproject/private/private.properties +2 -2
  60. data/setup_samples/sample_netbeans/nbproject/project.properties +5 -5
  61. data/setup_samples/sample_netbeans/nbproject/project.xml +13 -13
  62. data/setup_samples/sample_rubymine/.idea/encodings.xml +5 -5
  63. data/setup_samples/sample_rubymine/.idea/misc.xml +5 -5
  64. data/setup_samples/sample_rubymine/.idea/modules.xml +9 -9
  65. data/setup_samples/sample_rubymine/.idea/sample_rubymine.iml +9 -9
  66. data/setup_samples/sample_rubymine/.idea/scopes/scope_settings.xml +4 -4
  67. data/setup_samples/sample_rubymine/.idea/vcs.xml +7 -7
  68. data/setup_samples/sample_rubymine/.idea/workspace.xml +213 -213
  69. data/setup_samples/sample_rubymine/demo.rb +86 -86
  70. data/test/create_zoho.rb +66 -66
  71. data/test/create_zoho_account1.rb +68 -68
  72. data/test/create_zoho_account2.rb +72 -72
  73. data/test/demo.rb +87 -87
  74. data/test/google_search1.rb +16 -16
  75. data/test/google_search2.rb +19 -19
  76. data/test/login_1.rb +37 -37
  77. data/test/login_1a.rb +37 -37
  78. data/test/login_2.rb +32 -32
  79. data/test/zoho_exercise.rb +21 -21
  80. data/test/zoho_util.rb +487 -487
  81. data/tmp/placeholder.html +71 -71
  82. metadata +18 -49
@@ -1,420 +1,421 @@
1
- module Awetestlib
2
- module Regression
3
- # Methods for moving and resizing elements, manipulating the mouse, and checking for relative positioning of elements,
4
- # including overlap, overlay, etc.
5
- # @note Still experimental. Works with IE but not fully tested with Firefox or Chrome in Windows.
6
- # Not compatible with Mac
7
- # Rdoc is work in progress
8
- module DragAndDrop
9
-
10
- # Verify that specified *inner_element* is fully enclosed by *outer_element*.
11
- # @param [Watir::Element] inner_element A reference to a DOM element
12
- # @param [Watir::Element] outer_element A reference to a DOM element
13
- # @param [String] desc Contains a message or description intended to appear in the log and/or report output
14
- def verify_element_inside(inner_element, outer_element, desc = '')
15
- mark_testlevel("#{__method__.to_s.titleize}", 3)
16
- msg = build_message("#{inner_element.class.to_s} (:id=#{inner_element.id}) is fully enclosed by "+
17
- "#{outer_element.class.to_s} (:id=#{outer_element.id}).", desc)
18
- if overlay?(inner_element, outer_element, :inside)
19
- failed_to_log(msg)
20
- else
21
- passed_to_log(msg)
22
- true
23
- end
24
- rescue
25
- failed_to_log("Unable to verify that #{msg} '#{$!}'")
26
- end
27
-
28
- # Verify that two elements, identified by specified attribute and value, do not overlap on a given *side*.
29
- # @param [Symbol] above_element The element type for the first element, e.g. :div, :span, etc.
30
- # @param [Symbol] above_how The element attribute used to identify the *above_element*.
31
- # Valid values depend on the kind of element.
32
- # Common values: :text, :id, :title, :name, :class, :href (:link only)
33
- # @param [String, Regexp] above_what A string or a regular expression to be found in the *above_how* attribute that uniquely identifies the element.
34
- # @param [Symbol] below_element The element type for the second element, e.g. :div, :span, etc.
35
- # @param [Symbol] below_how The element attribute used to identify the *below_element*.
36
- # @param [String, Regexp] below_what A string or a regular expression to be found in the *below_how* attribute that uniquely identifies the element.
37
- # @param [Symbol] side :top, :bottom, :left, :right, :inside, or :outside
38
- # @param [String] desc Contains a message or description intended to appear in the log and/or report output
39
- def verify_no_element_overlap(browser, above_element, above_how, above_what, below_element, below_how, below_what, side, desc = '')
40
- mark_testlevel("#{__method__.to_s.titleize}", 3)
41
- msg = build_message("#{above_element.to_s.titleize} #{above_how}=>#{above_what} does not overlap "+
42
- "#{below_element.to_s.titleize} #{below_how}=>#{below_what} at the #{side}.", desc)
43
- above = browser.element(above_how, above_what)
44
- below = browser.element(below_how, below_what)
45
- if overlay?(above, below, side)
46
- failed_to_log(msg)
47
- else
48
- passed_to_log(msg)
49
- true
50
- end
51
- rescue
52
- failed_to_log("Unable to verify that #{msg} '#{$!}'")
53
- end
54
-
55
- def overlay?(inner, outer, side = :bottom)
56
- #mark_testlevel("#{__method__.to_s.titleize}", 3)
57
- inner_t, inner_b, inner_l, inner_r = inner.bounding_rectangle_offsets
58
- outer_t, outer_b, outer_l, outer_r = outer.bounding_rectangle_offsets
59
- #overlay = false
60
- case side
61
- when :bottom
62
- overlay = inner_b > outer_t
63
- when :top
64
- overlay = inner_t > outer_t
65
- when :left
66
- overlay = inner_l < outer_r
67
- when :right
68
- overlay = inner_r > outer_r
69
- when :inside
70
- overlay = !(inner_t > outer_t and
71
- inner_r < outer_r and
72
- inner_l > outer_l and
73
- inner_b < outer_b)
74
- else
75
- overlay = (inner_t > outer_b or
76
- inner_r > outer_l or
77
- inner_l < outer_r or
78
- inner_b < outer_t)
79
- end
80
- overlay
81
- rescue
82
- failed_to_log("Unable to determine overlay. '#{$!}'")
83
- end
84
-
85
- def hover(browser, element, wait = 2)
86
- w1, h1, x1, y1, xc1, yc1, xlr1, ylr1 = get_element_coordinates(browser, element, true)
87
- @ai.MoveMouse(xc1, yc1)
88
- sleep_for(1)
89
- end
90
-
91
- def move_element_with_handle(browser, element, handle_id, dx, dy)
92
- # msg = "Move element "
93
- # w1, h1, x1, y1, xc1, yc1, xlr1, ylr1 = get_element_coordinates(browser, element, true)
94
- # newx = w1 + dx
95
- # newy = h1 + dy
96
- # msg << " by [#{dx}, #{dy}] to expected [[#{newx}, #{newy}] "
97
- # handle = get_resize_handle(element, handle_id)
98
- # hw, hh, hx, hy, hxc, hyc, hxlr, hylr = get_element_coordinates(browser, handle, true)
99
-
100
- # drag_and_drop(hxc, hyc, dx, dy)
101
-
102
- # w2, h2, x2, y2, xc2, yc2, xlr2, ylr2 = get_element_coordinates(browser, element, true)
103
-
104
- # xerr = x2 - newx
105
- # yerr = y2 - newy
106
- # xdsp = (x1 - x2).abs
107
- # ydsp = (y1 - y2).abs
108
-
109
- # if x2 == newx and y2 == newy
110
- # msg << "succeeded."
111
- # passed_to_log(msg)
112
- # else
113
- # msg << "failed. "
114
- # failed_to_log(msg)
115
- # debug_to_log("x: actual #{x2}, error #{xerr}, displace #{xdsp}. y: actual #{y2}, error #{yerr}, displace #{ydsp}.")
116
- # end
117
-
118
- end
119
-
120
- def resize_element_with_handle(browser, element, target, dx, dy=nil)
121
- #TODO enhance to accept differing percentages in each direction
122
- msg = "Resize element "
123
- w1, h1, x1, y1, xc1, yc1, xlr1, ylr1 = get_element_coordinates(browser, element, true)
124
- if dy
125
- deltax = dx
126
- deltay = dy
127
- neww = w1 + dx
128
- newh = h1 + dy
129
- msg << " by [#{dx}, #{dy}] " #"" to expected dimension [#{neww}, #{newh}] "
130
- else
131
- deltax, deltay, neww, newh = adjust_dimensions_by_percent(w1, h1, dx, true)
132
- msg << "by #{dx} percent " #"" to expected dimension [#{neww}, #{newh}] "
133
- end
134
- handle = get_resize_handle_by_class(element, target) #, true)
135
- sleep_for(0.5)
136
- hw, hh, hx, hy, hxc, hyc, hxlr, hylr = get_element_coordinates(browser, handle, true)
137
- hxlr_diff = 0
138
- hylr_diff = 0
139
-
140
- # TODO These adjustments are adhoc and empirical. Need to be derived more rigorously
141
- if @browserAbbrev == 'IE'
142
- hxlr_diff = (xlr1 - hxlr)
143
- hylr_diff = (ylr1 - hylr)
144
- x_start = hxlr - 2
145
- y_start = hylr - 2
146
- else
147
- hxlr_diff = (xlr1 - hxlr) / 2 unless (xlr1 - hxlr) == 0
148
- hylr_diff = (ylr1 - hylr) / 2 unless (ylr1 - hylr) == 0
149
- x_start = hxlr
150
- y_start = hylr
151
- end
152
-
153
- newxlr = xlr1 + deltax
154
- newylr = ylr1 + deltay
155
- # msg << ", lower right [#{newxlr}, #{newylr}] - "
156
- sleep_for(0.5)
157
-
158
- drag_and_drop(x_start, y_start, deltax, deltay)
159
-
160
- sleep_for(1.5)
161
- w2, h2, x2, y2, xc2, yc2, xlr2, ylr2 = get_element_coordinates(browser, element, true)
162
-
163
- werr = w2 - neww
164
- herr = h2 - newh
165
-
166
- # TODO This adjustment is adhoc and empirical. Needs to be derived more rigorously
167
- xlrerr = xlr2 - newxlr + hxlr_diff
168
- ylrerr = ylr2 - newylr + hylr_diff
169
-
170
- xlrdsp = (xlr1 - xlr2).abs
171
- ylrdsp = (ylr1 - ylr2).abs
172
-
173
- debug_to_log("\n" +
174
- "\t\t hxlr_diff: #{hxlr_diff}\n" +
175
- "\t\t hylr_diff: #{hylr_diff}\n" +
176
- "\t\t werr: #{werr}\n" +
177
- "\t\t herr: #{herr}\n" +
178
- "\t\t xlrerr: #{xlrerr}\n" +
179
- "\t\t ylrerr: #{ylrerr}\n" +
180
- "\t\t xlrdsp: #{xlrdsp}\n" +
181
- "\t\t ylrdsp: #{ylrdsp}\n" +
182
- "\t\t @min_width: #{@min_width}\n" +
183
- "\t\t@min_height: #{@min_height}\n" +
184
- "\t\t x tol: #{@x_tolerance}\n" +
185
- "\t\t y tol: #{@y_tolerance}\n"
186
- )
187
-
188
- #TODO Add check that window _was_ resized.
189
- x_ok, x_msg = validate_move(w2, xlrerr, @x_tolerance, @min_width, xlr2)
190
- y_ok, y_msg = validate_move(h2, ylrerr, @y_tolerance, @min_height, ylr2)
191
- msg = msg + "x: #{x_msg}, y: #{y_msg}"
192
-
193
- if x_ok and y_ok
194
- passed_to_log(msg)
195
- else
196
- failed_to_log(msg)
197
- debug_to_log("x - actual #{xlr2}, error #{xlrerr}, displace #{xlrdsp}, y - actual #{ylr2}, error #{ylrerr}, displace #{ylrdsp}.")
198
- end
199
- sleep_for(1)
200
- rescue
201
- failed_to_log("Unable to validate resize. #{$!} (#{__LINE__})")
202
- sleep_for(1)
203
- end
204
-
205
- # :category: GUI
206
- def get_resize_handle_by_id(element, id, dbg=nil)
207
- handle = get_div_by_id(element, id, dbg)
208
- sleep_for(1)
209
- handle.flash(5)
210
- return handle
211
- end
212
-
213
- # :category: GUI
214
- def get_resize_handle_by_class(element, strg, dbg=nil)
215
- handle = get_div_by_class(element, strg, dbg)
216
- sleep_for(0.5)
217
- handle.flash(5)
218
- return handle
219
- end
220
-
221
- # :category: GUI
222
- def get_element_coordinates(browser, element, dbg=nil)
223
- bx, by, bw, bh = get_browser_coord(browser, dbg)
224
- if @browserAbbrev == 'IE'
225
- x_hack = @horizontal_hack_ie
226
- y_hack = @vertical_hack_ie
227
- elsif @browserAbbrev == 'FF'
228
- x_hack = @horizontal_hack_ff
229
- y_hack = @vertical_hack_ff
230
- end
231
- sleep_for(1)
232
- w, h = element.dimensions.to_a
233
- xc, yc = element.client_offset.to_a
234
- # xcc, ycc = element.client_center.to_a
235
- xcc = xc + w/2
236
- ycc = yc + h/2
237
- # screen offset:
238
- xs = bx + x_hack + xc - 1
239
- ys = by + y_hack + yc - 1
240
- # screen center:
241
- xsc = xs + w/2
242
- ysc = ys + h/2
243
- xslr = xs + w
244
- yslr = ys + h
245
- if dbg
246
- debug_to_log(
247
- "\n\t\tElement: #{element.inspect}"+
248
- "\n\t\tbrowser screen offset: x: #{bx} y: #{by}"+
249
- "\n\t\t dimensions: x: #{w} y: #{h}"+
250
- "\n\t\t client offset x: #{xc} y: #{yc}"+
251
- "\n\t\t screen offset x: #{xs} y: #{ys}"+
252
- "\n\t\t client center x: #{xcc} y: #{ycc}"+
253
- "\n\t\t screen center x: #{xsc} y: #{ysc}"+
254
- "\n\t\t screen lower right x: #{xslr} y: #{yslr}")
255
- end
256
- [w, h, xs, ys, xsc, ysc, xslr, yslr]
257
- end
258
-
259
- def adjust_dimensions_by_percent(w, h, p, returnnew=nil)
260
- p += 100
261
- nw = (w * (p/100.0)).to_i
262
- nh = (h * (p/100.0)).to_i
263
- deltaw = nw - w
264
- deltah = nh - h
265
- if returnnew
266
- [deltaw, deltah, nw, nh]
267
- else
268
- [deltaw, deltah]
269
- end
270
- end
271
-
272
- def get_browser_coord(browser=nil, dbg=nil)
273
- browser = @myBrowser if not browser
274
- title = browser.title
275
- x = @ai.WinGetPosX(title)
276
- y = @ai.WinGetPosY(title)
277
- w = @ai.WinGetPosWidth(title)
278
- h = @ai.WinGetPosHeight(title)
279
- if dbg
280
- debug_to_log("\n\t\tBrowser #{browser.inspect}\n"+
281
- "\t\tdimensions: x: #{w} y: #{h}"+
282
- "\t\tscreen offset x: #{x} y: #{y}")
283
- end
284
- [x, y, w, h]
285
- end
286
-
287
- def drag_and_drop(browser, how, what, delta_x, delta_y, desc = '')
288
- #TODO: webdriver
289
- msg = "Drag and drop element :#{how}=>#{what} by x=>#{delta_x} y=>#{delta_y}."
290
- msg << " #{desc}" if desc.length > 0
291
- drag_me = browser.div(how, what)
292
- drag_me.drag_and_drop_by(delta_x, delta_y)
293
- passed_to_log(msg)
294
- true
295
- rescue
296
- failed_to_log("Unable to #{msg} '#{$!}'")
297
- end
298
-
299
- def drag_and_drop(x1, y1, dx, dy, speed=nil)
300
- speed = 10 if not speed
301
- x2 = x1 + dx
302
- y2 = y1 + dy
303
- debug_to_log("drag_and_drop: start: [#{x1}, #{y1}] end: [#{x2}, #{y2}]")
304
-
305
- @ai.MouseMove(x1, y1, speed)
306
- @ai.MouseClick("primary", x1, y1)
307
- sleep_for(0.5)
308
- @ai.MouseClick("primary", x1, y1)
309
- sleep_for(0.5)
310
- @ai.MouseClickDrag("primary", x1, y1, x2, y2, speed)
311
- end
312
-
313
- def drag_and_drop_element(browser, element, dx, dy, speed = nil)
314
- speed = 10 if not speed
315
- w1, h1, x1, y1, xc1, yc1, xlr1, ylr1 = get_element_coordinates(browser, element, true)
316
- msg = "Move #{element} by [#{dx}, #{dy}] from center[#{xc1}, #{yc1}] "
317
- newxc = xc1 + dx
318
- newyc = yc1 + dy
319
- msg << "to center[[#{newxc}, #{newyc}]"
320
- sleep_for(0.5)
321
-
322
- drag_and_drop(xc1, yc1, dx, dy)
323
-
324
- sleep_for(1)
325
- w2, h2, x2, y2, xc2, yc2, xlr2, ylr2 = get_element_coordinates(browser, element, true)
326
-
327
- # TODO This adjustment is adhoc and empirical. Needs to be derived more rigorously
328
- xcerr = xc2 - xc1
329
- ycerr = yc2 - yc1
330
-
331
- debug_to_log("\n" +
332
- "\t\t xc1: #{xc1}\n" +
333
- "\t\t yc1: #{yc1}\n" +
334
- "\t\t xc2: #{xc2}\n" +
335
- "\t\t yc2: #{yc2}\n" +
336
- "\t\t xcerr: #{xlrerr}\n" +
337
- "\t\t ycerr: #{ylrerr}\n" +
338
- "\t\t x tol: #{@x_tolerance}\n" +
339
- "\t\t y tol: #{@y_tolerance}\n"
340
- )
341
-
342
- #TODO Add check that window _was_ resized.
343
- x_ok, x_msg = validate_drag_drop(xcerr, @x_tolerance, newxc, xc2)
344
- y_ok, y_msg = validate_drag_drop(ycerr, @y_tolerance, newyc, yc2)
345
- msg = msg + "x: #{x_msg}, y: #{y_msg}"
346
-
347
- if x_ok and y_ok
348
- passed_to_log(msg)
349
- else
350
- failed_to_log(msg)
351
- end
352
- sleep_for(1)
353
- rescue
354
- failed_to_log("Unable to validate drag and drop. #{$!} (#{__LINE__})")
355
- sleep_for(1)
356
- end
357
-
358
- def right_click(element)
359
- x = element.left_edge_absolute + 2
360
- y = element.top_edge_absolute + 2
361
- @ai.MouseClick("secondary", x, y)
362
- end
363
-
364
- def left_click(element)
365
- x = element.left_edge_absolute + 2
366
- y = element.top_edge_absolute + 2
367
- @ai.MouseClick("primary", x, y)
368
- end
369
-
370
- def screen_offset(element, browser=nil)
371
- bx, by, bw, bh = get_browser_coord(browser)
372
- ex = element.left_edge
373
- ey = element.top_edge
374
- [bx + ex, by + ey]
375
- end
376
-
377
- def screen_center(element, browser=nil)
378
- bx, by, bw, bh = get_browser_coord(browser)
379
- w, h = element.dimensions.to_a
380
- cx = bx + w/2
381
- cy = by + h/2
382
- [cx, cy]
383
- end
384
-
385
- def screen_lower_right(element, browser=nil)
386
- bx, by, bw, bh = get_browser_coord(browser)
387
- w, h = element.dimensions.to_a
388
- [bx + w, by + h]
389
- end
390
-
391
- def verify_resize(d, err, tol, min, act)
392
- ary = [false, "failed, actual #{act} err #{err}"]
393
- if err == 0
394
- ary = [true, 'succeeded ']
395
- #TODO need to find way to calculate this adjustment
396
- elsif d <= min + 4
397
- ary = [true, "reached minimum (#{min}) "]
398
- elsif err.abs <= tol
399
- ary = [true, "within tolerance (+-#{tol}px) "]
400
- end
401
- ary
402
- end
403
-
404
- alias validate_move verify_resize
405
- alias validate_resize verify_resize
406
-
407
- def validate_drag_drop(err, tol, exp, act)
408
- ary = [false, "failed, expected: #{exp}, actual: #{act}, err: #{err}"]
409
- if err == 0
410
- ary = [true, 'succeeded ']
411
- elsif err.abs <= tol
412
- ary = [true, "within tolerance (+-#{tol}px) "]
413
- end
414
- ary
415
- end
416
-
417
- end
418
- end
419
- end
420
-
1
+ module Awetestlib
2
+ module Regression
3
+ # Methods for moving and resizing elements, manipulating the mouse, and checking for relative positioning of elements,
4
+ # including overlap, overlay, etc.
5
+ # @note Still experimental. Works with IE but not fully tested with Firefox or Chrome in Windows using Watir-webdriver.
6
+ # Not compatible with Mac
7
+ # Rdoc is work in progress
8
+ module DragAndDrop
9
+
10
+ # Verify that specified *inner_element* is fully enclosed by *outer_element*.
11
+ # @param [Watir::Element] inner_element A reference to a DOM element
12
+ # @param [Watir::Element] outer_element A reference to a DOM element
13
+ # @param [String] desc Contains a message or description intended to appear in the log and/or report output
14
+ def verify_element_inside(inner_element, outer_element, desc = '')
15
+ mark_testlevel("#{__method__.to_s.titleize}", 3)
16
+ msg = build_message("#{inner_element.class.to_s} (:id=#{inner_element.id}) is fully enclosed by "+
17
+ "#{outer_element.class.to_s} (:id=#{outer_element.id}).", desc)
18
+ if overlay?(inner_element, outer_element, :inside)
19
+ failed_to_log(msg)
20
+ else
21
+ passed_to_log(msg)
22
+ true
23
+ end
24
+ rescue
25
+ failed_to_log("Unable to verify that #{msg} '#{$!}'")
26
+ end
27
+
28
+ # Verify that two elements, identified by specified attribute and value, do not overlap on a given *side*.
29
+ # @param [Symbol] above_element The element type for the first element, e.g. :div, :span, etc.
30
+ # @param [Symbol] above_how The element attribute used to identify the *above_element*.
31
+ # Valid values depend on the kind of element.
32
+ # Common values: :text, :id, :title, :name, :class, :href (:link only)
33
+ # @param [String, Regexp] above_what A string or a regular expression to be found in the *above_how* attribute that uniquely identifies the element.
34
+ # @param [Symbol] below_element The element type for the second element, e.g. :div, :span, etc.
35
+ # @param [Symbol] below_how The element attribute used to identify the *below_element*.
36
+ # @param [String, Regexp] below_what A string or a regular expression to be found in the *below_how* attribute that uniquely identifies the element.
37
+ # @param [Symbol] side :top, :bottom, :left, :right, :inside, or :outside
38
+ # @param [String] desc Contains a message or description intended to appear in the log and/or report output
39
+ def verify_no_element_overlap(browser, above_element, above_how, above_what, below_element, below_how, below_what, side, desc = '')
40
+ mark_testlevel("#{__method__.to_s.titleize}", 3)
41
+ msg = build_message("#{above_element.to_s.titleize} #{above_how}=>#{above_what} does not overlap "+
42
+ "#{below_element.to_s.titleize} #{below_how}=>#{below_what} at the #{side}.", desc)
43
+ above = browser.element(above_how, above_what)
44
+ below = browser.element(below_how, below_what)
45
+ if overlay?(above, below, side)
46
+ failed_to_log(msg)
47
+ else
48
+ passed_to_log(msg)
49
+ true
50
+ end
51
+ rescue
52
+ failed_to_log("Unable to verify that #{msg} '#{$!}'")
53
+ end
54
+
55
+ def overlay?(inner, outer, side = :bottom)
56
+ #mark_testlevel("#{__method__.to_s.titleize}", 3)
57
+ inner_t, inner_b, inner_l, inner_r = inner.bounding_rectangle_offsets
58
+ outer_t, outer_b, outer_l, outer_r = outer.bounding_rectangle_offsets
59
+ #overlay = false
60
+ case side
61
+ when :bottom
62
+ overlay = inner_b > outer_t
63
+ when :top
64
+ overlay = inner_t > outer_t
65
+ when :left
66
+ overlay = inner_l < outer_r
67
+ when :right
68
+ overlay = inner_r > outer_r
69
+ when :inside
70
+ overlay = !(inner_t > outer_t and
71
+ inner_r < outer_r and
72
+ inner_l > outer_l and
73
+ inner_b < outer_b)
74
+ else
75
+ overlay = (inner_t > outer_b or
76
+ inner_r > outer_l or
77
+ inner_l < outer_r or
78
+ inner_b < outer_t)
79
+ end
80
+ overlay
81
+ rescue
82
+ failed_to_log("Unable to determine overlay. '#{$!}'")
83
+ end
84
+
85
+ def hover(browser, element, wait = 2)
86
+ w1, h1, x1, y1, xc1, yc1, xlr1, ylr1 = get_element_coordinates(browser, element, true)
87
+ @ai.MoveMouse(xc1, yc1)
88
+ sleep_for(1)
89
+ end
90
+
91
+ def move_element_with_handle(browser, element, handle_id, dx, dy)
92
+ # msg = "Move element "
93
+ # w1, h1, x1, y1, xc1, yc1, xlr1, ylr1 = get_element_coordinates(browser, element, true)
94
+ # newx = w1 + dx
95
+ # newy = h1 + dy
96
+ # msg << " by [#{dx}, #{dy}] to expected [[#{newx}, #{newy}] "
97
+ # handle = get_resize_handle(element, handle_id)
98
+ # hw, hh, hx, hy, hxc, hyc, hxlr, hylr = get_element_coordinates(browser, handle, true)
99
+
100
+ # drag_and_drop(hxc, hyc, dx, dy)
101
+
102
+ # w2, h2, x2, y2, xc2, yc2, xlr2, ylr2 = get_element_coordinates(browser, element, true)
103
+
104
+ # xerr = x2 - newx
105
+ # yerr = y2 - newy
106
+ # xdsp = (x1 - x2).abs
107
+ # ydsp = (y1 - y2).abs
108
+
109
+ # if x2 == newx and y2 == newy
110
+ # msg << "succeeded."
111
+ # passed_to_log(msg)
112
+ # else
113
+ # msg << "failed. "
114
+ # failed_to_log(msg)
115
+ # debug_to_log("x: actual #{x2}, error #{xerr}, displace #{xdsp}. y: actual #{y2}, error #{yerr}, displace #{ydsp}.")
116
+ # end
117
+
118
+ end
119
+
120
+ def resize_element_with_handle(browser, element, target, dx, dy=nil)
121
+ #TODO enhance to accept differing percentages in each direction
122
+ msg = "Resize element "
123
+ w1, h1, x1, y1, xc1, yc1, xlr1, ylr1 = get_element_coordinates(browser, element, true)
124
+ if dy
125
+ deltax = dx
126
+ deltay = dy
127
+ neww = w1 + dx
128
+ newh = h1 + dy
129
+ msg << " by [#{dx}, #{dy}] " #"" to expected dimension [#{neww}, #{newh}] "
130
+ else
131
+ deltax, deltay, neww, newh = adjust_dimensions_by_percent(w1, h1, dx, true)
132
+ msg << "by #{dx} percent " #"" to expected dimension [#{neww}, #{newh}] "
133
+ end
134
+ handle = get_resize_handle_by_class(element, target) #, true)
135
+ sleep_for(0.5)
136
+ hw, hh, hx, hy, hxc, hyc, hxlr, hylr = get_element_coordinates(browser, handle, true)
137
+ hxlr_diff = 0
138
+ hylr_diff = 0
139
+
140
+ # TODO These adjustments are adhoc and empirical. Need to be derived more rigorously
141
+ if @browserAbbrev == 'IE'
142
+ hxlr_diff = (xlr1 - hxlr)
143
+ hylr_diff = (ylr1 - hylr)
144
+ x_start = hxlr - 2
145
+ y_start = hylr - 2
146
+ else
147
+ hxlr_diff = (xlr1 - hxlr) / 2 unless (xlr1 - hxlr) == 0
148
+ hylr_diff = (ylr1 - hylr) / 2 unless (ylr1 - hylr) == 0
149
+ x_start = hxlr
150
+ y_start = hylr
151
+ end
152
+
153
+ newxlr = xlr1 + deltax
154
+ newylr = ylr1 + deltay
155
+ # msg << ", lower right [#{newxlr}, #{newylr}] - "
156
+ sleep_for(0.5)
157
+
158
+ drag_and_drop(x_start, y_start, deltax, deltay)
159
+
160
+ sleep_for(1.5)
161
+ w2, h2, x2, y2, xc2, yc2, xlr2, ylr2 = get_element_coordinates(browser, element, true)
162
+
163
+ werr = w2 - neww
164
+ herr = h2 - newh
165
+
166
+ # TODO This adjustment is adhoc and empirical. Needs to be derived more rigorously
167
+ xlrerr = xlr2 - newxlr + hxlr_diff
168
+ ylrerr = ylr2 - newylr + hylr_diff
169
+
170
+ xlrdsp = (xlr1 - xlr2).abs
171
+ ylrdsp = (ylr1 - ylr2).abs
172
+
173
+ debug_to_log("\n" +
174
+ "\t\t hxlr_diff: #{hxlr_diff}\n" +
175
+ "\t\t hylr_diff: #{hylr_diff}\n" +
176
+ "\t\t werr: #{werr}\n" +
177
+ "\t\t herr: #{herr}\n" +
178
+ "\t\t xlrerr: #{xlrerr}\n" +
179
+ "\t\t ylrerr: #{ylrerr}\n" +
180
+ "\t\t xlrdsp: #{xlrdsp}\n" +
181
+ "\t\t ylrdsp: #{ylrdsp}\n" +
182
+ "\t\t @min_width: #{@min_width}\n" +
183
+ "\t\t@min_height: #{@min_height}\n" +
184
+ "\t\t x tol: #{@x_tolerance}\n" +
185
+ "\t\t y tol: #{@y_tolerance}\n"
186
+ )
187
+
188
+ #TODO Add check that window _was_ resized.
189
+ x_ok, x_msg = validate_move(w2, xlrerr, @x_tolerance, @min_width, xlr2)
190
+ y_ok, y_msg = validate_move(h2, ylrerr, @y_tolerance, @min_height, ylr2)
191
+ msg = msg + "x: #{x_msg}, y: #{y_msg}"
192
+
193
+ if x_ok and y_ok
194
+ passed_to_log(msg)
195
+ else
196
+ failed_to_log(msg)
197
+ debug_to_log("x - actual #{xlr2}, error #{xlrerr}, displace #{xlrdsp}, y - actual #{ylr2}, error #{ylrerr}, displace #{ylrdsp}.")
198
+ end
199
+ sleep_for(1)
200
+ rescue
201
+ failed_to_log("Unable to validate resize. #{$!} (#{__LINE__})")
202
+ sleep_for(1)
203
+ end
204
+
205
+ # :category: GUI
206
+ def get_resize_handle_by_id(element, id, dbg=nil)
207
+ handle = get_div_by_id(element, id, dbg)
208
+ sleep_for(1)
209
+ handle.flash(5)
210
+ return handle
211
+ end
212
+
213
+ # :category: GUI
214
+ def get_resize_handle_by_class(element, strg, dbg=nil)
215
+ handle = get_div_by_class(element, strg, dbg)
216
+ sleep_for(0.5)
217
+ handle.flash(5)
218
+ return handle
219
+ end
220
+
221
+ # :category: GUI
222
+ def get_element_coordinates(browser, element, dbg=nil)
223
+ bx, by, bw, bh = get_browser_coord(browser, dbg)
224
+ if @browserAbbrev == 'IE'
225
+ x_hack = @horizontal_hack_ie
226
+ y_hack = @vertical_hack_ie
227
+ elsif @browserAbbrev == 'FF'
228
+ x_hack = @horizontal_hack_ff
229
+ y_hack = @vertical_hack_ff
230
+ end
231
+ sleep_for(1)
232
+ w, h = element.dimensions.to_a
233
+ xc, yc = element.client_offset.to_a
234
+ # xcc, ycc = element.client_center.to_a
235
+ xcc = xc + w/2
236
+ ycc = yc + h/2
237
+ # screen offset:
238
+ xs = bx + x_hack + xc - 1
239
+ ys = by + y_hack + yc - 1
240
+ # screen center:
241
+ xsc = xs + w/2
242
+ ysc = ys + h/2
243
+ xslr = xs + w
244
+ yslr = ys + h
245
+ if dbg
246
+ debug_to_log(
247
+ "\n\t\tElement: #{element.inspect}"+
248
+ "\n\t\tbrowser screen offset: x: #{bx} y: #{by}"+
249
+ "\n\t\t dimensions: x: #{w} y: #{h}"+
250
+ "\n\t\t client offset x: #{xc} y: #{yc}"+
251
+ "\n\t\t screen offset x: #{xs} y: #{ys}"+
252
+ "\n\t\t client center x: #{xcc} y: #{ycc}"+
253
+ "\n\t\t screen center x: #{xsc} y: #{ysc}"+
254
+ "\n\t\t screen lower right x: #{xslr} y: #{yslr}")
255
+ end
256
+ [w, h, xs, ys, xsc, ysc, xslr, yslr]
257
+ end
258
+
259
+ def adjust_dimensions_by_percent(w, h, p, returnnew=nil)
260
+ p += 100
261
+ nw = (w * (p/100.0)).to_i
262
+ nh = (h * (p/100.0)).to_i
263
+ deltaw = nw - w
264
+ deltah = nh - h
265
+ if returnnew
266
+ [deltaw, deltah, nw, nh]
267
+ else
268
+ [deltaw, deltah]
269
+ end
270
+ end
271
+
272
+ def get_browser_coord(browser=nil, dbg=nil)
273
+ browser = @myBrowser if not browser
274
+ title = browser.title
275
+ x = @ai.WinGetPosX(title)
276
+ y = @ai.WinGetPosY(title)
277
+ w = @ai.WinGetPosWidth(title)
278
+ h = @ai.WinGetPosHeight(title)
279
+ if dbg
280
+ debug_to_log("\n\t\tBrowser #{browser.inspect}\n"+
281
+ "\t\tdimensions: x: #{w} y: #{h}"+
282
+ "\t\tscreen offset x: #{x} y: #{y}")
283
+ end
284
+ [x, y, w, h]
285
+ end
286
+
287
+ def drag_and_drop_div(browser, how, what, delta_x, delta_y, desc = '')
288
+ #TODO: webdriver
289
+ #TODO: assumes element is div
290
+ msg = "Drag and drop element :#{how}=>#{what} by x=>#{delta_x} y=>#{delta_y}."
291
+ msg << " #{desc}" if desc.length > 0
292
+ drag_me = browser.div(how, what)
293
+ drag_me.drag_and_drop_by(delta_x, delta_y)
294
+ passed_to_log(msg)
295
+ true
296
+ rescue
297
+ failed_to_log(unable_to)
298
+ end
299
+
300
+ def drag_and_drop(x1, y1, dx, dy, speed=nil)
301
+ speed = 10 if not speed
302
+ x2 = x1 + dx
303
+ y2 = y1 + dy
304
+ debug_to_log("drag_and_drop: start: [#{x1}, #{y1}] end: [#{x2}, #{y2}]")
305
+
306
+ @ai.MouseMove(x1, y1, speed)
307
+ @ai.MouseClick("primary", x1, y1)
308
+ sleep_for(0.5)
309
+ @ai.MouseClick("primary", x1, y1)
310
+ sleep_for(0.5)
311
+ @ai.MouseClickDrag("primary", x1, y1, x2, y2, speed)
312
+ end
313
+
314
+ def drag_and_drop_element(browser, element, dx, dy, speed = nil)
315
+ speed = 10 if not speed
316
+ w1, h1, x1, y1, xc1, yc1, xlr1, ylr1 = get_element_coordinates(browser, element, true)
317
+ msg = "Move #{element} by [#{dx}, #{dy}] from center[#{xc1}, #{yc1}] "
318
+ newxc = xc1 + dx
319
+ newyc = yc1 + dy
320
+ msg << "to center[[#{newxc}, #{newyc}]"
321
+ sleep_for(0.5)
322
+
323
+ drag_and_drop(xc1, yc1, dx, dy)
324
+
325
+ sleep_for(1)
326
+ w2, h2, x2, y2, xc2, yc2, xlr2, ylr2 = get_element_coordinates(browser, element, true)
327
+
328
+ # TODO This adjustment is adhoc and empirical. Needs to be derived more rigorously
329
+ xcerr = xc2 - xc1
330
+ ycerr = yc2 - yc1
331
+
332
+ debug_to_log("\n" +
333
+ "\t\t xc1: #{xc1}\n" +
334
+ "\t\t yc1: #{yc1}\n" +
335
+ "\t\t xc2: #{xc2}\n" +
336
+ "\t\t yc2: #{yc2}\n" +
337
+ "\t\t xcerr: #{xlrerr}\n" +
338
+ "\t\t ycerr: #{ylrerr}\n" +
339
+ "\t\t x tol: #{@x_tolerance}\n" +
340
+ "\t\t y tol: #{@y_tolerance}\n"
341
+ )
342
+
343
+ #TODO Add check that window _was_ resized.
344
+ x_ok, x_msg = validate_drag_drop(xcerr, @x_tolerance, newxc, xc2)
345
+ y_ok, y_msg = validate_drag_drop(ycerr, @y_tolerance, newyc, yc2)
346
+ msg = msg + "x: #{x_msg}, y: #{y_msg}"
347
+
348
+ if x_ok and y_ok
349
+ passed_to_log(msg)
350
+ else
351
+ failed_to_log(msg)
352
+ end
353
+ sleep_for(1)
354
+ rescue
355
+ failed_to_log("Unable to validate drag and drop. #{$!} (#{__LINE__})")
356
+ sleep_for(1)
357
+ end
358
+
359
+ def right_click(element)
360
+ x = element.left_edge_absolute + 2
361
+ y = element.top_edge_absolute + 2
362
+ @ai.MouseClick("secondary", x, y)
363
+ end
364
+
365
+ def left_click(element)
366
+ x = element.left_edge_absolute + 2
367
+ y = element.top_edge_absolute + 2
368
+ @ai.MouseClick("primary", x, y)
369
+ end
370
+
371
+ def screen_offset(element, browser=nil)
372
+ bx, by, bw, bh = get_browser_coord(browser)
373
+ ex = element.left_edge
374
+ ey = element.top_edge
375
+ [bx + ex, by + ey]
376
+ end
377
+
378
+ def screen_center(element, browser=nil)
379
+ bx, by, bw, bh = get_browser_coord(browser)
380
+ w, h = element.dimensions.to_a
381
+ cx = bx + w/2
382
+ cy = by + h/2
383
+ [cx, cy]
384
+ end
385
+
386
+ def screen_lower_right(element, browser=nil)
387
+ bx, by, bw, bh = get_browser_coord(browser)
388
+ w, h = element.dimensions.to_a
389
+ [bx + w, by + h]
390
+ end
391
+
392
+ def verify_resize(d, err, tol, min, act)
393
+ ary = [false, "failed, actual #{act} err #{err}"]
394
+ if err == 0
395
+ ary = [true, 'succeeded ']
396
+ #TODO need to find way to calculate this adjustment
397
+ elsif d <= min + 4
398
+ ary = [true, "reached minimum (#{min}) "]
399
+ elsif err.abs <= tol
400
+ ary = [true, "within tolerance (+-#{tol}px) "]
401
+ end
402
+ ary
403
+ end
404
+
405
+ alias validate_move verify_resize
406
+ alias validate_resize verify_resize
407
+
408
+ def validate_drag_drop(err, tol, exp, act)
409
+ ary = [false, "failed, expected: #{exp}, actual: #{act}, err: #{err}"]
410
+ if err == 0
411
+ ary = [true, 'succeeded ']
412
+ elsif err.abs <= tol
413
+ ary = [true, "within tolerance (+-#{tol}px) "]
414
+ end
415
+ ary
416
+ end
417
+
418
+ end
419
+ end
420
+ end
421
+