watir_pump 0.4.4 → 0.4.5

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