watir 6.14.0 → 6.15.0

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 (133) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +24 -6
  3. data/CHANGES.md +10 -0
  4. data/Gemfile +0 -2
  5. data/README.md +1 -1
  6. data/Rakefile +2 -2
  7. data/lib/watir.rb +2 -3
  8. data/lib/watir/adjacent.rb +2 -2
  9. data/lib/watir/alert.rb +5 -9
  10. data/lib/watir/attribute_helper.rb +2 -3
  11. data/lib/watir/browser.rb +5 -17
  12. data/lib/watir/capabilities.rb +11 -0
  13. data/lib/watir/cell_container.rb +2 -2
  14. data/lib/watir/container.rb +7 -8
  15. data/lib/watir/cookies.rb +2 -12
  16. data/lib/watir/element_collection.rb +2 -2
  17. data/lib/watir/elements/button.rb +2 -11
  18. data/lib/watir/elements/element.rb +43 -25
  19. data/lib/watir/elements/hidden.rb +1 -1
  20. data/lib/watir/elements/iframe.rb +7 -5
  21. data/lib/watir/elements/option.rb +2 -13
  22. data/lib/watir/elements/select.rb +6 -22
  23. data/lib/watir/elements/table.rb +2 -2
  24. data/lib/watir/exception.rb +1 -2
  25. data/lib/watir/generator/base/idl_sorter.rb +1 -1
  26. data/lib/watir/generator/base/spec_extractor.rb +2 -2
  27. data/lib/watir/generator/base/visitor.rb +1 -1
  28. data/lib/watir/generator/html/generator.rb +0 -1
  29. data/lib/watir/generator/html/spec_extractor.rb +1 -1
  30. data/lib/watir/generator/html/visitor.rb +1 -1
  31. data/lib/watir/generator/svg/spec_extractor.rb +1 -1
  32. data/lib/watir/generator/svg/visitor.rb +1 -1
  33. data/lib/watir/js_execution.rb +11 -0
  34. data/lib/watir/js_snippets.rb +1 -1
  35. data/lib/watir/js_snippets/elementObscured.js +14 -0
  36. data/lib/watir/js_snippets/selectedText.js +17 -0
  37. data/lib/watir/legacy_wait.rb +5 -5
  38. data/lib/watir/locators.rb +16 -5
  39. data/lib/watir/locators/anchor/selector_builder.rb +38 -0
  40. data/lib/watir/locators/button/locator.rb +14 -12
  41. data/lib/watir/locators/button/selector_builder.rb +0 -22
  42. data/lib/watir/locators/button/selector_builder/xpath.rb +67 -12
  43. data/lib/watir/locators/button/validator.rb +2 -1
  44. data/lib/watir/locators/cell/selector_builder.rb +0 -14
  45. data/lib/watir/locators/cell/selector_builder/xpath.rb +21 -0
  46. data/lib/watir/locators/element/locator.rb +60 -153
  47. data/lib/watir/locators/element/selector_builder.rb +103 -84
  48. data/lib/watir/locators/element/selector_builder/regexp_disassembler.rb +66 -0
  49. data/lib/watir/locators/element/selector_builder/xpath.rb +195 -82
  50. data/lib/watir/locators/element/selector_builder/xpath_support.rb +27 -0
  51. data/lib/watir/locators/element/validator.rb +2 -9
  52. data/lib/watir/locators/row/selector_builder.rb +5 -22
  53. data/lib/watir/locators/row/selector_builder/xpath.rb +53 -0
  54. data/lib/watir/locators/text_area/selector_builder.rb +1 -1
  55. data/lib/watir/locators/text_area/selector_builder/xpath.rb +19 -0
  56. data/lib/watir/locators/text_field/locator.rb +11 -8
  57. data/lib/watir/locators/text_field/selector_builder.rb +0 -23
  58. data/lib/watir/locators/text_field/selector_builder/xpath.rb +33 -4
  59. data/lib/watir/locators/text_field/validator.rb +4 -4
  60. data/lib/watir/radio_set.rb +5 -5
  61. data/lib/watir/row_container.rb +2 -2
  62. data/lib/watir/user_editable.rb +2 -2
  63. data/lib/watir/version.rb +1 -1
  64. data/lib/watir/wait.rb +24 -37
  65. data/lib/watir/window.rb +11 -8
  66. data/lib/watirspec/remote_server.rb +3 -1
  67. data/spec/locator_spec_helper.rb +1 -1
  68. data/spec/spec_helper.rb +25 -1
  69. data/spec/unit/anchor_locator_spec.rb +68 -0
  70. data/spec/unit/capabilities_spec.rb +27 -0
  71. data/spec/unit/element_locator_spec.rb +184 -101
  72. data/spec/unit/logger_spec.rb +5 -0
  73. data/spec/watirspec/adjacent_spec.rb +34 -34
  74. data/spec/watirspec/after_hooks_spec.rb +78 -35
  75. data/spec/watirspec/alert_spec.rb +10 -0
  76. data/spec/watirspec/browser_spec.rb +27 -1
  77. data/spec/watirspec/element_hidden_spec.rb +6 -0
  78. data/spec/watirspec/elements/button_spec.rb +5 -11
  79. data/spec/watirspec/elements/buttons_spec.rb +1 -1
  80. data/spec/watirspec/elements/checkbox_spec.rb +2 -15
  81. data/spec/watirspec/elements/date_time_field_spec.rb +6 -1
  82. data/spec/watirspec/elements/dd_spec.rb +0 -17
  83. data/spec/watirspec/elements/del_spec.rb +0 -14
  84. data/spec/watirspec/elements/div_spec.rb +0 -18
  85. data/spec/watirspec/elements/dl_spec.rb +0 -17
  86. data/spec/watirspec/elements/dt_spec.rb +0 -17
  87. data/spec/watirspec/elements/element_spec.rb +177 -17
  88. data/spec/watirspec/elements/elements_spec.rb +7 -6
  89. data/spec/watirspec/elements/em_spec.rb +0 -13
  90. data/spec/watirspec/elements/filefield_spec.rb +0 -11
  91. data/spec/watirspec/elements/form_spec.rb +6 -0
  92. data/spec/watirspec/elements/hn_spec.rb +0 -14
  93. data/spec/watirspec/elements/iframe_spec.rb +15 -0
  94. data/spec/watirspec/elements/ins_spec.rb +0 -14
  95. data/spec/watirspec/elements/labels_spec.rb +1 -1
  96. data/spec/watirspec/elements/li_spec.rb +0 -14
  97. data/spec/watirspec/elements/link_spec.rb +22 -14
  98. data/spec/watirspec/elements/links_spec.rb +13 -0
  99. data/spec/watirspec/elements/list_spec.rb +15 -0
  100. data/spec/watirspec/elements/ol_spec.rb +0 -14
  101. data/spec/watirspec/elements/option_spec.rb +0 -10
  102. data/spec/watirspec/elements/p_spec.rb +0 -14
  103. data/spec/watirspec/elements/pre_spec.rb +0 -14
  104. data/spec/watirspec/elements/radio_spec.rb +0 -14
  105. data/spec/watirspec/elements/select_list_spec.rb +0 -10
  106. data/spec/watirspec/elements/span_spec.rb +4 -15
  107. data/spec/watirspec/elements/strong_spec.rb +4 -15
  108. data/spec/watirspec/elements/table_nesting_spec.rb +1 -1
  109. data/spec/watirspec/elements/table_spec.rb +7 -0
  110. data/spec/watirspec/elements/text_field_spec.rb +10 -2
  111. data/spec/watirspec/elements/text_fields_spec.rb +1 -1
  112. data/spec/watirspec/elements/tr_spec.rb +1 -1
  113. data/spec/watirspec/elements/ul_spec.rb +0 -14
  114. data/spec/watirspec/html/closeable.html +8 -0
  115. data/spec/watirspec/html/forms_with_input_elements.html +28 -23
  116. data/spec/watirspec/html/nested_elements.html +9 -9
  117. data/spec/watirspec/html/obscured.html +34 -0
  118. data/spec/watirspec/html/tables.html +13 -13
  119. data/spec/watirspec/radio_set_spec.rb +5 -0
  120. data/spec/watirspec/selector_builder/button_spec.rb +254 -0
  121. data/spec/watirspec/selector_builder/cell_spec.rb +93 -0
  122. data/spec/watirspec/selector_builder/element_spec.rb +639 -0
  123. data/spec/watirspec/selector_builder/row_spec.rb +150 -0
  124. data/spec/watirspec/selector_builder/text_spec.rb +170 -0
  125. data/spec/watirspec/support/rspec_matchers.rb +6 -1
  126. data/spec/watirspec/user_editable_spec.rb +4 -0
  127. data/spec/watirspec/wait_spec.rb +65 -14
  128. data/spec/watirspec/window_switching_spec.rb +54 -1
  129. data/spec/watirspec_helper.rb +2 -0
  130. data/watir.gemspec +7 -1
  131. metadata +86 -8
  132. data/lib/watir/locators/text_area/locator.rb +0 -13
  133. data/lib/watir/xpath_support.rb +0 -18
@@ -0,0 +1,150 @@
1
+ require 'watirspec_helper'
2
+
3
+ describe Watir::Locators::Row::SelectorBuilder do
4
+ let(:attributes) { Watir::HTMLElement.attribute_list }
5
+ let(:selector_builder) { described_class.new(attributes, @scope_tag_name) }
6
+
7
+ describe '#build' do
8
+ after(:each) do |example|
9
+ next if example.metadata[:skip_after]
10
+
11
+ @scope_tag_name ||= @query_scope.tag_name
12
+
13
+ built = selector_builder.build(@selector)
14
+ expect(built).to eq [@wd_locator, (@remaining || {})]
15
+
16
+ next unless @data_locator || @tag_name
17
+
18
+ expect { @located = @query_scope.wd.first(@wd_locator) }.not_to raise_exception
19
+
20
+ if @data_locator
21
+ expect(@located.attribute('data-locator')).to eq(@data_locator)
22
+ else
23
+ expect {
24
+ expect(@located.tag_name).to eq @tag_name
25
+ }.not_to raise_exception
26
+ end
27
+ end
28
+
29
+ context 'with query scopes' do
30
+ before(:each) do
31
+ browser.goto(WatirSpec.url_for('tables.html'))
32
+ end
33
+
34
+ it 'with only table query scope' do
35
+ @query_scope = browser.element(id: 'outer').locate
36
+ @selector = {}
37
+ @wd_locator = {xpath: "./*[local-name()='tr'] | ./*[local-name()='tbody']/*[local-name()='tr'] | " \
38
+ "./*[local-name()='thead']/*[local-name()='tr'] | ./*[local-name()='tfoot']/*[local-name()='tr']"}
39
+ @data_locator = 'first row'
40
+ end
41
+
42
+ it 'with tbody query scope' do
43
+ @query_scope = browser.element(id: 'first').locate
44
+ @selector = {}
45
+ @wd_locator = {xpath: "./*[local-name()='tr']"}
46
+ @data_locator = 'tbody row'
47
+ end
48
+
49
+ it 'with thead query scope' do
50
+ @query_scope = browser.element(id: 'tax_headers').locate
51
+ @selector = {}
52
+ @wd_locator = {xpath: "./*[local-name()='tr']"}
53
+ @data_locator = 'thead row'
54
+ end
55
+
56
+ it 'with tfoot query scope' do
57
+ @query_scope = browser.element(id: 'tax_totals').locate
58
+ @selector = {}
59
+ @wd_locator = {xpath: "./*[local-name()='tr']"}
60
+ @data_locator = 'tfoot row'
61
+ end
62
+ end
63
+
64
+ context 'with index' do
65
+ before(:each) do
66
+ browser.goto(WatirSpec.url_for('tables.html'))
67
+ end
68
+
69
+ it 'positive' do
70
+ @query_scope = browser.element(id: 'outer').locate
71
+ @selector = {index: 1}
72
+ @wd_locator = {xpath: "(./*[local-name()='tr'] | ./*[local-name()='tbody']/*[local-name()='tr'] | " \
73
+ "./*[local-name()='thead']/*[local-name()='tr'] | ./*[local-name()='tfoot']/*[local-name()='tr'])[2]"}
74
+ @data_locator = 'middle row'
75
+ end
76
+
77
+ it 'negative' do
78
+ @query_scope = browser.element(id: 'outer').locate
79
+ @selector = {index: -3}
80
+ @wd_locator = {xpath: "(./*[local-name()='tr'] | ./*[local-name()='tbody']/*[local-name()='tr'] | " \
81
+ "./*[local-name()='thead']/*[local-name()='tr'] | ./*[local-name()='tfoot']/*[local-name()='tr'])[last()-2]"}
82
+ @data_locator = 'first row'
83
+ end
84
+
85
+ it 'last' do
86
+ @query_scope = browser.element(id: 'outer').locate
87
+ @selector = {index: -1}
88
+ @wd_locator = {xpath: "(./*[local-name()='tr'] | ./*[local-name()='tbody']/*[local-name()='tr'] | " \
89
+ "./*[local-name()='thead']/*[local-name()='tr'] | ./*[local-name()='tfoot']/*[local-name()='tr'])[last()]"}
90
+ @data_locator = 'last row'
91
+ end
92
+
93
+ it 'does not return index if it is zero' do
94
+ @query_scope = browser.element(id: 'outer').locate
95
+ @selector = {index: 0}
96
+ @wd_locator = {xpath: "./*[local-name()='tr'] | ./*[local-name()='tbody']/*[local-name()='tr'] | " \
97
+ "./*[local-name()='thead']/*[local-name()='tr'] | ./*[local-name()='tfoot']/*[local-name()='tr']"}
98
+ @data_locator = 'first row'
99
+ end
100
+
101
+ it 'raises exception when index is not an Integer', skip_after: true do
102
+ @query_scope = browser.element(id: 'outer').locate
103
+ selector = {index: 'foo'}
104
+ msg = 'expected Integer, got "foo":String'
105
+ expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
106
+ end
107
+ end
108
+
109
+ context 'with multiple locators' do
110
+ before(:each) do
111
+ browser.goto(WatirSpec.url_for('tables.html'))
112
+ @query_scope = browser.table.locate
113
+ end
114
+
115
+ it 'attribute and class' do
116
+ @selector = {id: 'gregory', class: /brick/}
117
+ @wd_locator = {xpath: "./*[local-name()='tr'][contains(@class, 'brick')][@id='gregory'] | " \
118
+ "./*[local-name()='tbody']/*[local-name()='tr'][contains(@class, 'brick')][@id='gregory'] | " \
119
+ "./*[local-name()='thead']/*[local-name()='tr'][contains(@class, 'brick')][@id='gregory'] | " \
120
+ "./*[local-name()='tfoot']/*[local-name()='tr'][contains(@class, 'brick')][@id='gregory']"}
121
+ @data_locator = 'House row'
122
+ end
123
+ end
124
+
125
+ context 'returns locators that can not be directly translated' do
126
+ before(:each) do
127
+ browser.goto(WatirSpec.url_for('tables.html'))
128
+ @query_scope = browser.table(id: 'outer').locate
129
+ end
130
+
131
+ it 'any text value' do
132
+ @selector = {text: 'Gregory'}
133
+ @wd_locator = {xpath: "./*[local-name()='tr'] | ./*[local-name()='tbody']/*[local-name()='tr'] | " \
134
+ "./*[local-name()='thead']/*[local-name()='tr'] | ./*[local-name()='tfoot']/*[local-name()='tr']"}
135
+ @remaining = {text: 'Gregory'}
136
+ end
137
+ end
138
+
139
+ it 'delegates adjacent to Element SelectorBuilder' do
140
+ browser.goto(WatirSpec.url_for('tables.html'))
141
+
142
+ @scope_tag_name = 'table'
143
+ @query_scope = browser.element(id: 'gregory').locate
144
+
145
+ @selector = {adjacent: :ancestor, index: 1}
146
+ @wd_locator = {xpath: './ancestor::*[2]'}
147
+ @data_locator = 'top table'
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,170 @@
1
+ require 'watirspec_helper'
2
+
3
+ describe Watir::Locators::TextField::SelectorBuilder do
4
+ let(:attributes) { Watir::HTMLElement.attribute_list }
5
+ let(:scope_tag_name) { nil }
6
+ let(:selector_builder) { described_class.new(attributes) }
7
+ let(:uppercase) { 'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ' }
8
+ let(:lowercase) { 'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ' }
9
+ let(:negative_types) do
10
+ "translate(@type,'#{uppercase}','#{lowercase}')!='file' and "\
11
+ "translate(@type,'#{uppercase}','#{lowercase}')!='radio' and " \
12
+ "translate(@type,'#{uppercase}','#{lowercase}')!='checkbox' and " \
13
+ "translate(@type,'#{uppercase}','#{lowercase}')!='submit' and " \
14
+ "translate(@type,'#{uppercase}','#{lowercase}')!='reset' and " \
15
+ "translate(@type,'#{uppercase}','#{lowercase}')!='image' and " \
16
+ "translate(@type,'#{uppercase}','#{lowercase}')!='button' and " \
17
+ "translate(@type,'#{uppercase}','#{lowercase}')!='hidden' and " \
18
+ "translate(@type,'#{uppercase}','#{lowercase}')!='range' and " \
19
+ "translate(@type,'#{uppercase}','#{lowercase}')!='color' and " \
20
+ "translate(@type,'#{uppercase}','#{lowercase}')!='date' and " \
21
+ "translate(@type,'#{uppercase}','#{lowercase}')!='datetime-local'"
22
+ end
23
+
24
+ describe '#build' do
25
+ after(:each) do |example|
26
+ next if example.metadata[:skip_after]
27
+
28
+ @query_scope ||= browser
29
+
30
+ built = selector_builder.build(@selector)
31
+ expect(built).to eq [@wd_locator, (@remaining || {})]
32
+
33
+ next unless @data_locator || @tag_name
34
+
35
+ expect { @located = @query_scope.wd.first(@wd_locator) }.not_to raise_exception
36
+
37
+ if @data_locator
38
+ expect(@located.attribute('data-locator')).to eq(@data_locator)
39
+ else
40
+ expect {
41
+ expect(@located.tag_name).to eq @tag_name
42
+ }.not_to raise_exception
43
+ end
44
+ end
45
+
46
+ it 'without any arguments' do
47
+ browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
48
+ @selector = {}
49
+ @wd_locator = {xpath: ".//*[local-name()='input'][not(@type) or (#{negative_types})]"}
50
+ @data_locator = 'input name'
51
+ end
52
+
53
+ context 'with type' do
54
+ before(:each) { browser.goto(WatirSpec.url_for('forms_with_input_elements.html')) }
55
+
56
+ it 'specified text field type that is text' do
57
+ @selector = {type: 'text'}
58
+ @wd_locator = {xpath: ".//*[local-name()='input']" \
59
+ "[translate(@type,'#{uppercase}','#{lowercase}')='text']"}
60
+ @data_locator = 'first text'
61
+ end
62
+
63
+ it 'specified text field type that is not text' do
64
+ @selector = {type: 'number'}
65
+ @wd_locator = {xpath: ".//*[local-name()='input']" \
66
+ "[translate(@type,'#{uppercase}','#{lowercase}')='number']"}
67
+ @data_locator = '42'
68
+ end
69
+
70
+ it 'true locates text field with a type specified' do
71
+ @selector = {type: true}
72
+ @wd_locator = {xpath: ".//*[local-name()='input'][#{negative_types}]"}
73
+ @data_locator = 'input name'
74
+ end
75
+
76
+ it 'false locates text field without type specified' do
77
+ @selector = {type: false}
78
+ @wd_locator = {xpath: ".//*[local-name()='input'][not(@type)]"}
79
+ @data_locator = 'input name'
80
+ end
81
+
82
+ it 'raises exception when a non-text field type input is specified', skip_after: true do
83
+ selector = {type: 'checkbox'}
84
+ msg = 'TextField Elements can not be located by type: checkbox'
85
+ expect { selector_builder.build(selector) }
86
+ .to raise_exception Watir::Exception::LocatorException, msg
87
+ end
88
+ end
89
+
90
+ context 'with index' do
91
+ before(:each) do
92
+ browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
93
+ end
94
+
95
+ it 'positive' do
96
+ @selector = {index: 4}
97
+ @wd_locator = {xpath: "(.//*[local-name()='input'][not(@type) or (#{negative_types})])[5]"}
98
+ @data_locator = 'dev'
99
+ end
100
+
101
+ it 'negative' do
102
+ @selector = {index: -3}
103
+ @wd_locator = {xpath: "(.//*[local-name()='input'][not(@type) or (#{negative_types})])[last()-2]"}
104
+ @data_locator = '42'
105
+ end
106
+
107
+ it 'last' do
108
+ @selector = {index: -1}
109
+ @wd_locator = {xpath: "(.//*[local-name()='input'][not(@type) or (#{negative_types})])[last()]"}
110
+ @data_locator = 'last text'
111
+ end
112
+
113
+ it 'does not return index if it is zero' do
114
+ @selector = {index: 0}
115
+ @wd_locator = {xpath: ".//*[local-name()='input'][not(@type) or (#{negative_types})]"}
116
+ @data_locator = 'input name'
117
+ end
118
+
119
+ it 'raises exception when index is not an Integer', skip_after: true do
120
+ selector = {index: 'foo'}
121
+ msg = 'expected Integer, got "foo":String'
122
+ expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
123
+ end
124
+ end
125
+
126
+ context 'with text' do
127
+ before(:each) { browser.goto(WatirSpec.url_for('forms_with_input_elements.html')) }
128
+
129
+ it 'String for value' do
130
+ @selector = {text: 'Developer'}
131
+ @wd_locator = {xpath: ".//*[local-name()='input'][not(@type) or (#{negative_types})]"}
132
+ @remaining = {text: 'Developer'}
133
+ end
134
+
135
+ it 'Simple Regexp for value' do
136
+ @selector = {text: /Dev/}
137
+ @wd_locator = {xpath: ".//*[local-name()='input'][not(@type) or (#{negative_types})]"}
138
+ @remaining = {text: /Dev/}
139
+ end
140
+
141
+ it 'returns complicated Regexp to the locator as a value' do
142
+ @selector = {text: /^foo$/}
143
+ @wd_locator = {xpath: ".//*[local-name()='input'][not(@type) or (#{negative_types})]"}
144
+ @remaining = {text: /^foo$/}
145
+ end
146
+ end
147
+
148
+ context 'with multiple locators' do
149
+ before(:each) do
150
+ browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
151
+ end
152
+
153
+ it 'locates using tag name, class, attributes and text' do
154
+ @selector = {text: 'Developer', class: /c/, id: true}
155
+ @wd_locator = {xpath: ".//*[local-name()='input'][contains(@class, 'c')]" \
156
+ "[not(@type) or (#{negative_types})][@id]"}
157
+ @remaining = {text: 'Developer'}
158
+ end
159
+
160
+ it 'delegates adjacent to Element SelectorBuilder' do
161
+ browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
162
+ @query_scope = browser.element(id: 'new_user_email').locate
163
+
164
+ @selector = {adjacent: :ancestor, index: 1}
165
+ @wd_locator = {xpath: './ancestor::*[2]'}
166
+ @data_locator = 'form'
167
+ end
168
+ end
169
+ end
170
+ end
@@ -1,12 +1,17 @@
1
1
  if defined?(RSpec)
2
2
  DEPRECATION_WARNINGS = %i[selector_parameters
3
+ ready_state
3
4
  class_array
4
5
  use_capabilities
5
6
  visible_text
7
+ link_text
6
8
  text_regexp
9
+ stale_exists
7
10
  stale_visible
8
11
  stale_present
9
- select_by].freeze
12
+ select_by
13
+ wait_until_present
14
+ wait_while_present].freeze
10
15
 
11
16
  DEPRECATION_WARNINGS.each do |deprecation|
12
17
  RSpec::Matchers.define "have_deprecated_#{deprecation}" do
@@ -128,6 +128,10 @@ describe Watir::UserEditable do
128
128
  it "raises UnknownObjectException if the text field doesn't exist" do
129
129
  expect { browser.text_field(id: 'no_such_id').set('secret') }.to raise_unknown_object_exception
130
130
  end
131
+
132
+ it 'raises ObjectReadOnlyException if the object is read only' do
133
+ expect { browser.text_field(id: 'new_user_code').set('Foo') }.to raise_object_read_only_exception
134
+ end
131
135
  end
132
136
 
133
137
  describe '#set!' do
@@ -107,48 +107,63 @@ describe Watir::Element do
107
107
  describe '#wait_until_present' do
108
108
  it 'waits until the element appears' do
109
109
  browser.a(id: 'show_bar').click
110
- expect { browser.div(id: 'bar').wait_until_present(timeout: 5) }.to_not raise_exception
110
+ expect {
111
+ expect { browser.div(id: 'bar').wait_until_present(timeout: 5) }.to_not raise_exception
112
+ }.to have_deprecated_wait_until_present
111
113
  end
112
114
 
113
115
  it 'waits until the element re-appears' do
114
116
  browser.link(id: 'readd_bar').click
115
- expect { browser.div(id: 'bar').wait_until_present }.to_not raise_exception
117
+ expect {
118
+ expect { browser.div(id: 'bar').wait_until_present }.to_not raise_exception
119
+ }.to have_deprecated_wait_until_present
116
120
  end
117
121
 
118
122
  it "times out if the element doesn't appear" do
119
123
  inspected = '#<Watir::Div: located: true; {:id=>"bar", :tag_name=>"div"}>'
120
124
  error = Watir::Wait::TimeoutError
121
- message = "timed out after 1 seconds, waiting for element #{inspected} to become present"
125
+ message = "timed out after 1 seconds, waiting for #{inspected} to become present"
122
126
 
123
- expect { browser.div(id: 'bar').wait_until_present(timeout: 1) }.to raise_error(error, message)
127
+ expect {
128
+ expect { browser.div(id: 'bar').wait_until_present(timeout: 1) }.to raise_error(error, message)
129
+ }.to have_deprecated_wait_until_present
124
130
  end
125
131
 
126
132
  it 'uses provided interval' do
127
133
  element = browser.div(id: 'bar')
128
134
  expect(element).to receive(:present?).twice
129
135
 
130
- expect { element.wait_until_present(timeout: 0.4, interval: 0.2) }.to raise_timeout_exception
136
+ expect {
137
+ expect { element.wait_until_present(timeout: 0.4, interval: 0.2) }.to raise_timeout_exception
138
+ }.to have_deprecated_wait_until_present
131
139
  end
132
140
  end
133
141
 
134
142
  describe '#wait_while_present' do
135
143
  it 'waits until the element disappears' do
136
144
  browser.a(id: 'hide_foo').click
137
- expect { browser.div(id: 'foo').wait_while_present(timeout: 2) }.to_not raise_exception
145
+ expect {
146
+ expect { browser.div(id: 'foo').wait_while_present(timeout: 2) }.to_not raise_exception
147
+ }.to have_deprecated_wait_while_present
138
148
  end
139
149
 
140
150
  it "times out if the element doesn't disappear" do
141
151
  error = Watir::Wait::TimeoutError
142
152
  inspected = '#<Watir::Div: located: true; {:id=>"foo", :tag_name=>"div"}>'
143
- message = "timed out after 1 seconds, waiting for element #{inspected} not to be present"
144
- expect { browser.div(id: 'foo').wait_while_present(timeout: 1) }.to raise_error(error, message)
153
+ message = "timed out after 1 seconds, waiting for #{inspected} not to be present"
154
+ expect {
155
+ expect { browser.div(id: 'foo').wait_while_present(timeout: 1) }.to raise_error(error, message)
156
+ }.to have_deprecated_wait_while_present
145
157
  end
146
158
 
147
159
  it 'uses provided interval' do
160
+ error = Watir::Wait::TimeoutError
148
161
  element = browser.div(id: 'foo')
149
- expect(element).to receive(:present?).twice
162
+ expect(element).to receive(:present?).and_return(true).twice
150
163
 
151
- expect { element.wait_until_present(timeout: 0.4, interval: 0.2) }.to raise_timeout_exception
164
+ expect {
165
+ expect { element.wait_while_present(timeout: 0.4, interval: 0.2) }.to raise_error(error)
166
+ }.to have_deprecated_wait_while_present
152
167
  end
153
168
 
154
169
  it 'does not error when element goes stale' do
@@ -157,13 +172,17 @@ describe Watir::Element do
157
172
  allow(element).to receive(:stale?).and_return(false, true)
158
173
 
159
174
  browser.a(id: 'hide_foo').click
160
- expect { element.wait_while_present(timeout: 1) }.to_not raise_exception
175
+ expect {
176
+ expect { element.wait_while_present(timeout: 1) }.to_not raise_exception
177
+ }.to have_deprecated_wait_while_present
161
178
  end
162
179
 
163
180
  it 'waits until the selector no longer matches' do
164
181
  element = browser.link(name: 'add_select').wait_until(&:exists?)
165
182
  browser.link(id: 'change_select').click
166
- expect { element.wait_while_present }.not_to raise_error
183
+ expect {
184
+ expect { element.wait_while_present }.not_to raise_error
185
+ }.to have_deprecated_wait_while_present
167
186
  end
168
187
  end
169
188
 
@@ -303,6 +322,34 @@ describe Watir::Element do
303
322
  expect { element.wait_while(custom: '') }.to_not raise_exception
304
323
  end
305
324
 
325
+ it 'accepts keywords and block' do
326
+ element = browser.div(id: 'foo')
327
+ browser.a(id: 'hide_foo').click
328
+ expect { element.wait_while(custom: '', &:present?) }.to_not raise_exception
329
+ end
330
+
331
+ it 'browser accepts keywords' do
332
+ expect { browser.wait_until(title: 'wait test') }.to_not raise_exception
333
+ expect { browser.wait_until(title: 'wrong') }.to raise_timeout_exception
334
+ end
335
+
336
+ it 'alert accepts keywords' do
337
+ browser.goto WatirSpec.url_for('alerts.html')
338
+
339
+ begin
340
+ browser.button(id: 'alert').click
341
+ expect { browser.alert.wait_until(text: 'ok') }.to_not raise_exception
342
+ expect { browser.alert.wait_until(text: 'not ok') }.to raise_timeout_exception
343
+ ensure
344
+ browser.alert.ok
345
+ end
346
+ end
347
+
348
+ it 'window accepts keywords' do
349
+ expect { browser.window.wait_until(title: 'wait test') }.to_not raise_exception
350
+ expect { browser.window.wait_until(title: 'wrong') }.to raise_timeout_exception
351
+ end
352
+
306
353
  it 'times out when single keyword not met' do
307
354
  element = browser.div(id: 'foo')
308
355
  expect { element.wait_while(id: 'foo') }.to raise_timeout_exception
@@ -338,11 +385,15 @@ describe Watir do
338
385
  end
339
386
 
340
387
  it 'is used by Element#wait_until_present' do
341
- expect { browser.div(id: 'bar').wait_until_present }.to wait_and_raise_timeout_exception(timeout: 1)
388
+ expect {
389
+ expect { browser.div(id: 'bar').wait_until_present }.to wait_and_raise_timeout_exception(timeout: 1)
390
+ }.to have_deprecated_wait_until_present
342
391
  end
343
392
 
344
393
  it 'is used by Element#wait_while_present' do
345
- expect { browser.div(id: 'foo').wait_while_present }.to wait_and_raise_timeout_exception(timeout: 1)
394
+ expect {
395
+ expect { browser.div(id: 'foo').wait_while_present }.to wait_and_raise_timeout_exception(timeout: 1)
396
+ }.to have_deprecated_wait_while_present
346
397
  end
347
398
  end
348
399
  end