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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5c45b76e17d2e8c4e62e0d8cb713020357031879
4
- data.tar.gz: 5e8752075f3ab3ab1e82ef15a7603b8508c5f490
3
+ metadata.gz: c218633c4ac035844b5029134164f49fbbbffd09
4
+ data.tar.gz: d79b3c62f1b796e10a42d7306ce056a096a0ea5e
5
5
  SHA512:
6
- metadata.gz: 9eba4632b6c62af6a81b7003a17f566a470b3dab8141fe49ce03503195e45a9fe7af072212e4e9c774bf12813156dfb8fc75256361be1007b8cc4f9c56f38af3
7
- data.tar.gz: 9ca10dc331a610e02720c695d452dd5e11e5809ab7c74f6107ad200cce588f823c75d92846bef2699a52fd6cd9feaad34821a759f273c21ff9a28c3d654bec5d
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
- - [ ] Full test coverage
63
- - [ ] Wiki and README Documentation
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(so_module) do |klass, sym|
19
+ modules.compact.reduce(Configuration.objects_module) do |klass, sym|
20
20
  klass.const_get(sym)
21
21
  end
22
22
  end
@@ -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 = "Lookup#{strategy_sym.to_s.camelize}Strategy"
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 LookupRelativeTitleStrategy < LookupStrategy
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 LookupRelativePathStrategy < LookupStrategy
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 LookupMatchingStrategy < LookupStrategy
105
+ class MatchingStrategy < LookupStrategy
106
106
  def run
107
- lookup_sequence { [lookup_attrs[:locator]] }
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 LookupRootStrategy < LookupStrategy
112
+ class RootStrategy < LookupStrategy
113
113
  def run
114
114
  lookup_sequence { [{ xpath: '//body' }] }
115
115
  end
@@ -1,3 +1,3 @@
1
1
  module SeleniumRecord
2
- VERSION = '0.0.2'
2
+ VERSION = '0.0.3'
3
3
  end
@@ -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', '~> 4.1.8'
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.2
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-16 00:00:00.000000000 Z
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: 4.1.8
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: 4.1.8
26
+ version: 3.2.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement