domkey 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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>