ae_page_objects 1.4.1 → 1.5.0

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: 62a7c4ae245bff142532db643f26fd8d86cbeec5
4
- data.tar.gz: 7f08f9ba3ee29135124a6002eee99235e19854ea
3
+ metadata.gz: bdbc7b1c3cc7929e18cae25d6b5a0073bc941d85
4
+ data.tar.gz: 0767bbea656f6a123d00c2dae7c00673714272d3
5
5
  SHA512:
6
- metadata.gz: 360cc60ce2ff2ce7b5f4a4ca67ccc2c840df1a2aea9ca16fdad34629a3e9aba0d153c17514287b5be2756c12289d1f924f2f12477d7b2f4f9c6597dd8bb79213
7
- data.tar.gz: 16c0429209abafbccdc3e699d41426455ae54adf340ac9398cfa885b11768c77a3223583be15e016b12ae5adba359153fae0a619aacb441dff3730c99c95c11f
6
+ metadata.gz: 12c29ba3329811692f161d16a46dc95bf187492c49585295e183f2d63bc356420a3ea76a4cb158b77f49db322517f18b674020741424389427f975c7189d3fb9
7
+ data.tar.gz: fa23580da483d787a283c96ac7495780ff52b17dd7563892aa4e89bed21205e15a97b64de1a547aafeb373f3391496fce569bf1f933d443b241e9e15eeca5d63
@@ -18,12 +18,6 @@ module AePageObjects
18
18
  autoload :Inflector, 'ae_page_objects/util/inflector'
19
19
  autoload :Waiter, 'ae_page_objects/util/waiter'
20
20
 
21
- module Concerns
22
- autoload :LoadEnsuring, 'ae_page_objects/concerns/load_ensuring'
23
- autoload :Staleable, 'ae_page_objects/concerns/staleable'
24
- autoload :Visitable, 'ae_page_objects/concerns/visitable'
25
- end
26
-
27
21
  module MultipleWindows
28
22
  autoload :Browser, 'ae_page_objects/multiple_windows/browser'
29
23
  autoload :Window, 'ae_page_objects/multiple_windows/window'
@@ -66,6 +60,24 @@ module AePageObjects
66
60
  end
67
61
  end
68
62
  end
63
+
64
+ def self.wait_until(seconds_to_wait = nil, error_message = nil)
65
+ seconds_to_wait ||= Capybara.default_wait_time
66
+ start_time = Time.now
67
+
68
+ until result = yield
69
+ delay = seconds_to_wait - (Time.now - start_time)
70
+
71
+ if delay <= 0
72
+ raise WaitTimeoutError, error_message || "Timed out waiting for condition"
73
+ end
74
+
75
+ sleep(0.05)
76
+ raise FrozenInTime, "Time appears to be frozen" if Time.now == start_time
77
+ end
78
+
79
+ result
80
+ end
69
81
  end
70
82
 
71
83
  require 'ae_page_objects/core_ext/module'
@@ -1,6 +1,46 @@
1
1
  module AePageObjects
2
2
  class Document < Node
3
- include Concerns::Visitable
3
+ class << self
4
+ def can_load_from_current_url?
5
+ return true if paths.empty?
6
+
7
+ url = current_url_without_params
8
+
9
+ paths.any? do |path|
10
+ site.path_recognizes_url?(path, url)
11
+ end
12
+ end
13
+
14
+ def visit(*args)
15
+ args = args.dup
16
+ inner_options = args.last.is_a?(::Hash)? args.last : {}
17
+
18
+ path = inner_options.delete(:via) || paths.first
19
+
20
+ full_path = site.generate_path(path, *args)
21
+ raise PathNotResolvable, "#{self.name} not visitable via #{paths.first}(#{args.inspect})" unless full_path
22
+
23
+ Capybara.current_session.visit(full_path)
24
+
25
+ new
26
+ end
27
+
28
+ private
29
+
30
+ def paths
31
+ @paths ||= []
32
+ end
33
+
34
+ def path(path_method)
35
+ raise ArgumentError, "path must be a symbol or string" if ! path_method.is_a?(Symbol) && ! path_method.is_a?(String)
36
+
37
+ paths << path_method
38
+ end
39
+
40
+ def site
41
+ @site ||= Site.from(self)
42
+ end
43
+ end
4
44
 
5
45
  attr_reader :window
6
46
 
@@ -19,10 +59,19 @@ module AePageObjects
19
59
  self
20
60
  end
21
61
 
22
- class << self
23
62
  private
24
- def site
25
- @site ||= Site.from(self)
63
+
64
+ def ensure_loaded!
65
+ begin
66
+ AePageObjects.wait_until { self.class.can_load_from_current_url? }
67
+ rescue WaitTimeoutError
68
+ raise LoadingPageFailed, "#{self.class.name} cannot be loaded with url '#{current_url_without_params}'"
69
+ end
70
+
71
+ begin
72
+ super
73
+ rescue LoadingElementFailed => e
74
+ raise LoadingPageFailed, e.message
26
75
  end
27
76
  end
28
77
  end
@@ -1,19 +1,26 @@
1
+ require 'ae_page_objects/util/page_polling'
2
+
1
3
  module AePageObjects
2
4
  class DocumentLoader
5
+ include AePageObjects::PagePolling
6
+
3
7
  def initialize(query, strategy)
4
8
  @query = query
5
9
  @strategy = strategy
6
10
  end
7
11
 
8
12
  def load
9
- Waiter.wait_until do
10
- @query.conditions.each do |document_condition|
11
- if document = @strategy.load_document_with_condition(document_condition)
12
- return document
13
+ begin
14
+ poll_until do
15
+ @query.conditions.each do |document_condition|
16
+ if document = @strategy.load_document_with_condition(document_condition)
17
+ return document
18
+ end
13
19
  end
14
- end
15
20
 
16
- nil
21
+ nil
22
+ end
23
+ rescue AePageObjects::WaitTimeoutError
17
24
  end
18
25
 
19
26
  raise DocumentLoadError, @strategy.document_not_loaded_error_message(@query)
@@ -1,6 +1,7 @@
1
+ require 'ae_page_objects/util/page_polling'
2
+
1
3
  module AePageObjects
2
4
  class ElementProxy
3
-
4
5
  # Remove all instance methods so even things like class()
5
6
  # get handled by method_missing(). <lifted from activerecord>
6
7
  instance_methods.each do |m|
@@ -9,6 +10,8 @@ module AePageObjects
9
10
  end
10
11
  end
11
12
 
13
+ include AePageObjects::PagePolling
14
+
12
15
  def initialize(element_class, *args)
13
16
  @element_class = element_class
14
17
  @args = args
@@ -61,35 +64,30 @@ module AePageObjects
61
64
  end
62
65
 
63
66
  def wait_until_visible(timeout = nil)
64
- is_visible = Waiter.wait_until(timeout) do
65
- inst = presence
66
- ! inst.nil? && inst.visible?
67
+ with_reloaded_element(timeout) do
68
+ !@loaded_element.nil? && @loaded_element.visible?
67
69
  end
68
70
 
69
- unless is_visible
70
- raise ElementNotVisible, "element_class: #{@element_class}, options: #{@options.inspect}"
71
- end
71
+ rescue AePageObjects::WaitTimeoutError
72
+ raise ElementNotVisible, "element_class: #{@element_class}, options: #{@options.inspect}"
72
73
  end
73
74
 
74
75
  def wait_until_hidden(timeout = nil)
75
- is_hidden = Waiter.wait_until(timeout) do
76
- inst = presence
77
- inst.nil? || ! inst.visible?
76
+ with_reloaded_element(timeout) do
77
+ @loaded_element.nil? || !@loaded_element.visible?
78
78
  end
79
79
 
80
- unless is_hidden
81
- raise ElementNotHidden, "element_class: #{@element_class}, options: #{@options.inspect}"
82
- end
80
+ rescue AePageObjects::WaitTimeoutError
81
+ raise ElementNotHidden, "element_class: #{@element_class}, options: #{@options.inspect}"
83
82
  end
84
83
 
85
84
  def wait_until_present(timeout = nil)
86
- is_present = Waiter.wait_until(timeout) do
87
- ! presence.nil?
85
+ with_reloaded_element(timeout) do
86
+ !@loaded_element.nil?
88
87
  end
89
88
 
90
- unless is_present
91
- raise ElementNotPresent, "element_class: #{@element_class}, options: #{@options.inspect}"
92
- end
89
+ rescue AePageObjects::WaitTimeoutError
90
+ raise ElementNotPresent, "element_class: #{@element_class}, options: #{@options.inspect}"
93
91
  end
94
92
 
95
93
  def wait_for_presence(timeout = nil)
@@ -98,13 +96,12 @@ module AePageObjects
98
96
  end
99
97
 
100
98
  def wait_until_absent(timeout = nil)
101
- is_absent = Waiter.wait_until(timeout) do
102
- check_absence
99
+ with_reloaded_element(timeout) do
100
+ @loaded_element.nil?
103
101
  end
104
102
 
105
- unless is_absent
106
- raise ElementNotAbsent, "element_class: #{@element_class}, options: #{@options.inspect}"
107
- end
103
+ rescue AePageObjects::WaitTimeoutError
104
+ raise ElementNotAbsent, "element_class: #{@element_class}, options: #{@options.inspect}"
108
105
  end
109
106
 
110
107
  def wait_for_absence(timeout = nil)
@@ -132,7 +129,7 @@ module AePageObjects
132
129
  super || @element_class.allocate.respond_to?(*args)
133
130
  end
134
131
 
135
- private
132
+ private
136
133
 
137
134
  def load_element
138
135
  @element_class.new(*@args)
@@ -142,20 +139,30 @@ module AePageObjects
142
139
  @loaded_element ||= load_element
143
140
  end
144
141
 
145
- def check_absence
146
- load_element
142
+ def reload_element
143
+ @loaded_element = load_element
147
144
 
148
- false
145
+ true
149
146
  rescue LoadingElementFailed
147
+ @loaded_element = nil
148
+
150
149
  true
151
150
  rescue => e
152
151
  if Capybara.current_session.driver.is_a?(Capybara::Selenium::Driver) &&
153
152
  e.is_a?(Selenium::WebDriver::Error::StaleElementReferenceError)
154
- # ignore and spin around for another check
153
+
154
+ # Inconclusive. Leave the handling up to the caller
155
155
  false
156
156
  else
157
157
  raise
158
158
  end
159
159
  end
160
+
161
+ def with_reloaded_element(timeout)
162
+ poll_until(timeout) do
163
+ reload_conclusive = reload_element
164
+ reload_conclusive && yield
165
+ end
166
+ end
160
167
  end
161
168
  end
@@ -1,66 +1,86 @@
1
1
  module AePageObjects
2
2
  class Node
3
- module Methods
4
- def initialize(capybara_node)
5
- @node = capybara_node
6
- end
7
-
8
- def node
9
- @node
10
- end
11
-
12
- def document
13
- raise "Must implement!"
14
- end
3
+ extend Dsl
15
4
 
5
+ class << self
16
6
  def current_url
17
- self.class.current_url
7
+ Capybara.current_session.current_url.sub(/^https?:\/\/[^\/]*/, '')
18
8
  end
19
9
 
20
10
  def current_url_without_params
21
- self.class.current_url_without_params
11
+ current_url.sub(/(\?|\#).*/, '')
22
12
  end
13
+ end
14
+
15
+ def initialize(capybara_node)
16
+ @node = capybara_node
17
+ @stale = false
23
18
 
24
- METHODS_TO_DELEGATE_TO_NODE = [:find, :all, :value, :set, :text, :visible?]
25
- METHODS_TO_DELEGATE_TO_NODE.each do |m|
26
- class_eval <<-RUBY
27
- def #{m}(*args, &block)
28
- node.send(:#{m}, *args, &block)
29
- rescue Capybara::ElementNotFound => e
30
- raise LoadingElementFailed, e.message
31
- end
32
- RUBY
19
+ ensure_loaded!
20
+ end
21
+
22
+ def node
23
+ if stale?
24
+ raise StalePageObject, "Can't access stale page object '#{self}'"
33
25
  end
34
26
 
35
- private
27
+ @node
28
+ end
36
29
 
37
- def eval_locator(locator)
38
- return [] unless locator
30
+ def stale?
31
+ @stale
32
+ end
39
33
 
40
- if locator.respond_to?(:call)
41
- locator = instance_eval(&locator)
42
- end
34
+ def stale!
35
+ @stale = true
36
+ end
43
37
 
44
- locator.is_a?(Array) ? locator : [locator.to_s]
45
- end
38
+ def document
39
+ raise "Must implement!"
46
40
  end
47
41
 
48
- module ClassMethods
49
- def current_url
50
- Capybara.current_session.current_url.sub(/^https?:\/\/[^\/]*/, '')
51
- end
42
+ def current_url
43
+ self.class.current_url
44
+ end
52
45
 
53
- def current_url_without_params
54
- current_url.sub(/(\?|\#).*/, '')
46
+ def current_url_without_params
47
+ self.class.current_url_without_params
48
+ end
49
+
50
+ METHODS_TO_DELEGATE_TO_NODE = [:find, :all, :value, :set, :text, :visible?]
51
+ METHODS_TO_DELEGATE_TO_NODE.each do |m|
52
+ class_eval <<-RUBY
53
+ def #{m}(*args, &block)
54
+ node.send(:#{m}, *args, &block)
55
+ rescue Capybara::ElementNotFound => e
56
+ raise LoadingElementFailed, e.message
57
+ end
58
+ RUBY
59
+ end
60
+
61
+ private
62
+
63
+ def eval_locator(locator)
64
+ return [] unless locator
65
+
66
+ if locator.respond_to?(:call)
67
+ locator = instance_eval(&locator)
55
68
  end
69
+
70
+ locator.is_a?(Array) ? locator : [locator.to_s]
56
71
  end
57
72
 
58
- extend Dsl
73
+ def loaded_locator
74
+ end
59
75
 
60
- include Methods
61
- extend ClassMethods
76
+ def ensure_loaded!
77
+ if locator = loaded_locator
78
+ find(*eval_locator(locator))
79
+ end
62
80
 
63
- include Concerns::LoadEnsuring
64
- include Concerns::Staleable
81
+ self
82
+ rescue Capybara::ElementNotFound => e
83
+ raise LoadingElementFailed, e.message
84
+ end
65
85
  end
66
86
  end
@@ -8,7 +8,7 @@ module AePageObjects
8
8
  end
9
9
 
10
10
  def current_document=(document)
11
- @current_document.send(:stale!) if @current_document
11
+ @current_document.stale! if @current_document
12
12
  @current_document = document
13
13
  end
14
14
 
@@ -0,0 +1,12 @@
1
+ module AePageObjects
2
+ module PagePolling
3
+
4
+ private
5
+
6
+ def poll_until(timeout = nil, &block)
7
+ AePageObjects.wait_until(timeout) do
8
+ Capybara.using_wait_time(0, &block)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,38 +1,32 @@
1
+ require 'ae_page_objects/util/page_polling'
2
+
1
3
  module AePageObjects
2
4
  module Waiter
3
- def self.wait_until(timeout = nil, &block)
4
- seconds_to_wait = timeout || Capybara.default_wait_time
5
- start_time = Time.now
6
-
7
- until result = Capybara.using_wait_time(0, &block)
8
- delay = seconds_to_wait - (Time.now - start_time)
9
-
10
- if delay <= 0
11
- return false
12
- end
5
+ class << self
6
+ include AePageObjects::PagePolling
13
7
 
14
- sleep(0.05)
15
- raise FrozenInTime, "Time appears to be frozen" if Time.now == start_time
8
+ def wait_until(timeout = nil, &block)
9
+ warn "[DEPRECATION WARNING]: AePageObjects::Waiter.wait_until is deprecated and will be removed in version 2.0.0. Use AePageObjects.wait_until instead."
10
+ wait_until_return_false(timeout, &block)
16
11
  end
17
12
 
18
- result
19
- end
20
-
21
- def self.wait_for(*args, &block)
22
- warn "[DEPRECATION WARNING]: AePageObjects::Waiter.wait_for is deprecated and will be removed in version 2.0.0. Use AePageObjects::Waiter.wait_until instead."
23
- wait_until(*args, &block)
24
- end
25
-
26
- def self.wait_until!(timeout = nil)
27
- result = wait_until(timeout) do
28
- yield
13
+ def wait_for(timeout = nil, &block)
14
+ warn "[DEPRECATION WARNING]: AePageObjects::Waiter.wait_for is deprecated and will be removed in version 2.0.0. Use AePageObjects.wait_until instead."
15
+ wait_until_return_false(timeout, &block)
29
16
  end
30
17
 
31
- unless result
32
- raise WaitTimeoutError, "Timed out waiting for condition"
18
+ def wait_until!(timeout = nil, &block)
19
+ warn "[DEPRECATION WARNING]: AePageObjects::Waiter.wait_until! is deprecated and will be removed in version 2.0.0. Use AePageObjects.wait_until instead."
20
+ poll_until(timeout, &block)
33
21
  end
34
22
 
35
- result
23
+ private
24
+
25
+ def wait_until_return_false(timeout, &block)
26
+ poll_until(timeout, &block)
27
+ rescue WaitTimeoutError
28
+ false
29
+ end
36
30
  end
37
31
  end
38
32
  end
@@ -1,3 +1,3 @@
1
1
  module AePageObjects
2
- VERSION = '1.4.1'.freeze
2
+ VERSION = '1.5.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ae_page_objects
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.1
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Donnie Tognazzini
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-28 00:00:00.000000000 Z
11
+ date: 2016-05-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: capybara
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: '1.1'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '2.3'
22
+ version: '2.8'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: '1.1'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '2.3'
32
+ version: '2.8'
33
33
  description: Capybara Page Objects pattern
34
34
  email:
35
35
  - engineering@appfolio.com
@@ -38,9 +38,6 @@ extensions: []
38
38
  extra_rdoc_files: []
39
39
  files:
40
40
  - lib/ae_page_objects.rb
41
- - lib/ae_page_objects/concerns/load_ensuring.rb
42
- - lib/ae_page_objects/concerns/staleable.rb
43
- - lib/ae_page_objects/concerns/visitable.rb
44
41
  - lib/ae_page_objects/core/application_router.rb
45
42
  - lib/ae_page_objects/core/basic_router.rb
46
43
  - lib/ae_page_objects/core/dsl.rb
@@ -71,6 +68,7 @@ files:
71
68
  - lib/ae_page_objects/util/hash_symbolizer.rb
72
69
  - lib/ae_page_objects/util/inflector.rb
73
70
  - lib/ae_page_objects/util/internal_helpers.rb
71
+ - lib/ae_page_objects/util/page_polling.rb
74
72
  - lib/ae_page_objects/util/singleton.rb
75
73
  - lib/ae_page_objects/util/waiter.rb
76
74
  - lib/ae_page_objects/version.rb
@@ -1,26 +0,0 @@
1
- module AePageObjects
2
- module Concerns
3
- module LoadEnsuring
4
-
5
- def initialize(*args)
6
- super
7
- ensure_loaded!
8
- end
9
-
10
- private
11
-
12
- def loaded_locator
13
- end
14
-
15
- def ensure_loaded!
16
- if locator = loaded_locator
17
- find(*eval_locator(locator))
18
- end
19
-
20
- self
21
- rescue Capybara::ElementNotFound => e
22
- raise LoadingElementFailed, e.message
23
- end
24
- end
25
- end
26
- end
@@ -1,25 +0,0 @@
1
- module AePageObjects
2
- module Concerns
3
- module Staleable
4
-
5
- def stale?
6
- !!@stale
7
- end
8
-
9
- def node
10
- if stale?
11
- raise StalePageObject, "Can't access stale page object '#{self}'"
12
- end
13
-
14
- super
15
- end
16
-
17
- private
18
-
19
- def stale!
20
- @stale = true
21
- end
22
-
23
- end
24
- end
25
- end
@@ -1,66 +0,0 @@
1
- module AePageObjects
2
- module Concerns
3
- module Visitable
4
-
5
- def self.included(target)
6
- target.extend ClassMethods
7
- end
8
-
9
- private
10
-
11
- def ensure_loaded!
12
- unless Waiter.wait_until { self.class.can_load_from_current_url? }
13
- raise LoadingPageFailed, "#{self.class.name} cannot be loaded with url '#{current_url_without_params}'"
14
- end
15
-
16
- begin
17
- super
18
- rescue LoadingElementFailed => e
19
- raise LoadingPageFailed, e.message
20
- end
21
- end
22
-
23
- module VisitMethod
24
- def visit(*args)
25
- args = args.dup
26
- inner_options = args.last.is_a?(::Hash)? args.last : {}
27
-
28
- path = inner_options.delete(:via) || paths.first
29
-
30
- full_path = site.generate_path(path, *args)
31
- raise PathNotResolvable, "#{self.name} not visitable via #{paths.first}(#{args.inspect})" unless full_path
32
-
33
- Capybara.current_session.visit(full_path)
34
- new
35
- end
36
- end
37
-
38
- module ClassMethods
39
-
40
- def can_load_from_current_url?
41
- return true if paths.empty?
42
-
43
- url = current_url_without_params
44
-
45
- paths.any? do |path|
46
- site.path_recognizes_url?(path, url)
47
- end
48
- end
49
-
50
- private
51
-
52
- def paths
53
- @paths ||= []
54
- end
55
-
56
- def path(path_method)
57
- raise ArgumentError, "path must be a symbol or string" if ! path_method.is_a?(Symbol) && ! path_method.is_a?(String)
58
-
59
- paths << path_method
60
-
61
- extend VisitMethod
62
- end
63
- end
64
- end
65
- end
66
- end