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 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