symbiont 0.11.0 → 0.12.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.
@@ -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