seleniumrecord 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +249 -5
- data/lib/selenium_record/actions.rb +10 -0
- data/lib/selenium_record/axiable.rb +5 -1
- data/lib/selenium_record/component_autoload.rb +1 -1
- data/lib/selenium_record/core.rb +0 -4
- data/lib/selenium_record/lookup.rb +6 -6
- data/lib/selenium_record/version.rb +1 -1
- data/selenium_record.gemspec +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c218633c4ac035844b5029134164f49fbbbffd09
|
4
|
+
data.tar.gz: d79b3c62f1b796e10a42d7306ce056a096a0ea5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3315d71b705d77a4a943aab0ab82733b1bb31db8e49f4dd7ac9c39557e9b63150c02c34bc5048a454d00e0f093d3b57a9132fe972cfd46ca413b447457687d46
|
7
|
+
data.tar.gz: 2eaeecf4f932bc1494bfb89e3e230a84de40a8d5cc2b15ce2b2848bb7fbc63f24178869b4fbd40b3d2caa8c9630c8617797c4f4dcd2292b5bc8bd02343fe4dd8
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
## 0.0.3
|
2
|
+
|
3
|
+
* Fixed SeleniumRecord::Lookup::MatchingStrategy
|
4
|
+
* Renamed Lookup strategies for cleaner code
|
5
|
+
* Added Basic Documentation
|
6
|
+
* Added method `focus` to `SeleniumRecord::Actions` module
|
7
|
+
|
8
|
+
## 0.0.2.revision
|
9
|
+
|
10
|
+
* Updated `activesupport` dependency gem version
|
11
|
+
|
1
12
|
## 0.0.2
|
2
13
|
|
3
14
|
* Added rake task for scaffolding
|
data/README.md
CHANGED
@@ -32,6 +32,253 @@ Options:
|
|
32
32
|
- 'navigation_components': [Array] The names of the navigation components
|
33
33
|
expected. Default: ['pages', 'tab']
|
34
34
|
|
35
|
+
## Usage
|
36
|
+
|
37
|
+
### Lookup strategy
|
38
|
+
|
39
|
+
Everytime you create a Selenium object it is fired the lookup process. This mean
|
40
|
+
that based on selected strategy is defined the value for `root_el` (an instance
|
41
|
+
of `Selenium::WebDriver::Element`). What really matters about this is that all
|
42
|
+
`find_element` or `find_elements` operations will be done always in the scope
|
43
|
+
of the `root_el`.
|
44
|
+
|
45
|
+
#### Hooks
|
46
|
+
|
47
|
+
The lookup process defines two hooks:
|
48
|
+
|
49
|
+
- before_load_dom: This hook allows you to do some actions before the lookup
|
50
|
+
process. For example, `SeleniumRecord::NavigationItem` takes this hook to
|
51
|
+
click on a menu page and start lookup only once the new page it is loaded.
|
52
|
+
|
53
|
+
- after_load_dom: This hook allows you to do some actions after lookup process.
|
54
|
+
For example, `SeleniumRecord::Base` takes this hook to inject components
|
55
|
+
defined.
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
# selenium_record/component_autoload.rb
|
59
|
+
|
60
|
+
# Inject components after loading dom, providing reader methods for
|
61
|
+
# accessing them
|
62
|
+
# @param names [Array<Symbol>] component names. Valid formats Regex:
|
63
|
+
# /(?<component_name>.*)_(?<component_type>view|tab|pill|modal|panel)$/
|
64
|
+
def component_reader(*names)
|
65
|
+
names.each { |name| create_component_reader name }
|
66
|
+
define_method :after_load_dom do
|
67
|
+
load_components names
|
68
|
+
end
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
**REMEMBER:** All selenium objects should define their lookup strategy through
|
73
|
+
the class method `lookup_strategy`.
|
74
|
+
|
75
|
+
#### Relative title
|
76
|
+
|
77
|
+
In the next example it is search in first place element relative to element for
|
78
|
+
locator returned by `title_locator` instance method. Once found this element
|
79
|
+
it is searched the `root_el` using a relative xpath.
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
# spec/support/selenium_objects/panels/image_panel.rb
|
83
|
+
module SeleniumObjects
|
84
|
+
module Panels
|
85
|
+
# Selenium Page Object to interact with areas sections for a page
|
86
|
+
class ImagePanel < Base::ApplicationView
|
87
|
+
lookup_strategy :relative_title, locator: { xpath: '../../..' }
|
88
|
+
|
89
|
+
# ...
|
90
|
+
```
|
91
|
+
|
92
|
+
#### Matching element
|
93
|
+
|
94
|
+
This strategy searchs exactly for the element which the locator passed as
|
95
|
+
parameter.
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
# spec/support/selenium_objects/panels/image_panel.rb
|
99
|
+
module SeleniumObjects
|
100
|
+
module Panels
|
101
|
+
# Selenium Page Object to interact with areas sections for a page
|
102
|
+
class ImagePanel < Base::ApplicationView
|
103
|
+
lookup_strategy :matching, locator: { xpath: ".//div[@class='todo-list']" }
|
104
|
+
# ...
|
105
|
+
```
|
106
|
+
|
107
|
+
|
108
|
+
#### Root
|
109
|
+
|
110
|
+
This strategy sets as `root_el` the element associated with html `body` tag
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
module SeleniumRecord
|
114
|
+
# Base model to be extended by all Selenium page objects
|
115
|
+
class NavigationItem < Base
|
116
|
+
lookup_strategy :root
|
117
|
+
# ...
|
118
|
+
```
|
119
|
+
|
120
|
+
### Dependency injection
|
121
|
+
|
122
|
+
When you call `component_reader` class method you pass a list of components that
|
123
|
+
will be injected into the current component once it is instantiated. They will
|
124
|
+
be available through the related accessor methods (Example: `filter_panel`).
|
125
|
+
|
126
|
+
#### Components
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
# spec/support/selenium_objects/panels/search/filter_panel
|
130
|
+
module SeleniumObjects
|
131
|
+
module Panels
|
132
|
+
class FilterPanel < Base::ApplicationPanel
|
133
|
+
# ...
|
134
|
+
def search
|
135
|
+
# Do search stuff
|
136
|
+
end
|
137
|
+
|
138
|
+
# spec/support/selenium_objects/views/search_view
|
139
|
+
module SeleniumObjects
|
140
|
+
module Views
|
141
|
+
class SearchView < Base::ApplicationView
|
142
|
+
navigate_to :labels
|
143
|
+
component_reader :filter_panel, :results_panel
|
144
|
+
# ...
|
145
|
+
```
|
146
|
+
|
147
|
+
In addition all method calls to instance methods of components will be proxied
|
148
|
+
through the container component if this component doesn't define the proper
|
149
|
+
method. In the previous example:
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
search_view # => SearchView instance
|
153
|
+
search_view.search # => equal to search_view.filter_panel.search
|
154
|
+
```
|
155
|
+
|
156
|
+
#### Action components
|
157
|
+
|
158
|
+
When you call `action_component_reader` class method you can pass a list of
|
159
|
+
components that will perform an action once they are instantiated. Because of
|
160
|
+
that, when you create an instance of `ConceptView` it will be generated only
|
161
|
+
the accessors methods to create the related instance of `DetailsTab` (equal to
|
162
|
+
other tabs).
|
163
|
+
|
164
|
+
As `DetailsTab` is a component of `ConceptView`, the attribute `parent_el` of
|
165
|
+
`DetailsTab` will match the `root_el` of `ConceptView`.
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
# spec/support/selenium_objects/tabs/details_tab
|
169
|
+
module SeleniumObjects
|
170
|
+
module Tabs
|
171
|
+
class DetailsTab < Base::ApplicationView
|
172
|
+
navigate_to :details
|
173
|
+
|
174
|
+
# spec/support/selenium_objects/views/concept_view.rb
|
175
|
+
module SeleniumObjects
|
176
|
+
module Views
|
177
|
+
class ConceptView < Base::ApplicationView
|
178
|
+
lookup_strategy :root
|
179
|
+
action_component_reader :main_tab, :details_tab, :audit_tab
|
180
|
+
|
181
|
+
```
|
182
|
+
|
183
|
+
If we focus on `DetailsTab`:
|
184
|
+
|
185
|
+
```ruby
|
186
|
+
class DetailsTab < Base::ApplicationView
|
187
|
+
navigate_to :details
|
188
|
+
```
|
189
|
+
|
190
|
+
The method `navigate_to` will perform a click on link with localized string
|
191
|
+
"details".
|
192
|
+
|
193
|
+
Of course you can customize to fit your needs this approach using a code like
|
194
|
+
this one. In the next example we change from expected `trans key` to
|
195
|
+
`trans "txt.views.layouts.sections.#{key}"`
|
196
|
+
|
197
|
+
```ruby
|
198
|
+
# spec/support/selenium_objects/base/application_tab.rb
|
199
|
+
module SeleniumObjects
|
200
|
+
module Base
|
201
|
+
# Base class for all selenium objects representing an application tab
|
202
|
+
class ApplicationTab < ::SeleniumRecord::NavigationItem
|
203
|
+
|
204
|
+
def self.navigate_to(key)
|
205
|
+
define_method :before_navigate do
|
206
|
+
@title = trans "txt.views.layouts.sections.#{key}"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# ...
|
211
|
+
```
|
212
|
+
|
213
|
+
### Scopes
|
214
|
+
|
215
|
+
Scopes allow you to execute code inside a block in the scope of the
|
216
|
+
`Selenium::WebDriver::Element` associated to the scope definition. To define
|
217
|
+
a scoped block you use the syntax: `scope :my_symbol { #stuff }`.
|
218
|
+
The code will be executed in the context of the element with locator defined
|
219
|
+
through method `my_symbol_locator`.
|
220
|
+
|
221
|
+
#### Using locator symbol
|
222
|
+
|
223
|
+
```ruby
|
224
|
+
# spec/support/selenium_objects/views/concept_view.rb
|
225
|
+
module SeleniumObjects
|
226
|
+
module Views
|
227
|
+
class ConceptView < Base::ApplicationView
|
228
|
+
lookup_strategy :root
|
229
|
+
|
230
|
+
def create_new_version
|
231
|
+
scope :fieldset_relations do
|
232
|
+
# Methods from Actions module are executed relative to the element
|
233
|
+
# specified by fieldset_relations_locator
|
234
|
+
# See `selenium_record/actions` for more details
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def fieldset_relations_locator
|
239
|
+
{ xpath: ".//div[@class='relations']"
|
240
|
+
end
|
241
|
+
|
242
|
+
# ...
|
243
|
+
```
|
244
|
+
|
245
|
+
#### Extensions
|
246
|
+
|
247
|
+
Everytime you call methods like `find` or `find_elements`, it will be returned
|
248
|
+
the `Selenium::WebDriver::Element` instances with methods from modules:
|
249
|
+
|
250
|
+
- `SeleniumRecord::Axiable`
|
251
|
+
|
252
|
+
**WARNING**: Currently this behaviour it is only implemented for `find`
|
253
|
+
|
254
|
+
#### Plugins
|
255
|
+
|
256
|
+
As a good practice, all stuff related to a explicit javascript library should
|
257
|
+
be package inside plugins folder. As an example:
|
258
|
+
|
259
|
+
```
|
260
|
+
# spec/support/selenium_objects/plugins/jquery_autocomplete.rb
|
261
|
+
module SeleniumObjects
|
262
|
+
module Plugins
|
263
|
+
class JQueryAutocomplete < ::SeleniumRecord::Base
|
264
|
+
attr_accessor :input_el
|
265
|
+
# @param browser [Selenium::WebDriver::Driver]
|
266
|
+
# @param locator [Hash] The locator of the input text autocomplete element
|
267
|
+
def initialize(browser, locator)
|
268
|
+
@root_el = browser
|
269
|
+
@input_el = find(locator)
|
270
|
+
end
|
271
|
+
|
272
|
+
def perform(text)
|
273
|
+
@text = text
|
274
|
+
search_text
|
275
|
+
select_from_pulldown_menu
|
276
|
+
wait_for_tag_created
|
277
|
+
end
|
278
|
+
|
279
|
+
# ...
|
280
|
+
```
|
281
|
+
|
35
282
|
## Install
|
36
283
|
|
37
284
|
After running `rake selenium_record::install`, you should include a module in
|
@@ -59,11 +306,8 @@ should be completed for '1.0.0' version. Keep up to date!
|
|
59
306
|
|
60
307
|
## Roadmap
|
61
308
|
|
62
|
-
|
63
|
-
|
64
|
-
- [X] Basic install generator
|
65
|
-
- [X] ComponentAutoload integration in core (Currently present as a framework
|
66
|
-
extension)
|
309
|
+
SeleniumRecord is on its way towards 1.0.0. Please refer to
|
310
|
+
[issues](https://github.com/dsaenztagarro/selenium-record/issues) for details.
|
67
311
|
|
68
312
|
## Installation
|
69
313
|
|
@@ -35,6 +35,10 @@ module SeleniumRecord
|
|
35
35
|
el.clear
|
36
36
|
end
|
37
37
|
|
38
|
+
def click_on(locator)
|
39
|
+
find(locator).click
|
40
|
+
end
|
41
|
+
|
38
42
|
# Clicks on element and wait until all jquery events are dispatched
|
39
43
|
# @param how [Symbol] (:class, :class_name, :css, :id, :link_text, :link,
|
40
44
|
# :partial_link_text, :name, :tag_name, :xpath)
|
@@ -54,6 +58,12 @@ module SeleniumRecord
|
|
54
58
|
find(locator).send_keys(text || '')
|
55
59
|
end
|
56
60
|
|
61
|
+
# @param locator [Hash|Selenium::WebDriver::Element]
|
62
|
+
def focus(locator)
|
63
|
+
element = (locator.is_a?(Hash) && find(locator)) || locator
|
64
|
+
browser.action.move_to(element).perform
|
65
|
+
end
|
66
|
+
|
57
67
|
def submit
|
58
68
|
click(xpath: ".//button[@type='submit']")
|
59
69
|
wait_page_load
|
@@ -3,8 +3,12 @@ module SeleniumRecord
|
|
3
3
|
module Axiable
|
4
4
|
# @param element [Selenium::WebDriver::Element]
|
5
5
|
# @return [Selenium::WebDriver::Element] The preceding-sibling axis element
|
6
|
-
def preceding_sibling(tag_name)
|
6
|
+
def preceding_sibling(tag_name = '*')
|
7
7
|
find_element xpath: "./preceding-sibling::#{tag_name}"
|
8
8
|
end
|
9
|
+
|
10
|
+
def parent(tag_name = '*')
|
11
|
+
find_element xpath: "./parent::#{tag_name}"
|
12
|
+
end
|
9
13
|
end
|
10
14
|
end
|
@@ -16,7 +16,7 @@ module SeleniumRecord
|
|
16
16
|
# @return [Module] the module containing the classes for the marker type
|
17
17
|
# group
|
18
18
|
def self.extract_namespace(*modules)
|
19
|
-
modules.compact.reduce(
|
19
|
+
modules.compact.reduce(Configuration.objects_module) do |klass, sym|
|
20
20
|
klass.const_get(sym)
|
21
21
|
end
|
22
22
|
end
|
data/lib/selenium_record/core.rb
CHANGED
@@ -18,10 +18,6 @@ module SeleniumRecord
|
|
18
18
|
false
|
19
19
|
end
|
20
20
|
|
21
|
-
def click_on(locator)
|
22
|
-
find(locator).click
|
23
|
-
end
|
24
|
-
|
25
21
|
# @param [Hash] opts the options to find element
|
26
22
|
# @param opts [String] :global_scope Marks whether the global scope is used
|
27
23
|
# whenever a root element is not present
|
@@ -49,7 +49,7 @@ module SeleniumRecord
|
|
49
49
|
# @param strategy_sym [Symbol] lookup strategy corresponding with the
|
50
50
|
# name of a lookup strategy locator
|
51
51
|
def lookup_strategy(strategy_sym, opts = {})
|
52
|
-
locator_klass = "
|
52
|
+
locator_klass = "#{strategy_sym.to_s.camelize}Strategy"
|
53
53
|
Module.nesting.shift.const_get(locator_klass).new(self, opts).run
|
54
54
|
end
|
55
55
|
|
@@ -82,7 +82,7 @@ module SeleniumRecord
|
|
82
82
|
end
|
83
83
|
|
84
84
|
# Defines a lookup sequence relative to the title xpath
|
85
|
-
class
|
85
|
+
class RelativeTitleStrategy < LookupStrategy
|
86
86
|
def run
|
87
87
|
lookup_sequence do
|
88
88
|
[title_locator, lookup_attributes[:locator]]
|
@@ -92,7 +92,7 @@ module SeleniumRecord
|
|
92
92
|
|
93
93
|
# Defines a lookup sequence relative to the xpath of an element present in
|
94
94
|
# the selenium object
|
95
|
-
class
|
95
|
+
class RelativePathStrategy < LookupStrategy
|
96
96
|
def run
|
97
97
|
lookup_sequence do
|
98
98
|
[send("#{lookup_attributes[:to]}_locator"),
|
@@ -102,14 +102,14 @@ module SeleniumRecord
|
|
102
102
|
end
|
103
103
|
|
104
104
|
# Defines a lookup sequence matching an element path
|
105
|
-
class
|
105
|
+
class MatchingStrategy < LookupStrategy
|
106
106
|
def run
|
107
|
-
lookup_sequence { [
|
107
|
+
lookup_sequence { [lookup_attributes[:locator]] }
|
108
108
|
end
|
109
109
|
end
|
110
110
|
|
111
111
|
# Defines a lookup sequence matching the whole document body
|
112
|
-
class
|
112
|
+
class RootStrategy < LookupStrategy
|
113
113
|
def run
|
114
114
|
lookup_sequence { [{ xpath: '//body' }] }
|
115
115
|
end
|
data/selenium_record.gemspec
CHANGED
@@ -23,7 +23,7 @@ desc
|
|
23
23
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
24
24
|
spec.require_paths = ['lib']
|
25
25
|
|
26
|
-
spec.add_runtime_dependency 'activesupport', '~>
|
26
|
+
spec.add_runtime_dependency 'activesupport', '~> 3.2.0'
|
27
27
|
|
28
28
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
29
29
|
spec.add_development_dependency 'cane', '~> 2.6.2'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: seleniumrecord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Saenz Tagarro
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 3.2.0
|
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: 3.2.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|