watirloo 0.0.7

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.
Files changed (55) hide show
  1. data/.gitignore +22 -0
  2. data/History.txt +44 -0
  3. data/Manifest.txt +59 -0
  4. data/README.rdoc +94 -0
  5. data/Rakefile +68 -0
  6. data/VERSION +1 -0
  7. data/lib/watirloo/browsers.rb +73 -0
  8. data/lib/watirloo/desktop.rb +44 -0
  9. data/lib/watirloo/extension/firewatir_ducktape.rb +194 -0
  10. data/lib/watirloo/extension/object.rb +32 -0
  11. data/lib/watirloo/extension/watir_ducktape.rb +552 -0
  12. data/lib/watirloo/extension/watir_reflector.rb +83 -0
  13. data/lib/watirloo/locker.rb +85 -0
  14. data/lib/watirloo/page.rb +140 -0
  15. data/lib/watirloo.rb +16 -0
  16. data/spec/browser_spec.rb +38 -0
  17. data/spec/browser_threads_spec.rb +45 -0
  18. data/spec/checkbox_group_spec.rb +136 -0
  19. data/spec/checkbox_groups_spec.rb +55 -0
  20. data/spec/checkboxes_value_spec.rb +35 -0
  21. data/spec/desktop_spec.rb +54 -0
  22. data/spec/extra/browser_events_spec.rb +76 -0
  23. data/spec/extra/page_objects_metrics.rb +139 -0
  24. data/spec/face_mixing_spec.rb +55 -0
  25. data/spec/firewatir/attach_instance_test.rb +38 -0
  26. data/spec/firewatir/spec_results.html +263 -0
  27. data/spec/firewatir/spec_results.txt +23 -0
  28. data/spec/firewatir/spec_results_failed.txt +3 -0
  29. data/spec/html/census.html +332 -0
  30. data/spec/html/checkbox_group1.html +33 -0
  31. data/spec/html/frameset1.html +17 -0
  32. data/spec/html/labels.html +53 -0
  33. data/spec/html/no_title.html +13 -0
  34. data/spec/html/person.html +37 -0
  35. data/spec/html/radio_group.html +35 -0
  36. data/spec/html/select_lists.html +82 -0
  37. data/spec/input_element_spec.rb +51 -0
  38. data/spec/label_spec.rb +65 -0
  39. data/spec/locker_spec.rb +49 -0
  40. data/spec/page_spec.rb +91 -0
  41. data/spec/person_def_wrappers_spec.rb +40 -0
  42. data/spec/radio_group_spec.rb +95 -0
  43. data/spec/radio_groups_spec.rb +55 -0
  44. data/spec/reflector_spec.rb +82 -0
  45. data/spec/select_list_options_spec.rb +40 -0
  46. data/spec/select_lists_spec.rb +151 -0
  47. data/spec/spec_helper.rb +20 -0
  48. data/spec/spec_helper_ff.rb +5 -0
  49. data/spec/spec_helper_runner.rb +13 -0
  50. data/spec/spec_results.html +556 -0
  51. data/spec/spec_results.txt +175 -0
  52. data/spec/spec_results_failed.txt +1 -0
  53. data/spec/text_fields_spec.rb +56 -0
  54. data/watirloo.gemspec +122 -0
  55. metadata +150 -0
@@ -0,0 +1,552 @@
1
+ gem 'watir', '>=1.6.2'
2
+ require 'watir'
3
+ require 'watir/ie'
4
+
5
+ module Watir
6
+
7
+ # for firefox and ie
8
+ module RadioCheckGroupCommonWatir
9
+
10
+ # size or count of controls in a group
11
+ def size
12
+ @o.size
13
+ end
14
+ alias count size
15
+
16
+ # sets control in a group by either position in a group
17
+ # or by hidden value attribute
18
+ def set(what)
19
+ if what.kind_of?(Array)
20
+ what.each {|thing| set thing } #calls itself with Fixnum or String
21
+ else
22
+ if what.kind_of?(Fixnum)
23
+ get_by_position(what).set
24
+ elsif what.kind_of?(String)
25
+ get_by_value(what).set
26
+ else
27
+ raise ::Watir::Exception::WatirException, "argument error #{what} not allowed"
28
+ end
29
+ end
30
+ end
31
+
32
+ # returns array of value attributes
33
+ def values
34
+ raise ::Watir::Exception::WatirException, "method should be implemented"
35
+ end
36
+
37
+ # returns Radio||Checkbox from a group that
38
+ # has specific value attribute
39
+ def get_by_value value
40
+ raise ::Watir::Exception::WatirException, "method should be implemented"
41
+ end
42
+
43
+ # returns Radio||Checkbox from a group that
44
+ # occupies specifi position in a group
45
+ # WARNING: it is 1-based NOT 0-based
46
+ # the intention is to enumerate position staring with 1, the way
47
+ # customer would enumerate items
48
+ def get_by_position position
49
+ if (1..self.size).member? position
50
+ @o[position-1]
51
+ else
52
+ raise ::Watir::Exception::WatirException, "positon #{position} is out of range of size"
53
+ end
54
+ end
55
+
56
+ # returns radio object in a group by position or by value
57
+ # in a collection. FIXME this is a hack
58
+ def [](accessor)
59
+ if accessor.kind_of? Fixnum
60
+ get_by_position(accessor+1)
61
+ elsif accessor.kind_of? String
62
+ get_by_value accessor
63
+ end
64
+ end
65
+
66
+ end
67
+
68
+ # for IE only
69
+ module RadioCheckGroup
70
+
71
+ def values
72
+ opts = []
73
+ @o.each {|rc| opts << rc.ole_object.invoke('value')}
74
+ return opts
75
+ end
76
+
77
+ def get_by_value value
78
+ if values.member? value
79
+ @o.find {|rc| rc.ole_object.invoke('value') == value}
80
+ else
81
+ raise ::Watir::Exception::WatirException, "value #{value} not found in hidden_values"
82
+ end
83
+ end
84
+ end
85
+
86
+ #for firefox and ie
87
+ module RadioGroupCommonWatir
88
+
89
+ # Only one radio in RadioGroup can be selected just like
90
+ # only one option in single select list box can be selected.
91
+ # this method is a bit gratuitious because it will always return array
92
+ # with one item but it's here to keep the plural for compatibility with
93
+ # CheckboxGroup or SelectList. if at some point your page object gets changed from RadioGroup
94
+ # to SelectList your tests will not have to change
95
+ def selected_values
96
+ selected_value.to_a
97
+ end
98
+
99
+
100
+ # returns radio that is selected.
101
+ # there can only be one radio selected.
102
+ # in the event that none is selected it returns nil
103
+ # see selected_value commentary
104
+ def selected_radio
105
+ @o.find {|r| r.isSet?}
106
+ end
107
+
108
+ # if a radio button in a group is set then the group is set
109
+ # by default it should be set but many HTML implementations provide
110
+ # the radiogroup to the user with no default one set (Bad practice perhaps)
111
+ def set?
112
+ selected_radio ? true : false
113
+ end
114
+
115
+ end
116
+
117
+ # radios that share the same :name attribute form a RadioGroup.
118
+ # RadioGroup semantically behaves like single select list box
119
+ # usage: this class is accessed by Watir::Container#radio_group
120
+ # RadioGroup semantically behaves like single select list box.
121
+ #
122
+ # per HTML401: -
123
+ # "If no radio button in a set sharing the same control name
124
+ # is initially 'on', user agent behavior for choosing which
125
+ # control is initially 'on' is undefined
126
+ #
127
+ # The idea of having all radios off makes no sense but in the wild you can see lots of examples.
128
+ # it would be better to just have a single select list box with no items selected instead of radios.
129
+ # The point of having radios is that at least one radio is 'ON' providing a default value for the group
130
+ #
131
+ # @browser = Watir::IE.attach :url, //
132
+ # @browser.radio_group('food') # => RadioGroup with :name, 'food'
133
+ #
134
+ class RadioGroup
135
+
136
+ include RadioCheckGroupCommonWatir
137
+ include RadioCheckGroup
138
+ include RadioGroupCommonWatir
139
+
140
+ def initialize(container, how, what)
141
+ @container = container
142
+ @how = how
143
+ @what = what
144
+ @o = locate
145
+ end
146
+
147
+ def name
148
+ @name
149
+ end
150
+
151
+ def locate
152
+ @name = case @how
153
+ when :name then @what
154
+ when :index then
155
+ names = []
156
+ @container.radios.each do |r|
157
+ names << r.name
158
+ end
159
+ names.uniq.at(@what-1) # follow 1-based index addressing for Watir API
160
+ end
161
+ @container.radios.find_all {|r| r.name == @name}
162
+ end
163
+ private :locate
164
+
165
+ # which value is selected?. returns value text as string
166
+ # So per HTML401 spec I am not sure if we should ever have empyt array returned here
167
+ # if you do get empty array then I would speak with developers to fix this and explicity
168
+ # provide checked for one radio on page load.
169
+ def selected_value
170
+ selected_radio.ole_object.invoke('value')
171
+ end
172
+
173
+ # in the absence of visible text like in select list we treat value
174
+ # as a selected text invisible to the user
175
+ alias selected selected_value
176
+
177
+ end
178
+
179
+ class TextFields < ElementCollections
180
+
181
+ def reflect
182
+ ret = []
183
+ self.each do |item|
184
+ how, what = get_how_what get_attribs(item)
185
+ facename = suggest_def_name what
186
+ value = item.value
187
+ # this approach relies on doc element
188
+ ret << "face(:#{facename}) {doc.text_field(:#{how}, #{what.inspect})}"
189
+ ret << "#{facename}.value.should == #{value.inspect}"
190
+ end
191
+ ret
192
+ end
193
+
194
+ end
195
+
196
+ class RadioGroups < ElementCollections
197
+
198
+ def element_class; RadioGroup; end
199
+ def length
200
+ names = []
201
+ @container.radios.each do |r|
202
+ names << r.name
203
+ end
204
+ names.uniq.size #non repeating names
205
+ end
206
+
207
+ def reflect
208
+ ret = []
209
+ self.each do |item|
210
+ name = item.name
211
+ facename = suggest_def_name name
212
+ values = item.values
213
+ selected = item.selected
214
+ ret << "face(:#{facename}) {doc.radio_group(#{name.inspect})}"
215
+ ret << "#{facename}.values.should == #{values.inspect}"
216
+ ret << "#{facename}.selected.should == #{selected.inspect}"
217
+ end
218
+ ret
219
+ end
220
+
221
+
222
+ private
223
+ def iterator_object(i)
224
+ @container.radio_group(:index, i + 1)
225
+ end
226
+ end
227
+
228
+ module CheckboxGroupCommonWatir
229
+
230
+ # returns selected checkboxes as array
231
+ # when empty [] then nothing is selected
232
+ # when [checkbox, checkbox] = array of checkboxes that are selected
233
+ # that you can iterate over for tests.
234
+ def selected_checkboxes
235
+ @o.select {|cb| cb.isSet?}
236
+ end
237
+
238
+ # convenience method as a filter for selected_values
239
+ # returns:
240
+ # nil => when no checkbox is set
241
+ # 'value' => if one checkbox is set
242
+ # or bypass filter and return selected_values array
243
+ def selected_value
244
+ arr = selected_values
245
+ case arr.size
246
+ when 0 then nil
247
+ when 1 then arr[0]
248
+ else arr
249
+ end
250
+ end
251
+
252
+ # in case of checkbox there are no visible text items.
253
+ # We rely on value attributes that must be present
254
+ # to differentiate the checkbox in a group
255
+ # compare to SelectList where selected returns selected_item
256
+ alias selected selected_value
257
+
258
+
259
+ # if at least one checkbox is selected then the group is considered set
260
+ def set?
261
+ (selected_checkboxes != []) ? true : false
262
+ end
263
+
264
+ alias checked? set?
265
+
266
+ end
267
+
268
+ # Checkbox group semantically behaves like multi select list box.
269
+ # each checkbox is a menu item groupped by the common attribute :name
270
+ # each checkbox can be off initially (a bit different semantics than RadioGroup)
271
+ class CheckboxGroup
272
+
273
+ include RadioCheckGroupCommonWatir
274
+ include RadioCheckGroup
275
+ include CheckboxGroupCommonWatir
276
+
277
+ def initialize(container, how, what)
278
+ @container = container
279
+ @how = how
280
+ @what = what
281
+ @o = locate
282
+ end
283
+
284
+ def name
285
+ @name
286
+ end
287
+
288
+ def locate
289
+ @name = case @how
290
+ when :name then @what
291
+ when :index then
292
+ names = []
293
+ @container.checkboxes.each do |cb|
294
+ names << cb.name
295
+ end
296
+ names.uniq.at(@what-1) # follow 1-based index addressing for Watir API
297
+ end
298
+ @container.checkboxes.find_all {|cb| cb.name == @name}
299
+ end
300
+ private :locate
301
+
302
+ # returns array of value attributes. Each Checkbox in a group
303
+ # has a value which is invisible to the user
304
+ def selected_values
305
+ values = []
306
+ selected_checkboxes.each do |cb|
307
+ values << cb.ole_object.invoke('value')
308
+ end
309
+ return values
310
+ end
311
+ end
312
+
313
+ class CheckboxGroups < ElementCollections
314
+ def element_class; CheckboxGroup; end
315
+ def length
316
+ names = []
317
+ @container.checkboxes.each do |cb|
318
+ names << cb.name
319
+ end
320
+ names.uniq.size #non repeating names
321
+ end
322
+
323
+ def reflect
324
+ ret = []
325
+ self.each do |item|
326
+ name = item.name
327
+ facename = suggest_def_name(name)
328
+ values = item.values
329
+ selected = item.selected
330
+ ret << "face(:#{facename}) {doc.checkbox_group(#{name.inspect})}"
331
+ ret << "#{facename}.values.should == #{values.inspect}"
332
+ ret << "#{facename}.selected.should == #{selected.inspect}"
333
+ end
334
+ ret
335
+ end
336
+
337
+ private
338
+ def iterator_object(i)
339
+ @container.checkbox_group(:index, i + 1)
340
+ end
341
+ end
342
+
343
+
344
+ module Container
345
+
346
+ def radio_group(how, what=nil)
347
+ how, what = process_default :name, how, what
348
+ RadioGroup.new(self, how, what)
349
+ end
350
+
351
+ def radio_groups
352
+ RadioGroups.new(self)
353
+ end
354
+
355
+ def checkbox_group(how, what=nil)
356
+ how, what = process_default :name, how, what
357
+ CheckboxGroup.new(self, how, what)
358
+ end
359
+
360
+ def checkbox_groups
361
+ CheckboxGroups.new(self)
362
+ end
363
+
364
+ end
365
+
366
+ class RadioCheckCommon
367
+ alias set? isSet?
368
+ end
369
+
370
+ # these methods work for IE and for Firefox
371
+ module SelectListCommonWatir
372
+
373
+ # selected_items examples
374
+ # [] => nothing selected
375
+ # ['item'] => if one selected
376
+ # ['item1', 'item2', 'item3'] => several items selected
377
+ def selected_items
378
+ getSelectedItems
379
+ end
380
+
381
+ # selected_item is a convenience filter for selected_items
382
+ # returns
383
+ # nil if no options selected
384
+ # 'text' string if one option selected.
385
+ # or selected_items if more than one option selected
386
+ def selected_item
387
+ arr = selected_items # limit to one mehtod call
388
+ case arr.size
389
+ when 0 then nil
390
+ when 1 then arr[0]
391
+ else arr
392
+ end
393
+ end
394
+
395
+
396
+ # for selecte lists by default we return the text of an option
397
+ # compare to selected in RadioGroup or Checkbox group which return the
398
+ # value attributes since there is no visible text for the user
399
+ alias selected selected_item
400
+
401
+ # set :value or :text
402
+ def _set(how, what)
403
+ if what.kind_of? Array
404
+ what.each { |item| _set(how,item)} # call self with individual item
405
+ else
406
+ if what.kind_of? Fixnum # if by position then translate to set by text
407
+ if (0..items.size).member? what
408
+ _set :text, items[what-1]
409
+ else
410
+ raise ::Watir::Exception::WatirException, "number #{item} is out of range of item count"
411
+ end
412
+ else
413
+ select_item_in_select_list(how, what) #finally as :value or :text
414
+ end
415
+ end
416
+
417
+ end
418
+ private :_set
419
+
420
+
421
+
422
+
423
+ # similar to selected_items but returns array of option value attributes
424
+ def selected_values
425
+ assert_exists
426
+ arr = []
427
+ @o.each do |thisItem|
428
+ if thisItem.selected
429
+ arr << thisItem.value
430
+ end
431
+ end
432
+ return arr
433
+ end
434
+
435
+ # convinience method as a filter for select_values
436
+ # returns:
437
+ # nil for nothing selected.
438
+ # single value if only once selected or just
439
+ # or returns selected_values
440
+ def selected_value
441
+ arr = selected_values
442
+ case arr.size
443
+ when 0 then nil
444
+ when 1 then arr[0]
445
+ else arr
446
+ end
447
+ end
448
+
449
+
450
+ end
451
+
452
+ # SelectList acts like RadioGroup or CheckboxGroup
453
+ # They all have options to select
454
+ # There are two kinds of SelectLists. SingleSelect and MultiSelect
455
+ # SelectList presents user with visible items to select from.
456
+ # Each Item has a visible :text and invisible :value attributes
457
+ # (sometimes :value attributes are missing)
458
+ #
459
+ # In Watirloo
460
+ # The invisible :value attributes of options we call :values
461
+ # The visible :text of options we call :items
462
+ # The selected items as visible text we call :selected
463
+ # The selected items as values we call :selected_values
464
+ #
465
+ # example of single select list
466
+ #
467
+ # <select name="controlname">
468
+ # <option value="opt0"></option>
469
+ # <option value="opt1">item1</option>
470
+ # <option value="opt2" selected>item2</option>
471
+ # </select>
472
+ #
473
+ # items => ['', 'item1', 'item2']
474
+ # values => ['opt0','opt1', 'opt2']
475
+ # selected => ['item2']
476
+ # selected_values => ['opt2']
477
+ #
478
+ # example of multi select list
479
+ #
480
+ # <select name="controlname" multiple size=2>
481
+ # <option value="o1">item1
482
+ # <option value="o2" selected>item2
483
+ # <option value="o3" selected>item3
484
+ # </select>
485
+ #
486
+ # items => ['item1', 'item2', 'item3']
487
+ # values => ['o1','o2','o3']
488
+ # selected => ['item2', 'item3']
489
+ # selected_values => ['o2', 'o3']
490
+ #
491
+ class SelectList
492
+
493
+ include SelectListCommonWatir
494
+
495
+
496
+ # accepts one text item or array of text items. if array then sets one after another.
497
+ # For single select lists the last item in array wins
498
+ #
499
+ # examples
500
+ # select_list.set 'bla' # => single option text
501
+ # select_list.set ['bla','foo','gugu'] # => set 3 options by text. If
502
+ # this is a single select list box it will set each value in turn
503
+ # select_list set 1 # => set the first option in a list
504
+ # select_list.set [1,3,5] => set the first, third and fith options
505
+ def set(item)
506
+ _set(:text, item)
507
+ end
508
+
509
+ # set item by the option value attribute. if array then set one after anohter.
510
+ # see examples in set method
511
+ def set_value(value)
512
+ _set(:value, value)
513
+ end
514
+
515
+ # returns array of value attributes
516
+ # each option usually has a value attribute
517
+ # which is hidden to the person viewing the page
518
+ def values
519
+ a = []
520
+ attribute_value('options').each do |item|
521
+ a << item.value
522
+ end
523
+ return a
524
+ end
525
+
526
+ alias clear clearSelection
527
+
528
+ # alias, items or contents return the same visible text items
529
+ alias items getAllContents
530
+
531
+
532
+
533
+ def reflect
534
+ ret = []
535
+ self.each do |item|
536
+ name = item.name
537
+ facename = suggest_def_name name
538
+ values = item.values
539
+ items = item.items
540
+ selected_item = item.selected_item
541
+ selected_value = item.selected_value
542
+
543
+ ret << "face(:#{facename}) {doc.select_list(:name, #{name.inspect})}"
544
+ ret << "#{facename}.items.should == #{items.inspect}"
545
+ ret << "#{facename}.values.should == #{values.inspect}"
546
+ ret << "#{facename}.selected_item.should == #{selected_item.inspect}"
547
+ ret << "#{facename}.selected_value.should == #{selected_value.inspect}"
548
+ end
549
+ ret
550
+ end
551
+ end
552
+ end
@@ -0,0 +1,83 @@
1
+ =begin rdoc
2
+ Look Ma!, I can Has Reflect The Browser
3
+
4
+ Watir::Reflector module added to watir.
5
+ reflect watir element collections. reflections create wrapper methods
6
+ with suggested semantic naming based on id, name, value or combination.
7
+ the intention is to create a scaffolding for Watirloo::Page elements.
8
+ =end
9
+
10
+ module Watir
11
+
12
+ # Watirloo::Page objects scaffold creation. Talks to the current page and reflects
13
+ # the watir elements to be used for semantic test objects tests.
14
+ module Reflector
15
+
16
+ #cleanup the def name for some kind of semantic name
17
+ def suggest_def_name(how)
18
+ how.gsub!(/_+/,'_') # double underscores to one
19
+ how.gsub!(/^_/, '') # if it begins with undrscore kill it.
20
+ how.gsub!(/\s+/, '_') # kill spaces if for some strange reason they exist
21
+ how.underscore #Any CamelCase will be converted to camel_no_case
22
+ end
23
+
24
+ # glean(:text_fields, [:id, :name, :value]
25
+ # glean(:radios, [:id, :name, :value])
26
+ # glean and make a map of types and attributes needed for reflection
27
+ # this should be private I think
28
+ def get_attribs(item)
29
+ attribs = [:id, :name, :value]
30
+ h = {}
31
+ attribs.each do |k|
32
+ v = item.attribute_value k.to_s
33
+ h[k] = v
34
+ end
35
+ h
36
+ end
37
+
38
+ def get_how_what h
39
+ how, what = '', ''
40
+ if h[:id] != '' #First Choice: if id is not blank then we'll use it
41
+ how, what = :id, h[:id]
42
+ elsif h[:name] != '' #Second Choice: if name is not blank then we'll use it instead of id
43
+ how, what = :name, h[:name]
44
+ elsif h[:value] != ''
45
+ how, what = :value, h[:value]
46
+ end
47
+ [how, what]
48
+ end
49
+
50
+ # public interface for Reflector.
51
+ # ie.reflect # => returns object definitions for entire dom using ie as container
52
+ # ie.frame('main').select_lists.reflect# => returns definitions for select_lists
53
+ # only contained by the frame
54
+ # you can be as granular as needed
55
+ def reflect
56
+ puts "I has not exist. Implements me please"
57
+ end
58
+ end
59
+
60
+
61
+ module Container
62
+
63
+ # container asks collections to reflect themselves
64
+ # each collection knows how to reflect itself and what to reflect
65
+ def reflect
66
+ ref = []
67
+ [:radio_groups, :checkbox_groups, :text_fields, :select_lists].each do |type|
68
+ ret << self.send(type).reflect
69
+ end
70
+ return ref
71
+ end
72
+
73
+ end
74
+
75
+
76
+ class ElementCollections
77
+
78
+ # adds reflect method to element collections
79
+ include ::Watir::Reflector
80
+
81
+ end
82
+
83
+ end
@@ -0,0 +1,85 @@
1
+ module Watirloo
2
+
3
+
4
+ # manages references to browsers we care about to run tests agains.
5
+ # Saves references to window handles internall to yaml file so we can reuse the browser for tests by reattaching to it between tests.
6
+ # you put reference to a browser in storage. Next time you run a test you can restore the browser's reference instead fo staring a new one.
7
+ module Locker
8
+
9
+ @@locker_file = File.join(ENV['TEMP'], "watirloo_temp_locker.yml")
10
+
11
+ class << self
12
+
13
+ # hash of {key => IE.hwnd} to attach and reuse browsers
14
+ # example: mapping = {:default=> 234567, :bla => 234234}
15
+ def mapping
16
+ @mapping ||= read_mapping
17
+ end
18
+
19
+ def locker
20
+ @@locker_file
21
+ end
22
+
23
+ def locker=( locker )
24
+ @@locker_file = locker
25
+ end
26
+
27
+ # returns IE reference to a browser with a given key
28
+ def browser(key='default')
29
+ if key == 'default'
30
+ (@browser && @browser.exists?) ? @browser : @browser = attach_browser
31
+ else
32
+ attach_browser(key)
33
+ end
34
+ end
35
+
36
+ # add browser to storage for later reuse. by convention if you don't have any browsers it
37
+ # so you can later restore it and continue working with it.
38
+ # pass either browser referene or the hwnd Fixnum
39
+ def add(browser, key='default')
40
+ mapping[key] = browser.kind_of?(Watir::IE) ? browser.hwnd : browser
41
+ save_mapping
42
+ end
43
+
44
+ # remove browser from storage and from further reusing
45
+ def remove(key='default')
46
+ @browser = nil if key == 'default'
47
+ mapping.delete(key) if mapping[key]
48
+ save_mapping
49
+ end
50
+
51
+ # clear Storage
52
+ def clear
53
+ @browser = nil
54
+ mapping.clear
55
+ save_mapping
56
+ end
57
+
58
+ private
59
+
60
+ # TODO Change this all to Yaml::Store transaction mechanism. get rid of hand rolled stuff.
61
+ def read_mapping
62
+ if FileTest.exists?(locker)
63
+ loaded = YAML::load_file(locker)
64
+ #if file is empty or not well formed yaml
65
+ #or not a hash then return empty hash
66
+ loaded.kind_of?(Hash) ? loaded : {}
67
+ else
68
+ #empty hash if locker.yaml not there
69
+ #or malformed loaded not created yet
70
+ {}
71
+ end
72
+ end
73
+
74
+ def save_mapping
75
+ File.open(locker,'w') {|f| YAML.dump(mapping, f)}
76
+ end
77
+
78
+ # throws exception if can't attach to the known handle.
79
+ def attach_browser(key='default')
80
+ Watir::IE.attach(:hwnd, mapping[key])
81
+ end
82
+
83
+ end
84
+ end
85
+ end