seleniumrecord 0.0.2 → 0.0.3
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/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
|