watirloo 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
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