safariwatir 0.3.8 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ module ElementAttributes
2
+ def html_method_reader(m_name, html_attribute = nil)
3
+ attr_to_reference = (html_attribute ? html_attribute : m_name.to_s)
4
+ define_method(m_name) do
5
+ html_method(attr_to_reference) ? html_method(attr_to_reference) : ""
6
+ end
7
+ end
8
+
9
+ def html_attr_reader(m_name, html_attribute = nil)
10
+ attr_to_reference = (html_attribute ? html_attribute : m_name.to_s)
11
+ define_method(m_name) do
12
+ attr(attr_to_reference) ? attr(attr_to_reference) : ""
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,127 @@
1
+ require File.dirname(__FILE__) + '/../watir/exceptions'
2
+
3
+ module Locators
4
+
5
+ def document_locator
6
+ parent.document_locator
7
+ end
8
+
9
+ def locator
10
+ self.send("locator_by_#{how.to_s}".to_sym)
11
+ end
12
+
13
+ def locator_by_text
14
+ locator_by_method("innerText")
15
+ end
16
+
17
+ def locator_by_value
18
+ locator_by_method("value")
19
+ end
20
+
21
+ def locator_by_src
22
+ locator_by_attribute("src")
23
+ end
24
+
25
+ def locator_by_alt
26
+ locator_by_attribute("alt")
27
+ end
28
+
29
+ def locator_by_src
30
+ locator_by_attribute("src")
31
+ end
32
+
33
+ def locator_by_href
34
+ locator_by_attribute("href")
35
+ end
36
+
37
+ def locator_by_url
38
+ locator_by_attribute("href")
39
+ end
40
+
41
+ def locator_by_title
42
+ locator_by_attribute("title")
43
+ end
44
+
45
+ def locator_by_method(m_name)
46
+ "findByMethodValue(#{parent.locator}, #{tag_names}, \"#{m_name}\", #{encode_what})[0]"
47
+ end
48
+
49
+ def locator_by_attribute(attribute_name)
50
+ "findByAttributeValue(#{parent.locator}, #{tag_names}, \"#{attribute_name}\", #{encode_what})[0]"
51
+ end
52
+
53
+ def locator_by_xpath
54
+ xpath = what.gsub(/"/, "\'")
55
+ "findByXPath(#{document_locator}, #{parent.locator}, \"#{xpath}\")"
56
+ end
57
+
58
+ def locator_by_name
59
+ locator_by_attribute("name")
60
+ end
61
+
62
+ def locator_by_index
63
+ "findByTagNames(#{parent.locator}, #{tag_names})[#{what.to_i - 1}]"
64
+ end
65
+
66
+ def locator_by_class
67
+ locator_by_attribute("class")
68
+ end
69
+
70
+ def locator_by_id
71
+ locator_by_method("id")
72
+ end
73
+
74
+ def tag_names
75
+ t_names = tag.kind_of?(Array) ? tag : [tag]
76
+ "[" + (t_names.map { |t_name| "\"#{t_name.upcase}\"" }.join(", ")) + "]"
77
+ end
78
+
79
+ def encode_what
80
+ what.kind_of?(Regexp) ? "new RegexValueMatcher(/#{what.source}/)" : "new ExactValueMatcher(\"#{what.to_s}\")"
81
+ end
82
+
83
+ def method_missing(*args)
84
+ if args[0].to_s =~ /locator_by_/
85
+ raise Watir::Exception::MissingWayOfFindingObjectException
86
+ end
87
+ super(*args)
88
+ end
89
+
90
+ end
91
+
92
+ module InputLocators
93
+ include Locators
94
+
95
+ def locator_by_method(m_name)
96
+ "findInputByMethodValue(#{parent.locator}, \"#{input_type}\", \"#{m_name}\", #{encode_what})[0]"
97
+ end
98
+
99
+ def locator_by_attribute(attribute_name)
100
+ "findInputByAttributeValue(#{parent.locator}, \"#{input_type}\", \"#{attribute_name}\", #{encode_what})[0]"
101
+ end
102
+
103
+ def locator_by_index
104
+ "findInputsByType(#{parent.locator}, \"#{input_type}\")[#{what.to_i - 1}]"
105
+ end
106
+
107
+ end
108
+
109
+ module ButtonLocators
110
+ include Locators
111
+
112
+ def locator_by_index
113
+ "findAllMatching(#{parent.locator}, new ButtonMatcher())[#{what.to_i - 1}]"
114
+ end
115
+
116
+ def locator_by_attribute(attribute_name)
117
+ "filterToAttributeValue(findAllMatching(#{parent.locator}, new ButtonMatcher()), \"#{attribute_name}\", #{encode_what})[0]"
118
+ end
119
+
120
+ def locator_by_method(attribute_name)
121
+ "filterToMethodValue(findAllMatching(#{parent.locator}, new ButtonMatcher()), \"#{attribute_name}\", #{encode_what})[0]"
122
+ end
123
+
124
+ def locator_by_value
125
+ locator_by_attribute("value")
126
+ end
127
+ end
@@ -9,12 +9,144 @@ module Watir # :nodoc:
9
9
  TABLE_CELL_NOT_FOUND = "__safari_watir_cell_unfound__"
10
10
  EXTRA_ACTION_SUCCESS = "__safari_watir_extra_action__"
11
11
 
12
- JS_LIBRARY = %|
13
- function dispatchOnChange(element) {
14
- var event = document.createEvent('HTMLEvents');
12
+ JS_LIBRARY = <<JSCODE
13
+ /* Library functions */
14
+
15
+ var ButtonMatcher = function() {
16
+ this.match = function(ele) {
17
+ if (ele.tagName == "BUTTON") {
18
+ return(true);
19
+ }
20
+
21
+ if (ele.tagName == 'INPUT') {
22
+ return(["submit", "button", "reset"].indexOf(ele.type) != -1);
23
+ }
24
+
25
+ return(false);
26
+ }
27
+ }
28
+
29
+
30
+ var ExactValueMatcher = function(exactVal) {
31
+ this.match = function (val) {
32
+ return(val == exactVal);
33
+ }
34
+ }
35
+
36
+ var RegexValueMatcher = function(regEx) {
37
+ this.match = function (val) {
38
+ return(regEx.test(val));
39
+ }
40
+ }
41
+
42
+ function dispatchOnChange(scope, element) {
43
+ var event = scope.createEvent('HTMLEvents');
15
44
  event.initEvent('change', true, true);
16
45
  element.dispatchEvent(event);
17
- }|
46
+ }
47
+
48
+ function findByXPath(dscope, scope, expr) {
49
+ var result = dscope.evaluate(expr, scope, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
50
+ return(result ? result.singleNodeValue : null );
51
+ }
52
+
53
+ function filterToMethodValue(found_tags, m_name, m_value) {
54
+ var result_array = [];
55
+
56
+ for (var i = 0; i < found_tags.length; i++) {
57
+ if (m_value.match(found_tags[i][m_name])) {
58
+ result_array.push(found_tags[i]);
59
+ }
60
+ }
61
+ return(result_array);
62
+ }
63
+
64
+ function filterToAttributeValue(found_tags, attr_name, attr_value) {
65
+ var result_array = [];
66
+
67
+ for (var i = 0; i < found_tags.length; i++) {
68
+ if (attr_value.match(found_tags[i].getAttribute(attr_name))) {
69
+ result_array.push(found_tags[i]);
70
+ }
71
+ }
72
+ return(result_array);
73
+ }
74
+
75
+ function filterToTagNames(found_tags, tags) {
76
+ var result_array = [];
77
+
78
+ for (var i = 0; i < found_tags.length; i++) {
79
+ if (found_tags[i].tagName != 'META' && tags.indexOf(found_tags[i].tagName) != -1) {
80
+ result_array.push(found_tags[i]);
81
+ }
82
+ }
83
+ return(result_array);
84
+ }
85
+
86
+ function findByClassName(scope, cname, tags) {
87
+ var found_tags = scope.getElementsByClassName(cname);
88
+ return( filterToTagNames(tags) );
89
+ }
90
+
91
+ function findInputByMethodValue(scope, input_type, attribute, value) {
92
+ var found_tags = findInputsByType(scope, input_type);
93
+ return( filterToMethodValue(found_tags, attribute, value) );
94
+ }
95
+
96
+ function findInputByAttributeValue(scope, input_type, attribute, value) {
97
+ var found_tags = findInputsByType(scope, input_type);
98
+ return( filterToAttributeValue(found_tags, attribute, value) );
99
+ }
100
+
101
+ function findByMethodValue(scope, names, attribute, value) {
102
+ var found_tags = findByTagNames(scope, names);
103
+ return( filterToMethodValue(found_tags, attribute, value) );
104
+ }
105
+
106
+ function findByAttributeValue(scope, names, attribute, value) {
107
+ var found_tags = findByTagNames(scope, names);
108
+ return( filterToAttributeValue(found_tags, attribute, value) );
109
+ }
110
+
111
+ function findAllMatching(scope, ele_matcher) {
112
+ var result_array = [];
113
+ var found_tags = scope.getElementsByTagName('*');
114
+
115
+ for (var i = 0; i < found_tags.length; i++) {
116
+ if (ele_matcher.match(found_tags[i])) {
117
+ result_array.push(found_tags[i]);
118
+ }
119
+ }
120
+ return(result_array);
121
+ }
122
+
123
+ function findInputsByType(scope, input_type) {
124
+ var result_array = [];
125
+ var found_tags = scope.getElementsByTagName("input");
126
+
127
+ for (var i = 0; i < found_tags.length; i++) {
128
+ if (found_tags[i].type == input_type) {
129
+ result_array.push(found_tags[i]);
130
+ }
131
+ }
132
+ return(result_array);
133
+ }
134
+
135
+ function findByTagNames(scope, names) {
136
+ var result_array = [];
137
+ var found_tags = null;
138
+
139
+ for (var i = 0; i < names.length; i++) {
140
+ found_tags = scope.getElementsByTagName(names[i]);
141
+ for (var j = 0; j < found_tags.length; j++) {
142
+ result_array.push(found_tags[j]);
143
+ }
144
+ }
145
+ return(result_array);
146
+ }
147
+
148
+ /* Action Code */
149
+ JSCODE
18
150
 
19
151
  class JavaScripter # :nodoc:
20
152
  def operate(locator, operation)
@@ -64,19 +196,6 @@ if (element) {
64
196
  end
65
197
  end
66
198
 
67
- class FrameJavaScripter < JavaScripter # :nodoc:
68
- def initialize(frame)
69
- @page_container = "parent.#{frame.name}"
70
- end
71
-
72
- def wrap(script)
73
- # add in frame name when referencing parent or document
74
- script.gsub! /\bparent\b/, "parent.#{@page_container}"
75
- script.gsub! /\bdocument\b/, "#{@page_container}.document"
76
- super(script)
77
- end
78
- end
79
-
80
199
  class TableJavaScripter < JavaScripter # :nodoc:
81
200
  def_init :cell
82
201
 
@@ -100,6 +219,7 @@ if (element) {
100
219
  @appname = opts[:appname] || "Safari"
101
220
  @app = Appscript.app(@appname)
102
221
  @document = @app.documents[1]
222
+ @typing_lag = 0.08
103
223
  end
104
224
 
105
225
  def ensure_window_ready
@@ -161,10 +281,14 @@ if (element == undefined) {
161
281
  def get_attribute(name, element = @element)
162
282
  execute(element.operate { %|return element.getAttribute('#{name}')| }, element)
163
283
  end
284
+
285
+ def get_method_value(name, element = @element)
286
+ execute(element.operate { %|return element.#{name}| }, element)
287
+ end
164
288
 
165
289
 
166
- def document_text
167
- execute(%|return document.getElementsByTagName('BODY').item(0).innerText;|)
290
+ def document_text(element)
291
+ execute(%|return #{element.locator}.getElementsByTagName('BODY').item(0).innerText;|)
168
292
  end
169
293
 
170
294
  def document_html
@@ -197,32 +321,32 @@ element.style.backgroundColor = 'yellow';|
197
321
  end
198
322
 
199
323
  def element_exists?(element = @element, &block)
200
- block ||= Proc.new {}
201
- execute(element.operate(&block), element)
202
- return true
203
- rescue UnknownObjectException
324
+ response = eval_js(element.operate do
325
+ <<JSCODE
326
+ if (element == undefined || element == null) {
327
+ return(false);
328
+ }
329
+ return(true);
330
+ JSCODE
331
+ end)
332
+ case response
333
+ when ELEMENT_NOT_FOUND
204
334
  return false
335
+ else
336
+ return response
337
+ end
205
338
  end
206
339
 
207
340
  def select_option(element = @element)
208
- execute(element.operate do
209
- %|var selected = -1;
210
- var previous_selection = -2;
211
- for (var i = 0; i < element.options.length; i++) {
212
- if (element.options[i].selected) {
213
- previous_selection = i;
214
- }
215
- if (element.options[i].#{element.how} == '#{element.what}') {
216
- element.options[i].selected = true;
217
- selected = i;
341
+ execute(element.operate do %|
342
+ var other_options = element.parentNode.options;
343
+ for (var i = 0; i < other_options.length; i++) {
344
+ other_options[i].selected = undefined;
218
345
  }
219
- }
220
- if (selected == -1) {
221
- return '#{ELEMENT_NOT_FOUND}';
222
- } else if (previous_selection != selected) {
223
- element.selectedIndex = selected;
224
- dispatchOnChange(element.options[selected]);
225
- }
346
+ element.selected = "selected";
347
+ element.parentNode.selectedIndex = element.index;
348
+ dispatchOnChange(#{element.document_locator}, element);
349
+ dispatchOnChange(#{element.document_locator}, element.parentNode);
226
350
  |
227
351
  end, element)
228
352
  end
@@ -267,11 +391,32 @@ return selected;|
267
391
  sleep typing_lag
268
392
  execute(element.operate do
269
393
  %|element.value += '#{value}';
270
- dispatchOnChange(element);
271
- element.setSelectionRange(element.value.length, element.value.length);|
394
+ dispatchOnChange(#{element.document_locator}, element);
395
+ element.setSelectionRange(element.value.length, element.value.length);
396
+ |
272
397
  end, element)
273
398
  end
274
399
 
400
+ def set_file_field(element, value)
401
+ file_base_name = File.basename(value)
402
+ click_element(element)
403
+ sleep 0.4
404
+ se = Appscript.app("System Events")
405
+ open_popup = se.processes["Safari"].windows[1].sheets[1]
406
+ choose_button = open_popup.buttons[1]
407
+ search_field = open_popup.groups[1].text_fields[1]
408
+ search_by_file_name = open_popup.groups[1].splitter_groups[1].radio_groups[1].checkboxes[6]
409
+ sr_outline = open_popup.groups[1].splitter_groups[1].scroll_areas[2].outlines[1]
410
+ confirm_search_action = search_field.actions[2].get
411
+ search_field.value.set(file_base_name)
412
+ search_field.perform(confirm_search_action)
413
+ sleep 2
414
+ search_by_file_name.click
415
+ sleep 1
416
+ sr_outline.rows[1].select
417
+ choose_button.click
418
+ end
419
+
275
420
  def click_element(element = @element)
276
421
  page_load do
277
422
  # Not sure if these events should be either/or. But if you have an image with an onclick, it fires twice without the else clause.
@@ -384,6 +529,11 @@ for (var i = 0; i < document.links.length; i++) {
384
529
  def element_disabled?(element = @element)
385
530
  execute(element.operate { %|return element.disabled;| }, element)
386
531
  end
532
+
533
+ def operate_by_locator(element)
534
+ js.operate(%|var element = #{element.locator};
535
+ |, yield)
536
+ end
387
537
 
388
538
  def operate_by_input_value(element)
389
539
  js.operate(%|
@@ -397,23 +547,6 @@ for (var i = 0; i < elements.length; i++) {
397
547
  }|, yield)
398
548
  end
399
549
 
400
- def operate_by_name(element)
401
- js.operate(%|
402
- var elements = document.getElementsByName('#{element.what}');
403
- var element = undefined;
404
- for (var i = 0; i < elements.length; i++) {
405
- if (elements[i].tagName != 'META' && elements[i].tagName == '#{element.tag}') {
406
- #{handle_form_element_name_match(element)}
407
- }
408
- }|, yield)
409
- end
410
-
411
- def operate_by_class(element)
412
- js.operate(%|
413
- var elements = document.getElementsByClassName('#{element.what}');
414
- var element = elements[0];|, yield)
415
- end
416
-
417
550
  # Checkboxes/Radios have the same name, different values
418
551
  def handle_form_element_name_match(element)
419
552
  element_capture = %|element = elements[i];break;|
@@ -427,22 +560,6 @@ var element = elements[0];|, yield)
427
560
  end
428
561
  private :handle_form_element_name_match
429
562
 
430
- def operate_by_id(element)
431
- js.operate("var element = document.getElementById('#{element.what}');", yield)
432
- end
433
-
434
- def operate_by_index(element)
435
- js.operate(%|var element = document.getElementsByTagName('#{element.tag}')[#{element.what-1}];|, yield)
436
- end
437
-
438
- def operate_by_src(element, &block)
439
- operate_by(element, 'src', &block)
440
- end
441
-
442
- def operate_by_alt(element, &block)
443
- operate_by(element, 'alt', &block)
444
- end
445
-
446
563
  def operate_by_title(element, &block)
447
564
  operate_by(element, 'title', &block)
448
565
  end
@@ -455,14 +572,6 @@ var element = elements[0];|, yield)
455
572
  operate_by(element, 'innerText', &block)
456
573
  end
457
574
 
458
- def operate_by_xpath(element)
459
- xpath = element.what.gsub(/"/, "\'")
460
- js.operate(%|
461
- var result = document.evaluate("#{xpath}", document.documentElement, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
462
- var element = result ? result.singleNodeValue : null;
463
- |, yield)
464
- end
465
-
466
575
  def operate_by(element, attribute)
467
576
  js.operate(%|var elements = document.getElementsByTagName('#{element.tag}');
468
577
  var element = undefined;
@@ -507,15 +616,6 @@ end tell|, true)
507
616
  AppleScripter.new(TableJavaScripter.new(element))
508
617
  end
509
618
 
510
- def for_frame(frame)
511
- # verify the frame exists
512
- execute(
513
- %|if (parent.#{frame.name} == undefined) {
514
- return '#{FRAME_NOT_FOUND}';
515
- }|, frame)
516
- AppleScripter.new(FrameJavaScripter.new(frame))
517
- end
518
-
519
619
  def speak_value_of(element = @element)
520
620
  speak(get_value_for(element))
521
621
  end
@@ -547,13 +647,18 @@ SCRIPT`
547
647
 
548
648
  private
549
649
 
650
+ def tag_names(element = @element)
651
+ t_names = element.tag.kind_of?(Array) ? element.tag : [element.tag]
652
+ "[" + (t_names.map { |t_name| "\"#{t_name.downcase}\"" }.join(", ")) + "]"
653
+ end
654
+
550
655
  def execute(script, element = nil)
551
656
  response = eval_js(script)
552
657
  case response
553
658
  when NO_RESPONSE
554
659
  nil
555
660
  when ELEMENT_NOT_FOUND
556
- raise UnknownObjectException, "Unable to locate #{element.element_name} element with #{element.how} of #{element.what}"
661
+ raise element_not_found_exception(element)
557
662
  when TABLE_CELL_NOT_FOUND
558
663
  raise UnknownCellException, "Unable to locate a table cell with #{element.how} of #{element.what}"
559
664
  when FRAME_NOT_FOUND
@@ -562,6 +667,13 @@ SCRIPT`
562
667
  response
563
668
  end
564
669
  end
670
+
671
+ def element_not_found_exception(element)
672
+ if element.is_frame?
673
+ return UnknownFrameException.new("Unable to locate a frame, using :#{element.how} and \"#{element.what}\"")
674
+ end
675
+ UnknownObjectException.new("Unable to locate #{element.element_name}, using :#{element.how} and \"#{element.what}\"")
676
+ end
565
677
 
566
678
  def execute_and_ignore(script)
567
679
  eval_js(script)