watir 6.0.0.beta4 → 6.0.0.beta5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 04b089bcf4e58208a441dedb2d2404b8e20e2967
4
- data.tar.gz: 1994d0b6cc7f8c5c763da8558447f73bade0d3b9
3
+ metadata.gz: 935a787298648718688deca84d844924d69dc5b0
4
+ data.tar.gz: d6e4f016435c83c21ab6045eac35365c2fb0b370
5
5
  SHA512:
6
- metadata.gz: 4cdae8a09deebfaab7adb7cf413d5f3a4043485d716fa52c87deadf00d6c4d46e8644d9e16c1b1c285abdc4e6f5fe3104f10ace01264b897332835169d0003d7
7
- data.tar.gz: b220f0b235362602d735a17967c8e87859f864a65df54145ff87ed1a08ed4b650a07908e64513f2adaf558f1d5713dd2d35cd9e84b0e4b66b4e5edf65e2d8239
6
+ metadata.gz: 7e215494da9556e98fe9542a042ff80a64bedbef8071bc920a9653806b629e4876a0708f0b06cb318f69b8cdbc16855dc0704b630df0de83fac3b36225f406a5
7
+ data.tar.gz: 4b77b7a781336fc2534b5a91051e1b66e590eabdc85162dd8ee6aebf4ba1cecb79d29a766d284d0bc849b42b82e025c51e627b543d59981a0756f5e0c31d8065
data/CHANGES.md CHANGED
@@ -1,3 +1,9 @@
1
+ ### 6.0.0.beta5 (2016-09-25)
2
+
3
+ * Elements in collections can now be relocated after going stale
4
+ * Added visible locator to filter out matching elements that are hidden
5
+ * Element not found error messages now include selector information from parent elements
6
+
1
7
  ### 6.0.0.beta4 (2016-09-12)
2
8
 
3
9
  * Deprecate Watir#prefer_css setting
data/lib/watir/browser.rb CHANGED
@@ -311,11 +311,6 @@ module Watir
311
311
  true
312
312
  end
313
313
  end
314
- alias_method :ensure_not_stale, :assert_exists
315
-
316
- def reset!
317
- # no-op
318
- end
319
314
 
320
315
  def browser
321
316
  self
@@ -81,7 +81,9 @@ module Watir
81
81
 
82
82
  def to_a
83
83
  # TODO: optimize - lazy element_class instance?
84
- @to_a ||= elements.map { |e| element_class.new(@query_scope, element: e) }
84
+ @to_a ||= elements.map.with_index do |e, idx|
85
+ element_class.new(@query_scope, @selector.merge(element: e, index: idx))
86
+ end
85
87
  end
86
88
 
87
89
  private
@@ -24,12 +24,13 @@ module Watir
24
24
 
25
25
  def initialize(query_scope, selector)
26
26
  @query_scope = query_scope
27
- @selector = selector
28
- @element = nil
29
27
 
30
- unless @selector.kind_of? Hash
28
+ unless selector.kind_of? Hash
31
29
  raise ArgumentError, "invalid argument: #{selector.inspect}"
32
30
  end
31
+
32
+ @element = selector.delete(:element)
33
+ @selector = selector
33
34
  end
34
35
 
35
36
  #
@@ -47,7 +48,7 @@ module Watir
47
48
  alias_method :exist?, :exists?
48
49
 
49
50
  def inspect
50
- if @selector.key?(:element)
51
+ if @selector.empty?
51
52
  '#<%s:0x%x located=%s selector=%s>' % [self.class, hash*2, !!@element, '{element: (selenium element)}']
52
53
  else
53
54
  '#<%s:0x%x located=%s selector=%s>' % [self.class, hash*2, !!@element, selector_string]
@@ -513,10 +514,11 @@ module Watir
513
514
 
514
515
  # Ensure that the element exists, making sure that it is not stale and located if necessary
515
516
  def assert_exists
516
- @element ||= @selector[:element]
517
-
518
- if @element
519
- ensure_not_stale # ensure not stale
517
+ if @element && @selector.empty?
518
+ ensure_context
519
+ @element = nil if stale?
520
+ elsif @element && !stale?
521
+ return
520
522
  else
521
523
  @element = locate
522
524
  end
@@ -524,27 +526,14 @@ module Watir
524
526
  assert_element_found
525
527
  end
526
528
 
527
- # Ensure that the element isn't stale, by relocating if it is
528
- def ensure_not_stale
529
- ensure_context
530
-
531
- # Performance shortcut; only need recursive call to ensure context if stale in current context
532
- return unless stale?
533
- @element = @selector.key?(:element) ? nil : locate
534
- assert_element_found
535
- end
536
-
537
529
  def assert_element_found
538
530
  unless @element
539
531
  raise UnknownObjectException, "unable to locate element, using #{selector_string}"
540
532
  end
541
533
  end
542
534
 
543
- def reset!
544
- @element = nil
545
- end
546
-
547
535
  def locate
536
+ return if @selector.empty?
548
537
  ensure_context
549
538
 
550
539
  element_validator = element_validator_class.new
@@ -554,6 +543,18 @@ module Watir
554
543
  locator.locate
555
544
  end
556
545
 
546
+ protected
547
+
548
+ def selector_string
549
+ return @selector.inspect if @query_scope.is_a?(Browser)
550
+ query_scope = if @query_scope.is_a?(IFrame)
551
+ @query_scope.element.instance_variable_get("@query_scope")
552
+ else
553
+ @query_scope
554
+ end
555
+ "#{query_scope.selector_string} --> #{@selector.inspect}"
556
+ end
557
+
557
558
  private
558
559
 
559
560
  def locator_class
@@ -578,10 +579,6 @@ module Watir
578
579
  self.class.name.split('::').last
579
580
  end
580
581
 
581
- def selector_string
582
- @selector.inspect
583
- end
584
-
585
582
  # Ensure the driver is in the desired browser context
586
583
  def ensure_context
587
584
  @query_scope.is_a?(IFrame) ? @query_scope.switch_to! : @query_scope.assert_exists
@@ -620,7 +617,7 @@ module Watir
620
617
  def element_call
621
618
  yield
622
619
  rescue Selenium::WebDriver::Error::StaleElementReferenceError
623
- @element = @selector.key?(:element) ? nil : locate
620
+ @element = locate
624
621
  assert_element_found
625
622
  retry
626
623
  end
@@ -2,6 +2,7 @@ module Watir
2
2
  class IFrame < HTMLElement
3
3
 
4
4
  def locate
5
+ return if @selector.empty?
5
6
  @query_scope.assert_exists
6
7
 
7
8
  selector = @selector.merge(tag_name: frame_tag)
@@ -15,6 +16,11 @@ module Watir
15
16
  FramedDriver.new(element, driver)
16
17
  end
17
18
 
19
+ def ==(other)
20
+ return false unless other.is_a?(self.class)
21
+ wd == other.wd.is_a?(FramedDriver) ? other.wd.send(:wd) : other.wd
22
+ end
23
+
18
24
  def switch_to!
19
25
  locate.send :switch!
20
26
  end
@@ -62,28 +68,6 @@ module Watir
62
68
 
63
69
 
64
70
  class IFrameCollection < ElementCollection
65
-
66
- def to_a
67
- # In case `#all_elements` returns empty array, but `#elements`
68
- # returns non-empty array (i.e. any frame has loaded between these two calls),
69
- # index will return nil. That's why `#all_elements` should always
70
- # be called after `#elements.`
71
- element_indexes = elements.map { |el| all_elements.index(el) }
72
- element_indexes.map { |idx| element_class.new(@query_scope, tag_name: @selector[:tag_name], index: idx) }
73
- end
74
-
75
- private
76
-
77
- def all_elements
78
- selector = { tag_name: @selector[:tag_name] }
79
-
80
- element_validator = element_validator_class.new
81
- selector_builder = selector_builder_class.new(@query_scope, selector, element_class.attribute_list)
82
- locator = locator_class.new(@query_scope, selector, selector_builder, element_validator)
83
-
84
- locator.locate_all
85
- end
86
-
87
71
  end # IFrameCollection
88
72
 
89
73
 
@@ -27,32 +27,6 @@ module Watir
27
27
  driver.execute_script "return arguments[0].width", @element
28
28
  end
29
29
 
30
- #
31
- # Returns the image's height in pixels.
32
- #
33
- # @return [Fixnum] width
34
- #
35
-
36
- def height
37
- assert_exists
38
- driver.execute_script "return arguments[0].height", @element
39
- end
40
-
41
- def file_created_date
42
- assert_exists
43
- raise NotImplementedError, "not currently supported by Selenium"
44
- end
45
-
46
- def file_size
47
- assert_exists
48
- raise NotImplementedError, "not currently supported by Selenium"
49
- end
50
-
51
- def save(path)
52
- assert_exists
53
- raise NotImplementedError, "not currently supported by Selenium"
54
- end
55
-
56
30
  end # Image
57
31
 
58
32
  module Container
@@ -8,10 +8,10 @@ module Watir
8
8
  end # Row
9
9
 
10
10
  class RowCollection < TableRowCollection
11
- def elements
11
+ def to_a
12
12
  # we do this craziness since the xpath used will find direct child rows
13
13
  # before any rows inside thead/tbody/tfoot...
14
- super.sort_by { |e| e.attribute(:rowIndex).to_i }
14
+ super.sort_by { |e| e.attribute_value(:rowIndex).to_i }
15
15
  end
16
16
  end
17
17
  end # Watir
@@ -7,13 +7,18 @@ module Watir
7
7
  inherit_attributes_from Watir::TextArea
8
8
  remove_method :type # we want Input#type here, which was overriden by TextArea's attributes
9
9
 
10
- private
10
+ protected
11
11
 
12
12
  def selector_string
13
13
  selector = @selector.dup
14
14
  selector[:type] = '(any text type)'
15
15
  selector[:tag_name] = "input or textarea"
16
- selector.inspect
16
+
17
+ if @query_scope.is_a?(Browser) || @query_scope.is_a?(IFrame)
18
+ super
19
+ else
20
+ "#{@query_scope.selector_string} --> #{selector.inspect}"
21
+ end
17
22
  end
18
23
  end # TextField
19
24
 
@@ -38,11 +38,11 @@ module Watir
38
38
  def locate
39
39
  e = by_id and return e # short-circuit if :id is given
40
40
 
41
- if @selector.size == 1
42
- element = find_first_by_one
43
- else
44
- element = find_first_by_multiple
45
- end
41
+ element = if @selector.size == 1
42
+ find_first_by_one
43
+ else
44
+ find_first_by_multiple
45
+ end
46
46
 
47
47
  # This actually only applies when finding by xpath/css - browser.text_field(:xpath, "//input[@type='radio']")
48
48
  # We don't need to validate the element if we built the xpath ourselves.
@@ -64,16 +64,15 @@ module Watir
64
64
  private
65
65
 
66
66
  def by_id
67
- return unless id = @selector[:id] and id.is_a? String
68
-
69
67
  selector = @selector.dup
70
- selector.delete(:id)
68
+ id = selector.delete(:id)
69
+ return unless id.is_a? String
71
70
 
72
71
  tag_name = selector.delete(:tag_name)
73
72
  return unless selector.empty? # multiple attributes
74
73
 
75
74
  element = @query_scope.wd.find_element(:id, id)
76
- return if tag_name && !element_validator.validate(element, selector)
75
+ return if tag_name && !element_validator.validate(element, {tag_name: tag_name})
77
76
 
78
77
  element
79
78
  end
@@ -93,19 +92,27 @@ module Watir
93
92
  selector = selector_builder.normalized_selector
94
93
 
95
94
  idx = selector.delete(:index)
95
+ visible = selector.delete(:visible)
96
+
96
97
  how, what = selector_builder.build(selector)
97
98
 
98
99
  if how
99
100
  # could build xpath/css for selector
100
- if idx
101
- @query_scope.wd.find_elements(how, what)[idx]
101
+ if idx || !visible.nil?
102
+ idx ||= 0
103
+ elements = @query_scope.wd.find_elements(how, what)
104
+ elements = elements.select { |el| visible == el.displayed? } unless visible.nil?
105
+ elements[idx] unless elements.nil?
102
106
  else
103
107
  @query_scope.wd.find_element(how, what)
104
108
  end
105
109
  else
106
110
  # can't use xpath, probably a regexp in there
107
- if idx
108
- wd_find_by_regexp_selector(selector, :select)[idx]
111
+ if idx || !visible.nil?
112
+ idx ||= 0
113
+ elements = wd_find_by_regexp_selector(selector, :select)
114
+ elements = elements.select { |el| visible == el.displayed? } unless visible.nil?
115
+ elements[idx] unless elements.nil?
109
116
  else
110
117
  wd_find_by_regexp_selector(selector, :find)
111
118
  end
@@ -30,6 +30,10 @@ module Watir
30
30
  unless what.is_a?(Fixnum)
31
31
  raise TypeError, "expected Fixnum, got #{what.inspect}:#{what.class}"
32
32
  end
33
+ when :visible
34
+ unless what.is_a?(TrueClass) || what.is_a?(FalseClass)
35
+ raise TypeError, "expected TrueClass or FalseClass, got #{what.inspect}:#{what.class}"
36
+ end
33
37
  else
34
38
  unless VALID_WHATS.any? { |t| what.is_a? t }
35
39
  raise TypeError, "expected one of #{VALID_WHATS.inspect}, got #{what.inspect}:#{what.class}"
@@ -53,7 +57,7 @@ module Watir
53
57
 
54
58
  def normalize_selector(how, what)
55
59
  case how
56
- when :tag_name, :text, :xpath, :index, :class, :label, :css
60
+ when :tag_name, :text, :xpath, :index, :class, :label, :css, :visible
57
61
  # include :class since the valid attribute is 'class_name'
58
62
  # include :for since the valid attribute is 'html_for'
59
63
  [how, what]
data/lib/watir/window.rb CHANGED
@@ -200,13 +200,13 @@ module Watir
200
200
  @handle ||= locate
201
201
  end
202
202
 
203
- private
204
-
205
203
  # Referenced in EventuallyPresent
206
204
  def selector_string
207
205
  @selector.inspect
208
206
  end
209
207
 
208
+ private
209
+
210
210
  def locate
211
211
  if @selector.empty?
212
212
  nil
data/spec/element_spec.rb CHANGED
@@ -49,34 +49,24 @@ describe Watir::Element do
49
49
  end
50
50
  end
51
51
 
52
- describe "#reset!" do
53
- it "successfully relocates collection elements after a reset!" do
54
- browser.goto(WatirSpec.url_for("wait.html"))
55
- element = browser.div(id: 'foo')
56
- expect(element).to exist
57
- browser.refresh
58
- browser.div(id: 'foo').wait_until_present
59
-
60
- expect(element.exist?).to be false unless Watir.always_locate?
61
- element.send :reset!
62
- expect(element).to exist
63
- end
64
- end
65
-
66
52
  describe "#exists?" do
67
53
  before do
68
54
  browser.goto WatirSpec.url_for('removed_element.html')
69
55
  end
70
56
 
71
- it "returns false when an element from a collection becomes stale" do
57
+ it "relocates element from a collection when it becomes stale" do
72
58
  watir_element = browser.divs(id: "text").first
73
59
  expect(watir_element).to exist
74
60
 
75
61
  browser.refresh
76
62
 
77
- expect(watir_element).to_not exist
63
+ expect(watir_element).to exist
78
64
  end
79
65
 
66
+ it "returns false when tag name does not match id" do
67
+ watir_element = browser.span(id: "text")
68
+ expect(watir_element).to_not exist
69
+ end
80
70
  end
81
71
 
82
72
  describe "#element_call" do
@@ -129,4 +119,34 @@ describe Watir::Element do
129
119
  end.to output.to_stderr
130
120
  end
131
121
  end
122
+
123
+ describe "#selector_string" do
124
+ it "displays selector string for regular element" do
125
+ browser.goto(WatirSpec.url_for("wait.html"))
126
+ delegator = browser.div(:id, 'foo').when_present
127
+ message = delegator.instance_variable_get('@message')
128
+ expect(message).to eq 'waiting for {:id=>"foo", :tag_name=>"div"} to become present'
129
+ end
130
+
131
+ it "displays selector string for element from colection" do
132
+ browser.goto(WatirSpec.url_for("wait.html"))
133
+ delegator = browser.divs.last.when_present
134
+ message = delegator.instance_variable_get('@message')
135
+ expect(message).to match /waiting for {:tag_name=>\"div\", :index=>3} to become present/
136
+ end
137
+
138
+ it "displays selector string for nested element" do
139
+ browser.goto(WatirSpec.url_for("wait.html"))
140
+ delegator = browser.div(index: -1).div(:id, 'foo').when_present
141
+ message = delegator.instance_variable_get('@message')
142
+ expect(message).to eq 'waiting for {:index=>-1, :tag_name=>"div"} --> {:id=>"foo", :tag_name=>"div"} to become present'
143
+ end
144
+
145
+ it "displays selector string for nested element under frame" do
146
+ browser.goto(WatirSpec.url_for("nested_iframes.html"))
147
+ delegator = browser.iframe(id: 'one').iframe(:id, 'three').when_present
148
+ message = delegator.instance_variable_get('@message')
149
+ expect(message).to eq 'waiting for {:id=>"one", :tag_name=>"iframe"} --> {:id=>"three", :tag_name=>"iframe"} to become present'
150
+ end
151
+ end
132
152
  end
data/watir.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'watir'
5
- s.version = '6.0.0.beta4'
5
+ s.version = '6.0.0.beta5'
6
6
  s.platform = Gem::Platform::RUBY
7
7
  s.authors = ['Alex Rodionov', 'Titus Fortner']
8
8
  s.email = ['p0deje@gmail.com', 'titusfortner@gmail.com']
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: watir
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.0.beta4
4
+ version: 6.0.0.beta5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Rodionov
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-09-13 00:00:00.000000000 Z
12
+ date: 2016-09-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: selenium-webdriver