watir 6.15.1 → 6.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -2
  3. data/.travis.yml +2 -0
  4. data/CHANGES.md +13 -0
  5. data/Rakefile +6 -0
  6. data/lib/watir.rb +1 -0
  7. data/lib/watir/browser.rb +4 -1
  8. data/lib/watir/element_collection.rb +27 -17
  9. data/lib/watir/elements/element.rb +41 -14
  10. data/lib/watir/elements/iframe.rb +3 -1
  11. data/lib/watir/elements/radio.rb +7 -2
  12. data/lib/watir/elements/select.rb +1 -0
  13. data/lib/watir/locators.rb +21 -21
  14. data/lib/watir/locators/button/matcher.rb +40 -0
  15. data/lib/watir/locators/cell/selector_builder.rb +3 -0
  16. data/lib/watir/locators/element/locator.rb +29 -172
  17. data/lib/watir/locators/element/matcher.rb +127 -0
  18. data/lib/watir/locators/element/selector_builder.rb +69 -23
  19. data/lib/watir/locators/element/selector_builder/xpath.rb +3 -10
  20. data/lib/watir/locators/row/selector_builder.rb +5 -5
  21. data/lib/watir/locators/text_area/selector_builder.rb +0 -14
  22. data/lib/watir/locators/text_area/selector_builder/xpath.rb +2 -2
  23. data/lib/watir/locators/text_field/matcher.rb +38 -0
  24. data/lib/watir/radio_set.rb +28 -31
  25. data/lib/watir/scroll.rb +69 -0
  26. data/lib/watir/version.rb +1 -1
  27. data/spec/locator_spec_helper.rb +58 -14
  28. data/spec/unit/element_locator_spec.rb +46 -591
  29. data/spec/unit/match_elements/button_spec.rb +80 -0
  30. data/spec/unit/match_elements/element_spec.rb +368 -0
  31. data/spec/unit/match_elements/text_field_spec.rb +79 -0
  32. data/spec/unit/selector_builder/anchor_spec.rb +51 -0
  33. data/spec/unit/selector_builder/button_spec.rb +206 -0
  34. data/spec/unit/selector_builder/cell_spec.rb +63 -0
  35. data/spec/unit/selector_builder/element_spec.rb +744 -0
  36. data/spec/unit/selector_builder/row_spec.rb +111 -0
  37. data/spec/unit/selector_builder/text_field_spec.rb +189 -0
  38. data/spec/unit/selector_builder/textarea_spec.rb +25 -0
  39. data/spec/watirspec/browser_spec.rb +7 -8
  40. data/spec/watirspec/element_hidden_spec.rb +1 -2
  41. data/spec/watirspec/elements/element_spec.rb +52 -16
  42. data/spec/watirspec/elements/iframe_spec.rb +1 -1
  43. data/spec/watirspec/elements/select_list_spec.rb +1 -1
  44. data/spec/watirspec/html/obscured.html +3 -1
  45. data/spec/watirspec/html/scroll.html +32 -0
  46. data/spec/watirspec/relaxed_locate_spec.rb +6 -1
  47. data/spec/watirspec/scroll_spec.rb +106 -0
  48. data/spec/watirspec/support/rspec_matchers.rb +2 -0
  49. data/spec/watirspec/wait_spec.rb +1 -1
  50. data/watir.gemspec +2 -4
  51. metadata +36 -33
  52. data/lib/watir/locators/button/locator.rb +0 -32
  53. data/lib/watir/locators/button/validator.rb +0 -17
  54. data/lib/watir/locators/cell/locator.rb +0 -13
  55. data/lib/watir/locators/element/validator.rb +0 -11
  56. data/lib/watir/locators/row/locator.rb +0 -13
  57. data/lib/watir/locators/text_field/locator.rb +0 -31
  58. data/lib/watir/locators/text_field/validator.rb +0 -13
  59. data/spec/unit/anchor_locator_spec.rb +0 -68
  60. data/spec/watirspec/selector_builder/button_spec.rb +0 -250
  61. data/spec/watirspec/selector_builder/cell_spec.rb +0 -92
  62. data/spec/watirspec/selector_builder/element_spec.rb +0 -628
  63. data/spec/watirspec/selector_builder/row_spec.rb +0 -148
  64. data/spec/watirspec/selector_builder/text_spec.rb +0 -199
@@ -1,628 +0,0 @@
1
- require 'watirspec_helper'
2
-
3
- describe Watir::Locators::Element::SelectorBuilder do
4
- let(:selector_builder) { described_class.new(@attributes) }
5
-
6
- describe '#build' do
7
- after(:each) do |example|
8
- next if example.metadata[:skip_after]
9
-
10
- @attributes ||= Watir::HTMLElement.attribute_list
11
- @query_scope ||= browser
12
- expect(selector_builder.build(@selector)).to eq @built
13
-
14
- next unless @data_locator || @tag_name
15
-
16
- expect { @located = @query_scope.wd.first(@built) }.not_to raise_exception
17
-
18
- if @data_locator
19
- expect(@located.attribute('data-locator')).to eq(@data_locator)
20
- else
21
- expect {
22
- expect(@located.tag_name).to eq @tag_name
23
- }.not_to raise_exception
24
- end
25
- end
26
-
27
- it 'without any arguments' do
28
- @selector = {}
29
- @built = {xpath: './/*'}
30
- @tag_name = 'html'
31
- end
32
-
33
- context 'with xpath or css' do
34
- before(:each) do
35
- browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
36
- end
37
-
38
- it 'locates with xpath only' do
39
- @selector = {xpath: './/div'}
40
- @built = @selector.dup
41
- @data_locator = 'first div'
42
- end
43
-
44
- it 'locates with css only' do
45
- @selector = {css: 'div'}
46
- @built = @selector.dup
47
- @data_locator = 'first div'
48
- end
49
-
50
- it 'locates when attributes combined with xpath' do
51
- @selector = {xpath: './/div', random: 'foo'}
52
- @built = @selector.dup
53
- @data_locator = 'first div'
54
- end
55
-
56
- it 'locates when attributes combined with css' do
57
- @selector = {css: 'div', random: 'foo'}
58
- @built = @selector.dup
59
- @data_locator = 'first div'
60
- end
61
-
62
- it 'raises exception when using xpath & css', skip_after: true do
63
- selector = {xpath: './/*', css: 'div'}
64
- msg = ':xpath and :css cannot be combined ({:xpath=>".//*", :css=>"div"})'
65
- expect { selector_builder.build(selector) }.to raise_exception Watir::Exception::LocatorException, msg
66
- end
67
-
68
- it 'raises exception when not a String', skip_after: true do
69
- selector = {xpath: 7}
70
- msg = /expected one of \[String\], got 7:(Fixnum|Integer)/
71
- expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
72
- end
73
-
74
- xcontext 'Ideal Behavior' do
75
- it 'xpath' do
76
- selector = {xpath: ".//*[@id='foo']", tag_name: 'div'}
77
- expected = {xpath: ".//*[local-name()='div'][@id='foo']"}
78
-
79
- expect_built(selector, expected)
80
- end
81
-
82
- it 'css' do
83
- selector = {css: '.bar', tag_name: 'div'}
84
- expected = {css: 'div.bar'}
85
-
86
- expect_built(selector, expected)
87
- end
88
- end
89
- end
90
-
91
- context 'with tag_name' do
92
- before(:each) do
93
- browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
94
- end
95
-
96
- it 'with String equals' do
97
- @selector = {tag_name: 'div'}
98
- @built = {xpath: ".//*[local-name()='div']"}
99
- @data_locator = 'first div'
100
- end
101
-
102
- it 'with simple Regexp contains' do
103
- @selector = {tag_name: /div/}
104
- @built = {xpath: ".//*[contains(local-name(), 'div')]"}
105
- @data_locator = 'first div'
106
- end
107
-
108
- it 'with Symbol' do
109
- @selector = {tag_name: :div}
110
- @built = {xpath: ".//*[local-name()='div']"}
111
- @data_locator = 'first div'
112
- end
113
-
114
- it 'raises exception when not a String or Regexp', skip_after: true do
115
- selector = {tag_name: 7}
116
- msg = /expected one of \[String, Regexp, Symbol\], got 7:(Fixnum|Integer)/
117
- expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
118
- end
119
- end
120
-
121
- context 'with class names' do
122
- before(:each) do
123
- browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
124
- end
125
-
126
- it 'class_name is converted to class' do
127
- @selector = {class_name: 'user'}
128
- @built = {xpath: ".//*[contains(concat(' ', @class, ' '), ' user ')]"}
129
- @data_locator = 'form'
130
- end
131
-
132
- # TODO: This functionality is deprecated with "class_array"
133
- it 'values with spaces' do
134
- @selector = {class_name: 'multiple classes here'}
135
- @built = {xpath: ".//*[contains(concat(' ', @class, ' '), ' multiple classes here ')]"}
136
- @data_locator = 'first div'
137
- end
138
-
139
- it 'single String concatenates' do
140
- @selector = {class: 'user'}
141
- @built = {xpath: ".//*[contains(concat(' ', @class, ' '), ' user ')]"}
142
- @data_locator = 'form'
143
- end
144
-
145
- it 'Array of String concatenates with and' do
146
- @selector = {class: %w[multiple here]}
147
- @built = {xpath: ".//*[contains(concat(' ', @class, ' '), ' multiple ') and " \
148
- "contains(concat(' ', @class, ' '), ' here ')]"}
149
- @data_locator = 'first div'
150
- end
151
-
152
- it 'simple Regexp contains' do
153
- @selector = {class_name: /use/}
154
- @built = {xpath: ".//*[contains(@class, 'use')]"}
155
- @data_locator = 'form'
156
- end
157
-
158
- it 'Array of Regexp contains with and' do
159
- @selector = {class: [/mult/, /her/]}
160
- @built = {xpath: ".//*[contains(@class, 'mult') and contains(@class, 'her')]"}
161
- @data_locator = 'first div'
162
- end
163
-
164
- it 'single negated String concatenates with not' do
165
- @selector = {class: '!multiple'}
166
- @built = {xpath: ".//*[not(contains(concat(' ', @class, ' '), ' multiple '))]"}
167
- @tag_name = 'html'
168
- end
169
-
170
- it 'single Boolean true provides the at' do
171
- @selector = {class: true}
172
- @built = {xpath: './/*[@class]'}
173
- @data_locator = 'first div'
174
- end
175
-
176
- it 'single Boolean false provides the not atat' do
177
- @selector = {class: false}
178
- @built = {xpath: './/*[not(@class)]'}
179
- @tag_name = 'html'
180
- end
181
-
182
- it 'Array of mixed String, Regexp and Boolean contains and concatenates with and and not' do
183
- @selector = {class: [/mult/, 'classes', '!here']}
184
- @built = {xpath: ".//*[contains(@class, 'mult') and contains(concat(' ', @class, ' '), ' classes ') " \
185
- "and not(contains(concat(' ', @class, ' '), ' here '))]"}
186
- @data_locator = 'second div'
187
- end
188
-
189
- it 'raises exception when not a String or Regexp or Array', skip_after: true do
190
- selector = {class: 7}
191
- msg = /expected one of \[String, Regexp, TrueClass, FalseClass\], got 7:(Fixnum|Integer)/
192
- expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
193
- end
194
-
195
- it 'raises exception when Array values are not a String or Regexp', skip_after: true do
196
- selector = {class: [7]}
197
- msg = /expected one of \[String, Regexp, TrueClass, FalseClass\], got 7:(Fixnum|Integer)/
198
- expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
199
- end
200
-
201
- it 'raises exception when class and class_name are both used', skip_after: true do
202
- selector = {class: 'foo', class_name: 'bar'}
203
- msg = 'Can not use both :class and :class_name locators'
204
- expect { selector_builder.build(selector) }.to raise_exception Watir::Exception::LocatorException, msg
205
- end
206
-
207
- it 'raises exception when class array is empty', skip_after: true do
208
- selector = {class: []}
209
- msg = 'Can not locate elements with an empty Array for :class'
210
- expect { selector_builder.build(selector) }.to raise_exception Watir::Exception::LocatorException, msg
211
- end
212
- end
213
-
214
- context 'with attributes as predicates' do
215
- before(:each) do
216
- browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
217
- end
218
-
219
- it 'with href attribute' do
220
- @selector = {href: 'watirspec.css'}
221
- @built = {xpath: ".//*[normalize-space(@href)='watirspec.css']"}
222
- @data_locator = 'link'
223
- end
224
-
225
- it 'with string attribute' do
226
- @selector = {'name' => 'user_new'}
227
- @built = {xpath: ".//*[@name='user_new']"}
228
- @data_locator = 'form'
229
- end
230
-
231
- it 'with String equals' do
232
- @selector = {name: 'user_new'}
233
- @built = {xpath: ".//*[@name='user_new']"}
234
- @data_locator = 'form'
235
- end
236
-
237
- it 'with TrueClass no equals' do
238
- @selector = {tag_name: 'input', name: true}
239
- @built = {xpath: ".//*[local-name()='input'][@name]"}
240
- @data_locator = 'input name'
241
- end
242
-
243
- it 'with FalseClass not with no equals' do
244
- @selector = {tag_name: 'input', name: false}
245
- @built = {xpath: ".//*[local-name()='input'][not(@name)]"}
246
- @data_locator = 'input nameless'
247
- end
248
-
249
- it 'with multiple attributes: no equals and not with no equals and equals' do
250
- @selector = {readonly: true, foo: false, id: 'good_luck'}
251
- @built = {xpath: ".//*[@readonly and not(@foo) and @id='good_luck']"}
252
- @data_locator = 'Good Luck'
253
- end
254
-
255
- it 'raises exception when attribute value is not a Boolean, String or Regexp', skip_after: true do
256
- selector = {foo: 7}
257
- msg = /expected one of \[String, Regexp, TrueClass, FalseClass\], got 7:(Fixnum|Integer)/
258
- expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
259
- end
260
-
261
- it 'raises exception when attribute key is not a String or Regexp', skip_after: true do
262
- selector = {7 => 'foo'}
263
- msg = /Unable to build XPath using 7:(Fixnum|Integer)/
264
- expect { selector_builder.build(selector) }.to raise_exception Watir::Exception::LocatorException, msg
265
- end
266
- end
267
-
268
- context 'with attributes as partials' do
269
- before(:each) do
270
- browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
271
- end
272
-
273
- it 'with Regexp' do
274
- @selector = {name: /user/}
275
- @built = {xpath: ".//*[contains(@name, 'user')]"}
276
- @data_locator = 'form'
277
- end
278
-
279
- it 'with multiple Regexp attributes separated by and' do
280
- @selector = {readonly: /read/, id: /good/}
281
- @built = {xpath: ".//*[contains(@readonly, 'read') and contains(@id, 'good')]"}
282
- @data_locator = 'Good Luck'
283
- end
284
- end
285
-
286
- context 'with text' do
287
- before(:each) do
288
- browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
289
- end
290
-
291
- it 'String uses normalize space equals' do
292
- @selector = {text: 'Add user'}
293
- @built = {xpath: ".//*[normalize-space()='Add user']"}
294
- @data_locator = 'add user'
295
- end
296
-
297
- # Deprecated with :caption
298
- it 'with caption attribute' do
299
- @selector = {caption: 'Add user'}
300
- @built = {xpath: ".//*[normalize-space()='Add user']"}
301
- @data_locator = 'add user'
302
- end
303
-
304
- it 'raises exception when text is not a String or Regexp', skip_after: true do
305
- selector = {text: 7}
306
- msg = /expected one of \[String, Regexp\], got 7:(Fixnum|Integer)/
307
- expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
308
- end
309
- end
310
-
311
- context 'with index' do
312
- before(:each) do
313
- browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
314
- end
315
-
316
- it 'positive' do
317
- @selector = {tag_name: 'div', index: 7}
318
- @built = {xpath: "(.//*[local-name()='div'])[8]"}
319
- @data_locator = 'content'
320
- end
321
-
322
- it 'negative' do
323
- @selector = {tag_name: 'div', index: -7}
324
- @built = {xpath: "(.//*[local-name()='div'])[last()-6]"}
325
- @data_locator = 'second div'
326
- end
327
-
328
- it 'last' do
329
- @selector = {tag_name: 'div', index: -1}
330
- @built = {xpath: "(.//*[local-name()='div'])[last()]"}
331
- @data_locator = 'content'
332
- end
333
-
334
- it 'does not return index if it is zero' do
335
- @selector = {tag_name: 'div', index: 0}
336
- @built = {xpath: ".//*[local-name()='div']"}
337
- end
338
-
339
- it 'raises exception when index is not an Integer', skip_after: true do
340
- selector = {index: 'foo'}
341
- msg = /expected one of \[(Integer|Fixnum)\], got "foo":String/
342
- expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
343
- end
344
- end
345
-
346
- context 'with labels' do
347
- before(:each) do
348
- browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
349
- end
350
-
351
- it 'locates the element associated with the label element located by the text of the provided label key' do
352
- @selector = {label: 'Cars'}
353
- @built = {xpath: ".//*[@id=//label[normalize-space()='Cars']/@for "\
354
- "or parent::label[normalize-space()='Cars']]"}
355
- @data_locator = 'cars'
356
- end
357
-
358
- it 'does not use the label element when label is a valid attribute' do
359
- @attributes ||= Watir::Option.attribute_list
360
-
361
- @selector = {tag_name: 'option', label: 'Germany'}
362
- @built = {xpath: ".//*[local-name()='option'][@label='Germany']"}
363
- @data_locator = 'Berliner'
364
- end
365
- end
366
-
367
- context 'with adjacent locators' do
368
- before(:each) do
369
- browser.goto(WatirSpec.url_for('nested_elements.html'))
370
- end
371
-
372
- it 'raises exception when not a Symbol', skip_after: true do
373
- selector = {adjacent: 'foo', index: 0}
374
- msg = 'expected one of [Symbol], got "foo":String'
375
- expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
376
- end
377
-
378
- it 'raises exception when not a valid value', skip_after: true do
379
- selector = {adjacent: :foo, index: 0}
380
- msg = 'Unable to process adjacent locator with foo'
381
- expect { selector_builder.build(selector) }.to raise_exception Watir::Exception::LocatorException, msg
382
- end
383
-
384
- describe '#parent' do
385
- it 'with no other arguments' do
386
- @query_scope = browser.div(id: 'first_sibling')
387
- @selector = {adjacent: :ancestor, index: 0}
388
- @built = {xpath: './ancestor::*[1]'}
389
- @data_locator = 'parent'
390
- end
391
-
392
- it 'with index' do
393
- @query_scope = browser.div(id: 'first_sibling')
394
- @selector = {adjacent: :ancestor, index: 2}
395
- @built = {xpath: './ancestor::*[3]'}
396
- @data_locator = 'grandparent'
397
- end
398
-
399
- it 'with multiple locators' do
400
- @query_scope = browser.div(id: 'first_sibling')
401
- @selector = {adjacent: :ancestor, id: true, tag_name: 'div', class: 'ancestor', index: 1}
402
- @built = {xpath: "./ancestor::*[local-name()='div']"\
403
- "[contains(concat(' ', @class, ' '), ' ancestor ')][@id][2]"}
404
- @data_locator = 'grandparent'
405
- end
406
-
407
- it 'raises an exception if text locator is used', skip_after: true do
408
- selector = {adjacent: :ancestor, index: 0, text: 'Foo'}
409
- msg = 'Can not find parent element with text locator'
410
- expect { selector_builder.build(selector) }
411
- .to raise_exception Watir::Exception::LocatorException, msg
412
- end
413
- end
414
-
415
- describe '#following_sibling' do
416
- it 'with no other arguments' do
417
- @query_scope = browser.div(id: 'first_sibling')
418
- @selector = {adjacent: :following, index: 0}
419
- @built = {xpath: './following-sibling::*[1]'}
420
- @data_locator = 'between_siblings1'
421
- end
422
-
423
- it 'with index' do
424
- @query_scope = browser.div(id: 'first_sibling')
425
- @selector = {adjacent: :following, index: 2}
426
- @built = {xpath: './following-sibling::*[3]'}
427
- @data_locator = 'between_siblings2'
428
- end
429
-
430
- it 'with multiple locators' do
431
- @query_scope = browser.div(id: 'first_sibling')
432
- @selector = {adjacent: :following, tag_name: 'div', class: 'b', index: 0, id: true}
433
- @built = {xpath: "./following-sibling::*[local-name()='div']"\
434
- "[contains(concat(' ', @class, ' '), ' b ')][@id][1]"}
435
- @data_locator = 'second_sibling'
436
- end
437
-
438
- it 'with text' do
439
- @query_scope = browser.div(id: 'first_sibling')
440
- @selector = {adjacent: :following, text: 'Third', index: 0}
441
- @built = {xpath: "./following-sibling::*[normalize-space()='Third'][1]"}
442
- @data_locator = 'third_sibling'
443
- end
444
- end
445
-
446
- describe '#previous_sibling' do
447
- it 'with no other arguments' do
448
- @query_scope = browser.div(id: 'third_sibling')
449
- @selector = {adjacent: :preceding, index: 0}
450
- @built = {xpath: './preceding-sibling::*[1]'}
451
- @data_locator = 'between_siblings2'
452
- end
453
-
454
- it 'with index' do
455
- @query_scope = browser.div(id: 'third_sibling')
456
- @selector = {adjacent: :preceding, index: 2}
457
- @built = {xpath: './preceding-sibling::*[3]'}
458
- @data_locator = 'between_siblings1'
459
- end
460
-
461
- it 'with multiple locators' do
462
- @query_scope = browser.div(id: 'third_sibling')
463
- @selector = {adjacent: :preceding, tag_name: 'div', class: 'b', id: true, index: 0}
464
- @built = {xpath: "./preceding-sibling::*[local-name()='div']"\
465
- "[contains(concat(' ', @class, ' '), ' b ')][@id][1]"}
466
- @data_locator = 'second_sibling'
467
- end
468
-
469
- it 'with text' do
470
- @query_scope = browser.div(id: 'third_sibling')
471
- @selector = {adjacent: :preceding, text: 'Second', index: 0}
472
- @built = {xpath: "./preceding-sibling::*[normalize-space()='Second'][1]"}
473
- @data_locator = 'second_sibling'
474
- end
475
- end
476
-
477
- describe '#child' do
478
- it 'with no other arguments' do
479
- @query_scope = browser.div(id: 'first_sibling')
480
- @selector = {adjacent: :child, index: 0}
481
- @built = {xpath: './child::*[1]'}
482
- @data_locator = 'child span'
483
- end
484
-
485
- it 'with index' do
486
- @query_scope = browser.div(id: 'parent')
487
- @selector = {adjacent: :child, index: 2}
488
- @built = {xpath: './child::*[3]'}
489
- @data_locator = 'second_sibling'
490
- end
491
-
492
- it 'with multiple locators' do
493
- @query_scope = browser.div(id: 'parent')
494
- @selector = {adjacent: :child, tag_name: 'div', class: 'b', id: true, index: 0}
495
- @built = {xpath: "./child::*[local-name()='div']"\
496
- "[contains(concat(' ', @class, ' '), ' b ')][@id][1]"}
497
- @data_locator = 'second_sibling'
498
- end
499
-
500
- it 'with text' do
501
- @query_scope = browser.div(id: 'parent')
502
- @selector = {adjacent: :child, text: 'Second', index: 0}
503
- @built = {xpath: "./child::*[normalize-space()='Second'][1]"}
504
- @data_locator = 'second_sibling'
505
- end
506
- end
507
- end
508
-
509
- context 'with multiple locators' do
510
- before(:each) do
511
- browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
512
- end
513
-
514
- it 'locates using tag name, class, attributes and text' do
515
- @selector = {tag_name: 'div', class: 'content', contenteditable: 'true', text: 'Foo'}
516
- @built = {xpath: ".//*[local-name()='div'][contains(concat(' ', @class, ' '), ' content ')]" \
517
- "[normalize-space()='Foo'][@contenteditable='true']"}
518
- @data_locator = 'content'
519
- end
520
- end
521
-
522
- context 'with simple Regexp' do
523
- before(:each) do
524
- browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
525
- end
526
-
527
- it 'handles spaces' do
528
- @selector = {title: /od Lu/}
529
- @built = {xpath: ".//*[contains(@title, 'od Lu')]"}
530
- @data_locator = 'Good Luck'
531
- end
532
-
533
- it 'handles escaped characters' do
534
- @selector = {src: /ages\/but/}
535
- @built = {xpath: ".//*[contains(@src, 'ages/but')]"}
536
- @data_locator = 'submittable button'
537
- end
538
- end
539
-
540
- context 'with complex Regexp' do
541
- before(:each) do
542
- browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
543
- end
544
-
545
- it 'handles wildcards' do
546
- @selector = {src: /ages.*but/}
547
- @built = {xpath: ".//*[contains(@src, 'ages') and contains(@src, 'but')]", src: /ages.*but/}
548
- @data_locator = 'submittable button'
549
- end
550
-
551
- it 'handles optional characters' do
552
- @selector = {src: /ages ?but/}
553
- @built = {xpath: ".//*[contains(@src, 'ages') and contains(@src, 'but')]", src: /ages ?but/}
554
- @data_locator = 'submittable button'
555
- end
556
-
557
- it 'handles anchors' do
558
- @selector = {name: /^new_user_image$/}
559
- @built = {xpath: ".//*[contains(@name, 'new_user_image')]", name: /^new_user_image$/}
560
- @data_locator = 'submittable button'
561
- end
562
-
563
- it 'handles beginning anchor' do
564
- @selector = {src: /^i/}
565
- @built = {xpath: ".//*[starts-with(@src, 'i')]"}
566
- @data_locator = 'submittable button'
567
- end
568
-
569
- it 'does not use starts-with if visible locator used' do
570
- @selector = {id: /^vis/, visible_text: 'shown div'}
571
- @built = {xpath: ".//*[contains(@id, 'vis')]", id: /^vis/, visible_text: 'shown div'}
572
- end
573
-
574
- it 'handles case insensitive' do
575
- @selector = {action: /me/i}
576
- @built = {xpath: './/*[contains(translate(@action,' \
577
- "'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ'," \
578
- "'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ'), 'me')]"}
579
- @data_locator = 'form'
580
- end
581
- end
582
-
583
- # TODO: These can be moved to unit tests since no browser required
584
- context 'returns locators that can not be directly translated' do
585
- it 'attribute with complicated Regexp at end' do
586
- @selector = {action: /me$/}
587
- @built = {xpath: ".//*[contains(@action, 'me')]", action: /me$/}
588
- end
589
-
590
- it 'class with complicated Regexp' do
591
- @selector = {class: /he?r/}
592
- @built = {xpath: ".//*[contains(@class, 'h') and contains(@class, 'r')]", class: [/he?r/]}
593
- end
594
-
595
- it 'text with any Regexp' do
596
- @selector = {text: /Add/}
597
- @built = {xpath: './/*', text: /Add/}
598
- end
599
-
600
- it 'visible' do
601
- @selector = {tag_name: 'div', visible: true}
602
- @built = {xpath: ".//*[local-name()='div']", visible: true}
603
- end
604
-
605
- it 'not visible' do
606
- @selector = {tag_name: 'span', visible: false}
607
- @built = {xpath: ".//*[local-name()='span']", visible: false}
608
- end
609
-
610
- it 'visible text' do
611
- @selector = {tag_name: 'span', visible_text: 'foo'}
612
- @built = {xpath: ".//*[local-name()='span']", visible_text: 'foo'}
613
- end
614
-
615
- it 'raises exception when visible is not boolean', skip_after: true do
616
- selector = {visible: 'foo'}
617
- msg = 'expected one of [TrueClass, FalseClass], got "foo":String'
618
- expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
619
- end
620
-
621
- it 'raises exception when visible text is not a String or Regexp', skip_after: true do
622
- selector = {visible_text: 7}
623
- msg = /expected one of \[String, Regexp\], got 7:(Fixnum|Integer)/
624
- expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
625
- end
626
- end
627
- end
628
- end