domkey 0.2.0 → 0.3.0

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: 45e6ac05a48d93eede629f82f2a5b04b14037f62
4
- data.tar.gz: 9c3b5d281b8b000852489e1933de6b855b2975e3
3
+ metadata.gz: 0468e0993e03c228863792b2979fc0518aea17db
4
+ data.tar.gz: d36475ac117f17891905d01328dadca7bc08fe90
5
5
  SHA512:
6
- metadata.gz: aa5af099b7354c11538d238e9c4a59eb91cf41a7f7845fe10bd92659af309e7e65ebf1630d722952e17a39ca1a0e9a790e955a00d91df35a074ea9de9b83d3d1
7
- data.tar.gz: 2fe75c7ca69ba9f0656491cea2a358a048f815b5da77bc7d614425c4a4a5a353b653364b4f13b522e2a366de699744389e3244dcde80822a7ed9fd6ab727fe56
6
+ metadata.gz: ef11d67c2261cc2e7f4228bbe1f2466a1d82f4ebb8eedd895850c9e48d109080506ae91f6a40055184308e04f24395aedc5c81d0f48d5d7ba866d23b78a4e45d
7
+ data.tar.gz: 5b613799843aedb4959c422fe4dfcf91c28740903c78e4e86dc4b40e971ff803a77567df785e066ae702069bcc5becdb56246c98a7feba1012bc0e96b8cf49e4
@@ -2,5 +2,9 @@ module Domkey
2
2
  module Exception
3
3
  class Error < StandardError
4
4
  end
5
+ class NotImplementedError < Error
6
+ end
7
+ class NotFoundError < Error
8
+ end
5
9
  end
6
10
  end
@@ -1,3 +1,3 @@
1
1
  module Domkey
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -2,6 +2,7 @@ require 'domkey/view/page_object'
2
2
  require 'domkey/view/page_object_collection'
3
3
  require 'domkey/view/radio_group'
4
4
  require 'domkey/view/checkbox_group'
5
+ require 'domkey/view/select_list'
5
6
  require 'domkey/view/cargo'
6
7
 
7
8
  module Domkey
@@ -1,74 +1,23 @@
1
- require 'domkey/view/labeled_group'
1
+ require 'domkey/view/option_selectable_group'
2
+
2
3
  module Domkey
3
4
 
4
5
  module View
5
6
 
6
- # Acts like OptionSelectable object
7
7
  # CheckboxGroup allows you to interact with PageObjectCollection of checkboxes as a single PageObject.
8
- # Checkboxes collection is constrained by the same name attribute and acts like on object.
9
- # It behaves like a Multi Select list.
10
- # It can none, one or more options selected
11
- class CheckboxGroup < PageObjectCollection
12
-
13
- # clears all options and sets only the desired value(s)
14
- # @param [String, Regexp] find value attribute or match value and set that checkbox
15
- # @param [Array<String, Regexp>] find each value attribute and set each checkbox
16
- # @param [False] uncheck any checked checkboxes
17
- def set value
18
- validate_scope
19
- element.each { |e| e.clear }
20
- return unless value
21
- [*value].each do |v|
22
- e = case v
23
- when String
24
- element.find { |e| e.value == v }
25
- when Regexp
26
- element.find { |e| e.value.match(v) }
27
- end
28
- e ? e.set : fail(Exception::Error, "Checkbox to be set not found by value: #{v.inspect}")
29
- end
30
- end
31
-
32
- # @return [Array<String>] value attributes of each checked checkbox
33
- def value
34
- validate_scope
35
- element.find_all { |e| e.set? }.map { |e| e.value }
36
- end
37
-
38
- def options
39
- validate_scope
40
- element.map { |e| e.value }
41
- end
42
-
43
- # convert to LabeledGroup settable by corresponding label text
44
- def to_labeled
45
- LabeledGroup.new(self)
46
- end
47
-
48
- # @yield [PageObject]
49
- def each(&blk)
50
- validate_scope
51
- super(&blk)
52
- end
53
-
54
- # @return [Array<PageObject>]
55
- def to_a
56
- validate_scope
57
- super
58
- end
8
+ # Acts like OptionSelectable
9
+ # Checkboxes collection is constrained by the same name attribute
10
+ # Behaves like a multi Select list.
11
+ # It can have none, one or more options selected
12
+ class CheckboxGroup < OptionSelectableGroup
59
13
 
60
14
  private
61
15
 
62
- # precondition on acting on this collection
63
- # @return [true] when all checkboxes in collection share the same name attribute
64
- # @raise [Exception::Error] when where is more than one unique name attribute
65
- # --
66
- # returns true on subsequent unless magically more radios show up after initial validation
67
- def validate_scope
68
- return if @validated
69
- groups = element.map { |e| e.name }.uniq
70
- fail(Exception::Error, "CheckboxGroup definition scope too broad: Found #{groups.count} checkbox groups with names: #{groups}") unless (groups.size == 1)
71
- @validated = true
16
+ # @api private
17
+ # unselects all checkboxes before setting it with desired value
18
+ def before_set
19
+ validate_scope
20
+ each { |o| o.set false }
72
21
  end
73
22
  end
74
23
  end
@@ -2,8 +2,9 @@ module Domkey
2
2
 
3
3
  module View
4
4
 
5
- # return collection of PageObjects for label locators corresponding to id of each element in a collection
6
5
  class LabelMapper
6
+
7
+ # return collection of PageObjects for label locators corresponding to id of each element in a collection
7
8
  # @param [Array<PageObject>]
8
9
  # @param [PageObjectCollection]
9
10
  # @return [Array<PageObject>] where each PageObject is a locator for label for an id of a PageObject passed in parameters
@@ -12,6 +13,11 @@ module Domkey
12
13
  PageObject.new -> { label(for: e.element.id) }, e.container
13
14
  end
14
15
  end
16
+
17
+ # provide PageObject wrapping label corresponding to id of element in pageobject.
18
+ def self.find pageobject
19
+ PageObject.new -> { label(for: pageobject.element.id) }, pageobject.container
20
+ end
15
21
  end
16
22
  end
17
23
  end
@@ -16,10 +16,31 @@ module Domkey
16
16
  __setobj__(group)
17
17
  end
18
18
 
19
+ def before_set
20
+ __getobj__.set false
21
+ end
22
+
19
23
  # @param value [String] a label text to set a corresponding element referenced
20
24
  # @param value [Array<String>] one or more labels
21
25
  def set value
22
- __getobj__.set false
26
+ before_set
27
+ set_strategy(value)
28
+ end
29
+
30
+ # @return [Array<String>] label texts for selected elements
31
+ def value
32
+ selected_ones = __getobj__.find_all { |e| e.element.set? }
33
+ LabelMapper.for(selected_ones).map { |e| e.element.text }
34
+ end
35
+
36
+ # @return [Array<String>] label texts for all elements in a group
37
+ def options
38
+ LabelMapper.for(__getobj__).map { |e| e.element.text }
39
+ end
40
+
41
+ private
42
+
43
+ def set_strategy value
23
44
  labels = self.options
24
45
  indices = [*value].map do |what|
25
46
  i = case what
@@ -35,16 +56,6 @@ module Domkey
35
56
  end
36
57
  end
37
58
 
38
- # @return [Array<String>] label texts for selected elements
39
- def value
40
- selected_ones = __getobj__.find_all { |e| e.element.set? }
41
- LabelMapper.for(selected_ones).map { |e| e.element.text }
42
- end
43
-
44
- # @return [Array<String>] label texts for all elements in a group
45
- def options
46
- LabelMapper.for(__getobj__).map { |e| e.element.text }
47
- end
48
59
  end
49
60
  end
50
61
  end
@@ -0,0 +1,102 @@
1
+ module Domkey
2
+ module View
3
+ module OptionSelectable
4
+
5
+ # clears all options and sets only the desired value(s)
6
+ # @param [String, Regexp] sets default designated option by String or Regexp
7
+ # @param [Array<String, Regexp>] sets each String, Regexp
8
+ # @param [False] unselects all options
9
+ # @param [Hash{how => value}] selects by how strategy where how is a symbol :label, :index, :text, :value
10
+ # Clients need to implement individual strategy for each 'how' => 'value' pair based on what it means to be selected by what
11
+ def set value
12
+ before_set
13
+ set_strategy value
14
+ end
15
+
16
+ # @param [] opts. Represents a qualifier of what types of options to return. defaults to empty
17
+ # @return [Array<String>] when opts param emtpy returns array of default strings implemented by client
18
+ # @param [Symbol,Array<Symbol>] symbols represents what option selector to return
19
+ # @return [Array<Hash{what => value}] where what is a symbol for option selector, :index, :value, :text, :label
20
+ def value *opts
21
+ opts = opts.flatten
22
+ return value_by_default if (opts.empty? || opts.find { |e| e.kind_of?(String) })
23
+ value_by_options opts
24
+ end
25
+
26
+ # similar strategy to value but returns all options and not only selected ones
27
+ def options *opts
28
+ opts = opts.flatten
29
+ return options_by_default if opts.empty?
30
+ options_by opts
31
+ end
32
+
33
+ private
34
+
35
+ def options_by_default
36
+ fail Exception::NotImplementedError, "Subclass responsible for implementing"
37
+ end
38
+
39
+ def options_by opts
40
+ fail Exception::NotImplementedError, "Subclass responsible for implementing"
41
+ end
42
+
43
+ def value_by_default
44
+ fail Exception::NotImplementedError, "Subclass responsible for implementing"
45
+ end
46
+
47
+ def value_by_options options
48
+ fail Exception::NotImplementedError, "Subclass responsible for implementing"
49
+ end
50
+
51
+ def before_set
52
+ # hook. client can provide actions to be taken before setting this PageObject
53
+ end
54
+
55
+ # strategy for selecting OptionSelectable object
56
+ def set_strategy value
57
+ case value
58
+ when String
59
+ set_by_string(value)
60
+ when Regexp
61
+ set_by_regexp(value)
62
+ when Array
63
+ value.each { |v| set_strategy(v) }
64
+ when Hash
65
+ value.each_pair do |how, value|
66
+ case how
67
+ when :label
68
+ set_by_label(value)
69
+ when :text
70
+ set_strategy(value)
71
+ when :index
72
+ set_by_index(value)
73
+ when :value
74
+ set_by_value(value)
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ def set_by_string value
81
+ fail Exception::NotImplementedError, "Subclass responsible for implementing"
82
+ end
83
+
84
+ def set_by_regexp value
85
+ fail Exception::NotImplementedError, "Subclass responsible for implementing"
86
+ end
87
+
88
+ def set_by_label value
89
+ fail Exception::NotImplementedError, "Subclass responsible for implementing"
90
+ end
91
+
92
+ def set_by_index value
93
+ fail Exception::NotImplementedError, "Subclass responsible for implementing"
94
+ end
95
+
96
+ def set_by_value value
97
+ fail Exception::NotImplementedError, "Subclass responsible for implementing"
98
+ end
99
+
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,120 @@
1
+ require 'domkey/view/option_selectable'
2
+ require 'domkey/view/labeled_group'
3
+
4
+ module Domkey
5
+ module View
6
+
7
+ #OptionsSelectable CheckboxGroup, RadioGroup
8
+ class OptionSelectableGroup < PageObjectCollection
9
+
10
+ include OptionSelectable
11
+
12
+ def set_by_index value
13
+ [*value].each do |i|
14
+ self[i.to_i].set(true)
15
+ end
16
+ end
17
+
18
+ def set_by_label value
19
+ to_labeled.__send__(:set_strategy, value)
20
+ end
21
+
22
+ def set_by_regexp value
23
+ o = find { |o| o.value.match(value) }
24
+ o ? o.element.set : fail(Exception::NotFoundError, "Element not found with value: #{v.inspect}")
25
+ end
26
+
27
+ def set_by_string value
28
+ o = find { |o| o.value == value }
29
+ o ? o.element.set : fail(Exception::NotFoundError, "Element not found with value: #{v.inspect}")
30
+ end
31
+
32
+
33
+ def value_by_default
34
+ validate_scope
35
+ find_all { |e| e.element.set? }.map { |e| e.value }
36
+ end
37
+
38
+ def value_by_options opts
39
+ validate_scope
40
+ result = []
41
+ each_with_index do |e, i|
42
+ if e.element.set?
43
+
44
+ v = opts.map do |o|
45
+ case o
46
+ when :index
47
+ [o, i]
48
+ when :label, :text
49
+ [o, LabelMapper.find(e).element.text]
50
+ else
51
+ [o, e.send(o)]
52
+ end
53
+ end
54
+ result << Hash[v]
55
+ end
56
+ end
57
+ result
58
+ end
59
+
60
+ def options_by_default
61
+ validate_scope
62
+ map { |e| e.value }
63
+ end
64
+
65
+ def options_by opts
66
+ validate_scope
67
+ result = []
68
+ each_with_index do |e, i|
69
+
70
+ v = opts.map do |o|
71
+ case o
72
+ when :index
73
+ [o, i]
74
+ when :label, :text
75
+ [o, LabelMapper.find(e).element.text]
76
+ else
77
+ [o, e.send(o)]
78
+ end
79
+ end
80
+ result << Hash[v]
81
+ end
82
+
83
+ result
84
+ end
85
+
86
+ # convert to LabeledGroup settable by corresponding label text
87
+ def to_labeled
88
+ LabeledGroup.new(self)
89
+ end
90
+
91
+
92
+ # @yield [PageObject]
93
+ def each(&blk)
94
+ validate_scope
95
+ super(&blk)
96
+ end
97
+
98
+ # @return [Array<PageObject>]
99
+ def to_a
100
+ validate_scope
101
+ super
102
+ end
103
+
104
+ private
105
+
106
+ # precondition on acting on this collection
107
+ # @return [true] when all radios in collection share the same name attribute
108
+ # @raise [Exception::Error] when where is more than one unique name attribute
109
+ # --
110
+ # returns true on subsequent unless magically more radios show up after initial validation
111
+ def validate_scope
112
+ return if @validated
113
+ groups = element.map { |e| e.name }.uniq
114
+ fail(Exception::Error, "RadioGroup definition scope too broad: Found #{groups.count} radio groups with names: #{groups}") unless (groups.size == 1)
115
+ @validated = true
116
+ end
117
+
118
+ end
119
+ end
120
+ end
@@ -1,5 +1,5 @@
1
- require 'domkey/view/widgetry_package'
2
- require 'domkey/view/watir_widget'
1
+ require 'domkey/view/widgetry/package'
2
+ require 'domkey/view/widgetry/dispatcher'
3
3
 
4
4
  module Domkey
5
5
 
@@ -52,13 +52,13 @@ module Domkey
52
52
  class PageObject
53
53
 
54
54
  # @api private
55
- include WidgetryPackage
55
+ include Widgetry::Package
56
56
 
57
57
  # Each Semantic PageObject defines what value means for itself
58
58
  # @param [SemanticValue] Delegated to WebdriverElement and we expect it to respond to set
59
59
  # @parma [Hash{Symbol => SemanticValue}]
60
60
  def set value
61
- return watir_widget.set value unless value.respond_to?(:each_pair)
61
+ return widgetry_dispatcher.set value unless value.respond_to?(:each_pair)
62
62
  value.each_pair { |k, v| package.fetch(k).set(v) }
63
63
  end
64
64
 
@@ -68,22 +68,22 @@ module Domkey
68
68
  # @return [SemanticValue] delegated to WebdriverElement and we expect it to respond to value message
69
69
  # @return [Hash{Symbol => SemanticValue}]
70
70
  def value
71
- return watir_widget.value unless package.respond_to?(:each_pair)
71
+ return widgetry_dispatcher.value unless package.respond_to?(:each_pair)
72
72
  Hash[package.map { |key, pageobject| [key, pageobject.value] }]
73
73
  end
74
74
 
75
75
  def options
76
- return watir_widget.options unless package.respond_to?(:each_pair)
76
+ return widgetry_dispatcher.options unless package.respond_to?(:each_pair)
77
77
  Hash[package.map { |key, pageobject| [key, pageobject.options] }]
78
78
  end
79
79
 
80
80
  private
81
81
 
82
- # wrap instantiator with strategy for setting and getting value for watir object
82
+ # wrap instantiator with strategy for setting and getting value for underlying object
83
83
  # expects that element to respond to set and value
84
- # @returns [WatirWidget]
85
- def watir_widget
86
- WatirWidget.new(instantiator)
84
+ # @returns [Widgetry::Dispatcher] that responds to set, value, options
85
+ def widgetry_dispatcher
86
+ Widgetry.dispatcher(instantiator)
87
87
  end
88
88
 
89
89
  # @api private
@@ -96,7 +96,7 @@ module Domkey
96
96
  begin
97
97
  # peek inside suitcase that is proc. XXX ouch, ugly
98
98
  peeked_inside = package.call
99
- rescue NoMethodError
99
+ rescue StandardError
100
100
  return package #suitecase exploded, proc returned
101
101
  end
102
102
  if peeked_inside.respond_to?(:each_pair) # hash