watir 5.0.0 → 6.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/.document +5 -0
  3. data/.gitignore +21 -0
  4. data/.gitmodules +3 -0
  5. data/.travis.yml +35 -0
  6. data/CHANGES.md +1756 -0
  7. data/Gemfile +12 -0
  8. data/LICENSE +23 -0
  9. data/README.md +92 -0
  10. data/Rakefile +161 -32
  11. data/lib/watir.rb +127 -1
  12. data/lib/watir/after_hooks.rb +132 -0
  13. data/lib/watir/alert.rb +104 -0
  14. data/lib/watir/aliases.rb +6 -0
  15. data/lib/watir/atoms.rb +24 -0
  16. data/lib/watir/atoms/README +3 -0
  17. data/lib/watir/atoms/fireEvent.js +29 -0
  18. data/lib/watir/atoms/getAttribute.js +18 -0
  19. data/lib/watir/atoms/getInnerHtml.js +18 -0
  20. data/lib/watir/atoms/getOuterHtml.js +18 -0
  21. data/lib/watir/atoms/getParentElement.js +17 -0
  22. data/lib/watir/atoms/selectText.js +61 -0
  23. data/lib/watir/attribute_helper.rb +98 -0
  24. data/lib/watir/browser.rb +346 -0
  25. data/lib/watir/cell_container.rb +25 -0
  26. data/lib/watir/container.rb +51 -0
  27. data/lib/watir/cookies.rb +132 -0
  28. data/lib/watir/element_collection.rb +126 -0
  29. data/lib/watir/elements/area.rb +12 -0
  30. data/lib/watir/elements/button.rb +37 -0
  31. data/lib/watir/elements/cell.rb +17 -0
  32. data/lib/watir/elements/checkbox.rb +54 -0
  33. data/lib/watir/elements/dlist.rb +12 -0
  34. data/lib/watir/elements/element.rb +646 -0
  35. data/lib/watir/elements/file_field.rb +41 -0
  36. data/lib/watir/elements/font.rb +11 -0
  37. data/lib/watir/elements/form.rb +17 -0
  38. data/lib/watir/elements/hidden.rb +20 -0
  39. data/lib/watir/elements/html_elements.rb +2063 -0
  40. data/lib/watir/elements/iframe.rb +163 -0
  41. data/lib/watir/elements/image.rb +62 -0
  42. data/lib/watir/elements/input.rb +7 -0
  43. data/lib/watir/elements/link.rb +18 -0
  44. data/lib/watir/elements/option.rb +74 -0
  45. data/lib/watir/elements/radio.rb +42 -0
  46. data/lib/watir/elements/row.rb +17 -0
  47. data/lib/watir/elements/select.rb +238 -0
  48. data/lib/watir/elements/svg_elements.rb +667 -0
  49. data/lib/watir/elements/table.rb +42 -0
  50. data/lib/watir/elements/table_cell.rb +6 -0
  51. data/lib/watir/elements/table_row.rb +15 -0
  52. data/lib/watir/elements/table_section.rb +15 -0
  53. data/lib/watir/elements/text_area.rb +5 -0
  54. data/lib/watir/elements/text_field.rb +37 -0
  55. data/lib/watir/exception.rb +17 -0
  56. data/lib/watir/extensions/nokogiri.rb +14 -0
  57. data/lib/watir/extensions/select_text.rb +10 -0
  58. data/lib/watir/generator.rb +3 -0
  59. data/lib/watir/generator/base.rb +11 -0
  60. data/lib/watir/generator/base/generator.rb +115 -0
  61. data/lib/watir/generator/base/idl_sorter.rb +47 -0
  62. data/lib/watir/generator/base/spec_extractor.rb +138 -0
  63. data/lib/watir/generator/base/util.rb +21 -0
  64. data/lib/watir/generator/base/visitor.rb +157 -0
  65. data/lib/watir/generator/html.rb +15 -0
  66. data/lib/watir/generator/html/generator.rb +36 -0
  67. data/lib/watir/generator/html/spec_extractor.rb +50 -0
  68. data/lib/watir/generator/html/visitor.rb +21 -0
  69. data/lib/watir/generator/svg.rb +7 -0
  70. data/lib/watir/generator/svg/generator.rb +38 -0
  71. data/lib/watir/generator/svg/spec_extractor.rb +46 -0
  72. data/lib/watir/generator/svg/visitor.rb +21 -0
  73. data/lib/watir/has_window.rb +53 -0
  74. data/lib/watir/locators.rb +22 -0
  75. data/lib/watir/locators/button/locator.rb +38 -0
  76. data/lib/watir/locators/button/selector_builder.rb +27 -0
  77. data/lib/watir/locators/button/selector_builder/xpath.rb +29 -0
  78. data/lib/watir/locators/button/validator.rb +15 -0
  79. data/lib/watir/locators/cell/locator.rb +17 -0
  80. data/lib/watir/locators/cell/selector_builder.rb +24 -0
  81. data/lib/watir/locators/element/locator.rb +249 -0
  82. data/lib/watir/locators/element/selector_builder.rb +147 -0
  83. data/lib/watir/locators/element/selector_builder/css.rb +65 -0
  84. data/lib/watir/locators/element/selector_builder/xpath.rb +72 -0
  85. data/lib/watir/locators/element/validator.rb +23 -0
  86. data/lib/watir/locators/row/locator.rb +17 -0
  87. data/lib/watir/locators/row/selector_builder.rb +29 -0
  88. data/lib/watir/locators/text_area/locator.rb +13 -0
  89. data/lib/watir/locators/text_area/selector_builder.rb +22 -0
  90. data/lib/watir/locators/text_field/locator.rb +44 -0
  91. data/lib/watir/locators/text_field/selector_builder.rb +34 -0
  92. data/lib/watir/locators/text_field/selector_builder/xpath.rb +19 -0
  93. data/lib/watir/locators/text_field/validator.rb +20 -0
  94. data/lib/watir/row_container.rb +36 -0
  95. data/lib/watir/screenshot.rb +50 -0
  96. data/lib/watir/user_editable.rb +38 -0
  97. data/lib/watir/version.rb +3 -3
  98. data/lib/watir/wait.rb +250 -0
  99. data/lib/watir/wait/timer.rb +19 -0
  100. data/lib/watir/window.rb +244 -0
  101. data/lib/watir/xpath_support.rb +20 -0
  102. data/spec/always_locate_spec.rb +43 -0
  103. data/spec/browser_spec.rb +130 -0
  104. data/spec/click_spec.rb +19 -0
  105. data/spec/container_spec.rb +34 -0
  106. data/spec/element_locator_spec.rb +532 -0
  107. data/spec/element_spec.rb +136 -0
  108. data/spec/implementation.rb +216 -0
  109. data/spec/input_spec.rb +14 -0
  110. data/spec/locator_spec_helper.rb +57 -0
  111. data/spec/spec_helper.rb +35 -0
  112. data/spec/special_chars_spec.rb +13 -0
  113. data/support/doctest_helper.rb +78 -0
  114. data/support/travis.sh +44 -0
  115. data/support/version_differ.rb +59 -0
  116. data/watir.gemspec +37 -25
  117. metadata +288 -23
  118. data/lib/watir/loader.rb +0 -64
@@ -0,0 +1,65 @@
1
+ module Watir
2
+ module Locators
3
+ class Element
4
+ class SelectorBuilder
5
+ class CSS
6
+ def build(selectors)
7
+ return unless use_css?(selectors)
8
+
9
+ if selectors.empty?
10
+ css = '*'
11
+ else
12
+ css = ''
13
+ css << (selectors.delete(:tag_name) || '')
14
+
15
+ klass = selectors.delete(:class)
16
+ if klass
17
+ if klass.include? ' '
18
+ css << %([class="#{css_escape klass}"])
19
+ else
20
+ css << ".#{klass}"
21
+ end
22
+ end
23
+
24
+ href = selectors.delete(:href)
25
+ if href
26
+ css << %([href~="#{css_escape href}"])
27
+ end
28
+
29
+ selectors.each do |key, value|
30
+ key = key.to_s.tr("_", "-")
31
+ css << %([#{key}="#{css_escape value}"]) # TODO: proper escaping
32
+ end
33
+ end
34
+
35
+ [:css, css]
36
+ end
37
+
38
+ private
39
+
40
+ def use_css?(selectors)
41
+ return false unless Watir.prefer_css?
42
+
43
+ if selectors.key?(:text) || selectors.key?(:label) || selectors.key?(:index)
44
+ return false
45
+ end
46
+
47
+ if selectors[:tag_name] == 'input' && selectors.key?(:type)
48
+ return false
49
+ end
50
+
51
+ if selectors.key?(:class) && selectors[:class] !~ /^[\w-]+$/ui
52
+ return false
53
+ end
54
+
55
+ true
56
+ end
57
+
58
+ def css_escape(str)
59
+ str.gsub('"', '\\"')
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,72 @@
1
+ module Watir
2
+ module Locators
3
+ class Element
4
+ class SelectorBuilder
5
+ class XPath
6
+ def initialize(should_use_label_element)
7
+ @should_use_label_element = should_use_label_element
8
+ end
9
+
10
+ def build(selectors)
11
+ xpath = ".//"
12
+ xpath << (selectors.delete(:tag_name) || '*').to_s
13
+
14
+ selectors.delete :index
15
+
16
+ # the remaining entries should be attributes
17
+ unless selectors.empty?
18
+ xpath << "[" << attribute_expression(nil, selectors) << "]"
19
+ end
20
+
21
+ p xpath: xpath, selectors: selectors if $DEBUG
22
+
23
+ [:xpath, xpath]
24
+ end
25
+
26
+ # @todo Get rid of building
27
+ def attribute_expression(building, selectors)
28
+ f = selectors.map do |key, val|
29
+ if val.is_a?(Array)
30
+ "(" + val.map { |v| equal_pair(building, key, v) }.join(" or ") + ")"
31
+ else
32
+ equal_pair(building, key, val)
33
+ end
34
+ end
35
+ f.join(" and ")
36
+ end
37
+
38
+ # @todo Get rid of building
39
+ def equal_pair(building, key, value)
40
+ if key == :class
41
+ klass = XpathSupport.escape " #{value} "
42
+ "contains(concat(' ', @class, ' '), #{klass})"
43
+ elsif key == :label && @should_use_label_element
44
+ # we assume :label means a corresponding label element, not the attribute
45
+ text = "normalize-space()=#{XpathSupport.escape value}"
46
+ "(@id=//label[#{text}]/@for or parent::label[#{text}])"
47
+ else
48
+ "#{lhs_for(building, key)}=#{XpathSupport.escape value}"
49
+ end
50
+ end
51
+
52
+ # @todo Get rid of building
53
+ def lhs_for(_building, key)
54
+ case key
55
+ when :text, 'text'
56
+ 'normalize-space()'
57
+ when :href
58
+ # TODO: change this behaviour?
59
+ 'normalize-space(@href)'
60
+ when :type
61
+ # type attributes can be upper case - downcase them
62
+ # https://github.com/watir/watir/issues/72
63
+ XpathSupport.downcase('@type')
64
+ else
65
+ "@#{key.to_s.tr("_", "-")}"
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,23 @@
1
+ module Watir
2
+ module Locators
3
+ class Element
4
+ class Validator
5
+ def validate(element, selector)
6
+ selector_tag_name = selector[:tag_name]
7
+ element_tag_name = element.tag_name.downcase
8
+
9
+ if selector_tag_name
10
+ return unless selector_tag_name === element_tag_name
11
+ end
12
+
13
+ if element_tag_name == 'input'
14
+ # TODO - Verify this is desired behavior based on https://bugzilla.mozilla.org/show_bug.cgi?id=1290963
15
+ return if selector[:type] && selector[:type] != element.attribute(:type).downcase
16
+ end
17
+
18
+ element
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ module Watir
2
+ module Locators
3
+ class Row
4
+ class Locator < Element::Locator
5
+ def locate_all
6
+ find_all_by_multiple
7
+ end
8
+
9
+ private
10
+
11
+ def by_id
12
+ nil # avoid this
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,29 @@
1
+ module Watir
2
+ module Locators
3
+ class Row
4
+ class SelectorBuilder < Element::SelectorBuilder
5
+ def build_wd_selector(selectors)
6
+ return if selectors.values.any? { |e| e.kind_of? Regexp }
7
+ selectors.delete(:tag_name) || raise("internal error: no tag_name?!")
8
+
9
+ expressions = %w[./tr]
10
+ unless %w[tbody tfoot thead].include?(@parent.tag_name.downcase)
11
+ expressions += %w[./tbody/tr ./thead/tr ./tfoot/tr]
12
+ end
13
+
14
+ attr_expr = xpath_builder.attribute_expression(nil, selectors)
15
+
16
+ unless attr_expr.empty?
17
+ expressions.map! { |e| "#{e}[#{attr_expr}]" }
18
+ end
19
+
20
+ xpath = expressions.join(" | ")
21
+
22
+ p build_wd_selector: xpath if $DEBUG
23
+
24
+ [:xpath, xpath]
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,13 @@
1
+ module Watir
2
+ module Locators
3
+ class TextArea
4
+ class Locator < Element::Locator
5
+ private
6
+
7
+ def can_convert_regexp_to_contains?
8
+ false
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,22 @@
1
+ module Watir
2
+ module Locators
3
+ class TextArea
4
+ class SelectorBuilder < Element::SelectorBuilder
5
+ private
6
+
7
+ def normalize_selector(how, what)
8
+ # We need to iterate through located elements and fetch
9
+ # attribute value using Selenium because XPath doesn't understand
10
+ # difference between IDL vs content attribute.
11
+ # Current Element design doesn't allow to do that in any
12
+ # obvious way except to use regular expression.
13
+ if how == :value && what.kind_of?(String)
14
+ [how, Regexp.new('^' + Regexp.escape(what) + '$')]
15
+ else
16
+ super
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,44 @@
1
+ module Watir
2
+ module Locators
3
+ class TextField
4
+ class Locator < Element::Locator
5
+ def locate_all
6
+ find_all_by_multiple
7
+ end
8
+
9
+ private
10
+
11
+ def wd_find_first_by(how, what)
12
+ how, what = selector_builder.build_wd_selector(how => what) if how == :tag_name
13
+ super
14
+ end
15
+
16
+ def matches_selector?(element, rx_selector)
17
+ rx_selector = rx_selector.dup
18
+
19
+ tag_name = element.tag_name.downcase
20
+
21
+ [:text, :value, :label].each do |key|
22
+ if rx_selector.key?(key)
23
+ correct_key = tag_name == 'input' ? :value : :text
24
+ rx_selector[correct_key] = rx_selector.delete(key)
25
+ end
26
+ end
27
+
28
+ super
29
+ end
30
+
31
+ def by_id
32
+ element = super
33
+
34
+ if element && !Watir::TextField::NON_TEXT_TYPES.include?(element.attribute(:type))
35
+ if element.tag_name.downcase == 'textarea'
36
+ warn "Locating textareas with '#text_field' is deprecated. Please, use '#textarea' method instead."
37
+ end
38
+ element
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,34 @@
1
+ module Watir
2
+ module Locators
3
+ class TextField
4
+ class SelectorBuilder < Element::SelectorBuilder
5
+ def build_wd_selector(selectors)
6
+ return if selectors.values.any? { |e| e.kind_of? Regexp }
7
+
8
+ selectors.delete(:tag_name)
9
+
10
+ textarea_attr_exp = xpath_builder.attribute_expression(:textarea, selectors)
11
+ input_attr_exp = xpath_builder.attribute_expression(:input, selectors)
12
+
13
+ xpath = ".//input[(not(@type) or (#{negative_type_expr}))"
14
+ xpath << " and #{input_attr_exp}" unless input_attr_exp.empty?
15
+ xpath << "] "
16
+ xpath << "| .//textarea"
17
+ xpath << "[#{textarea_attr_exp}]" unless textarea_attr_exp.empty?
18
+
19
+ p build_wd_selector: xpath if $DEBUG
20
+
21
+ [:xpath, xpath]
22
+ end
23
+
24
+ private
25
+
26
+ def negative_type_expr
27
+ Watir::TextField::NON_TEXT_TYPES.map do |type|
28
+ "%s!=%s" % [XpathSupport.downcase('@type'), type.inspect]
29
+ end.join(' and ')
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,19 @@
1
+ module Watir
2
+ module Locators
3
+ class TextField
4
+ class SelectorBuilder
5
+ class XPath < Element::SelectorBuilder::XPath
6
+ def lhs_for(building, key)
7
+ if building == :input && key == :text
8
+ "@value"
9
+ elsif building == :textarea && key == :value
10
+ "text()"
11
+ else
12
+ super
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ module Watir
2
+ module Locators
3
+ class TextField
4
+ class Validator < Element::Validator
5
+ VALID_TEXT_FIELD_TAGS = %w[input textarea]
6
+
7
+ def validate(element, selector)
8
+ element_tag_name = element.tag_name.downcase
9
+
10
+ if element.tag_name.downcase == 'textarea'
11
+ warn "Locating textareas with '#text_field' is deprecated. Please, use '#textarea' method instead."
12
+ end
13
+ return unless VALID_TEXT_FIELD_TAGS.include?(element_tag_name)
14
+
15
+ element
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,36 @@
1
+ module Watir
2
+ module RowContainer
3
+
4
+ #
5
+ # Returns table row.
6
+ #
7
+
8
+ def row(*args)
9
+ Row.new(self, extract_selector(args).merge(tag_name: "tr"))
10
+ end
11
+
12
+ #
13
+ # Returns table rows collection.
14
+ #
15
+
16
+ def rows(*args)
17
+ RowCollection.new(self, extract_selector(args).merge(tag_name: "tr"))
18
+ end
19
+
20
+ #
21
+ # The table as a 2D Array of strings with the text of each cell.
22
+ #
23
+ # @return [Array<Array<String>>]
24
+ #
25
+
26
+ def strings
27
+ assert_exists
28
+
29
+ rows.inject [] do |res, row|
30
+ res << row.cells.map(&:text)
31
+ end
32
+ end
33
+ alias_method :to_a, :strings
34
+
35
+ end # RowContainer
36
+ end # Watir
@@ -0,0 +1,50 @@
1
+ module Watir
2
+ class Screenshot
3
+
4
+ def initialize(driver)
5
+ @driver = driver
6
+ end
7
+
8
+ #
9
+ # Saves screenshot to given path.
10
+ #
11
+ # @example
12
+ # browser.screenshot.save "screenshot.png"
13
+ #
14
+ # @param [String] path
15
+ #
16
+
17
+ def save(path)
18
+ @driver.save_screenshot(path)
19
+ end
20
+
21
+ #
22
+ # Represents screenshot as PNG image string.
23
+ #
24
+ # @example
25
+ # browser.screenshot.png
26
+ # #=> '\x95\xC7\x8C@1\xC07\x1C(Edb\x15\xB2\vL'
27
+ #
28
+ # @return [String]
29
+ #
30
+
31
+ def png
32
+ @driver.screenshot_as(:png)
33
+ end
34
+
35
+ #
36
+ # Represents screenshot as Base64 encoded string.
37
+ #
38
+ # @example
39
+ # browser.screenshot.base64
40
+ # #=> '7HWJ43tZDscPleeUuPW6HhN3x+z7vU/lufmH0qNTtTum94IBWMT46evImci1vnFGT'
41
+ #
42
+ # @return [String]
43
+ #
44
+
45
+ def base64
46
+ @driver.screenshot_as(:base64)
47
+ end
48
+
49
+ end # Screenshot
50
+ end # Watir