domkey 0.1.0 → 0.2.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.
@@ -2,45 +2,36 @@ module Domkey
2
2
 
3
3
  module View
4
4
 
5
+ # PageObjectCollection see PageObject for detailes.
6
+ # Compose PageObjectCollection with package and container
7
+ #
8
+ # What is a container? see PageObject container
9
+ #
10
+ # What is package? see PageObject package except the following:
11
+ # package can be one of the following:
12
+ # - definition of watir elements collection i.e. `-> { text_fields(:class, /^foo/)}`
13
+ # - a pageobject i.e. previously instantiated definition watir elements collection
14
+ # - hash where key defines subelement and value a definition or pageobject
15
+ # Usage:
16
+ # Clients would not usually instantate this class.
17
+ # A client class which acts as a View would use a :doms factory method to create PageObjectCollection
18
+ # TODO Example:
5
19
  class PageObjectCollection
6
- include Enumerable
7
-
8
- attr_accessor :watirproc, :container
9
-
10
- # PageObjectCollection see PageObject for detailes.
11
- # Compose PageObjectCollection with watirproc and container
12
- #
13
- # What is a container? see PageObject container
14
- #
15
- # What is watirproc? see PageObject watirproc except the following:
16
- # watirproc can be one of the following:
17
- # - definition of watir elements collection i.e. `-> { text_fields(:class, /^foo/)}`
18
- # - a pageobject i.e. previously instantiated definition watir elements collection
19
- # - hash where key defines subelement and value a definition or pageobject
20
- # Usage:
21
- # Clients would not usually instantate this class.
22
- # A client class which acts as a View would use a :doms factory method to create PageObjectCollection
23
- # Example:
24
- #
25
- def initialize watirproc, container=lambda { Domkey.browser }
26
- @container = container
27
- @watirproc = initialize_this watirproc
28
- end
29
20
 
30
- def element(key=false)
31
- return instantiator unless watirproc.respond_to?(:each_pair)
32
- return watirproc.fetch(key).element if key
33
- Hash[watirproc.map { |key, watirproc| [key, watirproc.element] }]
34
- end
21
+ include WidgetryPackage
22
+ include Enumerable
35
23
 
24
+ # @return [PageObject, Hash{Symbol => PageObjectCollection}]
36
25
  def each(&blk)
37
- if watirproc.respond_to?(:each_pair)
38
- watirproc.map { |k, v| [k, PageObjectCollection.new(lambda { v }, @container)] }.each { |k, v| yield Hash[k, v] }
26
+ if package.respond_to?(:each_pair)
27
+ package.map { |k, v| [k, PageObjectCollection.new(lambda { v }, @container)] }.each { |k, v| yield Hash[k, v] }
39
28
  else
40
29
  instantiator.each { |e| yield PageObject.new(lambda { e }, @container) }
41
30
  end
42
31
  end
43
32
 
33
+ # @param [Fixnum]
34
+ # @return [PageObject, Hash{Symbol => PageObjectCollection}]
44
35
  def [] idx
45
36
  to_a[idx]
46
37
  end
@@ -49,30 +40,21 @@ module Domkey
49
40
 
50
41
  private
51
42
 
52
- # --
53
- # recursive
54
- def initialize_this watirproc
55
- if watirproc.respond_to?(:each_pair) #hash
56
- Hash[watirproc.map { |key, watirproc| [key, PageObjectCollection.new(watirproc, container)] }]
43
+ # @api private
44
+ # Recursive. Examines each packages and turns each Proc into PageObject
45
+ def initialize_this package
46
+ if package.respond_to?(:each_pair) #hash
47
+ Hash[package.map { |key, package| [key, PageObjectCollection.new(package, container)] }]
57
48
  else
58
- if watirproc.respond_to?(:call) #proc
59
- watirproc
60
- elsif watirproc.respond_to?(:watirproc)
61
- watirproc.watirproc
49
+ if package.respond_to?(:call) #proc
50
+ package
51
+ elsif package.respond_to?(:package)
52
+ package.package
62
53
  else
63
- fail Exception::Error, "watirproc must be kind of hash, watirelement or pageobject but I got this: #{watirproc}"
54
+ fail Exception::Error, "package must be kind of hash, watirelement or pageobject but I got this: #{package}"
64
55
  end
65
56
  end
66
57
  end
67
-
68
- def instantiator
69
- container_at_runtime.instance_exec(&watirproc)
70
- end
71
-
72
- def container_at_runtime
73
- container.respond_to?(:call) ? container.call : container.send(:instantiator)
74
- end
75
-
76
58
  end
77
59
  end
78
60
  end
@@ -0,0 +1,70 @@
1
+ require 'domkey/view/labeled_group'
2
+ module Domkey
3
+
4
+ module View
5
+
6
+ # RadioGroup allows you to interact with PageObjectCollection of radios as a single PageObject
7
+ # Radios collection is constrained by the same name attribute and behaves like one object.
8
+ # It behaves like a single Select list.
9
+ # When one radio is selected in the collection the others become unselected.
10
+ class RadioGroup < PageObjectCollection
11
+
12
+ # @param [String] match text in value attribute and set that radio
13
+ def set value
14
+ validate_scope
15
+ return unless value
16
+ [*value].each do |v|
17
+ e = case v
18
+ when String
19
+ element.find { |e| e.value == v }
20
+ when Regexp
21
+ element.find { |e| e.value.match(v) }
22
+ end
23
+ e ? e.set : fail(Exception::Error, "RadioGroup value not found: #{v.inspect}")
24
+ end
25
+ end
26
+
27
+ # @return [String] text in value attribute of currently set
28
+ def value
29
+ validate_scope
30
+ element.find_all { |r| r.set? }.map { |e| e.value }
31
+ end
32
+
33
+ def options
34
+ validate_scope
35
+ element.map { |e| e.value }
36
+ end
37
+
38
+ # convert to LabeledGroup settable by corresponding label text
39
+ def to_labeled
40
+ LabeledGroup.new(self)
41
+ end
42
+
43
+ # @yield [PageObject]
44
+ def each(&blk)
45
+ validate_scope
46
+ super(&blk)
47
+ end
48
+
49
+ # @return [Array<PageObject>]
50
+ def to_a
51
+ validate_scope
52
+ super
53
+ end
54
+
55
+ private
56
+
57
+ # precondition on acting on this collection
58
+ # @return [true] when all radios in collection share the same name attribute
59
+ # @raise [Exception::Error] when where is more than one unique name attribute
60
+ # --
61
+ # returns true on subsequent unless magically more radios show up after initial validation
62
+ def validate_scope
63
+ return if @validated
64
+ groups = element.map { |e| e.name }.uniq
65
+ fail(Exception::Error, "RadioGroup definition scope too broad: Found #{groups.count} radio groups with names: #{groups}") unless (groups.size == 1)
66
+ @validated = true
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,106 @@
1
+ module Domkey
2
+
3
+ module View
4
+
5
+ # @api private
6
+ class WatirWidget
7
+
8
+ def initialize(object)
9
+ @object = object
10
+ object_class_name = @object.class.name.split('::').last
11
+ @set_method = "set_%s" % object_class_name
12
+ @value_method = "value_%s" % object_class_name
13
+ @options_method = "options_%s" % object_class_name
14
+ end
15
+
16
+ def set value
17
+ return __send__(@set_method, value) if respond_to?(@set_method, true)
18
+ @object.set value
19
+ end
20
+
21
+ def value
22
+ return __send__(@value_method) if respond_to?(@value_method, true)
23
+ @object.value
24
+ end
25
+
26
+ def options
27
+ return __send__(@options_method) if respond_to?(@options_method, true)
28
+ opts = @object.options
29
+ opts.count == 0 ? [] : opts
30
+ end
31
+
32
+ private
33
+
34
+ def options_Select
35
+ @object.options.map do |o|
36
+ {text: o.text,
37
+ value: o.value}
38
+ end
39
+ end
40
+
41
+ # for Watir::Select
42
+ # @param [String] text or label to be selected. Text visible to the user on the page
43
+ # @param [Array<String>] collection for multiselect to select
44
+ def set_Select value
45
+ @object.clear if @object.multiple?
46
+ set_Select_strategy value
47
+ end
48
+
49
+ def set_Select_strategy value
50
+ case value
51
+ when String
52
+ @object.select value
53
+ when Array
54
+ value.each { |v| set_Select_strategy v }
55
+ when Hash
56
+ value.each_pair do |how, what|
57
+
58
+ #-- select by option position: can be one or many index: 0, index: [0,1,2,3]
59
+ if how == :index
60
+ case what
61
+ when Fixnum
62
+ @object.options[what].select
63
+ when Array
64
+ what.each do |i|
65
+ @object.options[i].select
66
+ end
67
+ end
68
+ end
69
+
70
+ #-- select by option value: attribute (invisible to the user)
71
+ if how == :value
72
+ case what
73
+ when String
74
+ @object.select_value what
75
+ when Array
76
+ what.each { |v| @object.select_value v }
77
+ end
78
+ end
79
+
80
+ #-- select by text visible to the user. This is the same as default set 'Text' behavior
81
+ if how == :text
82
+ case what
83
+ when String
84
+ set_Select_strategy what
85
+ when Array
86
+ what.each { |v| set_Select_strategy v }
87
+ end
88
+ end
89
+
90
+ end
91
+
92
+ end
93
+
94
+ end
95
+
96
+ # @return [String] text or label from Select, not actual 'value' attribute?
97
+ # @return [Array<String>] collection for multiselect list
98
+ # @return [False] when nothing selected in multiselect list
99
+ def value_Select
100
+ @object.selected_options.map { |o| o.text }
101
+ end
102
+
103
+
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,48 @@
1
+ module Domkey
2
+
3
+ module View
4
+
5
+ module WidgetryPackage
6
+
7
+ attr_accessor :package, :container
8
+
9
+ # initialize PageObject or PageObjectCollection
10
+ # for PageObject expects WebdriverElement a single element definition i.e text_field, checkbox
11
+ # for PageObjectCollection expects WebdriverElement a collection definition i.e. text_fields, checkboxes
12
+ # @param package [Proc(WebdriverElement)]
13
+ # @param package [PageObject]
14
+ # @param package [Hash{Symbol => Proc(WebdriverElement)]
15
+ # @param package [Hash{Symbol => PageObject]
16
+ def initialize package, container=lambda { Domkey.browser }
17
+ @container = container
18
+ @package = initialize_this package
19
+ end
20
+
21
+ # access widgetry of watir elements composing this page object
22
+ # @param [Symbol] (false)
23
+ # @return [Hash{Symbol => WebdriverElement}]
24
+ # @return [WebdriverElement]
25
+ def element(key=false)
26
+ return instantiator unless package.respond_to?(:each_pair)
27
+ return package.fetch(key).element if key
28
+ Hash[package.map { |key, package| [key, package.element] }]
29
+ end
30
+
31
+ private
32
+
33
+ # talks to the browser
34
+ # returns runtime element in a specified container
35
+ # @return [WebdriverElement]
36
+ def instantiator
37
+ container_instantiator.instance_exec(&package)
38
+ end
39
+
40
+ # talks to the browser
41
+ # returns runtime container element in a browser/driver
42
+ # @return [WebdriverElement]
43
+ def container_instantiator
44
+ container.respond_to?(:call) ? container.call : container.send(:instantiator)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+
3
+ describe Domkey::View::CheckboxGroup do
4
+
5
+ class CollectionAsPageObjectCheckboxGroupView
6
+ include Domkey::View
7
+
8
+ def group
9
+ CheckboxGroup.new -> { checkboxes(name: 'fruit') }
10
+ end
11
+
12
+ def groups
13
+ CheckboxGroup.new -> { checkboxes(name: /^fruit/) }
14
+ end
15
+ end
16
+
17
+ before :all do
18
+ goto_html("test.html")
19
+ end
20
+
21
+ it 'two groups example' do
22
+ v = CollectionAsPageObjectCheckboxGroupView.new
23
+ expect { v.groups.to_a.size }.to raise_error
24
+ expect { v.groups.map { |e| e } }.to raise_error
25
+ expect { v.groups.count }.to raise_error
26
+ end
27
+
28
+ context "OptionSelectable object multi" do
29
+ # OptionSelectable object is an object that responds to options and is selectable by its optioins;
30
+ # RadioGroup, Select, CheckboxGroup. CheckboxGroup acts like Multi Select, RadioGroup acts like Single Select
31
+
32
+ before :each do
33
+ goto_html("test.html")
34
+
35
+ @v = CollectionAsPageObjectCheckboxGroupView.new
36
+ @v.group.count.should == 3
37
+ @v.group.to_a.each { |e| e.should be_kind_of(Domkey::View::PageObject) }
38
+ end
39
+
40
+ it 'initial value on test page' do
41
+ @v.group.value.should eql ['other']
42
+ end
43
+
44
+ it 'set value attribute by default. value returns array of value attribute' do
45
+ @v.group.set 'tomato'
46
+ @v.group.value.should eql ['tomato']
47
+ @v.group.set /^othe/
48
+ @v.group.value.should eql ['other']
49
+ end
50
+
51
+ it 'set array of value attribute. value returns array of value attribute' do
52
+ @v.group.set ['tomato']
53
+ @v.group.value.should eql ['tomato']
54
+
55
+ @v.group.set ['other', /tomat/]
56
+ @v.group.value.should eql ['tomato', 'other']
57
+ end
58
+
59
+ it 'set false clears all. value is empty array' do
60
+ @v.group.set false
61
+ @v.group.value.should eql []
62
+ end
63
+
64
+ it 'set empty array clears all. value is empty array' do
65
+ @v.group.set []
66
+ @v.group.value.should eql []
67
+ end
68
+
69
+ it 'set value string not found error' do
70
+ expect { @v.group.set 'toma' }.to raise_error
71
+ end
72
+
73
+ it 'set value regexp not found error' do
74
+ expect { @v.group.set /balaba/ }.to raise_error
75
+ end
76
+
77
+ it 'options' do
78
+ @v.group.options.should eql ["cucumber", "tomato", "other"]
79
+ end
80
+ end
81
+ end
@@ -17,15 +17,15 @@
17
17
  <br/>
18
18
 
19
19
  <div id='feature_1' class='pageobject'>
20
- <label for='feature_checkbox1'>Nude Beach</label>
20
+ <label for='feature_checkbox1'>Enable Checkbox for TextArea</label>
21
21
  <input id="feature_checkbox1" type="checkbox" class="check" onclick="featureEnabler('feature_checkbox1','feature_textarea1');"/><br/>
22
- <textarea id='feature_textarea1' readonly disabled>CheckboxTextField 1</textarea>
22
+ <textarea id='feature_textarea1' cols="30" readonly disabled style="background-color:#eee">CheckboxTextField 1</textarea>
23
23
  </div>
24
24
 
25
25
  <div id='feature_2' class='pageobject'>
26
26
  <label for='feature_checkbox2'>Golf Course</label>
27
27
  <input id='feature_checkbox2' type='checkbox' class="check" onclick="featureEnabler('feature_checkbox2','feature_textarea2');"/><br/>
28
- <textarea id='feature_textarea2' readonly disabled>CheckboxTextField 2</textarea>
28
+ <textarea id='feature_textarea2' cols="30" readonly disabled style="background-color:#eee">CheckboxTextField 2</textarea>
29
29
  </div>
30
30
 
31
31
  <script type="text/javascript">
@@ -33,14 +33,18 @@
33
33
  var cb = document.getElementById(cbe);
34
34
  var txt = document.getElementById(txte);
35
35
  if (cb.checked == true) {
36
- txt.readOnly = "";
37
- txt.disabled = "";
36
+ txt.readOnly = '';
37
+ txt.disabled = '';
38
+ txt.style = 'background-color: #fff';
38
39
  } else {
39
40
  txt.readOnly = 'readonly';
40
41
  txt.disabled = 'disabled';
42
+ txt.value = '';
43
+ txt.style = 'background-color: #eee';
41
44
  }
42
45
  }
43
46
  </script>
47
+ <br/>
44
48
 
45
49
  <div>
46
50
  <p>DateSelector</p>
@@ -49,5 +53,57 @@
49
53
  <input type='text' id="year_field" class="city"/>
50
54
  </div>
51
55
 
56
+ <div>
57
+ <p>RadioGroup named tool</p>
58
+ <label for='tool1'>Cucumber</label>
59
+ <input type='radio' name="tool" value="cucumber" id="tool1"/>
60
+ <label for='tool2'>Tomato</label>
61
+ <input type='radio' name="tool" value="tomato" id="tool2"/>
62
+ <label for='tool3'>Other</label>
63
+ <input type='radio' name="tool" value="other" id="tool3" checked/>
64
+ </div>
65
+
66
+ <div>
67
+ <p>RadioGroup named toolkey</p>
68
+ <input type='radio' name="toolkey" value="a cucumber"/><label for=""
69
+ <input type='radio' name="toolkey" value="a tomato"/>
70
+ <input type='radio' name="toolkey" value="some other" checked/>
71
+ </div>
72
+
73
+ <div>
74
+ <p>CheckboxGroup named fruit</p>
75
+ <label for='fruit1'>Cucumberama</label>
76
+ <input type='checkbox' name="fruit" value="cucumber" id="fruit1"/>
77
+ <label for='fruit2'>Tomatorama</label>
78
+ <input type='checkbox' name="fruit" value="tomato" id="fruit2"/>
79
+ <label for='fruit3'>Other</label>
80
+ <input type='checkbox' name="fruit" value="other" id="fruit3" checked/>
81
+ </div>
82
+
83
+ <div>
84
+ <p>CheckboxGroup named fruitkey</p>
85
+ <input type='checkbox' name="fruitkey" value="a cucumberama"/>
86
+ <input type='checkbox' name="fruitkey" value="a tomatorama"/>
87
+ <input type='checkbox' name="fruitkey" value="some otherama" checked/>
88
+ </div>
89
+
90
+ <div>
91
+ <select id="fruit_list">
92
+ <option value="tomato">Tomato</option>
93
+ <option value="gurken">Cucumber</option>
94
+ <option label="Other"/>
95
+ <option selected>Default</option>
96
+ </select>
97
+ </div>
98
+
99
+ <div>
100
+ <select multiple size="5" name="multiselect" id="multiselect">
101
+ <option value="1">Danish</option>
102
+ <option selected="selected" value="2">English</option>
103
+ <option selected value="3">Norwegian</option>
104
+ <option label='Polish'/>
105
+ <option>Swedish</option>
106
+ </select>
107
+ </div>
52
108
  </body>
53
109
  </html>