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,17 +0,0 @@
1
- module Watir
2
- module Locators
3
- class Button
4
- class Validator < Element::Validator
5
- def validate(element, _tag_name)
6
- tag_name = element.tag_name.downcase
7
- return unless %w[input button].include?(tag_name)
8
-
9
- # TODO: - Verify this is desired behavior based on https://bugzilla.mozilla.org/show_bug.cgi?id=1290963
10
- return if tag_name == 'input' && !Watir::Button::VALID_TYPES.include?(element.attribute(:type).downcase)
11
-
12
- element
13
- end
14
- end
15
- end
16
- end
17
- end
@@ -1,13 +0,0 @@
1
- module Watir
2
- module Locators
3
- class Cell
4
- class Locator < Element::Locator
5
- private
6
-
7
- def using_selenium(*)
8
- # force watir usage
9
- end
10
- end
11
- end
12
- end
13
- end
@@ -1,11 +0,0 @@
1
- module Watir
2
- module Locators
3
- class Element
4
- class Validator
5
- def validate(element, tag_name)
6
- element.tag_name.downcase =~ /#{tag_name}/
7
- end
8
- end
9
- end
10
- end
11
- end
@@ -1,13 +0,0 @@
1
- module Watir
2
- module Locators
3
- class Row
4
- class Locator < Element::Locator
5
- private
6
-
7
- def using_selenium(*)
8
- # force Watir usage
9
- end
10
- end
11
- end
12
- end
13
- end
@@ -1,31 +0,0 @@
1
- module Watir
2
- module Locators
3
- class TextField
4
- class Locator < Element::Locator
5
- private
6
-
7
- def using_selenium(*)
8
- # force Watir usage
9
- end
10
-
11
- def matches_values?(element, rx_selector)
12
- conversions = %i[text value label visible_text] & rx_selector.keys
13
-
14
- tag_name = nil
15
-
16
- conversions.each do |key|
17
- tag_name ||= element.tag_name.downcase
18
- correct_key = tag_name == 'input' ? :value : :text
19
- rx_selector[correct_key] = rx_selector.delete(key)
20
- end
21
-
22
- super
23
- end
24
-
25
- def text_regexp_deprecation(*)
26
- # does not apply to text_field
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,13 +0,0 @@
1
- module Watir
2
- module Locators
3
- class TextField
4
- class Validator < Element::Validator
5
- def validate(element, _tag_name)
6
- # Zero for Ruby 2.3, Ruby 2.4+ this evaluates true/false
7
- result = element.tag_name.casecmp('input')
8
- result.zero? || result.eq(true)
9
- end
10
- end
11
- end
12
- end
13
- end
@@ -1,68 +0,0 @@
1
- require_relative 'unit_helper'
2
-
3
- describe Watir::Locators::Element::Locator do
4
- include LocatorSpecHelper
5
-
6
- def locator(selector, attrs)
7
- attrs ||= Watir::HTMLElement.attributes
8
- element_validator = Watir::Locators::Element::Validator.new
9
- selector_builder = Watir::Locators::Anchor::SelectorBuilder.new(attrs)
10
- Watir::Locators::Element::Locator.new(browser, selector, selector_builder, element_validator)
11
- end
12
-
13
- it 'converts :visible_text with String to :link_text' do
14
- link = element(tag_name: 'a')
15
- expect_one(:link_text, 'exact text').and_return(link)
16
- expect(link).not_to receive(:text) # matching does not validate text
17
-
18
- locate_one(tag_name: 'a', visible_text: 'exact text')
19
- end
20
-
21
- it 'converts :visible_text with basic Regexp to :partial_link_text' do
22
- link = element(tag_name: 'a')
23
- expect_one(:partial_link_text, 'partial text').and_return(link)
24
- expect(link).not_to receive(:text) # matching does not validate text
25
-
26
- locate_one(tag_name: 'a', visible_text: /partial text/)
27
- end
28
-
29
- it 'does not convert :visible_text with complex Regexp' do
30
- elements = [
31
- element(tag_name: 'a', text: 'other text'),
32
- element(tag_name: 'a', text: 'matching complex!text')
33
- ]
34
- expect_all(:xpath, ".//*[local-name()='a']").and_return(elements)
35
-
36
- expect(locate_one(tag_name: 'a', visible_text: /complex.text/)).to eq(elements[1])
37
- end
38
-
39
- it 'does not convert :visible_text with casefold Regexp' do
40
- elements = [
41
- element(tag_name: 'a', text: 'other text'),
42
- element(tag_name: 'a', text: 'partial text')
43
- ]
44
- expect_all(:xpath, ".//*[local-name()='a']").and_return(elements)
45
-
46
- expect(locate_one(tag_name: 'a', visible_text: /partial text/i)).to eq(elements[1])
47
- end
48
-
49
- it 'does not convert :visible_text with String and other locators' do
50
- els = [
51
- element(tag_name: 'a', attributes: {class: 'klass', name: 'abc'}, text: 'other text'),
52
- element(tag_name: 'a', attributes: {class: 'klass', name: 'abc'}, text: 'exact text')
53
- ]
54
- expect_all(:xpath, ".//*[local-name()='a'][contains(concat(' ', @class, ' '), ' klass ')][@name]").and_return(els)
55
-
56
- expect(locate_one(tag_name: 'a', class: 'klass', name: /a|.c/, visible_text: 'exact text')).to eq(els[1])
57
- end
58
-
59
- it 'does not convert :visible_text with Regexp and other locators' do
60
- els = [
61
- element(tag_name: 'a', attributes: {class: 'klass', name: 'abc'}, text: 'other text'),
62
- element(tag_name: 'a', attributes: {class: 'klass', name: 'abc'}, text: 'partial text')
63
- ]
64
- expect_all(:xpath, ".//*[local-name()='a'][contains(concat(' ', @class, ' '), ' klass ')][@name]").and_return(els)
65
-
66
- expect(locate_one(tag_name: 'a', class: 'klass', name: /a|.c/, visible_text: /partial text/)).to eq(els[1])
67
- end
68
- end
@@ -1,250 +0,0 @@
1
- require 'watirspec_helper'
2
-
3
- describe Watir::Locators::Button::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(:default_types) do
10
- "translate(@type,'#{uppercase}','#{lowercase}')='button' or" \
11
- " translate(@type,'#{uppercase}','#{lowercase}')='reset' or"\
12
- " translate(@type,'#{uppercase}','#{lowercase}')='submit' or"\
13
- " translate(@type,'#{uppercase}','#{lowercase}')='image'"
14
- end
15
-
16
- describe '#build' do
17
- after(:each) do |example|
18
- next if example.metadata[:skip_after]
19
-
20
- @query_scope ||= browser
21
- expect(selector_builder.build(@selector)).to eq @built
22
-
23
- next unless @data_locator || @tag_name
24
-
25
- expect { @located = @query_scope.wd.first(@built) }.not_to raise_exception
26
-
27
- if @data_locator
28
- expect(@located.attribute('data-locator')).to eq(@data_locator)
29
- else
30
- expect {
31
- expect(@located.tag_name).to eq @tag_name
32
- }.not_to raise_exception
33
- end
34
- end
35
-
36
- it 'without any arguments' do
37
- browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
38
- @selector = {}
39
- @built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]"}
40
- @data_locator = 'user submit'
41
- end
42
-
43
- context 'with type' do
44
- before(:each) { browser.goto(WatirSpec.url_for('forms_with_input_elements.html')) }
45
-
46
- it 'false only locates with button without a type' do
47
- @selector = {type: false}
48
- @built = {xpath: ".//*[(local-name()='button' and not(@type))]"}
49
- @data_locator = 'No Type'
50
- end
51
-
52
- it 'true locates button or input with a type' do
53
- @selector = {type: true}
54
- @built = {xpath: ".//*[(local-name()='button' and @type) or " \
55
- "(local-name()='input' and (#{default_types}))]"}
56
- @data_locator = 'user submit'
57
- end
58
-
59
- it 'locates input or button element with specified type' do
60
- @selector = {type: 'reset'}
61
- @built = {xpath: ".//*[(local-name()='button' and " \
62
- "translate(@type,'#{uppercase}','#{lowercase}')='reset') or " \
63
- "(local-name()='input' and (translate(@type,'#{uppercase}','#{lowercase}')='reset'))]"}
64
- @data_locator = 'reset'
65
- end
66
-
67
- it 'raises exception when a non-button type input is specified', skip_after: true do
68
- selector = {type: 'checkbox'}
69
- msg = 'Button Elements can not be located by input type: checkbox'
70
- expect { selector_builder.build(selector) }
71
- .to raise_exception Watir::Exception::LocatorException, msg
72
- end
73
- end
74
-
75
- context 'with xpath or css' do
76
- before(:each) do
77
- browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
78
- end
79
-
80
- it 'returns tag name and type to the locator' do
81
- @selector = {xpath: '#disabled_button', tag_name: 'input', type: 'submit'}
82
- @built = {xpath: '#disabled_button', tag_name: 'input', type: 'submit'}
83
- end
84
- end
85
-
86
- context 'with text' do
87
- before(:each) { browser.goto(WatirSpec.url_for('forms_with_input_elements.html')) }
88
-
89
- it 'locates value of input element with String' do
90
- @selector = {text: 'Button'}
91
- @built = {xpath: ".//*[(local-name()='button' and normalize-space()='Button') or " \
92
- "(local-name()='input' and (#{default_types}) and @value='Button')]"}
93
- @data_locator = 'new user'
94
- end
95
-
96
- it 'locates text of button element with String' do
97
- @selector = {text: 'Button 2'}
98
- @built = {xpath: ".//*[(local-name()='button' and normalize-space()='Button 2') or " \
99
- "(local-name()='input' and (#{default_types}) and @value='Button 2')]"}
100
- @data_locator = 'Benjamin'
101
- end
102
-
103
- it 'locates value of input element with simple Regexp' do
104
- @selector = {text: /Button/}
105
- @built = {xpath: ".//*[(local-name()='button' and contains(text(), 'Button')) or " \
106
- "(local-name()='input' and (#{default_types}) and contains(@value, 'Button'))]"}
107
- @data_locator = 'new user'
108
- end
109
-
110
- it 'locates text of button element with simple Regexp' do
111
- @selector = {text: /Button 2/}
112
- @built = {xpath: ".//*[(local-name()='button' and contains(text(), 'Button 2')) or " \
113
- "(local-name()='input' and (#{default_types}) and contains(@value, 'Button 2'))]"}
114
- @data_locator = 'Benjamin'
115
- end
116
-
117
- it 'Simple Regexp for text' do
118
- @selector = {text: /n 2/}
119
- @built = {xpath: ".//*[(local-name()='button' and contains(text(), 'n 2')) or " \
120
- "(local-name()='input' and (#{default_types}) and contains(@value, 'n 2'))]"}
121
- @data_locator = 'Benjamin'
122
- end
123
-
124
- it 'Simple Regexp for value' do
125
- @selector = {text: /Prev/}
126
- @built = {xpath: ".//*[(local-name()='button' and contains(text(), 'Prev')) or " \
127
- "(local-name()='input' and (#{default_types}) and contains(@value, 'Prev'))]"}
128
- @data_locator = 'preview'
129
- end
130
-
131
- it 'returns complex Regexp to the locator' do
132
- @selector = {text: /^foo$/}
133
- @built = {xpath: ".//*[(local-name()='button' and contains(text(), 'foo')) or " \
134
- "(local-name()='input' and (#{default_types}) and contains(@value, 'foo'))]", text: /^foo$/}
135
- end
136
- end
137
-
138
- context 'with value' do
139
- before(:each) { browser.goto(WatirSpec.url_for('forms_with_input_elements.html')) }
140
-
141
- it 'input element value with String' do
142
- @selector = {value: 'Preview'}
143
- @built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]" \
144
- "[normalize-space()='Preview' or @value='Preview']"}
145
- @data_locator = 'preview'
146
- end
147
-
148
- it 'button element value with String' do
149
- @selector = {value: 'button_2'}
150
- @built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]" \
151
- "[normalize-space()='button_2' or @value='button_2']"}
152
- @data_locator = 'Benjamin'
153
- end
154
-
155
- it 'input element value with simple Regexp' do
156
- @selector = {value: /Prev/}
157
- @built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]" \
158
- "[contains(text(), 'Prev') or contains(@value, 'Prev')]"}
159
- @data_locator = 'preview'
160
- end
161
-
162
- it 'button element value with simple Regexp' do
163
- @selector = {value: /on_2/}
164
- @built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]" \
165
- "[contains(text(), 'on_2') or contains(@value, 'on_2')]"}
166
- @data_locator = 'Benjamin'
167
- end
168
-
169
- it 'button element text with String' do
170
- @selector = {value: 'Button 2'}
171
- @built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]" \
172
- "[normalize-space()='Button 2' or @value='Button 2']"}
173
- @data_locator = 'Benjamin'
174
- end
175
-
176
- it 'button element text with simple Regexp' do
177
- @selector = {value: /ton 2/}
178
- @built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]" \
179
- "[contains(text(), 'ton 2') or contains(@value, 'ton 2')]"}
180
- @data_locator = 'Benjamin'
181
- end
182
-
183
- it 'returns complex Regexp to the locator' do
184
- @selector = {value: /^foo$/}
185
- @built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]" \
186
- "[contains(text(), 'foo') or contains(@value, 'foo')]", value: /^foo$/}
187
- end
188
- end
189
-
190
- context 'with index' do
191
- before(:each) do
192
- browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
193
- end
194
-
195
- it 'positive' do
196
- @selector = {index: 3}
197
- @built = {xpath: "(.//*[(local-name()='button') or (local-name()='input' and (#{default_types}))])[4]"}
198
- @data_locator = 'preview'
199
- end
200
-
201
- it 'negative' do
202
- @selector = {index: -4}
203
- @built = {xpath: "(.//*[(local-name()='button') or " \
204
- "(local-name()='input' and (#{default_types}))])[last()-3]"}
205
- @data_locator = 'submittable button'
206
- end
207
-
208
- it 'last' do
209
- @selector = {index: -1}
210
- @built = {xpath: "(.//*[(local-name()='button') or " \
211
- "(local-name()='input' and (#{default_types}))])[last()]"}
212
- @data_locator = 'last button'
213
- end
214
-
215
- it 'does not return index if it is zero' do
216
- @selector = {index: 0}
217
- @built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]"}
218
- @data_locator = 'user submit'
219
- end
220
-
221
- it 'raises exception when index is not an Integer', skip_after: true do
222
- selector = {index: 'foo'}
223
- msg = /expected one of \[(Integer|Fixnum)\], got "foo":String/
224
- expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
225
- end
226
- end
227
-
228
- context 'with multiple locators' do
229
- before(:each) do
230
- browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
231
- end
232
-
233
- it 'locates using class and attributes' do
234
- @selector = {class: 'image', name: 'new_user_image', src: true}
235
- @built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]" \
236
- "[contains(concat(' ', @class, ' '), ' image ')][@name='new_user_image' and @src]"}
237
- @data_locator = 'submittable button'
238
- end
239
- end
240
-
241
- it 'delegates adjacent to Element SelectorBuilder' do
242
- browser.goto(WatirSpec.url_for('forms_with_input_elements.html'))
243
- @query_scope = browser.element(id: 'new_user_button').locate
244
-
245
- @selector = {adjacent: :ancestor, index: 2}
246
- @built = {xpath: './ancestor::*[3]'}
247
- @data_locator = 'body'
248
- end
249
- end
250
- end
@@ -1,92 +0,0 @@
1
- require 'watirspec_helper'
2
-
3
- describe Watir::Locators::Cell::SelectorBuilder do
4
- let(:attributes) { Watir::HTMLElement.attribute_list }
5
- let(:selector_builder) { described_class.new(attributes) }
6
-
7
- describe '#build' do
8
- after(:each) do |example|
9
- next if example.metadata[:skip_after]
10
-
11
- @query_scope ||= browser.element(id: 'gregory').locate
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
- it 'without any arguments' do
29
- browser.goto(WatirSpec.url_for('tables.html'))
30
- @selector = {}
31
- @built = {xpath: "./*[local-name()='th' or local-name()='td']"}
32
- @data_locator = 'first cell'
33
- end
34
-
35
- context 'with index' do
36
- before(:each) do
37
- browser.goto(WatirSpec.url_for('tables.html'))
38
- end
39
-
40
- it 'positive' do
41
- @selector = {index: 3}
42
- @built = {xpath: "(./*[local-name()='th' or local-name()='td'])[4]"}
43
- @data_locator = 'after tax'
44
- end
45
-
46
- it 'negative' do
47
- @selector = {index: -3}
48
- @built = {xpath: "(./*[local-name()='th' or local-name()='td'])[last()-2]"}
49
- @data_locator = 'before tax'
50
- end
51
-
52
- it 'last' do
53
- @selector = {index: -1}
54
- @built = {xpath: "(./*[local-name()='th' or local-name()='td'])[last()]"}
55
- @data_locator = 'after tax'
56
- end
57
-
58
- it 'does not return index if it is zero' do
59
- @selector = {index: 0}
60
- @built = {xpath: "./*[local-name()='th' or local-name()='td']"}
61
- @data_locator = 'first cell'
62
- end
63
-
64
- it 'raises exception when index is not an Integer', skip_after: true do
65
- selector = {index: 'foo'}
66
- msg = /expected one of \[(Integer|Fixnum)\], got "foo":String/
67
- expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
68
- end
69
- end
70
-
71
- context 'with multiple locators' do
72
- before(:each) do
73
- browser.goto(WatirSpec.url_for('tables.html'))
74
- end
75
-
76
- it 'attribute and text' do
77
- @selector = {headers: /before_tax/, text: '5 934'}
78
- @built = {xpath: "./*[local-name()='th' or local-name()='td']" \
79
- "[normalize-space()='5 934'][contains(@headers, 'before_tax')]"}
80
- @data_locator = 'before tax'
81
- end
82
- end
83
-
84
- it 'delegates adjacent to Element SelectorBuilder' do
85
- @query_scope = browser.element(id: 'p3').locate
86
-
87
- @selector = {adjacent: :ancestor, index: 2}
88
- @built = {xpath: './ancestor::*[3]'}
89
- @data_locator = 'top table'
90
- end
91
- end
92
- end