watir_pump 0.4.4 → 0.4.5

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: fbc8d45a395114f228e95ff0295d63f805413569
4
- data.tar.gz: 44ecc359ec890c7cebca9ea0c01b4083574b6c14
3
+ metadata.gz: 825e0f544c5d9359dc7d582330d6778c1ff643c7
4
+ data.tar.gz: 3ffb4f6c5084f2fbe28ac99137c628abd4866817
5
5
  SHA512:
6
- metadata.gz: d996f58058addce4787230775fd4812b0c54ec33961a798c221f80ec5e357388fc588bb9db6ecd25432feb0ec570dcc44a400c0b6493c6fb8beae136802be19d
7
- data.tar.gz: 2182e0353b6b46fb3a0194681fea3bcea8653db6040bbca6fa2890886c68fc29a8349260a2c87fec70ba1d5961a0be1f40163d476ada64997802cf213e1f283c
6
+ metadata.gz: 5b3628fb10dac751866eef5ae29f26b2580c8715a29ab89ace6ae0497693bfbf8ca9c396e8217e997e3ed7217fe45adbe448df354b7541f51dde1d4c6caa9938
7
+ data.tar.gz: 2479f5aea9ebcf75751f3a6cf1e07b3a6c96228a87a3eded35cdd525d55640bd8bb70fd28c5811f088c88e095a249806f411bd344ccd6b82e28c3f5181a6fb2e
@@ -14,6 +14,36 @@ require_relative 'components/dropdown_list'
14
14
  require_relative 'components/flag'
15
15
 
16
16
  module WatirPump
17
+ # Representation of a reusable page component.
18
+ #
19
+ # Next to class methods documented below it contains also dynamically
20
+ # generated methods for declaring +Watir::Elements+ belonging to the
21
+ # component.
22
+ #
23
+ # See {WatirPump::WATIR_METHOD_MAPPING} for a complete list of elemet methods.
24
+ #
25
+ # There are also dynamically generated class methods that create +reader+,
26
+ # +writer+ and +clicker+ instance methods.
27
+ # Please refer to {file:README.md} for more details.
28
+ #
29
+ # @example
30
+ # class MyComponent < WatirPump::Component
31
+ # # declaration of a div element
32
+ # # instance method `description` returns Watir::Div
33
+ # div :description, id: 'desc'
34
+ #
35
+ # # declaration of a div element reader
36
+ # # instance method `description` returns String
37
+ # div_reader :description, id: 'desc'
38
+ #
39
+ # # declaration of a button element clicker
40
+ # # instance method `login` clicks on the button
41
+ # button_clicker :login, id: 'submit'
42
+ #
43
+ # # declaration of a text_field writer
44
+ # # instance method `surname=(value)` sets value of the text_field
45
+ # text_field_writer :surname, id: 'surname'
46
+ # end
17
47
  class Component # rubocop:disable Metrics/ClassLength
18
48
  extend Forwardable
19
49
 
@@ -21,7 +51,12 @@ module WatirPump
21
51
 
22
52
  delegate Constants::METHODS_FORWARDED_TO_ROOT => :root
23
53
 
54
+ # Reference to browser instance
55
+ # @return [Watir::Browser]
24
56
  attr_reader :browser
57
+
58
+ # Parent {Component}. +nil+ for Pages
59
+ # @return [Component]
25
60
  attr_reader :parent
26
61
 
27
62
  class << self
@@ -35,10 +70,16 @@ module WatirPump
35
70
  end
36
71
  end
37
72
 
73
+ # Returns a set of declared element readers. Used by {form_data}
74
+ #
75
+ # @return [Set<Symbol>]
38
76
  def form_field_readers
39
77
  @form_field_readers ||= Set.new
40
78
  end
41
79
 
80
+ # Returns a set of declared element writers. Used by {fill_form}
81
+ #
82
+ # @return [Set<Symbol>]
42
83
  def form_field_writers
43
84
  @form_field_writers ||= Set.new
44
85
  end
@@ -48,11 +89,35 @@ module WatirPump
48
89
  include Components::DropdownList
49
90
  include Components::Flag
50
91
 
92
+ # Declares a custom element reader.
93
+ # @example
94
+ # custom_reader :price, -> { root.span(id: 'price').text.to_f }
95
+ # custom_reader :price2
96
+ #
97
+ # def price2
98
+ # root.span(id: 'price').text.to_f
99
+ # end
100
+ #
101
+ # @param [Symbol] name Name of the reader method
102
+ # @param [Proc] Method body (optional). If not provided a regular instance
103
+ # with given name has to be declared
51
104
  def custom_reader(name, code = nil)
52
105
  form_field_readers << name
53
106
  query(name, code) if code
54
107
  end
55
108
 
109
+ # Declares a custom element writer.
110
+ # @example
111
+ # custom_writer :price, ->(v) { root.text_field(id: 'price').set(v) }
112
+ # custom_writer :price2
113
+ #
114
+ # def price2=(v)
115
+ # root.text_field(id: 'price').set(v)
116
+ # end
117
+ #
118
+ # @param [Symbol] name Name of the writer method (without trailing '=')
119
+ # @param [Proc] Method body (optional). If not provided a regular instance
120
+ # with given name (with trailing '=') has to be declared
56
121
  def custom_writer(name, code = nil)
57
122
  form_field_writers << name
58
123
  query("#{name}=", code) if code
@@ -68,6 +133,7 @@ module WatirPump
68
133
  end
69
134
  end
70
135
  end
136
+ private_class_method :define_reader
71
137
 
72
138
  def self.define_writer(watir_method)
73
139
  define_method "#{watir_method}_writer" do |name, *args|
@@ -78,6 +144,7 @@ module WatirPump
78
144
  end
79
145
  end
80
146
  end
147
+ private_class_method :define_writer
81
148
 
82
149
  def self.define_accessor(watir_method) # rubocop:disable Metrics/AbcSize
83
150
  define_method "#{watir_method}_accessor" do |name, *args|
@@ -95,6 +162,7 @@ module WatirPump
95
162
  end
96
163
  end
97
164
  end
165
+ private_class_method :define_accessor
98
166
 
99
167
  # Methods for element content readers
100
168
  # span_reader, :title, id: asd
@@ -124,12 +192,28 @@ module WatirPump
124
192
  end
125
193
  end
126
194
 
195
+ # A shorthand to generate one-liner instance methods
196
+ #
197
+ # @example
198
+ # query :sum, ->(a, b) { a + b }
199
+ # # is equivalent to:
200
+ # def sum(a, b)
201
+ # a + b
202
+ # end
203
+ #
204
+ # @param [Symbol] name Name of the method
205
+ # @param [Proc] p Body of the method
127
206
  def query(name, p)
128
207
  define_method(name) do |*args|
129
208
  instance_exec(*args, &p)
130
209
  end
131
210
  end
132
211
 
212
+ # Declares an element located with lambda.
213
+ # @example
214
+ # element :name, -> { root.span(id: 'name') }
215
+ #
216
+ # @return [Watir::Element]
133
217
  def element(name, p)
134
218
  define_method(name) do |*args|
135
219
  ret = instance_exec(*args, &p)
@@ -143,6 +227,12 @@ module WatirPump
143
227
  end
144
228
  end
145
229
 
230
+ # Declares an element collection located with lambda.
231
+ # @example
232
+ # # mind the plural in watir method name: `lis` - not `li`!
233
+ # elements :items, -> { root.lis(class: 'item') }
234
+ #
235
+ # @return [Watir::ElementCollection]
146
236
  def elements(name, p)
147
237
  define_method(name) do |*args|
148
238
  ret = instance_exec(*args, &p)
@@ -156,11 +246,33 @@ module WatirPump
156
246
  end
157
247
  end
158
248
 
249
+ # Declares anonymous component (namespace).
250
+ # @example
251
+ # class HomePage < WatirPump::Page
252
+ # region :login_box, :div, id: 'login_box' do
253
+ # text_field :username, id: 'user'
254
+ # text_field :password, id: 'pass'
255
+ # button :login, id: 'login'
256
+ # end
257
+ #
258
+ # def do_login(user, pass)
259
+ # login_box.username.set user
260
+ # login_box.password.set pass
261
+ # login_box.login.click
262
+ # end
263
+ # end
159
264
  def region(name, loc_method = nil, *loc_args, &blk)
160
265
  klass = Class.new(Component) { instance_exec(&blk) }
161
266
  component(name, klass, loc_method, *loc_args)
162
267
  end
163
268
 
269
+ # Declares a component of a given class under a given method name.
270
+ # @example
271
+ # component :login_form1, LoginForm, :div, id: 'login_form1'
272
+ # component :login_form2, LoginForm, -> { root.div(id: 'login_form2') }
273
+ #
274
+ # @param [Symbol] name Name of the method to access the component instance
275
+ # @param [Class] klass Class of the declared component
164
276
  def component(name, klass, loc_method = nil, *loc_args)
165
277
  define_method(name) do |*args|
166
278
  node = find_element_raw(watir_method: loc_method,
@@ -177,6 +289,14 @@ module WatirPump
177
289
  end
178
290
  end
179
291
 
292
+ # Declares a component collection
293
+ # of a given class under a given method name.
294
+ # @example
295
+ # components :products1, ProductList, :divs, class: 'product'
296
+ # components :products2, ProductList, -> { root.divs(class: 'product') }
297
+ #
298
+ # @param [Symbol] name Name of the method to access the component list
299
+ # @param [Class] klass Class of the component in the list
180
300
  def components(name, klass, loc_method = nil, *loc_args)
181
301
  define_method(name) do |*args|
182
302
  nodes = find_element_raw(watir_method: loc_method,
@@ -193,6 +313,13 @@ module WatirPump
193
313
  end
194
314
  end
195
315
 
316
+ # Decorate the result of given method with a list of wrapper classes.
317
+ #
318
+ # @example
319
+ # decorate :products, ProductCollection, AccessByNameCollection
320
+ #
321
+ # @param [Symbol] method Name of the method to be decorated
322
+ # @param [*Class] klasses List of wrapper classes
196
323
  def decorate(method, *klasses)
197
324
  klasses.each do |klass|
198
325
  original_name = "#{method}_before_#{klass}".to_sym
@@ -202,53 +329,47 @@ module WatirPump
202
329
  end
203
330
  end
204
331
  end
332
+ end # << self
205
333
 
206
- def decorate2(method, code)
207
- original_name = "#{method}_before_decorate2".to_sym
208
- alias_method original_name, method
209
- define_method method do |*args|
210
- v = send(original_name, *args)
211
- instance_exec(v, &code)
212
- end
213
- end
214
- end
215
-
334
+ # Invoked implicity by WatirPump framework.
335
+ #
336
+ # @param [Watir::Browser] browser Reference to browser instance
337
+ # @param [Component] parent Parent Component
338
+ # @param [Watir::Element] root_node Component mounting point in the DOM tree
216
339
  def initialize(browser, parent = nil, root_node = nil)
217
340
  @browser = browser
218
341
  @parent = parent
219
342
  @root_node = root_node
220
343
  end
221
344
 
345
+ # Component mounting point in the DOM tree.
346
+ # All component elements are located relatively to it.
347
+ # For {Page} instances it points to +browser+
348
+ #
349
+ # @return [Watir::Element]
222
350
  def root
223
351
  return @root_node if @root_node
224
352
  return browser if parent.nil?
225
- ret = parent.root
226
- ret.class.name.include?('Collection') ? ret.first : ret
353
+ parent.root
227
354
  end
228
355
  alias node root
229
356
 
230
- def form_field_writers
231
- return @form_field_writers if @form_field_writers
232
- @form_field_writers = Set.new
233
- self.class.ancestors.each do |a|
234
- if a.respond_to? :form_field_writers
235
- @form_field_writers += a.form_field_writers
236
- end
237
- end
238
- @form_field_writers
239
- end
240
-
241
- def form_field_readers
242
- return @form_field_readers if @form_field_readers
243
- @form_field_readers = Set.new
244
- self.class.ancestors.each do |a|
245
- if a.respond_to? :form_field_readers
246
- @form_field_readers += a.form_field_readers
247
- end
248
- end
249
- @form_field_readers
250
- end
251
-
357
+ # Invokes element writer methods of given names with given values
358
+ # @example
359
+ # class MyPage < WatirPump::Page
360
+ # text_field_writer :first_name, id: 'first_name'
361
+ # text_field_writer :last_name, id: 'last_name'
362
+ # flag_writer :confirmed, id: 'confirmed'
363
+ # end
364
+ # MyPage.use do
365
+ # fill_form(first_name: 'John', last_name: 'Smith', confirmed: true)
366
+ # # is a shorthand for:
367
+ # self.first_name = 'John'
368
+ # self.last_name = 'Smith'
369
+ # self.confirmed = true
370
+ # end
371
+ #
372
+ # @param Hash data Names of writer methods (symbols), and values for them.
252
373
  def fill_form(data)
253
374
  missing = data.to_h.keys - form_field_writers.to_a
254
375
  unless missing.empty?
@@ -259,12 +380,30 @@ module WatirPump
259
380
  end
260
381
  end
261
382
 
383
+ # Same as {fill_form} but additionally invokes `submit` method if it exists.
384
+ # Otherwise raises an Exception.
385
+ #
386
+ # @param Hash data Names of writer methods (symbols), and values for them.
262
387
  def fill_form!(data)
263
388
  fill_form(data)
264
389
  raise ':fill_form! requries :submit method' unless respond_to? :submit
265
390
  submit
266
391
  end
267
392
 
393
+ # Invokes all reader methods at once and returns their values.
394
+ # @example
395
+ # class MyPage < WatirPump::Page
396
+ # span_reader :first_name, id: 'first_name'
397
+ # span_reader :last_name, id: 'last_name'
398
+ # flag_reader :confirmed, id: 'confirmed'
399
+ # end
400
+ # MyPage.use do
401
+ # data = form_data
402
+ # data == {first_name: 'John', last_name: 'Smith', confirmed: true}
403
+ # end
404
+ #
405
+ # @return [Hash] Names of declared reader methods (symbols)
406
+ # and values they returned.
268
407
  def form_data
269
408
  {}.tap do |h|
270
409
  form_field_readers.map do |field|
@@ -273,6 +412,30 @@ module WatirPump
273
412
  end
274
413
  end
275
414
 
415
+ private
416
+
417
+ def form_field_writers
418
+ return @form_field_writers if @form_field_writers
419
+ @form_field_writers = Set.new
420
+ self.class.ancestors.each do |a|
421
+ if a.respond_to? :form_field_writers
422
+ @form_field_writers += a.form_field_writers
423
+ end
424
+ end
425
+ @form_field_writers
426
+ end
427
+
428
+ def form_field_readers
429
+ return @form_field_readers if @form_field_readers
430
+ @form_field_readers = Set.new
431
+ self.class.ancestors.each do |a|
432
+ if a.respond_to? :form_field_readers
433
+ @form_field_readers += a.form_field_readers
434
+ end
435
+ end
436
+ @form_field_readers
437
+ end
438
+
276
439
  def find_element(watir_method, args, loc_args = nil)
277
440
  find_element_raw(watir_method: watir_method,
278
441
  watir_method_args: args,
@@ -39,6 +39,7 @@ module WatirPump
39
39
  h4
40
40
  h5
41
41
  h6
42
+ li
42
43
  ].freeze
43
44
  end
44
45
  end
@@ -5,18 +5,30 @@ require 'addressable/template'
5
5
  require_relative 'component'
6
6
 
7
7
  module WatirPump
8
+ # Representation of a single page of the application under test.
9
+ #
10
+ # Implements +Singleton+ pattern.
8
11
  class Page < Component
9
12
  class << self
10
13
  extend Forwardable
11
14
 
15
+ # List of class methods forwarded to the singleton instance
12
16
  INSTANCE_DELEGATED_METHODS = %i[
13
17
  browser
14
18
  open open_yield open_dsl
15
19
  use use_yield use_dsl
16
- act act_yield use_dsl
20
+ act act_yield act_dsl
21
+ loaded?
22
+ matches_current_url?
23
+ url_template
17
24
  ].freeze
18
25
  delegate INSTANCE_DELEGATED_METHODS => :instance
19
26
 
27
+ # Class macro declaring Page's URI template. Example: +'/jobs/\{job_id}'+
28
+ #
29
+ # @see https://github.com/sporkmonger/addressable
30
+ # @param [String] uri URI of current page.
31
+ # Compliant with +Addressable::Template+
20
32
  def uri(uri = nil)
21
33
  return @uri if @uri
22
34
  if uri.nil?
@@ -29,15 +41,27 @@ module WatirPump
29
41
  @uri
30
42
  end
31
43
 
32
- def loaded?
33
- Addressable::Template.new(instance.url_template).match browser.url
34
- end
35
-
44
+ # Returns singleton instance of current Page
45
+ #
46
+ # @return [Page]
36
47
  def instance
37
48
  @instance ||= new(WatirPump.config.browser)
38
49
  end
39
50
  end # << self
40
51
 
52
+ # Returns complete (base plus URI) URL template for current Page
53
+ #
54
+ # @return [String]
55
+ def url_template
56
+ WatirPump.config.base_url + self.class.uri
57
+ end
58
+
59
+ # Opens the page in the browser and executes passed block in the scope
60
+ # of the page instance. Depending on the value of
61
+ # +WatirPump.config.call_page_blocks_with_yield+ method {open_yield}
62
+ # or {open_dsl} is called internally
63
+ #
64
+ # @param [Hash] params Parameters for the URL template
41
65
  def open(params = {}, &blk)
42
66
  if WatirPump.config.call_page_blocks_with_yield
43
67
  open_yield(params, &blk)
@@ -46,6 +70,17 @@ module WatirPump
46
70
  end
47
71
  end
48
72
 
73
+ # Opens the page in the browser and executes passed block in the scope
74
+ # of the page instance. Current +page+ and +browser+ references are
75
+ # passed to the yielded block.
76
+ #
77
+ # @example
78
+ # UserPage.open_yield(id: 123) do |page, browser|
79
+ # puts page.root.h1.text
80
+ # puts browser.title
81
+ # end
82
+ #
83
+ # @param [Hash] params Parameters for the URL template
49
84
  def open_yield(params = {}, &blk)
50
85
  url = Addressable::Template.new(url_template).expand(params).to_s
51
86
  browser.goto url
@@ -53,6 +88,16 @@ module WatirPump
53
88
  self
54
89
  end
55
90
 
91
+ # Opens the page in the browser and executes passed block in the scope
92
+ # of the page instance (+instance_exec+).
93
+ #
94
+ # @example
95
+ # UserPage.open_dsl(id: 123) do
96
+ # puts root.h1.text
97
+ # puts browser.title
98
+ # end
99
+ #
100
+ # @param [Hash] params Parameters for the URL template
56
101
  def open_dsl(params = {}, &blk)
57
102
  url = Addressable::Template.new(url_template).expand(params).to_s
58
103
  browser.goto url
@@ -60,6 +105,10 @@ module WatirPump
60
105
  self
61
106
  end
62
107
 
108
+ # Executes passed block in the scope of the page instance.
109
+ # Depending on the value of
110
+ # +WatirPump.config.call_page_blocks_with_yield+ method {use_yield}
111
+ # or {use_dsl} is called internally
63
112
  def use(&blk)
64
113
  if WatirPump.config.call_page_blocks_with_yield
65
114
  use_yield(&blk)
@@ -69,6 +118,15 @@ module WatirPump
69
118
  end
70
119
  alias act use
71
120
 
121
+ # Executes passed block in the scope of the page instance.
122
+ # Current +page+ and +browser+ references are
123
+ # passed to the yielded block.
124
+ #
125
+ # @example
126
+ # UserPage.use_yield do |page, browser|
127
+ # puts page.root.h1.text
128
+ # puts browser.title
129
+ # end
72
130
  def use_yield
73
131
  wait_for_loaded
74
132
  yield self, browser
@@ -76,6 +134,14 @@ module WatirPump
76
134
  end
77
135
  alias act_yield use_yield
78
136
 
137
+ # Executes passed block in the scope of the page instance.
138
+ # (+instance_exec+)
139
+ #
140
+ # @example
141
+ # UserPage.use_dsl do
142
+ # puts root.h1.text
143
+ # puts browser.title
144
+ # end
79
145
  def use_dsl(&blk)
80
146
  wait_for_loaded
81
147
  instance_exec(&blk)
@@ -83,10 +149,9 @@ module WatirPump
83
149
  end
84
150
  alias act_dsl use_dsl
85
151
 
86
- def url_template
87
- WatirPump.config.base_url + self.class.uri
88
- end
89
-
152
+ # Waits until current Page is loaded
153
+ #
154
+ # @return [Page] self
90
155
  def wait_for_loaded
91
156
  Watir::Wait.until(message: "Timeout waiting for #{self} to load") do
92
157
  loaded?
@@ -94,12 +159,19 @@ module WatirPump
94
159
  self
95
160
  end
96
161
 
162
+ # Predicate denoting if page is ready to be interacted with
163
+ # Overload in child class to customize the readiness criteria
164
+ #
165
+ # @return [Boolean]
97
166
  def loaded?
98
- self.class.loaded?
167
+ matches_current_url?
99
168
  end
100
169
 
101
- def uri
102
- self.class.uri
170
+ # Predicate denoting if current browser URL matches pages `uri` template
171
+ #
172
+ # @return [Boolean]
173
+ def matches_current_url?
174
+ Addressable::Template.new(url_template).match browser.url
103
175
  end
104
176
  end
105
177
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: watir_pump
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.4
4
+ version: 0.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bartek Wilczek
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-09-06 00:00:00.000000000 Z
11
+ date: 2018-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport