page_magic 1.0.0.alpha18 → 1.0.0.alpha19
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 +4 -4
- data/Gemfile +8 -9
- data/Gemfile.lock +16 -30
- data/README.md +18 -6
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/circle.yml +1 -1
- data/lib/page_magic/class_methods.rb +20 -0
- data/lib/page_magic/driver.rb +21 -0
- data/lib/page_magic/drivers.rb +7 -0
- data/lib/page_magic/element/selector_methods.rb +2 -0
- data/lib/page_magic/element.rb +31 -21
- data/lib/page_magic/elements.rb +17 -4
- data/lib/page_magic/instance_methods.rb +19 -1
- data/lib/page_magic/session.rb +5 -6
- data/lib/page_magic.rb +2 -6
- data/spec/element_spec.rb +10 -4
- data/spec/page_magic/class_methods_spec.rb +29 -0
- data/spec/page_magic/elements_spec.rb +6 -3
- data/spec/page_magic/instance_methods_spec.rb +29 -4
- data/spec/page_magic/session_spec.rb +38 -18
- data/spec/spec_helper.rb +0 -1
- metadata +34 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3c6619b6e1c9d8dfc99efdf0c0e7ebe74a47d982
|
4
|
+
data.tar.gz: 1cf1b031cd205134d43abd54d73026f9d41ad864
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be32d07b0103409b817333a632091d1b5b88f3173c1562c39df3dfa2e3d98f26a8e36a95d6ef2f878a7d4240c192d2165452a18d77ac52b0b0c6d27f2bd8451a
|
7
|
+
data.tar.gz: db76720173bdcb1d0fb43fe1721386d0c36e32c76fd354fabde19798cbddc1ba59b376a32942073a6aeb92ee1c3cfd4f948c8711d0ddff63e994d9e6572c5f78
|
data/Gemfile
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
|
3
|
-
gem 'capybara'
|
4
|
-
gem 'activesupport'
|
5
|
-
gem 'wait'
|
3
|
+
gem 'capybara', '~> 2'
|
4
|
+
gem 'activesupport', '~> 4'
|
5
|
+
gem 'wait', '~> 0'
|
6
6
|
|
7
7
|
group :test do
|
8
8
|
gem 'watir-webdriver'
|
@@ -15,10 +15,9 @@ group :test do
|
|
15
15
|
end
|
16
16
|
|
17
17
|
group :development do
|
18
|
-
gem 'jeweler'
|
19
|
-
gem 'rubocop', require: 'rubocop/rake_task'
|
20
|
-
gem '
|
21
|
-
gem '
|
22
|
-
gem '
|
23
|
-
gem 'github-markup'
|
18
|
+
gem 'jeweler', '~> 2.0'
|
19
|
+
gem 'rubocop', '~> 0.34', require: 'rubocop/rake_task'
|
20
|
+
gem 'yard', '~> 0.8'
|
21
|
+
gem 'redcarpet', '~> 3.3'
|
22
|
+
gem 'github-markup', '~> 1.4'
|
24
23
|
end
|
data/Gemfile.lock
CHANGED
@@ -12,8 +12,6 @@ GEM
|
|
12
12
|
astrolabe (1.3.1)
|
13
13
|
parser (~> 2.2)
|
14
14
|
builder (3.2.2)
|
15
|
-
byebug (5.0.0)
|
16
|
-
columnize (= 0.9.0)
|
17
15
|
capybara (2.1.0)
|
18
16
|
mime-types (>= 1.16)
|
19
17
|
nokogiri (>= 1.3.3)
|
@@ -26,8 +24,6 @@ GEM
|
|
26
24
|
cliver (0.2.2)
|
27
25
|
codeclimate-test-reporter (0.4.8)
|
28
26
|
simplecov (>= 0.7.1, < 1.0.0)
|
29
|
-
coderay (1.1.0)
|
30
|
-
columnize (0.9.0)
|
31
27
|
diff-lcs (1.2.5)
|
32
28
|
docile (1.1.5)
|
33
29
|
faraday (0.8.9)
|
@@ -57,22 +53,21 @@ GEM
|
|
57
53
|
json (1.8.1)
|
58
54
|
jwt (0.1.11)
|
59
55
|
multi_json (>= 1.5)
|
60
|
-
|
61
|
-
|
62
|
-
mini_portile (0.5.1)
|
56
|
+
mime-types (2.6.2)
|
57
|
+
mini_portile (0.6.2)
|
63
58
|
minitest (5.7.0)
|
64
59
|
multi_json (1.11.2)
|
65
60
|
multi_xml (0.5.5)
|
66
61
|
multipart-post (1.2.0)
|
67
|
-
nokogiri (1.6.
|
68
|
-
mini_portile (~> 0.
|
62
|
+
nokogiri (1.6.6.2)
|
63
|
+
mini_portile (~> 0.6.0)
|
69
64
|
oauth2 (0.9.3)
|
70
65
|
faraday (>= 0.8, < 0.10)
|
71
66
|
jwt (~> 0.1.8)
|
72
67
|
multi_json (~> 1.3)
|
73
68
|
multi_xml (~> 0.5)
|
74
69
|
rack (~> 1.2)
|
75
|
-
parser (2.2.
|
70
|
+
parser (2.2.3.0)
|
76
71
|
ast (>= 1.1, < 3.0)
|
77
72
|
poltergeist (1.4.1)
|
78
73
|
capybara (~> 2.1.0)
|
@@ -80,20 +75,13 @@ GEM
|
|
80
75
|
multi_json (~> 1.0)
|
81
76
|
websocket-driver (>= 0.2.0)
|
82
77
|
powerpack (0.1.1)
|
83
|
-
pry (0.10.3)
|
84
|
-
coderay (~> 1.1.0)
|
85
|
-
method_source (~> 0.8.1)
|
86
|
-
slop (~> 3.4)
|
87
|
-
pry-byebug (3.2.0)
|
88
|
-
byebug (~> 5.0)
|
89
|
-
pry (~> 0.10)
|
90
78
|
pullreview-coverage (0.0.5)
|
91
79
|
certifi
|
92
80
|
simplecov (>= 0.7.1, < 1.0.0)
|
93
|
-
rack (1.
|
81
|
+
rack (1.6.4)
|
94
82
|
rack-protection (1.5.0)
|
95
83
|
rack
|
96
|
-
rack-test (0.6.
|
84
|
+
rack-test (0.6.3)
|
97
85
|
rack (>= 1.0)
|
98
86
|
rainbow (2.0.0)
|
99
87
|
rake (10.2.2)
|
@@ -113,7 +101,7 @@ GEM
|
|
113
101
|
diff-lcs (>= 1.2.0, < 2.0)
|
114
102
|
rspec-support (~> 3.3.0)
|
115
103
|
rspec-support (3.3.0)
|
116
|
-
rubocop (0.34.
|
104
|
+
rubocop (0.34.2)
|
117
105
|
astrolabe (~> 1.3)
|
118
106
|
parser (>= 2.2.2.5, < 3.0)
|
119
107
|
powerpack (~> 0.1)
|
@@ -135,7 +123,6 @@ GEM
|
|
135
123
|
rack (~> 1.4)
|
136
124
|
rack-protection (~> 1.4)
|
137
125
|
tilt (~> 1.3, >= 1.3.4)
|
138
|
-
slop (3.6.0)
|
139
126
|
thread_safe (0.3.5)
|
140
127
|
tilt (1.4.1)
|
141
128
|
tzinfo (1.2.2)
|
@@ -153,19 +140,18 @@ PLATFORMS
|
|
153
140
|
ruby
|
154
141
|
|
155
142
|
DEPENDENCIES
|
156
|
-
activesupport
|
157
|
-
capybara
|
143
|
+
activesupport (~> 4)
|
144
|
+
capybara (~> 2)
|
158
145
|
codeclimate-test-reporter
|
159
|
-
github-markup
|
160
|
-
jeweler
|
146
|
+
github-markup (~> 1.4)
|
147
|
+
jeweler (~> 2.0)
|
161
148
|
poltergeist
|
162
|
-
pry-byebug
|
163
149
|
pullreview-coverage
|
164
|
-
redcarpet
|
150
|
+
redcarpet (~> 3.3)
|
165
151
|
rspec
|
166
|
-
rubocop
|
152
|
+
rubocop (~> 0.34)
|
167
153
|
simplecov
|
168
154
|
sinatra
|
169
|
-
wait
|
155
|
+
wait (~> 0)
|
170
156
|
watir-webdriver
|
171
|
-
yard
|
157
|
+
yard (~> 0.8)
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
[](https://codeclimate.com/github/Ladtech/page_magic) [](https://codeclimate.com/github/Ladtech/page_magic/coverage) [](https://www.pullreview.com/github/Ladtech/page_magic/reviews/master)
|
1
|
+
[](https://circleci.com/gh/Ladtech/page_magic) [](https://codeclimate.com/github/Ladtech/page_magic) [](https://codeclimate.com/github/Ladtech/page_magic/coverage) [](https://www.pullreview.com/github/Ladtech/page_magic/reviews/master)
|
2
2
|
#PageMagic
|
3
3
|
PageMagic is an API for testing web applications.
|
4
4
|
|
@@ -12,7 +12,7 @@ Wouldn't it be great if there was a framework that could:
|
|
12
12
|
|
13
13
|
Well PageMagic might just be the answer!
|
14
14
|
|
15
|
-
Give it a try and let us know what you think!
|
15
|
+
Give it a try and let us know what you think! There will undoubtedly be things that can be improved and issues that we are not aware of so your feedback/pull requests are greatly appreciated!
|
16
16
|
|
17
17
|
# Installation
|
18
18
|
`gem install page_magic --pre`
|
@@ -101,8 +101,20 @@ class MessageView
|
|
101
101
|
include PageMagic
|
102
102
|
end
|
103
103
|
```
|
104
|
+
### Hooks
|
105
|
+
PageMagic lets you define an on_load hook for your pages. This lets you right any custom wait logic you might need
|
106
|
+
before letting execution continue.
|
107
|
+
```ruby
|
108
|
+
class LoginPage
|
109
|
+
# ... code defining elements as shown above
|
110
|
+
|
111
|
+
on_load do
|
112
|
+
# wait code here
|
113
|
+
end
|
114
|
+
end
|
115
|
+
```
|
104
116
|
|
105
|
-
|
117
|
+
### Helper methods
|
106
118
|
Using elements that are defined on a page is great, but if you are enacting a procedure through interacting with a few of them then your code could end up with some pretty repetitive code. In this case you can define helper methods instead.
|
107
119
|
|
108
120
|
In the above [example](#an example) we used a helper called `login`.
|
@@ -157,15 +169,15 @@ Here we have defined the 'message' element using a block that takes subject argu
|
|
157
169
|
session.message(subject: 'test message')
|
158
170
|
```
|
159
171
|
## Interaction hooks
|
160
|
-
Frequently, you are going to have to work with pages that make heavy use of ajax. This means that just because you've clicked something, it doesn't mean that the action is finished. For these occasions PageMagic provides `
|
172
|
+
Frequently, you are going to have to work with pages that make heavy use of ajax. This means that just because you've clicked something, it doesn't mean that the action is finished. For these occasions PageMagic provides `before_events` and `after_events` hooks that you use to perform custom actions and wait for things to happen. In the case of our web based mail client, we could imagine that when deleting the email, a fancy spinner is displayed whilst the application sends an ajax request to have the message deleted. In this case we wouldn't want to proceed until this has disappeared.
|
161
173
|
|
162
174
|
```ruby
|
163
175
|
class MessagePage
|
164
176
|
include PageMagic
|
165
177
|
## code defining other elements, such as subject and body
|
166
178
|
|
167
|
-
link(:delete
|
168
|
-
|
179
|
+
link(:delete id: 'delete-message') do
|
180
|
+
after_events do
|
169
181
|
wait_until{fancy_animation_has_disappeared?}
|
170
182
|
end
|
171
183
|
end
|
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.0.
|
1
|
+
1.0.0.alpha19
|
data/circle.yml
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
module PageMagic
|
2
|
+
# module ClassMethods - contains class level methods for PageObjects
|
3
|
+
module ClassMethods
|
4
|
+
DEFAULT_ON_LOAD = proc {}
|
5
|
+
|
6
|
+
# getter setter for storing the page url
|
7
|
+
# @param [String] url the url of the page
|
8
|
+
def url(url = nil)
|
9
|
+
@url = url if url
|
10
|
+
@url
|
11
|
+
end
|
12
|
+
|
13
|
+
# sets block to run when page has loaded
|
14
|
+
# if one has not been set on the page object class it will return a default block that does nothing
|
15
|
+
def on_load(&block)
|
16
|
+
return @on_load || DEFAULT_ON_LOAD unless block
|
17
|
+
@on_load = block
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/page_magic/driver.rb
CHANGED
@@ -2,15 +2,36 @@ module PageMagic
|
|
2
2
|
# class Driver - instances are factories for drivers used by PageMagic
|
3
3
|
class Driver
|
4
4
|
attr_reader :supported_browsers, :handler
|
5
|
+
# Creates a driver definition
|
6
|
+
# @example
|
7
|
+
# Driver.new do |rack_application, options|
|
8
|
+
# require 'capybara/driver_class'
|
9
|
+
# Capybara::Driver::Class.new(app, options)
|
10
|
+
# end
|
11
|
+
# @yield[rack_application, options, browser_name]
|
12
|
+
# @yieldparam [Object] rack_application rack compatible application
|
13
|
+
# @yieldparam [Hash] options hash containing driver specific options
|
14
|
+
# @yieldparam [Symbol] browser_name the name of the required browser name
|
15
|
+
# @param [*Symbol] supported_browsers list of browsers names. These are the names that
|
16
|
+
# you will refer to them by when creating a session
|
17
|
+
# @yieldreturn [Object] Capybara compliant driver
|
5
18
|
def initialize(*supported_browsers, &block)
|
6
19
|
@handler = block
|
7
20
|
@supported_browsers = supported_browsers
|
8
21
|
end
|
9
22
|
|
23
|
+
# Determines if the given browser name is supported by this driver definition
|
24
|
+
# @param [Symbol] browser name of browser
|
25
|
+
# @return [Boolean] true if definition supports the given driver name
|
10
26
|
def support?(browser)
|
11
27
|
supported_browsers.include?(browser)
|
12
28
|
end
|
13
29
|
|
30
|
+
# Build a new driver instance based on this definition
|
31
|
+
# @param [Object] app - rack compatible application
|
32
|
+
# @param [Symbol] browser name of required browser
|
33
|
+
# @param [Hash] options driver specific options
|
34
|
+
# @return [Object] Capybara compliant driver instance
|
14
35
|
def build(app, browser:, options:{})
|
15
36
|
handler.call(app, options, browser)
|
16
37
|
end
|
data/lib/page_magic/drivers.rb
CHANGED
@@ -7,10 +7,14 @@ module PageMagic
|
|
7
7
|
@all ||= []
|
8
8
|
end
|
9
9
|
|
10
|
+
# Make a driver available for selection when creating calling {PageMagic.session}
|
11
|
+
# @param [Driver] driver driver definition
|
10
12
|
def register(driver)
|
11
13
|
all << driver
|
12
14
|
end
|
13
15
|
|
16
|
+
# Find a driver definition based on its registered name
|
17
|
+
# @param [Symbol] browser registered name of the required browser
|
14
18
|
def find(browser)
|
15
19
|
all.find { |driver| driver.support?(browser) }
|
16
20
|
end
|
@@ -27,6 +31,9 @@ module PageMagic
|
|
27
31
|
end
|
28
32
|
end
|
29
33
|
|
34
|
+
# returns true if this driver instance is equal to the supplied object
|
35
|
+
# @param [Object] other subject of equality check
|
36
|
+
# @return [Boolean] true if the object is a match
|
30
37
|
def ==(other)
|
31
38
|
other.is_a?(Drivers) && all == other.all
|
32
39
|
end
|
@@ -2,6 +2,8 @@ module PageMagic
|
|
2
2
|
class Element
|
3
3
|
# module SelectorMethods - adds method for getting and setting an element selector
|
4
4
|
module SelectorMethods
|
5
|
+
# Gets/Sets a selector
|
6
|
+
# @param [Hash] selector method for locating the browser element. E.g. text: 'the text'
|
5
7
|
def selector(selector = nil)
|
6
8
|
return @selector unless selector
|
7
9
|
@selector = selector
|
data/lib/page_magic/element.rb
CHANGED
@@ -8,13 +8,13 @@ module PageMagic
|
|
8
8
|
EVENT_TYPES = [:set, :select, :select_option, :unselect_option, :click]
|
9
9
|
DEFAULT_HOOK = proc {}.freeze
|
10
10
|
|
11
|
-
attr_reader :type, :name, :parent_page_element
|
11
|
+
attr_reader :type, :name, :parent_page_element
|
12
12
|
|
13
13
|
include Elements, MethodObserver, SelectorMethods
|
14
14
|
extend Elements, SelectorMethods
|
15
15
|
|
16
|
-
def initialize(name, parent_page_element, type: :element, selector: {},
|
17
|
-
@browser_element =
|
16
|
+
def initialize(name, parent_page_element, type: :element, selector: {}, prefetched_browser_element: nil, &block)
|
17
|
+
@browser_element = prefetched_browser_element
|
18
18
|
@selector = selector
|
19
19
|
|
20
20
|
@before_hook = DEFAULT_HOOK
|
@@ -26,29 +26,51 @@ module PageMagic
|
|
26
26
|
expand(&block) if block
|
27
27
|
end
|
28
28
|
|
29
|
+
# expand the element definition by evaluating the given block in the scope of this object
|
30
|
+
# @param [*Object] args list of arguments to be supplied to the given block
|
29
31
|
def expand(*args, &block)
|
30
32
|
instance_exec(*args, &block)
|
31
33
|
self
|
32
34
|
end
|
33
35
|
|
36
|
+
# @return [Boolean] returns true if this element contains helper methods or sub element definitions
|
34
37
|
def section?
|
35
38
|
!element_definitions.empty? || singleton_methods_added?
|
36
39
|
end
|
37
40
|
|
41
|
+
# @return [Object] returns the overall of the parent page element. this will ultimately be the {Session} wrapping
|
42
|
+
# Capybara session
|
38
43
|
def session
|
39
44
|
@parent_page_element.session
|
40
45
|
end
|
41
46
|
|
42
|
-
|
47
|
+
# Get/Sets the block of code to be run before an event is triggered on an element. See {EVENT_TYPES} for the list of
|
48
|
+
# events that this block will be triggered for. The block is run in the scope of the element object
|
49
|
+
def before_events(&block)
|
43
50
|
return @before_hook unless block
|
44
51
|
@before_hook = block
|
45
52
|
end
|
46
53
|
|
47
|
-
|
54
|
+
# Get/Sets the block of code to be run after an event is triggered on an element. See {EVENT_TYPES} for the list of
|
55
|
+
# events that this block will be triggered for. The block is run in the scope of the element object
|
56
|
+
def after_events(&block)
|
48
57
|
return @after_hook unless block
|
49
58
|
@after_hook = block
|
50
59
|
end
|
51
60
|
|
61
|
+
# @return [Object] the Capybara browser element that this element definition is tied to.
|
62
|
+
def browser_element
|
63
|
+
return @browser_element if @browser_element
|
64
|
+
|
65
|
+
fail UndefinedSelectorException, 'Pass a locator/define one on the class' if selector.empty?
|
66
|
+
|
67
|
+
query = Query.find(type).build(query_selector, query_options)
|
68
|
+
|
69
|
+
@browser_element = parent_browser_element.find(*query).tap do |raw_element|
|
70
|
+
wrap_events(raw_element)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
52
74
|
def method_missing(method, *args, &block)
|
53
75
|
ElementContext.new(self).send(method, args.first, &block)
|
54
76
|
rescue ElementMissingException
|
@@ -64,22 +86,10 @@ module PageMagic
|
|
64
86
|
super || element_context.respond_to?(*args) || browser_element.respond_to?(*args)
|
65
87
|
end
|
66
88
|
|
67
|
-
def browser_element(*_args)
|
68
|
-
return @browser_element if @browser_element
|
69
|
-
|
70
|
-
fail UndefinedSelectorException, 'Pass a locator/define one on the class' if selector.empty?
|
71
|
-
|
72
|
-
query = Query.find(type).build(query_selector, query_options)
|
73
|
-
|
74
|
-
@browser_element = parent_browser_element.find(*query).tap do |raw_element|
|
75
|
-
wrap_events(raw_element)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
89
|
def ==(other)
|
80
90
|
return false unless other.is_a?(Element)
|
81
|
-
this = [type, name, selector,
|
82
|
-
this == [other.type, other.name, other.selector, other.
|
91
|
+
this = [type, name, selector, before_events, after_events]
|
92
|
+
this == [other.type, other.name, other.selector, other.before_events, other.after_events]
|
83
93
|
end
|
84
94
|
|
85
95
|
private
|
@@ -101,8 +111,8 @@ module PageMagic
|
|
101
111
|
next unless raw_element.respond_to?(action_method)
|
102
112
|
apply_hooks(raw_element: raw_element,
|
103
113
|
capybara_method: action_method,
|
104
|
-
before_hook:
|
105
|
-
after_hook:
|
114
|
+
before_hook: before_events,
|
115
|
+
after_hook: after_events)
|
106
116
|
end
|
107
117
|
end
|
108
118
|
|
data/lib/page_magic/elements.rb
CHANGED
@@ -2,18 +2,29 @@ require 'active_support/inflector'
|
|
2
2
|
module PageMagic
|
3
3
|
# module Elements - contains methods that add element definitions to the objects it is mixed in to
|
4
4
|
module Elements
|
5
|
+
# hooks for objects that inherit classes that include the Elements module
|
6
|
+
module InheritanceHooks
|
7
|
+
# Copies parent element definitions on to subclass
|
8
|
+
# @param [Class] clazz - inheritting class
|
9
|
+
def inherited(clazz)
|
10
|
+
clazz.element_definitions.merge!(element_definitions)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
5
14
|
INVALID_METHOD_NAME_MSG = 'a method already exists with this method name'
|
6
15
|
TYPES = [:text_field, :button, :link, :checkbox, :select_list, :radios, :textarea]
|
7
16
|
|
8
17
|
class << self
|
9
18
|
def included(clazz)
|
10
|
-
|
11
|
-
clazz.element_definitions.merge!(element_definitions)
|
12
|
-
end
|
19
|
+
clazz.extend(InheritanceHooks)
|
13
20
|
end
|
14
21
|
alias_method :extended, :included
|
15
22
|
end
|
16
23
|
|
24
|
+
# Get all {Element} definitions
|
25
|
+
# @param [Object] browser_element capybara browser element from which the definitions can be sourced
|
26
|
+
# @param [*Object] args argument to be passed to block used to expand the {Element} definitions
|
27
|
+
# @return [Array] list of {Element} defintions
|
17
28
|
def elements(browser_element, *args)
|
18
29
|
element_definitions.values.collect { |definition| definition.call(browser_element, *args) }
|
19
30
|
end
|
@@ -54,7 +65,7 @@ module PageMagic
|
|
54
65
|
name = compute_name(args, section_class)
|
55
66
|
|
56
67
|
options = { type: __callee__ }
|
57
|
-
selector ? options[:selector] = selector : options[:
|
68
|
+
selector ? options[:selector] = selector : options[:prefetched_browser_element] = args.delete_at(0)
|
58
69
|
|
59
70
|
add_element_definition(name) do |parent_browser_element, *e_args|
|
60
71
|
section_class.new(name, parent_browser_element, options).expand(*e_args, &block)
|
@@ -63,6 +74,8 @@ module PageMagic
|
|
63
74
|
|
64
75
|
TYPES.each { |type| alias_method type, :element }
|
65
76
|
|
77
|
+
# @return [Hash] element definition names mapped to blocks that can be used to create unique instances of
|
78
|
+
# and {Element} definitions
|
66
79
|
def element_definitions
|
67
80
|
@element_definitions ||= {}
|
68
81
|
end
|
@@ -12,23 +12,31 @@ module PageMagic
|
|
12
12
|
@browser_element = browser
|
13
13
|
end
|
14
14
|
|
15
|
+
# @return the current page title
|
15
16
|
def title
|
16
17
|
browser.title
|
17
18
|
end
|
18
19
|
|
20
|
+
# check for the presense of specific text on the page
|
21
|
+
# @param [String] string the string to check for
|
22
|
+
# @return [Boolean]
|
19
23
|
def text_on_page?(string)
|
20
24
|
text.downcase.include?(string.downcase)
|
21
25
|
end
|
22
26
|
|
27
|
+
# Visit this page based on the class level registered url
|
23
28
|
def visit
|
24
29
|
browser.visit self.class.url
|
25
|
-
|
30
|
+
execute_on_load
|
26
31
|
end
|
27
32
|
|
33
|
+
# @return the page text
|
28
34
|
def text
|
29
35
|
browser.text
|
30
36
|
end
|
31
37
|
|
38
|
+
# proxy to the defined page element definitions
|
39
|
+
# @return [Object] the result of accessing the requested page element through its definition
|
32
40
|
def method_missing(method, *args)
|
33
41
|
element_context.send(method, *args)
|
34
42
|
end
|
@@ -37,10 +45,20 @@ module PageMagic
|
|
37
45
|
super || element_context.respond_to?(*args)
|
38
46
|
end
|
39
47
|
|
48
|
+
# @return [Array] class level defined element definitions
|
40
49
|
def element_definitions
|
41
50
|
self.class.element_definitions
|
42
51
|
end
|
43
52
|
|
53
|
+
# executes block stored using {ClassMethods#on_load} against self
|
54
|
+
# @return [Element] self
|
55
|
+
def execute_on_load
|
56
|
+
instance_eval(&self.class.on_load)
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
44
62
|
def element_context
|
45
63
|
ElementContext.new(self)
|
46
64
|
end
|
data/lib/page_magic/session.rb
CHANGED
@@ -4,6 +4,7 @@ module PageMagic
|
|
4
4
|
class Session
|
5
5
|
URL_MISSING_MSG = 'a path must be mapped or a url supplied'
|
6
6
|
REGEXP_MAPPING_MSG = 'URL could not be derived because mapping is a Regexp'
|
7
|
+
INVALID_MAPPING_MSG = 'mapping must be a string or regexp'
|
7
8
|
|
8
9
|
attr_reader :raw_session, :transitions
|
9
10
|
|
@@ -58,7 +59,7 @@ module PageMagic
|
|
58
59
|
else
|
59
60
|
fail InvalidURLException, URL_MISSING_MSG
|
60
61
|
end
|
61
|
-
@current_page = page.new(self) if page
|
62
|
+
@current_page = page.new(self).execute_on_load if page
|
62
63
|
self
|
63
64
|
end
|
64
65
|
|
@@ -104,18 +105,16 @@ module PageMagic
|
|
104
105
|
|
105
106
|
def find_mapped_page(path)
|
106
107
|
mapping = transitions.keys.find do |key|
|
107
|
-
|
108
|
+
matches?(path, key)
|
108
109
|
end
|
109
110
|
transitions[mapping]
|
110
111
|
end
|
111
112
|
|
112
|
-
def
|
113
|
+
def matches?(string, matcher)
|
113
114
|
if matcher.is_a?(Regexp)
|
114
115
|
string =~ matcher
|
115
|
-
elsif matcher.is_a?(String)
|
116
|
-
string == matcher
|
117
116
|
else
|
118
|
-
|
117
|
+
string == matcher
|
119
118
|
end
|
120
119
|
end
|
121
120
|
end
|
data/lib/page_magic.rb
CHANGED
@@ -4,6 +4,7 @@ require 'page_magic/exceptions'
|
|
4
4
|
require 'page_magic/session'
|
5
5
|
require 'page_magic/instance_methods'
|
6
6
|
require 'page_magic/elements'
|
7
|
+
require 'page_magic/class_methods'
|
7
8
|
require 'page_magic/element_context'
|
8
9
|
require 'page_magic/element'
|
9
10
|
require 'page_magic/drivers'
|
@@ -28,13 +29,8 @@ module PageMagic
|
|
28
29
|
|
29
30
|
def included(clazz)
|
30
31
|
clazz.class_eval do
|
31
|
-
def self.url(url = nil)
|
32
|
-
@url = url if url
|
33
|
-
@url
|
34
|
-
end
|
35
|
-
|
36
32
|
include(InstanceMethods)
|
37
|
-
extend(Elements)
|
33
|
+
extend(Elements, ClassMethods)
|
38
34
|
end
|
39
35
|
end
|
40
36
|
end
|
data/spec/element_spec.rb
CHANGED
@@ -39,7 +39,10 @@ module PageMagic
|
|
39
39
|
|
40
40
|
describe '#respond_to?' do
|
41
41
|
subject do
|
42
|
-
described_class.new(:name,
|
42
|
+
described_class.new(:name,
|
43
|
+
Object.new,
|
44
|
+
type: :element,
|
45
|
+
prefetched_browser_element: double(element_method: '')) do
|
43
46
|
element :sub_element, css: '.sub-element'
|
44
47
|
end
|
45
48
|
end
|
@@ -59,6 +62,9 @@ module PageMagic
|
|
59
62
|
describe '#browser_element' do
|
60
63
|
let!(:browser) { double('browser') }
|
61
64
|
|
65
|
+
it 'calls the on_load hook' do
|
66
|
+
end
|
67
|
+
|
62
68
|
context 'options supplied to selector' do
|
63
69
|
it 'passes them on to the cappybara finder method' do
|
64
70
|
options = { count: 1 }
|
@@ -112,7 +118,7 @@ module PageMagic
|
|
112
118
|
end
|
113
119
|
|
114
120
|
it 'should return a prefetched value' do
|
115
|
-
element = described_class.new(:help, page, type: :link,
|
121
|
+
element = described_class.new(:help, page, type: :link, prefetched_browser_element: :prefetched_object)
|
116
122
|
expect(element.browser_element).to eq(:prefetched_object)
|
117
123
|
end
|
118
124
|
|
@@ -185,7 +191,7 @@ module PageMagic
|
|
185
191
|
describe 'hooks' do
|
186
192
|
subject do
|
187
193
|
described_class.new(:my_button, page, type: :button, selector: { id: 'my_button' }) do
|
188
|
-
|
194
|
+
before_events do
|
189
195
|
call_in_before_hook
|
190
196
|
end
|
191
197
|
end
|
@@ -201,7 +207,7 @@ module PageMagic
|
|
201
207
|
context 'method called in before hook' do
|
202
208
|
subject do
|
203
209
|
described_class.new(:my_button, page, type: :button, selector: { id: 'my_button' }) do
|
204
|
-
|
210
|
+
after_events do
|
205
211
|
call_in_after_hook
|
206
212
|
end
|
207
213
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module PageMagic
|
2
|
+
describe ClassMethods do
|
3
|
+
subject do
|
4
|
+
Object.new.tap { |o| o.extend(described_class) }
|
5
|
+
end
|
6
|
+
describe '#url' do
|
7
|
+
it 'get/sets a value' do
|
8
|
+
subject.url(:url)
|
9
|
+
expect(subject.url).to eq(:url)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'on_load' do
|
14
|
+
context 'block not set' do
|
15
|
+
it 'returns a default block' do
|
16
|
+
expect(subject.on_load).to be(described_class::DEFAULT_ON_LOAD)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'block set' do
|
21
|
+
it 'returns that block' do
|
22
|
+
expected_block = proc {}
|
23
|
+
subject.on_load(&expected_block)
|
24
|
+
expect(subject.on_load).to be(expected_block)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -120,7 +120,10 @@ module PageMagic
|
|
120
120
|
describe 'location' do
|
121
121
|
context 'a prefetched object' do
|
122
122
|
it 'should add a section' do
|
123
|
-
expected_section = Element.new(:page_section,
|
123
|
+
expected_section = Element.new(:page_section,
|
124
|
+
parent_page_element,
|
125
|
+
type: :element,
|
126
|
+
prefetched_browser_element: :object)
|
124
127
|
page_elements.element :page_section, :object
|
125
128
|
expect(expected_section).to eq(page_elements.elements(parent_page_element).first)
|
126
129
|
end
|
@@ -130,7 +133,7 @@ module PageMagic
|
|
130
133
|
describe 'session handle' do
|
131
134
|
it 'should be on instances created from a class' do
|
132
135
|
browser_element = double(:browser_element, find: :browser_element)
|
133
|
-
parent = double('parent', session: :current_session,
|
136
|
+
parent = double('parent', session: :current_session, prefetched_browser_element: browser_element)
|
134
137
|
page_elements.element :page_section, selector
|
135
138
|
|
136
139
|
section = page_elements.element_definitions[:page_section].call(parent)
|
@@ -141,7 +144,7 @@ module PageMagic
|
|
141
144
|
it 'should be on instances created dynamically using the section method' do
|
142
145
|
browser_element = double('browser_element')
|
143
146
|
allow(browser_element).to receive(:find)
|
144
|
-
parent = double('parent', session: :current_session,
|
147
|
+
parent = double('parent', session: :current_session, prefetched_browser_element: browser_element)
|
145
148
|
|
146
149
|
page_elements.element :page_section, css: :selector do
|
147
150
|
end
|
@@ -1,13 +1,33 @@
|
|
1
1
|
module PageMagic
|
2
2
|
describe InstanceMethods do
|
3
3
|
include_context :webapp_fixture
|
4
|
-
|
5
|
-
|
4
|
+
|
5
|
+
let(:page_class) do
|
6
|
+
Class.new do
|
6
7
|
include PageMagic
|
7
8
|
url '/page1'
|
8
9
|
link(:next_page, text: 'next page')
|
9
10
|
end
|
10
|
-
|
11
|
+
end
|
12
|
+
|
13
|
+
subject do
|
14
|
+
page_class.new.tap(&:visit)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'execute_on_load' do
|
18
|
+
it 'runs the on_load_hook in the context of self' do
|
19
|
+
instance = subject
|
20
|
+
page_class.on_load do
|
21
|
+
extend RSpec::Matchers
|
22
|
+
expect(self).to be(instance)
|
23
|
+
end
|
24
|
+
|
25
|
+
subject.execute_on_load
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'returns self' do
|
29
|
+
expect(subject.execute_on_load).to be(subject)
|
30
|
+
end
|
11
31
|
end
|
12
32
|
|
13
33
|
context '#respond_to?' do
|
@@ -20,10 +40,15 @@ module PageMagic
|
|
20
40
|
end
|
21
41
|
end
|
22
42
|
|
23
|
-
describe 'visit' do
|
43
|
+
describe '#visit' do
|
24
44
|
it 'goes to the class define url' do
|
25
45
|
expect(subject.session.current_path).to eq('/page1')
|
26
46
|
end
|
47
|
+
|
48
|
+
it 'runs the on load handler' do
|
49
|
+
expect(subject).to receive(:execute_on_load).and_call_original
|
50
|
+
subject.visit
|
51
|
+
end
|
27
52
|
end
|
28
53
|
|
29
54
|
describe 'session' do
|
@@ -77,34 +77,54 @@ module PageMagic
|
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
80
|
+
describe '#wait' do
|
81
|
+
it 'passes the supplied block to the wait api' do
|
82
|
+
block = proc { :executed }
|
83
|
+
allow_any_instance_of(Wait).to receive(:until).and_call_original
|
84
|
+
expect(subject.wait_until(&block)).to eq(:executed)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
80
88
|
describe '#visit' do
|
81
89
|
let(:session) do
|
82
90
|
allow(browser).to receive(:visit)
|
83
91
|
PageMagic::Session.new(browser, url)
|
84
92
|
end
|
85
93
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
94
|
+
context 'page supplied' do
|
95
|
+
it 'sets the current page' do
|
96
|
+
session.define_page_mappings '/page' => page
|
97
|
+
session.visit(page)
|
98
|
+
expect(session.current_page).to be_a(page)
|
99
|
+
end
|
91
100
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
101
|
+
it 'uses the current url and the path in the page mappings' do
|
102
|
+
session.define_page_mappings '/page' => page
|
103
|
+
expect(browser).to receive(:visit).with("#{browser.current_url}/page")
|
104
|
+
session.visit(page)
|
105
|
+
end
|
97
106
|
|
98
|
-
|
99
|
-
|
100
|
-
|
107
|
+
context 'no mappings found' do
|
108
|
+
it 'raises an error' do
|
109
|
+
expect { session.visit(page) }.to raise_exception InvalidURLException, described_class::URL_MISSING_MSG
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'mapping is a regular expression' do
|
114
|
+
it 'raises an error' do
|
115
|
+
session.define_page_mappings(/mapping/ => page)
|
116
|
+
expect { session.visit(page) }.to raise_exception InvalidURLException, described_class::REGEXP_MAPPING_MSG
|
117
|
+
end
|
101
118
|
end
|
102
|
-
end
|
103
119
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
120
|
+
it 'calls the onload hook' do
|
121
|
+
on_load_hook_called = false
|
122
|
+
page.on_load do
|
123
|
+
on_load_hook_called = true
|
124
|
+
end
|
125
|
+
session.define_page_mappings('/page' => page)
|
126
|
+
session.visit(page)
|
127
|
+
expect(on_load_hook_called).to eq(true)
|
108
128
|
end
|
109
129
|
end
|
110
130
|
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,141 +1,127 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: page_magic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.alpha19
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leon Davis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-11-
|
11
|
+
date: 2015-11-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: capybara
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activesupport
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '4'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '4'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: wait
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: jeweler
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
61
|
+
version: '2.0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
68
|
+
version: '2.0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rubocop
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
75
|
+
version: '0.34'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: pry-byebug
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
82
|
+
version: '0.34'
|
97
83
|
- !ruby/object:Gem::Dependency
|
98
84
|
name: yard
|
99
85
|
requirement: !ruby/object:Gem::Requirement
|
100
86
|
requirements:
|
101
|
-
- - "
|
87
|
+
- - "~>"
|
102
88
|
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
89
|
+
version: '0.8'
|
104
90
|
type: :development
|
105
91
|
prerelease: false
|
106
92
|
version_requirements: !ruby/object:Gem::Requirement
|
107
93
|
requirements:
|
108
|
-
- - "
|
94
|
+
- - "~>"
|
109
95
|
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
96
|
+
version: '0.8'
|
111
97
|
- !ruby/object:Gem::Dependency
|
112
98
|
name: redcarpet
|
113
99
|
requirement: !ruby/object:Gem::Requirement
|
114
100
|
requirements:
|
115
|
-
- - "
|
101
|
+
- - "~>"
|
116
102
|
- !ruby/object:Gem::Version
|
117
|
-
version: '
|
103
|
+
version: '3.3'
|
118
104
|
type: :development
|
119
105
|
prerelease: false
|
120
106
|
version_requirements: !ruby/object:Gem::Requirement
|
121
107
|
requirements:
|
122
|
-
- - "
|
108
|
+
- - "~>"
|
123
109
|
- !ruby/object:Gem::Version
|
124
|
-
version: '
|
110
|
+
version: '3.3'
|
125
111
|
- !ruby/object:Gem::Dependency
|
126
112
|
name: github-markup
|
127
113
|
requirement: !ruby/object:Gem::Requirement
|
128
114
|
requirements:
|
129
|
-
- - "
|
115
|
+
- - "~>"
|
130
116
|
- !ruby/object:Gem::Version
|
131
|
-
version: '
|
117
|
+
version: '1.4'
|
132
118
|
type: :development
|
133
119
|
prerelease: false
|
134
120
|
version_requirements: !ruby/object:Gem::Requirement
|
135
121
|
requirements:
|
136
|
-
- - "
|
122
|
+
- - "~>"
|
137
123
|
- !ruby/object:Gem::Version
|
138
|
-
version: '
|
124
|
+
version: '1.4'
|
139
125
|
description: Framework for modeling and interacting with webpages which wraps capybara
|
140
126
|
email: info@lad-tech.com
|
141
127
|
executables: []
|
@@ -158,6 +144,7 @@ files:
|
|
158
144
|
- VERSION
|
159
145
|
- circle.yml
|
160
146
|
- lib/page_magic.rb
|
147
|
+
- lib/page_magic/class_methods.rb
|
161
148
|
- lib/page_magic/driver.rb
|
162
149
|
- lib/page_magic/drivers.rb
|
163
150
|
- lib/page_magic/drivers/poltergeist.rb
|
@@ -176,6 +163,7 @@ files:
|
|
176
163
|
- page_magic.gemspec
|
177
164
|
- spec/element_spec.rb
|
178
165
|
- spec/member_methods_spec.rb
|
166
|
+
- spec/page_magic/class_methods_spec.rb
|
179
167
|
- spec/page_magic/driver_spec.rb
|
180
168
|
- spec/page_magic/drivers/poltergeist_spec.rb
|
181
169
|
- spec/page_magic/drivers/rack_test_spec.rb
|