symbiont 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,185 +1,186 @@
1
- module Symbiont
2
- # Calls the Watir module to get a list of the factory methods that
3
- # Watir uses to reference and access web objects.
4
- #
5
- # @return [Array] factory method list
6
- def self.elements
7
- unless @elements
8
- @elements = Watir::Container.instance_methods
9
- #@elements.delete(:extract_selector)
10
- end
11
- @elements
12
- end
13
-
14
- def self.settable
15
- @settable ||= [:text_field, :file_field, :textarea]
16
- end
17
-
18
- def self.selectable
19
- @selectable ||= [:select_list]
20
- end
21
-
22
- def self.settable?(element)
23
- settable.include? element.to_sym
24
- end
25
-
26
- def self.selectable?(element)
27
- selectable.include? element.to_sym
28
- end
29
-
30
- module Element
31
- # Iterates through Watir factory methods. Each method is defined
32
- # as a method that can be called on a page class. This is what
33
- # allows element definitions to be created.
34
- Symbiont.elements.each do |element|
35
- define_method element do |*signature, &block|
36
- identifier, locator = parse_signature(signature)
37
- context = context_from_signature(locator, &block)
38
- define_element_accessor(identifier, locator, element, &context)
39
- define_set_accessor(identifier, locator, element, &context) if Symbiont.settable?(element)
40
- define_select_accessor(identifier, locator, element, &context) if Symbiont.selectable?(element)
41
- end
42
- end
43
-
44
- private
45
-
46
- # Defines an accessor method for an element that allows the friendly
47
- # name of the element to be proxied to a Watir element object that
48
- # corresponds to the element type.
49
- #
50
- # @param identifier [Symbol] friendly name of element definition
51
- # @param locator [Hash] locators for referencing the element
52
- # @param element [Symbol] name of Watir-based object
53
- # @param block [Proc] a context block
54
- #
55
- # @example
56
- # This element definition:
57
- # text_field :weight, id: 'wt', index: 0
58
- #
59
- # passed in like this:
60
- # :weight, {:id => 'wt', :index => 0}, :text_field
61
- #
62
- # This allows access like this:
63
- # @page.weight.set '200'
64
- #
65
- # Access could also be done this way:
66
- # @page.weight(id: 'wt').set '200'
67
- #
68
- # The second approach would lead to the *values variable having
69
- # an array like this: [{:id => 'wt'}].
70
- #
71
- # A third approach would be to utilize one element definition
72
- # within the context of another. Consider the following element
73
- # definitions:
74
- # article :practice, id: 'practice'
75
- #
76
- # a :page_link do |text|
77
- # practice.a(text: text)
78
- # end
79
- #
80
- # These could be utilized as such:
81
- # on_view(Practice).page_link('Click Me').click
82
- #
83
- # This approach would lead to the *values variable having
84
- # an array like this: ["Click Me"].
85
- def define_element_accessor(identifier, locator, element, &block)
86
- define_method "#{identifier}".to_sym do |*values|
87
- if block_given?
88
- instance_exec(*values, &block)
89
- else
90
- reference_element(element, locator)
91
- end
92
- end
93
- end
94
-
95
- # Defines an accessor method for an element that allows the value of
96
- # the element to be set via appending an "=" to the friendly name
97
- # (identifier) of the element passed in.
98
- #
99
- # @param identifier [Symbol] friendly name of element definition
100
- # @param locator [Hash] locators for referencing the element
101
- # @param element [Symbol] name of Watir-based object
102
- # @param block [Proc] a context block
103
- #
104
- # @example
105
- # This element definition:
106
- # text_field :weight, id: 'wt'
107
- #
108
- # Can be accessed in two ways:
109
- # @page.weight.set '200'
110
- # @page.weight = '200'
111
- #
112
- # The second approach would lead to the *values variable having
113
- # an array like this: ['200']. The first approach would be
114
- # handled by define_element_accessor instead.
115
- def define_set_accessor(identifier, locator, element, &block)
116
- define_method "#{identifier}=".to_sym do |*values|
117
- accessor = if block_given?
118
- instance_exec(&block)
119
- else
120
- reference_element(element, locator)
121
- end
122
-
123
- if accessor.respond_to?(:set)
124
- accessor.set *values
125
- else
126
- accessor.send_keys *values
127
- end
128
- end
129
- end
130
-
131
- # Defines an accessor method for an element that allows the value of
132
- # the element to be selected via appending an "=" to the friendly
133
- # name (identifier) of the element passed in.
134
- #
135
- # @param identifier [Symbol] friendly name of element definition
136
- # @param locator [Hash] locators for referencing the element
137
- # @param element [Symbol] name of Watir-based object
138
- # @param block [Proc] a context block
139
- #
140
- # @example
141
- # This element definition:
142
- # select_list :city, id: 'city'
143
- #
144
- # Can be accessed in two ways:
145
- # @page.city.select 'Chicago'
146
- # @page.city = 'Chicago'
147
- #
148
- # The second approach would lead to the *values variable having
149
- # an array like this: ['City']. The first approach would be
150
- # handled by define_element_accessor instead.
151
- def define_select_accessor(identifier, locator, element, &block)
152
- define_method "#{identifier}=".to_sym do |*values|
153
- if block_given?
154
- instance_exec(&block).select *values
155
- else
156
- reference_element(element, locator).select *values
157
- end
158
- end
159
- end
160
-
161
- # Returns the identifier and locator portions of an element definition.
162
- #
163
- # @param signature [Array] full element definition
164
- # @return [String] identifier and locator portions
165
- def parse_signature(signature)
166
- return signature.shift, signature.shift
167
- end
168
-
169
- # Returns the block or proc that serves as a context for an element
170
- # definition.
171
- #
172
- # @param locator [Array] locators from element definition
173
- # @param block [Proc] a context block
174
- # @return [Proc] the context block or nil if there is no procedure
175
- def context_from_signature(*locator, &block)
176
- if block_given?
177
- block
178
- else
179
- context = locator.shift
180
- context.is_a?(Proc) && locator.empty? ? context : nil
181
- end
182
- end
183
-
184
- end
185
- end
1
+ module Symbiont
2
+ # Calls the Watir module to get a list of the factory methods that
3
+ # Watir uses to reference and access web objects.
4
+ #
5
+ # @return [Array] factory method list
6
+ def self.elements
7
+ unless @elements
8
+ @elements = Watir::Container.instance_methods
9
+ # @elements.delete(:extract_selector)
10
+ end
11
+ @elements
12
+ end
13
+
14
+ def self.settable
15
+ @settable ||= [:text_field, :file_field, :textarea]
16
+ end
17
+
18
+ def self.selectable
19
+ @selectable ||= [:select_list]
20
+ end
21
+
22
+ def self.settable?(element)
23
+ settable.include? element.to_sym
24
+ end
25
+
26
+ def self.selectable?(element)
27
+ selectable.include? element.to_sym
28
+ end
29
+
30
+ module Element
31
+ # Iterates through Watir factory methods. Each method is defined
32
+ # as a method that can be called on a page class. This is what
33
+ # allows element definitions to be created.
34
+ Symbiont.elements.each do |element|
35
+ define_method element do |*signature, &block|
36
+ identifier, locator = parse_signature(signature)
37
+ context = context_from_signature(locator, &block)
38
+ define_element_accessor(identifier, locator, element, &context)
39
+ define_set_accessor(identifier, locator, element, &context) if Symbiont.settable?(element)
40
+ define_select_accessor(identifier, locator, element, &context) if Symbiont.selectable?(element)
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ # Defines an accessor method for an element that allows the friendly
47
+ # name of the element to be proxied to a Watir element object that
48
+ # corresponds to the element type.
49
+ #
50
+ # @param identifier [Symbol] friendly name of element definition
51
+ # @param locator [Hash] locators for referencing the element
52
+ # @param element [Symbol] name of Watir-based object
53
+ # @param block [Proc] a context block
54
+ #
55
+ # @example
56
+ # This element definition:
57
+ # text_field :weight, id: 'wt', index: 0
58
+ #
59
+ # passed in like this:
60
+ # :weight, {:id => 'wt', :index => 0}, :text_field
61
+ #
62
+ # This allows access like this:
63
+ # @page.weight.set '200'
64
+ #
65
+ # Access could also be done this way:
66
+ # @page.weight(id: 'wt').set '200'
67
+ #
68
+ # The second approach would lead to the *values variable having
69
+ # an array like this: [{:id => 'wt'}].
70
+ #
71
+ # A third approach would be to utilize one element definition
72
+ # within the context of another. Consider the following element
73
+ # definitions:
74
+ # article :practice, id: 'practice'
75
+ #
76
+ # a :page_link do |text|
77
+ # practice.a(text: text)
78
+ # end
79
+ #
80
+ # These could be utilized as such:
81
+ # on_view(Practice).page_link('Click Me').click
82
+ #
83
+ # This approach would lead to the *values variable having
84
+ # an array like this: ["Click Me"].
85
+ def define_element_accessor(identifier, locator, element, &block)
86
+ define_method "#{identifier}".to_sym do |*values|
87
+ if block_given?
88
+ instance_exec(*values, &block)
89
+ else
90
+ reference_element(element, locator)
91
+ end
92
+ end
93
+ end
94
+
95
+ # Defines an accessor method for an element that allows the value of
96
+ # the element to be set via appending an "=" to the friendly name
97
+ # (identifier) of the element passed in.
98
+ #
99
+ # @param identifier [Symbol] friendly name of element definition
100
+ # @param locator [Hash] locators for referencing the element
101
+ # @param element [Symbol] name of Watir-based object
102
+ # @param block [Proc] a context block
103
+ #
104
+ # @example
105
+ # This element definition:
106
+ # text_field :weight, id: 'wt'
107
+ #
108
+ # Can be accessed in two ways:
109
+ # @page.weight.set '200'
110
+ # @page.weight = '200'
111
+ #
112
+ # The second approach would lead to the *values variable having
113
+ # an array like this: ['200']. The first approach would be
114
+ # handled by define_element_accessor instead.
115
+ def define_set_accessor(identifier, locator, element, &block)
116
+ define_method "#{identifier}=".to_sym do |*values|
117
+ accessor =
118
+ if block_given?
119
+ instance_exec(&block)
120
+ else
121
+ reference_element(element, locator)
122
+ end
123
+
124
+ if accessor.respond_to?(:set)
125
+ accessor.set(*values)
126
+ else
127
+ accessor.send_keys(*values)
128
+ end
129
+ end
130
+ end
131
+
132
+ # Defines an accessor method for an element that allows the value of
133
+ # the element to be selected via appending an "=" to the friendly
134
+ # name (identifier) of the element passed in.
135
+ #
136
+ # @param identifier [Symbol] friendly name of element definition
137
+ # @param locator [Hash] locators for referencing the element
138
+ # @param element [Symbol] name of Watir-based object
139
+ # @param block [Proc] a context block
140
+ #
141
+ # @example
142
+ # This element definition:
143
+ # select_list :city, id: 'city'
144
+ #
145
+ # Can be accessed in two ways:
146
+ # @page.city.select 'Chicago'
147
+ # @page.city = 'Chicago'
148
+ #
149
+ # The second approach would lead to the *values variable having
150
+ # an array like this: ['City']. The first approach would be
151
+ # handled by define_element_accessor instead.
152
+ def define_select_accessor(identifier, locator, element, &block)
153
+ define_method "#{identifier}=".to_sym do |*values|
154
+ if block_given?
155
+ instance_exec(&block).select(*values)
156
+ else
157
+ reference_element(element, locator).select(*values)
158
+ end
159
+ end
160
+ end
161
+
162
+ # Returns the identifier and locator portions of an element definition.
163
+ #
164
+ # @param signature [Array] full element definition
165
+ # @return [String] identifier and locator portions
166
+ def parse_signature(signature)
167
+ # return signature.shift, signature.shift
168
+ [signature.shift, signature.shift]
169
+ end
170
+
171
+ # Returns the block or proc that serves as a context for an element
172
+ # definition.
173
+ #
174
+ # @param locator [Array] locators from element definition
175
+ # @param block [Proc] a context block
176
+ # @return [Proc] the context block or nil if there is no procedure
177
+ def context_from_signature(*locator, &block)
178
+ if block_given?
179
+ block
180
+ else
181
+ context = locator.shift
182
+ context.is_a?(Proc) && locator.empty? ? context : nil
183
+ end
184
+ end
185
+ end
186
+ end
@@ -1,9 +1,9 @@
1
- module Symbiont
2
- module Errors
3
- class NoUrlForDefinition < StandardError; end
4
- class NoUrlMatchForDefinition < StandardError; end
5
- class NoTitleForDefinition < StandardError; end
6
- class WorkflowPathNotFound < StandardError; end
7
- class WorkflowActionNotFound < StandardError; end
8
- end
9
- end
1
+ module Symbiont
2
+ module Errors
3
+ class NoUrlForDefinition < StandardError; end
4
+ class NoUrlMatchForDefinition < StandardError; end
5
+ class NoTitleForDefinition < StandardError; end
6
+ class WorkflowPathNotFound < StandardError; end
7
+ class WorkflowActionNotFound < StandardError; end
8
+ end
9
+ end
@@ -1,87 +1,75 @@
1
- module Symbiont
2
- module Factory
3
- include Workflow
4
-
5
- # Creates a definition context for actions. If an existing context
6
- # exists, that context will be re-used.
7
- #
8
- # @param definition [Class] the name of a definition class
9
- # @param visit [Boolean] true if the context needs to be called into view
10
- # @param block [Proc] logic to execute in the context of the definition
11
- # @return [Object] instance of the definition
12
- def on(definition, visit=false, &block)
13
- if @page.kind_of?(definition)
14
- block.call @page if block
15
- return @page
16
- end
17
-
18
- if @context.kind_of?(definition)
19
- block.call @context if block
20
-
21
- unless @page.kind_of?(definition)
22
- @page = @context
23
- end
24
-
25
- return @context
26
- end
27
-
28
- @page = definition.new(@browser)
29
- @page.view if visit
30
-
31
- @page.has_correct_url? if @page.respond_to?(:url_matches)
32
- @page.has_correct_title? if @page.respond_to?(:title_is)
33
-
34
- @model = @page
35
-
36
- block.call @page if block
37
-
38
- @page
39
- end
40
-
41
- alias_method :on_page, :on
42
- alias_method :while_on, :on
43
-
44
- # Creates a definition context for actions and establishes the
45
- # context for display.
46
- #
47
- # @param definition [Class] the name of a definition class
48
- # @param block [Proc] logic to execute in the context of the definition
49
- # @return [Object] instance of the definition
50
- def on_view(definition, &block)
51
- on(definition, true, &block)
52
- end
53
-
54
- alias_method :on_visit, :on_view
55
-
56
- # Creates a definition context for actions. Unlike the on() factory,
57
- # on_new will always create a new context and will never re-use an
58
- # existing one.
59
- #
60
- # @param definition [Class] the name of a definition class
61
- # @param block [Proc] logic to execute in the context of the definition
62
- # @return [Object] instance of the definition
63
- def on_new(definition, &block)
64
- @page = nil
65
- @model = nil
66
-
67
- if @context.kind_of?(definition)
68
- @context = nil
69
- end
70
-
71
- on(definition, &block)
72
- end
73
-
74
- # Creates a definition context for actions. If an existing context
75
- # exists, that context will be re-used. This also sets a context that
76
- # will be used for that definition even if the active definition
77
- # changes.
78
- #
79
- # @param definition [Class] the name of a definition class
80
- # @param block [Proc] logic to execute within the context of the definition
81
- # @return [Object] instance of the definition
82
- def on_set(definition, &block)
83
- on(definition, &block)
84
- @context = @page
85
- end
86
- end
87
- end
1
+ module Symbiont
2
+ module Factory
3
+ # Creates a definition context for actions. If an existing context
4
+ # exists, that context will be re-used.
5
+ #
6
+ # @param definition [Class] the name of a definition class
7
+ # @param visit [Boolean] true if the context needs to be called into view
8
+ # @param block [Proc] logic to execute in the context of the definition
9
+ # @return [Object] instance of the definition
10
+ def on(definition, visit = false, &block)
11
+ if @page.is_a?(definition)
12
+ block.call @page if block
13
+ return @page
14
+ end
15
+
16
+ if @context.is_a?(definition)
17
+ block.call @context if block
18
+ @page = @context
19
+ return @context
20
+ end
21
+
22
+ @page = definition.new(@browser)
23
+ @page.view if visit
24
+
25
+ @model = @page
26
+
27
+ block.call @page if block
28
+
29
+ @page
30
+ end
31
+
32
+ alias_method :on_page, :on
33
+ alias_method :while_on, :on
34
+
35
+ # Creates a definition context for actions and establishes the
36
+ # context for display.
37
+ #
38
+ # @param definition [Class] the name of a definition class
39
+ # @param block [Proc] logic to execute in the context of the definition
40
+ # @return [Object] instance of the definition
41
+ def on_view(definition, &block)
42
+ on(definition, true, &block)
43
+ end
44
+
45
+ alias_method :on_visit, :on_view
46
+
47
+ # Creates a definition context for actions. Unlike the on() factory,
48
+ # on_new will always create a new context and will never re-use an
49
+ # existing one.
50
+ #
51
+ # @param definition [Class] the name of a definition class
52
+ # @param block [Proc] logic to execute in the context of the definition
53
+ # @return [Object] instance of the definition
54
+ def on_new(definition, &block)
55
+ @page = nil
56
+ @model = nil
57
+
58
+ @context = nil if @context.is_a?(definition)
59
+ on(definition, &block)
60
+ end
61
+
62
+ # Creates a definition context for actions. If an existing context
63
+ # exists, that context will be re-used. This also sets a context that
64
+ # will be used for that definition even if the active definition
65
+ # changes.
66
+ #
67
+ # @param definition [Class] the name of a definition class
68
+ # @param block [Proc] logic to execute within the context of the definition
69
+ # @return [Object] instance of the definition
70
+ def on_set(definition, &block)
71
+ on(definition, &block)
72
+ @context = @page
73
+ end
74
+ end
75
+ end
@@ -1,50 +1,52 @@
1
- module Symbiont
2
- module Helpers
3
-
4
- private
5
-
6
- def url_is_empty
7
- puts "\nERROR".on_red
8
- puts "The url_is assertion is empty on the definition #{retrieve_class(caller)}.".cyan
9
- raise Symbiont::Errors::NoUrlForDefinition
10
- end
11
-
12
- def url_match_is_empty
13
- puts "\nERROR".on_red
14
- puts "The url_matches assertion is empty on the definition #{retrieve_class(caller)}.".cyan
15
- raise Symbiont::Errors::NoUrlMatchForDefinition
16
- end
17
-
18
- def title_is_empty
19
- puts "\nERROR".on_red
20
- puts "The title_is assertion is empty on the definition #{retrieve_class(caller)}.".cyan
21
- raise Symbiont::Errors::NoTitleForDefinition
22
- end
23
-
24
- def no_url_is_provided
25
- puts "\nERROR".on_red
26
- puts "You called a '#{retrieve_method(caller)}' action but the definition #{self.class} does not have a url_is assertion.".cyan
27
- raise Symbiont::Errors::NoUrlForDefinition
28
- end
29
-
30
- def no_url_matches_is_provided
31
- puts "\nERROR".on_red
32
- puts "You called a '#{retrieve_method(caller)}' action but the definition #{self.class} does not have a url_matches assertion.".cyan
33
- raise Symbiont::Errors::NoUrlMatchForDefinition
34
- end
35
-
36
- def no_title_is_provided
37
- puts "\nERROR".on_red
38
- puts "You called a '#{retrieve_method(caller)}' action but the definition #{self.class} does not have a title_is assertion.".cyan
39
- raise Symbiont::Errors::NoTitleForDefinition
40
- end
41
-
42
- def retrieve_class(caller)
43
- caller[1][/`.*'/][8..-3]
44
- end
45
-
46
- def retrieve_method(caller)
47
- caller[0][/`.*'/][1..-2]
48
- end
49
- end
50
- end
1
+ module Symbiont
2
+ module Helpers
3
+ private
4
+
5
+ def url_is_empty
6
+ puts "\nERROR".on_red
7
+ puts "The url_is assertion is empty on the definition #{retrieve_class(caller)}.".cyan
8
+ raise Symbiont::Errors::NoUrlForDefinition
9
+ end
10
+
11
+ def url_match_is_empty
12
+ puts "\nERROR".on_red
13
+ puts "The url_matches assertion is empty on the definition #{retrieve_class(caller)}.".cyan
14
+ raise Symbiont::Errors::NoUrlMatchForDefinition
15
+ end
16
+
17
+ def title_is_empty
18
+ puts "\nERROR".on_red
19
+ puts "The title_is assertion is empty on the definition #{retrieve_class(caller)}.".cyan
20
+ raise Symbiont::Errors::NoTitleForDefinition
21
+ end
22
+
23
+ def no_url_is_provided
24
+ puts "\nERROR".on_red
25
+ puts "You called a '#{retrieve_method(caller)}' action but the \
26
+ definition #{self.class} does not have a url_is assertion.".cyan
27
+ raise Symbiont::Errors::NoUrlForDefinition
28
+ end
29
+
30
+ def no_url_matches_is_provided
31
+ puts "\nERROR".on_red
32
+ puts "You called a '#{retrieve_method(caller)}' action but the \
33
+ definition #{self.class} does not have a url_matches assertion.".cyan
34
+ raise Symbiont::Errors::NoUrlMatchForDefinition
35
+ end
36
+
37
+ def no_title_is_provided
38
+ puts "\nERROR".on_red
39
+ puts "You called a '#{retrieve_method(caller)}' action but the \
40
+ definition #{self.class} does not have a title_is assertion.".cyan
41
+ raise Symbiont::Errors::NoTitleForDefinition
42
+ end
43
+
44
+ def retrieve_class(caller)
45
+ caller[1][/`.*'/][8..-3]
46
+ end
47
+
48
+ def retrieve_method(caller)
49
+ caller[0][/`.*'/][1..-2]
50
+ end
51
+ end
52
+ end