watir 6.15.1 → 6.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -2
- data/.travis.yml +2 -0
- data/CHANGES.md +13 -0
- data/Rakefile +6 -0
- data/lib/watir.rb +1 -0
- data/lib/watir/browser.rb +4 -1
- data/lib/watir/element_collection.rb +27 -17
- data/lib/watir/elements/element.rb +41 -14
- data/lib/watir/elements/iframe.rb +3 -1
- data/lib/watir/elements/radio.rb +7 -2
- data/lib/watir/elements/select.rb +1 -0
- data/lib/watir/locators.rb +21 -21
- data/lib/watir/locators/button/matcher.rb +40 -0
- data/lib/watir/locators/cell/selector_builder.rb +3 -0
- data/lib/watir/locators/element/locator.rb +29 -172
- data/lib/watir/locators/element/matcher.rb +127 -0
- data/lib/watir/locators/element/selector_builder.rb +69 -23
- data/lib/watir/locators/element/selector_builder/xpath.rb +3 -10
- data/lib/watir/locators/row/selector_builder.rb +5 -5
- data/lib/watir/locators/text_area/selector_builder.rb +0 -14
- data/lib/watir/locators/text_area/selector_builder/xpath.rb +2 -2
- data/lib/watir/locators/text_field/matcher.rb +38 -0
- data/lib/watir/radio_set.rb +28 -31
- data/lib/watir/scroll.rb +69 -0
- data/lib/watir/version.rb +1 -1
- data/spec/locator_spec_helper.rb +58 -14
- data/spec/unit/element_locator_spec.rb +46 -591
- data/spec/unit/match_elements/button_spec.rb +80 -0
- data/spec/unit/match_elements/element_spec.rb +368 -0
- data/spec/unit/match_elements/text_field_spec.rb +79 -0
- data/spec/unit/selector_builder/anchor_spec.rb +51 -0
- data/spec/unit/selector_builder/button_spec.rb +206 -0
- data/spec/unit/selector_builder/cell_spec.rb +63 -0
- data/spec/unit/selector_builder/element_spec.rb +744 -0
- data/spec/unit/selector_builder/row_spec.rb +111 -0
- data/spec/unit/selector_builder/text_field_spec.rb +189 -0
- data/spec/unit/selector_builder/textarea_spec.rb +25 -0
- data/spec/watirspec/browser_spec.rb +7 -8
- data/spec/watirspec/element_hidden_spec.rb +1 -2
- data/spec/watirspec/elements/element_spec.rb +52 -16
- data/spec/watirspec/elements/iframe_spec.rb +1 -1
- data/spec/watirspec/elements/select_list_spec.rb +1 -1
- data/spec/watirspec/html/obscured.html +3 -1
- data/spec/watirspec/html/scroll.html +32 -0
- data/spec/watirspec/relaxed_locate_spec.rb +6 -1
- data/spec/watirspec/scroll_spec.rb +106 -0
- data/spec/watirspec/support/rspec_matchers.rb +2 -0
- data/spec/watirspec/wait_spec.rb +1 -1
- data/watir.gemspec +2 -4
- metadata +36 -33
- data/lib/watir/locators/button/locator.rb +0 -32
- data/lib/watir/locators/button/validator.rb +0 -17
- data/lib/watir/locators/cell/locator.rb +0 -13
- data/lib/watir/locators/element/validator.rb +0 -11
- data/lib/watir/locators/row/locator.rb +0 -13
- data/lib/watir/locators/text_field/locator.rb +0 -31
- data/lib/watir/locators/text_field/validator.rb +0 -13
- data/spec/unit/anchor_locator_spec.rb +0 -68
- data/spec/watirspec/selector_builder/button_spec.rb +0 -250
- data/spec/watirspec/selector_builder/cell_spec.rb +0 -92
- data/spec/watirspec/selector_builder/element_spec.rb +0 -628
- data/spec/watirspec/selector_builder/row_spec.rb +0 -148
- data/spec/watirspec/selector_builder/text_spec.rb +0 -199
@@ -1,148 +0,0 @@
|
|
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
|
-
expect(selector_builder.build(@selector)).to eq @built
|
14
|
-
|
15
|
-
next unless @data_locator || @tag_name
|
16
|
-
|
17
|
-
expect { @located = @query_scope.wd.first(@built) }.not_to raise_exception
|
18
|
-
|
19
|
-
if @data_locator
|
20
|
-
expect(@located.attribute('data-locator')).to eq(@data_locator)
|
21
|
-
else
|
22
|
-
expect {
|
23
|
-
expect(@located.tag_name).to eq @tag_name
|
24
|
-
}.not_to raise_exception
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
context 'with query scopes' do
|
29
|
-
before(:each) do
|
30
|
-
browser.goto(WatirSpec.url_for('tables.html'))
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'with only table query scope' do
|
34
|
-
@query_scope = browser.element(id: 'outer').locate
|
35
|
-
@selector = {}
|
36
|
-
@built = {xpath: "./*[local-name()='tr'] | ./*[local-name()='tbody']/*[local-name()='tr'] | " \
|
37
|
-
"./*[local-name()='thead']/*[local-name()='tr'] | ./*[local-name()='tfoot']/*[local-name()='tr']"}
|
38
|
-
@data_locator = 'first row'
|
39
|
-
end
|
40
|
-
|
41
|
-
it 'with tbody query scope' do
|
42
|
-
@query_scope = browser.element(id: 'first').locate
|
43
|
-
@selector = {}
|
44
|
-
@built = {xpath: "./*[local-name()='tr']"}
|
45
|
-
@data_locator = 'tbody row'
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'with thead query scope' do
|
49
|
-
@query_scope = browser.element(id: 'tax_headers').locate
|
50
|
-
@selector = {}
|
51
|
-
@built = {xpath: "./*[local-name()='tr']"}
|
52
|
-
@data_locator = 'thead row'
|
53
|
-
end
|
54
|
-
|
55
|
-
it 'with tfoot query scope' do
|
56
|
-
@query_scope = browser.element(id: 'tax_totals').locate
|
57
|
-
@selector = {}
|
58
|
-
@built = {xpath: "./*[local-name()='tr']"}
|
59
|
-
@data_locator = 'tfoot row'
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
context 'with index' do
|
64
|
-
before(:each) do
|
65
|
-
browser.goto(WatirSpec.url_for('tables.html'))
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'positive' do
|
69
|
-
@query_scope = browser.element(id: 'outer').locate
|
70
|
-
@selector = {index: 1}
|
71
|
-
@built = {xpath: "(./*[local-name()='tr'] | ./*[local-name()='tbody']/*[local-name()='tr'] | " \
|
72
|
-
"./*[local-name()='thead']/*[local-name()='tr'] | ./*[local-name()='tfoot']/*[local-name()='tr'])[2]"}
|
73
|
-
@data_locator = 'middle row'
|
74
|
-
end
|
75
|
-
|
76
|
-
it 'negative' do
|
77
|
-
@query_scope = browser.element(id: 'outer').locate
|
78
|
-
@selector = {index: -3}
|
79
|
-
@built = {xpath: "(./*[local-name()='tr'] | ./*[local-name()='tbody']/*[local-name()='tr'] | " \
|
80
|
-
"./*[local-name()='thead']/*[local-name()='tr'] | ./*[local-name()='tfoot']/*[local-name()='tr'])[last()-2]"}
|
81
|
-
@data_locator = 'first row'
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'last' do
|
85
|
-
@query_scope = browser.element(id: 'outer').locate
|
86
|
-
@selector = {index: -1}
|
87
|
-
@built = {xpath: "(./*[local-name()='tr'] | ./*[local-name()='tbody']/*[local-name()='tr'] | " \
|
88
|
-
"./*[local-name()='thead']/*[local-name()='tr'] | ./*[local-name()='tfoot']/*[local-name()='tr'])[last()]"}
|
89
|
-
@data_locator = 'last row'
|
90
|
-
end
|
91
|
-
|
92
|
-
it 'does not return index if it is zero' do
|
93
|
-
@query_scope = browser.element(id: 'outer').locate
|
94
|
-
@selector = {index: 0}
|
95
|
-
@built = {xpath: "./*[local-name()='tr'] | ./*[local-name()='tbody']/*[local-name()='tr'] | " \
|
96
|
-
"./*[local-name()='thead']/*[local-name()='tr'] | ./*[local-name()='tfoot']/*[local-name()='tr']"}
|
97
|
-
@data_locator = 'first row'
|
98
|
-
end
|
99
|
-
|
100
|
-
it 'raises exception when index is not an Integer', skip_after: true do
|
101
|
-
@query_scope = browser.element(id: 'outer').locate
|
102
|
-
selector = {index: 'foo'}
|
103
|
-
msg = /expected one of \[(Integer|Fixnum)\], got "foo":String/
|
104
|
-
expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
context 'with multiple locators' do
|
109
|
-
before(:each) do
|
110
|
-
browser.goto(WatirSpec.url_for('tables.html'))
|
111
|
-
@query_scope = browser.table.locate
|
112
|
-
end
|
113
|
-
|
114
|
-
it 'attribute and class' do
|
115
|
-
@selector = {id: 'gregory', class: /brick/}
|
116
|
-
@built = {xpath: "./*[local-name()='tr'][contains(@class, 'brick')][@id='gregory'] | " \
|
117
|
-
"./*[local-name()='tbody']/*[local-name()='tr'][contains(@class, 'brick')][@id='gregory'] | " \
|
118
|
-
"./*[local-name()='thead']/*[local-name()='tr'][contains(@class, 'brick')][@id='gregory'] | " \
|
119
|
-
"./*[local-name()='tfoot']/*[local-name()='tr'][contains(@class, 'brick')][@id='gregory']"}
|
120
|
-
@data_locator = 'House row'
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
context 'returns locators that can not be directly translated' do
|
125
|
-
before(:each) do
|
126
|
-
browser.goto(WatirSpec.url_for('tables.html'))
|
127
|
-
@query_scope = browser.table(id: 'outer').locate
|
128
|
-
end
|
129
|
-
|
130
|
-
it 'any text value' do
|
131
|
-
@selector = {text: 'Gregory'}
|
132
|
-
@built = {xpath: "./*[local-name()='tr'] | ./*[local-name()='tbody']/*[local-name()='tr'] | " \
|
133
|
-
"./*[local-name()='thead']/*[local-name()='tr'] | ./*[local-name()='tfoot']/*[local-name()='tr']", text: 'Gregory'}
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
it 'delegates adjacent to Element SelectorBuilder' do
|
138
|
-
browser.goto(WatirSpec.url_for('tables.html'))
|
139
|
-
|
140
|
-
@scope_tag_name = 'table'
|
141
|
-
@query_scope = browser.element(id: 'gregory').locate
|
142
|
-
|
143
|
-
@selector = {adjacent: :ancestor, index: 1}
|
144
|
-
@built = {xpath: './ancestor::*[2]'}
|
145
|
-
@data_locator = 'top table'
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
@@ -1,199 +0,0 @@
|
|
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
|
-
expect(selector_builder.build(@selector)).to eq @built
|
31
|
-
|
32
|
-
next unless @data_locator || @tag_name
|
33
|
-
|
34
|
-
expect { @located = @query_scope.wd.first(@built) }.not_to raise_exception
|
35
|
-
|
36
|
-
if @data_locator
|
37
|
-
expect(@located.attribute('data-locator')).to eq(@data_locator)
|
38
|
-
else
|
39
|
-
expect {
|
40
|
-
expect(@located.tag_name).to eq @tag_name
|
41
|
-
}.not_to raise_exception
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
it 'without any arguments' do
|
46
|
-
browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
|
47
|
-
@selector = {}
|
48
|
-
@built = {xpath: ".//*[local-name()='input'][not(@type) or (#{negative_types})]"}
|
49
|
-
@data_locator = 'input name'
|
50
|
-
end
|
51
|
-
|
52
|
-
context 'with type' do
|
53
|
-
before(:each) { browser.goto(WatirSpec.url_for('forms_with_input_elements.html')) }
|
54
|
-
|
55
|
-
it 'specified text field type that is text' do
|
56
|
-
@selector = {type: 'text'}
|
57
|
-
@built = {xpath: ".//*[local-name()='input']" \
|
58
|
-
"[translate(@type,'#{uppercase}','#{lowercase}')='text']"}
|
59
|
-
@data_locator = 'first text'
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'specified text field type that is not text' do
|
63
|
-
@selector = {type: 'number'}
|
64
|
-
@built = {xpath: ".//*[local-name()='input']" \
|
65
|
-
"[translate(@type,'#{uppercase}','#{lowercase}')='number']"}
|
66
|
-
@data_locator = '42'
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'true locates text field with a type specified' do
|
70
|
-
@selector = {type: true}
|
71
|
-
@built = {xpath: ".//*[local-name()='input'][#{negative_types}]"}
|
72
|
-
@data_locator = 'input name'
|
73
|
-
end
|
74
|
-
|
75
|
-
it 'false locates text field without type specified' do
|
76
|
-
@selector = {type: false}
|
77
|
-
@built = {xpath: ".//*[local-name()='input'][not(@type)]"}
|
78
|
-
@data_locator = 'input name'
|
79
|
-
end
|
80
|
-
|
81
|
-
it 'raises exception when a non-text field type input is specified', skip_after: true do
|
82
|
-
selector = {type: 'checkbox'}
|
83
|
-
msg = 'TextField Elements can not be located by type: checkbox'
|
84
|
-
expect { selector_builder.build(selector) }
|
85
|
-
.to raise_exception Watir::Exception::LocatorException, msg
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
context 'with index' do
|
90
|
-
before(:each) do
|
91
|
-
browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
|
92
|
-
end
|
93
|
-
|
94
|
-
it 'positive' do
|
95
|
-
@selector = {index: 4}
|
96
|
-
@built = {xpath: "(.//*[local-name()='input'][not(@type) or (#{negative_types})])[5]"}
|
97
|
-
@data_locator = 'dev'
|
98
|
-
end
|
99
|
-
|
100
|
-
it 'negative' do
|
101
|
-
@selector = {index: -3}
|
102
|
-
@built = {xpath: "(.//*[local-name()='input'][not(@type) or (#{negative_types})])[last()-2]"}
|
103
|
-
@data_locator = '42'
|
104
|
-
end
|
105
|
-
|
106
|
-
it 'last' do
|
107
|
-
@selector = {index: -1}
|
108
|
-
@built = {xpath: "(.//*[local-name()='input'][not(@type) or (#{negative_types})])[last()]"}
|
109
|
-
@data_locator = 'last text'
|
110
|
-
end
|
111
|
-
|
112
|
-
it 'does not return index if it is zero' do
|
113
|
-
@selector = {index: 0}
|
114
|
-
@built = {xpath: ".//*[local-name()='input'][not(@type) or (#{negative_types})]"}
|
115
|
-
@data_locator = 'input name'
|
116
|
-
end
|
117
|
-
|
118
|
-
it 'raises exception when index is not an Integer', skip_after: true do
|
119
|
-
selector = {index: 'foo'}
|
120
|
-
msg = /expected one of \[(Integer|Fixnum)\], got "foo":String/
|
121
|
-
expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
context 'with text' do
|
126
|
-
before(:each) { browser.goto(WatirSpec.url_for('forms_with_input_elements.html')) }
|
127
|
-
|
128
|
-
it 'String for value' do
|
129
|
-
@selector = {text: 'Developer'}
|
130
|
-
@built = {xpath: ".//*[local-name()='input'][not(@type) or (#{negative_types})]", text: 'Developer'}
|
131
|
-
end
|
132
|
-
|
133
|
-
it 'Simple Regexp for value' do
|
134
|
-
@selector = {text: /Dev/}
|
135
|
-
@built = {xpath: ".//*[local-name()='input'][not(@type) or (#{negative_types})]", text: /Dev/}
|
136
|
-
end
|
137
|
-
|
138
|
-
it 'returns complicated Regexp to the locator as a value' do
|
139
|
-
@selector = {text: /^foo$/}
|
140
|
-
@built = {xpath: ".//*[local-name()='input'][not(@type) or (#{negative_types})]", text: /^foo$/}
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
context 'with label' do
|
145
|
-
before(:each) { browser.goto(WatirSpec.url_for('forms_with_input_elements.html')) }
|
146
|
-
|
147
|
-
it 'using String' do
|
148
|
-
@selector = {label: 'First name'}
|
149
|
-
@built = {xpath: ".//*[local-name()='input'][not(@type) or (#{negative_types})]" \
|
150
|
-
"[@id=//label[normalize-space()='First name']/@for or parent::label[normalize-space()='First name']]"}
|
151
|
-
@data_locator = 'input name'
|
152
|
-
end
|
153
|
-
|
154
|
-
it 'uses String with hidden text' do
|
155
|
-
@selector = {label: 'With hidden text'}
|
156
|
-
@built = {xpath: ".//*[local-name()='input'][not(@type) or (#{negative_types})]" \
|
157
|
-
"[@id=//label[normalize-space()='With hidden text']/@for or parent::label[normalize-space()='With hidden text']]"}
|
158
|
-
@data_locator = 'hidden'
|
159
|
-
end
|
160
|
-
|
161
|
-
# Desired Behavior
|
162
|
-
xit 'using simple Regexp' do
|
163
|
-
@selector = {label: /First/}
|
164
|
-
@built = {xpath: ".//*[local-name()='input'][not(@type) or (#{negative_types})]" \
|
165
|
-
"[@id=//label[contains(text(), 'First')]/@for or parent::label[contains(text(), 'First')]]"}
|
166
|
-
@data_locator = 'input name'
|
167
|
-
end
|
168
|
-
|
169
|
-
# Desired Behavior
|
170
|
-
xit 'using complex Regexp' do
|
171
|
-
@selector = {label: /([qa])st? name/}
|
172
|
-
@built = {xpath: ".//*[local-name()='input'][not(@type) or (#{negative_types})]" \
|
173
|
-
"[@id=//label[contains(text(), 's') and contains(text(), ' name')]/@for or " \
|
174
|
-
"parent::label[contains(text(), 's') and contains(text(), ' name')]]", label_element: /([qa])st? name/}
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
context 'with multiple locators' do
|
179
|
-
before(:each) do
|
180
|
-
browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
|
181
|
-
end
|
182
|
-
|
183
|
-
it 'locates using tag name, class, attributes and text' do
|
184
|
-
@selector = {text: 'Developer', class: /c/, id: true}
|
185
|
-
@built = {xpath: ".//*[local-name()='input'][contains(@class, 'c')]" \
|
186
|
-
"[not(@type) or (#{negative_types})][@id]", text: 'Developer'}
|
187
|
-
end
|
188
|
-
|
189
|
-
it 'delegates adjacent to Element SelectorBuilder' do
|
190
|
-
browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
|
191
|
-
@query_scope = browser.element(id: 'new_user_email').locate
|
192
|
-
|
193
|
-
@selector = {adjacent: :ancestor, index: 1}
|
194
|
-
@built = {xpath: './ancestor::*[2]'}
|
195
|
-
@data_locator = 'form'
|
196
|
-
end
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|