site_prism 2.15 → 2.15.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +9 -9
- data/lib/site_prism.rb +1 -1
- data/lib/site_prism/addressable_url_matcher.rb +18 -18
- data/lib/site_prism/element_container.rb +6 -6
- data/lib/site_prism/error.rb +90 -0
- data/lib/site_prism/loadable.rb +5 -2
- data/lib/site_prism/section.rb +7 -5
- data/lib/site_prism/version.rb +1 -1
- metadata +11 -11
- data/lib/site_prism/exceptions.rb +0 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 77f8efa7a200630bd4f6bb6c79afeb4e8e2a018f
|
4
|
+
data.tar.gz: ab7dd809c5018e60bbeb754e1c450c8cfc19b8a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f3c9f957a980efd3262f028b211c8bb52a53d415a08e79e3b950b8d2ee90dad48bf74c2bd92a202f2fa4a4bae7f60d08d15d2176f539561ddfca7d98f81ce376
|
7
|
+
data.tar.gz: 3eba16133d0b5d874455f863aac542101137e446d3b81bd2e404f65dc69164572b2c5ff261db1b31cf2c797555ac9ada8166828e1ca2d1c34832db690c15ab64
|
data/README.md
CHANGED
@@ -13,7 +13,7 @@ Make sure to add your project/company to https://github.com/natritmeyer/site_pri
|
|
13
13
|
|
14
14
|
We love it when people want to get involved with our Open Source Project.
|
15
15
|
|
16
|
-
We have a brief set of setup docs [HERE](https://github.com/natritmeyer/site_prism/development_setup.md)
|
16
|
+
We have a brief set of setup docs [HERE](https://github.com/natritmeyer/site_prism/blob/master/development_setup.md)
|
17
17
|
|
18
18
|
## Supported Rubies / Browsers
|
19
19
|
|
@@ -35,7 +35,7 @@ class Home < SitePrism::Page
|
|
35
35
|
set_url_matcher /google.com\/?/
|
36
36
|
|
37
37
|
element :search_field, 'input[name="q"]'
|
38
|
-
element :search_button,
|
38
|
+
element :search_button, 'button[name="btnK"]'
|
39
39
|
elements :footer_links, '#footer a'
|
40
40
|
section :menu, MenuSection, '#gbx3'
|
41
41
|
end
|
@@ -47,7 +47,7 @@ class SearchResults < SitePrism::Page
|
|
47
47
|
sections :search_results, SearchResultSection, '#results li'
|
48
48
|
|
49
49
|
def search_result_links
|
50
|
-
search_results.map {|
|
50
|
+
search_results.map { |result| result.title['href'] }
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
@@ -79,7 +79,7 @@ Then(/^the home page should contain the menu and the search form$/) do
|
|
79
79
|
end
|
80
80
|
|
81
81
|
When(/^I search for Sausages$/) do
|
82
|
-
@home.search_field.set
|
82
|
+
@home.search_field.set 'Sausages'
|
83
83
|
@home.search_button.click
|
84
84
|
end
|
85
85
|
|
@@ -195,7 +195,7 @@ a simple example:
|
|
195
195
|
|
196
196
|
```ruby
|
197
197
|
class UserProfile < SitePrism::Page
|
198
|
-
set_url
|
198
|
+
set_url '/users{/username}'
|
199
199
|
end
|
200
200
|
```
|
201
201
|
|
@@ -203,7 +203,7 @@ end
|
|
203
203
|
|
204
204
|
```ruby
|
205
205
|
class Search < SitePrism::Page
|
206
|
-
set_url
|
206
|
+
set_url '/search{?query*}'
|
207
207
|
end
|
208
208
|
```
|
209
209
|
|
@@ -225,7 +225,7 @@ The `#load` method takes parameters and will apply them to the URL. Using the ex
|
|
225
225
|
|
226
226
|
```ruby
|
227
227
|
class UserProfile < SitePrism::Page
|
228
|
-
set_url
|
228
|
+
set_url '/users{/username}'
|
229
229
|
end
|
230
230
|
|
231
231
|
@user_profile = UserProfile.new
|
@@ -237,7 +237,7 @@ end
|
|
237
237
|
|
238
238
|
```ruby
|
239
239
|
class Search < SitePrism::Page
|
240
|
-
set_url
|
240
|
+
set_url '/search{?query*}'
|
241
241
|
end
|
242
242
|
|
243
243
|
@search = Search.new
|
@@ -259,7 +259,7 @@ currently viewed page. For example, with the following URL template:
|
|
259
259
|
|
260
260
|
```ruby
|
261
261
|
class Account < SitePrism::Page
|
262
|
-
set_url
|
262
|
+
set_url '/accounts/{id}{?query*}'
|
263
263
|
end
|
264
264
|
```
|
265
265
|
|
data/lib/site_prism.rb
CHANGED
@@ -5,11 +5,6 @@ require 'base64'
|
|
5
5
|
|
6
6
|
module SitePrism
|
7
7
|
class AddressableUrlMatcher
|
8
|
-
COMPONENT_NAMES = %i[scheme user password host
|
9
|
-
port path query fragment ].freeze
|
10
|
-
|
11
|
-
COMPONENT_PREFIXES = { query: '?', fragment: '#' }.freeze
|
12
|
-
|
13
8
|
attr_reader :pattern
|
14
9
|
|
15
10
|
def initialize(pattern)
|
@@ -22,7 +17,7 @@ module SitePrism
|
|
22
17
|
def mappings(url)
|
23
18
|
uri = Addressable::URI.parse(url)
|
24
19
|
result = {}
|
25
|
-
|
20
|
+
component_names.each do |component|
|
26
21
|
component_result = component_matches(component, uri)
|
27
22
|
return nil unless component_result
|
28
23
|
|
@@ -62,7 +57,7 @@ module SitePrism
|
|
62
57
|
end
|
63
58
|
|
64
59
|
def extract_component_templates
|
65
|
-
|
60
|
+
component_names.each_with_object({}) do |component, templates|
|
66
61
|
component_url = to_substituted_uri.public_send(component).to_s
|
67
62
|
|
68
63
|
next unless component_url && !component_url.empty?
|
@@ -71,15 +66,13 @@ module SitePrism
|
|
71
66
|
component_url = component_url.sub(substituted_value, template_value)
|
72
67
|
end
|
73
68
|
|
74
|
-
|
75
|
-
Addressable::Template.new(component_url.to_s)
|
69
|
+
templates[component] = Addressable::Template.new(component_url)
|
76
70
|
end
|
77
71
|
end
|
78
72
|
|
79
|
-
# Returns empty hash if the template omits the component
|
80
|
-
#
|
81
|
-
#
|
82
|
-
# or nil if the match fails.
|
73
|
+
# Returns empty hash if the template omits the component or a set of
|
74
|
+
# substitutions if the provided URI component matches the template
|
75
|
+
# component or nil if the match fails.
|
83
76
|
def component_matches(component, uri)
|
84
77
|
component_template = component_templates[component]
|
85
78
|
return {} unless component_template
|
@@ -88,7 +81,7 @@ module SitePrism
|
|
88
81
|
return mappings if mappings
|
89
82
|
# to support Addressable's expansion of queries
|
90
83
|
# ensure it's parsing the fragment as appropriate (e.g. {?params*})
|
91
|
-
prefix =
|
84
|
+
prefix = component_prefixes[component]
|
92
85
|
return nil unless prefix
|
93
86
|
component_template.extract(prefix + component_url)
|
94
87
|
end
|
@@ -129,10 +122,9 @@ module SitePrism
|
|
129
122
|
pattern.scan(/{[^}]+}/)
|
130
123
|
end
|
131
124
|
|
132
|
-
# If a slug begins with non-alpha characters,
|
133
|
-
#
|
134
|
-
#
|
135
|
-
# so that Addressable's URI parser can see it as such.
|
125
|
+
# If a slug begins with non-alpha characters, it may denote the start of
|
126
|
+
# a new component (e.g. query or fragment). We emit thie prefix as part of
|
127
|
+
# the substituted slug so that Addressable's URI parser can see it as such.
|
136
128
|
def slug_prefix(slug)
|
137
129
|
prefix = slug.match(/\A{([^A-Za-z]+)/)
|
138
130
|
prefix && prefix[1] || ''
|
@@ -144,5 +136,13 @@ module SitePrism
|
|
144
136
|
sha = Digest::SHA1.digest(index.to_s)
|
145
137
|
Base64.urlsafe_encode64(sha).gsub(/[^A-Za-z]/, '')[0..5]
|
146
138
|
end
|
139
|
+
|
140
|
+
def component_names
|
141
|
+
%i[scheme user password host port path query fragment]
|
142
|
+
end
|
143
|
+
|
144
|
+
def component_prefixes
|
145
|
+
{ query: '?', fragment: '#' }
|
146
|
+
end
|
147
147
|
end
|
148
148
|
end
|
@@ -12,8 +12,9 @@ module SitePrism
|
|
12
12
|
Capybara.default_max_wait_time
|
13
13
|
end
|
14
14
|
|
15
|
-
def raise_if_block(obj, name, has_block)
|
15
|
+
def raise_if_block(obj, name, has_block, type)
|
16
16
|
return unless has_block
|
17
|
+
warn "Type passed in: #{type}"
|
17
18
|
|
18
19
|
raise SitePrism::UnsupportedBlock, "#{obj.class}##{name}"
|
19
20
|
end
|
@@ -62,7 +63,7 @@ module SitePrism
|
|
62
63
|
def element(name, *find_args)
|
63
64
|
build(name, *find_args) do
|
64
65
|
define_method(name) do |*runtime_args, &element_block|
|
65
|
-
raise_if_block(self, name, !element_block.nil
|
66
|
+
raise_if_block(self, name, !element_block.nil?, :element)
|
66
67
|
_find(*merge_args(find_args, runtime_args))
|
67
68
|
end
|
68
69
|
end
|
@@ -71,7 +72,7 @@ module SitePrism
|
|
71
72
|
def elements(name, *find_args)
|
72
73
|
build(name, *find_args) do
|
73
74
|
define_method(name) do |*runtime_args, &element_block|
|
74
|
-
raise_if_block(self, name, !element_block.nil
|
75
|
+
raise_if_block(self, name, !element_block.nil?, :elements)
|
75
76
|
_all(*merge_args(find_args, runtime_args))
|
76
77
|
end
|
77
78
|
end
|
@@ -101,7 +102,7 @@ module SitePrism
|
|
101
102
|
section_class, find_args = extract_section_options(args, &block)
|
102
103
|
build(name, *find_args) do
|
103
104
|
define_method(name) do |*runtime_args, &element_block|
|
104
|
-
raise_if_block(self, name, !element_block.nil
|
105
|
+
raise_if_block(self, name, !element_block.nil?, :sections)
|
105
106
|
_all(*merge_args(find_args, runtime_args)).map do |element|
|
106
107
|
section_class.new(self, element)
|
107
108
|
end
|
@@ -238,8 +239,7 @@ module SitePrism
|
|
238
239
|
|
239
240
|
def create_no_selector(method_name)
|
240
241
|
define_method(method_name) do
|
241
|
-
raise SitePrism::NoSelectorForElement.
|
242
|
-
"#{self.class.name} => :#{method_name} needs a selector"
|
242
|
+
raise SitePrism::NoSelectorForElement, "#{self.class}##{method_name}"
|
243
243
|
end
|
244
244
|
end
|
245
245
|
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SitePrism
|
4
|
+
# Generic SitePrism family of errors which specific errors are children of
|
5
|
+
class SitePrismError < StandardError; end
|
6
|
+
|
7
|
+
# Generic PageLoad family of errors inherit from this error
|
8
|
+
class PageLoadError < SitePrismError; end
|
9
|
+
|
10
|
+
# A page calls #load with no URL set
|
11
|
+
class NoUrlForPageError < PageLoadError; end
|
12
|
+
|
13
|
+
# A page calls #displayed? with no URL matcher set
|
14
|
+
class NoUrlMatcherForPageError < PageLoadError; end
|
15
|
+
|
16
|
+
# The URL matcher was not recognised as a Regex or String and as such
|
17
|
+
# it couldn't be parsed by Addressable
|
18
|
+
class InvalidUrlMatcherError < PageLoadError
|
19
|
+
def message
|
20
|
+
warn 'Templated port numbers are unsupported.'
|
21
|
+
|
22
|
+
'Your URL and/or matcher could not be interpreted.'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# A SitePrism defined DSL item was defined without a selector
|
27
|
+
class InvalidElementError < SitePrismError
|
28
|
+
def message
|
29
|
+
"#{super} has been derived from an item with no selectors defined."
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# The condition that was being evaluated inside the block did not evaluate
|
34
|
+
# to true within the time limit
|
35
|
+
class TimeoutError < SitePrismError
|
36
|
+
def message
|
37
|
+
"Timed out after #{super}s."
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# These errors are not yet migrated and are fired from their source
|
42
|
+
# They are raised when the meta-programmed method has not yielded true
|
43
|
+
# in the prescribed time limit
|
44
|
+
class ExistenceTimeoutError < TimeoutError; end
|
45
|
+
class NonExistenceTimeoutError < TimeoutError; end
|
46
|
+
class ElementVisibilityTimeoutError < TimeoutError; end
|
47
|
+
class ElementInvisibilityTimeoutError < TimeoutError; end
|
48
|
+
|
49
|
+
# A Block was passed to the method, which it cannot interpret
|
50
|
+
class UnsupportedBlockError < SitePrismError
|
51
|
+
def message
|
52
|
+
warn 'section and iframe are the only items which can accept a block.'
|
53
|
+
|
54
|
+
"#{super} does not accept blocks."
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# A Block was required, but not passed into the iframe at runtime
|
59
|
+
class MissingBlockError < SitePrismError
|
60
|
+
def message
|
61
|
+
'You can only use iFrames in a block context - Please pass in a block.'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# A page was loaded via #load - And then failed one of the load validations
|
66
|
+
# that was either pre-defined or defined by the user
|
67
|
+
class FailedLoadValidationError < PageLoadError
|
68
|
+
def message
|
69
|
+
if super == self.class.to_s
|
70
|
+
'Failed to load - No reason specified.'
|
71
|
+
else
|
72
|
+
"Failed to load. Reason: #{super}"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Legacy Error Code aliases for backwards compatibility
|
78
|
+
NoUrlForPage = NoUrlForPageError
|
79
|
+
NoUrlMatcherForPage = NoUrlMatcherForPageError
|
80
|
+
InvalidUrlMatcher = InvalidUrlMatcherError
|
81
|
+
NoSelectorForElement = InvalidElementError
|
82
|
+
TimeoutException = TimeoutError
|
83
|
+
TimeOutWaitingForExistenceError = Class.new(StandardError) # To avoid message leaking
|
84
|
+
TimeOutWaitingForNonExistenceError = Class.new(StandardError) # To avoid message leaking
|
85
|
+
TimeOutWaitingForElementVisibility = Class.new(StandardError) # To avoid message leaking
|
86
|
+
TimeOutWaitingForElementInvisibility = Class.new(StandardError) # To avoid message leaking
|
87
|
+
UnsupportedBlock = UnsupportedBlockError
|
88
|
+
BlockMissingError = MissingBlockError
|
89
|
+
NotLoadedError = FailedLoadValidationError
|
90
|
+
end
|
data/lib/site_prism/loadable.rb
CHANGED
@@ -25,6 +25,10 @@ module SitePrism
|
|
25
25
|
#
|
26
26
|
# @param block [&block] A block which returns true if the page
|
27
27
|
# loaded successfully, or false if it did not.
|
28
|
+
# This block can contain up to 2 elements in an array
|
29
|
+
# The first is the physical validation test to be truthily evaluated
|
30
|
+
# If this does not pass, then the 2nd item (If defined), is output
|
31
|
+
# as an error message to the NotLoadedError Error that will be thrown
|
28
32
|
def load_validation(&block)
|
29
33
|
_load_validations << block
|
30
34
|
end
|
@@ -62,8 +66,7 @@ module SitePrism
|
|
62
66
|
# Within the block, cache loaded? to optimize performance.
|
63
67
|
self.loaded = loaded?
|
64
68
|
|
65
|
-
|
66
|
-
raise ::SitePrism::NotLoadedError, message unless loaded
|
69
|
+
raise SitePrism::NotLoadedError, load_error unless loaded
|
67
70
|
|
68
71
|
yield self
|
69
72
|
ensure
|
data/lib/site_prism/section.rb
CHANGED
@@ -8,6 +8,7 @@ module SitePrism
|
|
8
8
|
include ElementChecker
|
9
9
|
include Loadable
|
10
10
|
include ElementContainer
|
11
|
+
extend Forwardable
|
11
12
|
|
12
13
|
attr_reader :root_element, :parent
|
13
14
|
|
@@ -42,12 +43,13 @@ module SitePrism
|
|
42
43
|
page.visible?
|
43
44
|
end
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
46
|
+
def_delegators :capybara_session,
|
47
|
+
:execute_script,
|
48
|
+
:evaluate_script,
|
49
|
+
:within_frame
|
48
50
|
|
49
|
-
def
|
50
|
-
Capybara.current_session
|
51
|
+
def capybara_session
|
52
|
+
Capybara.current_session
|
51
53
|
end
|
52
54
|
|
53
55
|
def parent_page
|
data/lib/site_prism/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: site_prism
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.15.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nat Ritmeyer
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-07-
|
12
|
+
date: 2018-07-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: addressable
|
@@ -34,7 +34,7 @@ dependencies:
|
|
34
34
|
version: '2.14'
|
35
35
|
- - "<"
|
36
36
|
- !ruby/object:Gem::Version
|
37
|
-
version: '3.
|
37
|
+
version: '3.3'
|
38
38
|
type: :runtime
|
39
39
|
prerelease: false
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -44,7 +44,7 @@ dependencies:
|
|
44
44
|
version: '2.14'
|
45
45
|
- - "<"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '3.
|
47
|
+
version: '3.3'
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: cucumber
|
50
50
|
requirement: !ruby/object:Gem::Requirement
|
@@ -105,16 +105,16 @@ dependencies:
|
|
105
105
|
name: rubocop
|
106
106
|
requirement: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - "
|
108
|
+
- - "<"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '0.
|
110
|
+
version: '0.58'
|
111
111
|
type: :development
|
112
112
|
prerelease: false
|
113
113
|
version_requirements: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
|
-
- - "
|
115
|
+
- - "<"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: '0.
|
117
|
+
version: '0.58'
|
118
118
|
- !ruby/object:Gem::Dependency
|
119
119
|
name: selenium-webdriver
|
120
120
|
requirement: !ruby/object:Gem::Requirement
|
@@ -135,14 +135,14 @@ dependencies:
|
|
135
135
|
requirements:
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: '0.
|
138
|
+
version: '0.16'
|
139
139
|
type: :development
|
140
140
|
prerelease: false
|
141
141
|
version_requirements: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
143
|
- - "~>"
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: '0.
|
145
|
+
version: '0.16'
|
146
146
|
description: |-
|
147
147
|
SitePrism gives you a simple, clean and semantic DSL for describing your site.
|
148
148
|
SitePrism implements the Page Object Model pattern on top of Capybara.
|
@@ -159,7 +159,7 @@ files:
|
|
159
159
|
- lib/site_prism/addressable_url_matcher.rb
|
160
160
|
- lib/site_prism/element_checker.rb
|
161
161
|
- lib/site_prism/element_container.rb
|
162
|
-
- lib/site_prism/
|
162
|
+
- lib/site_prism/error.rb
|
163
163
|
- lib/site_prism/loadable.rb
|
164
164
|
- lib/site_prism/page.rb
|
165
165
|
- lib/site_prism/section.rb
|
@@ -1,40 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module SitePrism
|
4
|
-
class NoUrlForPage < StandardError; end
|
5
|
-
class NoUrlMatcherForPage < StandardError; end
|
6
|
-
|
7
|
-
class InvalidUrlMatcher < StandardError
|
8
|
-
def message
|
9
|
-
"Could not automatically match your URL. \
|
10
|
-
Templated port numbers are unsupported."
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
class NoSelectorForElement < StandardError; end
|
15
|
-
|
16
|
-
class TimeoutException < StandardError
|
17
|
-
def message
|
18
|
-
"Timed out after #{super}s while waiting for block to evaluate as true."
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
class TimeOutWaitingForExistenceError < StandardError; end
|
23
|
-
class TimeOutWaitingForNonExistenceError < StandardError; end
|
24
|
-
class TimeOutWaitingForElementVisibility < StandardError; end
|
25
|
-
class TimeOutWaitingForElementInvisibility < StandardError; end
|
26
|
-
|
27
|
-
class UnsupportedBlock < StandardError
|
28
|
-
def message
|
29
|
-
"#{super} does not accept blocks, did you mean to define a (i)frame?"
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
class BlockMissingError < StandardError
|
34
|
-
def message
|
35
|
-
'You can only use iFrames in a block context. See docs for more details.'
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
NotLoadedError = Class.new(StandardError)
|
40
|
-
end
|