watir 6.0.0.beta4 → 6.0.0.beta5

Sign up to get free protection for your applications and to get access to all the features.
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