fluent 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/HISTORY.md +21 -0
  3. data/lib/fluent.rb +29 -2
  4. data/lib/fluent/enclosers.rb +35 -0
  5. data/lib/fluent/evaluators.rb +82 -0
  6. data/lib/fluent/factory.rb +31 -0
  7. data/lib/fluent/generators.rb +116 -18
  8. data/lib/fluent/platform_selenium.rb +18 -0
  9. data/lib/fluent/platform_selenium/platform_object.rb +21 -0
  10. data/lib/fluent/platform_watir/platform_object.rb +181 -14
  11. data/lib/fluent/platform_watir/platform_web_elements/checkbox.rb +21 -0
  12. data/lib/fluent/platform_watir/platform_web_elements/radio.rb +21 -0
  13. data/lib/fluent/platform_watir/platform_web_elements/select_list.rb +30 -4
  14. data/lib/fluent/platform_watir/platform_web_elements/text_field.rb +13 -0
  15. data/lib/fluent/platform_watir/platform_web_elements/web_element.rb +84 -5
  16. data/lib/fluent/platforms.rb +2 -1
  17. data/lib/fluent/version.rb +1 -1
  18. data/lib/fluent/web_elements/cell.rb +16 -0
  19. data/lib/fluent/web_elements/checkbox.rb +4 -0
  20. data/lib/fluent/web_elements/div.rb +16 -0
  21. data/lib/fluent/web_elements/list_item.rb +16 -0
  22. data/lib/fluent/web_elements/ordered_list.rb +16 -0
  23. data/lib/fluent/web_elements/radio.rb +4 -0
  24. data/lib/fluent/web_elements/select_list.rb +4 -0
  25. data/lib/fluent/web_elements/span.rb +16 -0
  26. data/lib/fluent/web_elements/table.rb +16 -0
  27. data/lib/fluent/web_elements/text_area.rb +16 -0
  28. data/lib/fluent/web_elements/text_field.rb +8 -0
  29. data/lib/fluent/web_elements/unordered_list.rb +16 -0
  30. data/lib/fluent/web_elements/web_element.rb +12 -0
  31. data/spec/enclosers_spec.rb +38 -0
  32. data/spec/evaluators_spec.rb +88 -0
  33. data/spec/factory_spec.rb +42 -0
  34. data/spec/fluent_spec.rb +32 -1
  35. data/spec/generators/cell_generators_spec.rb +50 -0
  36. data/spec/generators/div_generators_spec.rb +49 -0
  37. data/spec/generators/list_item_generators_spec.rb +53 -0
  38. data/spec/generators/ordered_list_generators_spec.rb +53 -0
  39. data/spec/generators/span_generators_spec.rb +49 -0
  40. data/spec/generators/table_generators_spec.rb +49 -0
  41. data/spec/generators/text_area_generators_spec.rb +55 -0
  42. data/spec/generators/unordered_list_generators_spec.rb +53 -0
  43. data/spec/generators_spec.rb +40 -0
  44. data/spec/mock_app.rb +17 -0
  45. data/spec/platform_object_spec.rb +9 -0
  46. data/spec/web_element_spec.rb +15 -0
  47. data/spec/web_element_watir_spec.rb +123 -5
  48. data/spec/web_elements/checkbox_spec.rb +21 -0
  49. data/spec/web_elements/radio_spec.rb +21 -0
  50. data/spec/web_elements/select_list_spec.rb +41 -0
  51. data/spec/web_elements/text_field_spec.rb +16 -0
  52. metadata +48 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 517921e222ad7a40ccb585b10e1b951e014a8959
4
- data.tar.gz: b4685be3d80ab1d3602f83fcbf0bfca5fde45ebd
3
+ metadata.gz: 865fd6926b13f1303315bd27fdf75450a651bd96
4
+ data.tar.gz: 2580430caa258e3d409a0b231d7b39a18d804f66
5
5
  SHA512:
6
- metadata.gz: a390c6b5f7273ea9c881a52dfb4c357f6e839afdd1988d143979a82fc3e4b3374209a221ce238180c2c6085e6535d540947c1556f64c300f2e4f8973a836a3a9
7
- data.tar.gz: e327f85cd71bc75d8364668b3c90d6cb98fb3397057132874f5aa1534e2548d18ebab0fa25f1cbeba11a6eac23745c2df5c4209b79030dac410cdf9dc86aac60
6
+ metadata.gz: 28d8369390312cf460c41cce6fe3cb321cdef0af8b22418477bf222be8e062e7a92d9ce1297a3b7b8f8220a6f09094823e77234e1333a930cb9cf3edbf2be6e9
7
+ data.tar.gz: aaa9eb4cef3b0ab94213c3e408703bcf93663c9ce6baa89151809ae6fa682e6e5a98a4f27959eceda43a7f331c829cd487c081ee40005d3ad22d74301bad3d99
data/HISTORY.md CHANGED
@@ -1,6 +1,27 @@
1
1
  Change Log and History
2
2
  ======================
3
3
 
4
+ Version 0.2.0 / 2013-10-21
5
+ --------------------------
6
+
7
+ This is a significant update of Fluent. Some of the highlights:
8
+
9
+ * The Selenium platform object is now supported. This is *only* to show that multiple platforms can be supported. Selenium is not fully supported to the same level that Watir-WebDriver is.
10
+
11
+ * New web elements are handled as part of the generators mechanism. The new elements are: div, span, ordered and unordered lists along with their list items, text areas, and tables along with their cells.
12
+
13
+ * A new mechanism called "enclosers" has been introduced. One aspect of this is that frames and iframes are now supported. More specifically, elements within frames can be specified in element definitions. Another aspect of this is that it is possible to handle JavaScript messages in terms of alerts, confirmations, and prompts.
14
+
15
+ * A new mechanism called "evaluators" has been introduced. The idea of this is that you can evaluate aspects at the page level or the browser level. The evaluators provided are: url, remove cookies, refresh, run script, screenshot, markup, title, text, wait for app, and wait for pending requests.
16
+
17
+ * Element and page level wait states have been added. A 'wait until' method is provided for both page-level and element-level concerns. Element level wait states are also provided by 'when present' (also: 'when actionable'), 'when not present' (also: 'when not actionable'), 'when visible', and 'when not visible'.
18
+
19
+ * A factory mechanism has been provided so that context methods can be used to provide a more concise interface for using page and activity definitions. Currently the factory methods provided are 'on view' and 'on'.
20
+
21
+ * Various generic web element methods have been exposed: tag name, html, flash, style, attribute, fire event, class name, value, id, send keys, scroll into view, focus, hover, double click, and clear. These are provided so that you can use Fluent similar to how you would use Watir-WebDriver directly.
22
+
23
+ * A start has been made at providing specific web element methods. For example, for text fields, checkboxes, radios, and select lists, you can call methods against those objects just as you would if using Watir-WebDriver.
24
+
4
25
  Version 0.1.0 / 2013-10-18
5
26
  --------------------------
6
27
 
data/lib/fluent.rb CHANGED
@@ -1,7 +1,10 @@
1
1
  require 'fluent/version'
2
2
  require 'fluent/errors'
3
3
  require 'fluent/logger'
4
+ require 'fluent/factory'
4
5
  require 'fluent/platforms'
6
+ require 'fluent/enclosers'
7
+ require 'fluent/evaluators'
5
8
  require 'fluent/generators'
6
9
 
7
10
  require 'watir-webdriver'
@@ -9,6 +12,8 @@ require 'selenium-webdriver'
9
12
 
10
13
  module Fluent
11
14
  include Platforms
15
+ include Evaluators
16
+ include Enclosers
12
17
 
13
18
  # Browser drivers will be:
14
19
  # [Watir::Browser] or [Selenium::WebDriver::Driver]
@@ -39,7 +44,7 @@ module Fluent
39
44
 
40
45
  Fluent.trace("#{caller.class} #{caller} is now Fluent.")
41
46
  end
42
-
47
+
43
48
  # The initialize method will be invoked when a definition includes Fluent.
44
49
  # A few key things are happening here that are critical to everything
45
50
  # working properly:
@@ -47,7 +52,7 @@ module Fluent
47
52
  # (2) A platform object is created for that browser.
48
53
  #
49
54
  # @param browser [Object] a browser instance with a tool driver
50
- def initialize(browser=nil)
55
+ def initialize(browser=nil, visit=nil)
51
56
  @browser = browser
52
57
  @browser = Watir::Browser.new if browser.nil? or browser == :watir
53
58
  @browser = Selenium::WebDriver.for :firefox if browser == :selenium
@@ -55,6 +60,28 @@ module Fluent
55
60
  Fluent::trace("Fluent attached to browser: #{@browser}")
56
61
 
57
62
  establish_platform_object_for @browser
63
+
64
+ view if visit && respond_to?(:view)
65
+ end
66
+
67
+ # Returns the default wait value for pages. This value is the default
68
+ # value beyond which a timeout is assumed.
69
+ def self.page_level_wait
70
+ @page_wait ||= 15
71
+ end
72
+
73
+ def self.page_level_wait=(value)
74
+ @page_wait = value
75
+ end
76
+
77
+ # Returns the default wait value for elements on a page. This value is
78
+ # the default value beyond which a timeout is assumed.
79
+ def self.element_level_wait
80
+ @element_wait ||= 5
81
+ end
82
+
83
+ def self.element_level_wait=(value)
84
+ @element_wait = value
58
85
  end
59
86
 
60
87
  def self.can_be_enabled
@@ -0,0 +1,35 @@
1
+ module Fluent
2
+ module Enclosers
3
+
4
+ # Provides a context for an action that will generate a JavaScript alert
5
+ # message box. The alert invocation will be overridden by the platform.
6
+ #
7
+ # @param block [Proc] the code that generates the alert
8
+ # @return [String] the message contained in the alert message box
9
+ def will_alert(&block)
10
+ platform.will_alert(&block)
11
+ end
12
+
13
+ # Provides a context for an action that will generate a JavaScript
14
+ # confirmation message box. The confirmation invocation will be
15
+ # overridden by the platform.
16
+ #
17
+ # @param response [Boolean] true to accept the confirmation, false to cancel it
18
+ # @param block [Proc] the code that generates the confirmation
19
+ # @return [String] the message contained in the confirmation message box
20
+ def will_confirm(response, &block)
21
+ platform.will_confirm(response, &block)
22
+ end
23
+
24
+ # Provides a context for an action that will generate a JavaScript prompt
25
+ # message box. The prompt invocation will be overridden by the platform.
26
+ #
27
+ # @param response [String] the value to be used in the prompt
28
+ # @param block [Proc] the code that generates the prompt
29
+ # @return [Hash] :message for the prompt message, :default_value for
30
+ # the value that the prompt had before the response was applied
31
+ def will_prompt(response, &block)
32
+ platform.will_prompt(response, &block)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,82 @@
1
+ module Fluent
2
+ module Evaluators
3
+
4
+ ## Browser-Level Actions ##
5
+
6
+ def url
7
+ platform.url
8
+ end
9
+
10
+ def remove_cookies
11
+ platform.remove_cookies
12
+ end
13
+
14
+ def refresh
15
+ platform.refresh
16
+ end
17
+
18
+ def run_script(script)
19
+ platform.run_script(script)
20
+ end
21
+
22
+ def screenshot(file)
23
+ platform.screenshot file
24
+ end
25
+
26
+ alias_method :current_url, :url
27
+ alias_method :clear_cookies, :remove_cookies
28
+ alias_method :refresh_page, :refresh
29
+ alias_method :execute_script, :run_script
30
+ alias_method :save_screenshot, :screenshot
31
+
32
+ ## Page-Level Actions ##
33
+
34
+ def markup
35
+ platform.markup
36
+ end
37
+
38
+ def title
39
+ platform.title
40
+ end
41
+
42
+ def text
43
+ platform.text
44
+ end
45
+
46
+ def wait_for_app(value=1)
47
+ sleep value
48
+ end
49
+
50
+ # Attempts to wait for pending jQuery requests and indicate if the
51
+ # requests did not occur in a given time period.
52
+ #
53
+ # @param time_limit [Numeric] time to wait for the block to return true
54
+ # @param message_if_timeout [String] the message to include with the error
55
+ def wait_for_pending_requests(time_limit=30, message_if_timeout=nil)
56
+ end_time = ::Time.now + time_limit
57
+ until ::Time.now > end_time
58
+ return if browser.execute_script('return jQuery.active') == 0
59
+ wait_for_app 0.5
60
+ end
61
+ message = 'Pending jQuery requests never indicated completion.' unless message_if_timeout
62
+ raise message
63
+ end
64
+
65
+ # Provides a context for an action that must succeed within a given time
66
+ # period. The logic here is simply that the result of the action will be
67
+ # true (meaning the action was carried out) or false, which means the
68
+ # action did not succeed in the time allotted.
69
+ #
70
+ # @param timeout [Integer] the amount of time in seconds to wait
71
+ # @param message [String] the text to return if the action did not occur in time
72
+ # @param block [Proc] the code that calls the desired action
73
+ def wait_until(timeout=Fluent.page_level_wait, message=nil, &block)
74
+ platform.wait_until(timeout, message, &block)
75
+ end
76
+
77
+ alias_method :html, :markup
78
+ alias_method :page_title, :title
79
+ alias_method :page_text, :text
80
+ alias_method :wait_for, :wait_until
81
+ end
82
+ end
@@ -0,0 +1,31 @@
1
+ module Fluent
2
+ module Factory
3
+
4
+ # Creates a definition context for actions.
5
+ #
6
+ # @param definition [Class] the name of a definition class
7
+ # @param block [Proc] logic to execute within the context of the definition
8
+ # @return [Object] instance of the definition
9
+ def on(definition, visit=false, &block)
10
+ return @active if @active.kind_of?(definition)
11
+ @active = definition.new(@browser, visit)
12
+ block.call @active if block
13
+ @active
14
+ end
15
+
16
+ alias_method :on_page, :on
17
+ alias_method :while_on, :on
18
+
19
+ # Creates a definition context for actions and establishes the
20
+ # context for display.
21
+ #
22
+ # @param definition [Class] the name of a definition class
23
+ # @param block [Proc] logic to execute within the context of the definition
24
+ def on_view(definition, &block)
25
+ on(definition, true, &block)
26
+ end
27
+
28
+ alias_method :on_visit, :on_view
29
+
30
+ end
31
+ end
@@ -22,10 +22,29 @@ module Fluent
22
22
  valid_title
23
23
  end
24
24
  end
25
+
26
+ def look_for(widget, timeout=::Fluent.element_level_wait)
27
+ define_method('check_objects') do
28
+ if self.respond_to? "#{widget}_object"
29
+ self.send("#{widget}_object").when_present(timeout)
30
+ else
31
+ raise "\n\nThe '#{widget}' object was not declared and could not be checked."
32
+ end
33
+ end
34
+ end
35
+
36
+ # This is required to allow declaring element definitions as being
37
+ # within a frame in a page definition. The logic here makes sure that
38
+ # the enclosed element definitions have their actions generated.
39
+ def within_frame(locator, &block)
40
+ frame = []
41
+ frame << locator
42
+ block.call(frame)
43
+ end
25
44
 
26
45
  def link(identifier, locator)
27
46
  define_method(identifier) do
28
- return platform.link_click(locator)
47
+ return platform.link_click(locator.clone)
29
48
  end
30
49
 
31
50
  common_definition_methods(identifier, locator, __method__)
@@ -33,7 +52,23 @@ module Fluent
33
52
 
34
53
  def paragraph(identifier, locator)
35
54
  define_method(identifier) do
36
- return platform.paragraph_text(locator)
55
+ return platform.paragraph_text(locator.clone)
56
+ end
57
+
58
+ common_definition_methods(identifier, locator, __method__)
59
+ end
60
+
61
+ def div(identifier, locator)
62
+ define_method(identifier) do
63
+ return platform.div_text(locator.clone)
64
+ end
65
+
66
+ common_definition_methods(identifier, locator, __method__)
67
+ end
68
+
69
+ def span(identifier, locator)
70
+ define_method(identifier) do
71
+ return platform.span_text(locator.clone)
37
72
  end
38
73
 
39
74
  common_definition_methods(identifier, locator, __method__)
@@ -41,7 +76,7 @@ module Fluent
41
76
 
42
77
  def button(identifier, locator)
43
78
  define_method(identifier) do
44
- return platform.button_click(locator)
79
+ return platform.button_click(locator.clone)
45
80
  end
46
81
 
47
82
  common_definition_methods(identifier, locator, __method__)
@@ -49,11 +84,23 @@ module Fluent
49
84
 
50
85
  def text_field(identifier, locator)
51
86
  define_method(identifier) do
52
- return platform.text_field_get(locator)
87
+ return platform.text_field_get(locator.clone)
53
88
  end
54
89
 
55
90
  define_method("#{identifier}=") do |value|
56
- return platform.text_field_set(locator, value)
91
+ return platform.text_field_set(locator.clone, value)
92
+ end
93
+
94
+ common_definition_methods(identifier, locator, __method__)
95
+ end
96
+
97
+ def text_area(identifier, locator)
98
+ define_method(identifier) do
99
+ return platform.text_area_get(locator.clone)
100
+ end
101
+
102
+ define_method("#{identifier}=") do |value|
103
+ return platform.text_area_set(locator.clone, value)
57
104
  end
58
105
 
59
106
  common_definition_methods(identifier, locator, __method__)
@@ -61,15 +108,15 @@ module Fluent
61
108
 
62
109
  def checkbox(identifier, locator)
63
110
  define_method("#{identifier}_checked?") do
64
- return platform.checkbox_check_state(locator)
111
+ return platform.checkbox_check_state(locator.clone)
65
112
  end
66
113
 
67
114
  define_method("check_#{identifier}") do
68
- return platform.checkbox_check(locator)
115
+ return platform.checkbox_check(locator.clone)
69
116
  end
70
117
 
71
118
  define_method("uncheck_#{identifier}") do
72
- return platform.checkbox_uncheck(locator)
119
+ return platform.checkbox_uncheck(locator.clone)
73
120
  end
74
121
 
75
122
  common_definition_methods(identifier, locator, __method__)
@@ -77,13 +124,13 @@ module Fluent
77
124
 
78
125
  def select_list(identifier, locator)
79
126
  define_method(identifier) do
80
- return platform.select_list_get_selected(locator)
127
+ return platform.select_list_get_selected(locator.clone)
81
128
  end
82
129
 
83
130
  alias_method "#{identifier}_option?".to_sym, "#{identifier}".to_sym
84
131
 
85
132
  define_method("#{identifier}=") do |value|
86
- return platform.select_list_set(locator, value)
133
+ return platform.select_list_set(locator.clone, value)
87
134
  end
88
135
 
89
136
  define_method("#{identifier}_options?") do
@@ -92,7 +139,7 @@ module Fluent
92
139
  end
93
140
 
94
141
  define_method("#{identifier}_value?") do
95
- return platform.select_list_get_value(locator)
142
+ return platform.select_list_get_value(locator.clone)
96
143
  end
97
144
 
98
145
  common_definition_methods(identifier, locator, __method__)
@@ -100,11 +147,11 @@ module Fluent
100
147
 
101
148
  def radio(identifier, locator)
102
149
  define_method("select_#{identifier}") do
103
- return platform.radio_select(locator)
150
+ return platform.radio_select(locator.clone)
104
151
  end
105
152
 
106
153
  define_method("#{identifier}_selected?") do
107
- return platform.radio_check_state(locator)
154
+ return platform.radio_check_state(locator.clone)
108
155
  end
109
156
 
110
157
  alias_method "#{identifier}_set?".to_sym, "#{identifier}_selected?".to_sym
@@ -112,20 +159,71 @@ module Fluent
112
159
 
113
160
  common_definition_methods(identifier, locator, __method__)
114
161
  end
162
+
163
+ def ordered_list(identifier, locator)
164
+ define_method(identifier) do
165
+ return platform.ordered_list_text(locator.clone)
166
+ end
167
+
168
+ common_definition_methods(identifier, locator, __method__)
169
+ common_definition_methods(identifier, locator, 'ol')
170
+ end
171
+
172
+ def unordered_list(identifier, locator)
173
+ define_method(identifier) do
174
+ return platform.unordered_list_text(locator.clone)
175
+ end
176
+
177
+ common_definition_methods(identifier, locator, __method__)
178
+ common_definition_methods(identifier, locator, 'ul')
179
+ end
180
+
181
+ def list_item(identifier, locator)
182
+ define_method(identifier) do
183
+ return platform.list_item_text(locator.clone)
184
+ end
185
+
186
+ common_definition_methods(identifier, locator, __method__)
187
+ common_definition_methods(identifier, locator, 'li')
188
+ end
189
+
190
+ def table(identifier, locator)
191
+ define_method(identifier) do
192
+ return platform.table_text(locator.clone)
193
+ end
194
+
195
+ common_definition_methods(identifier, locator, __method__)
196
+ end
197
+
198
+ def cell(identifier, locator)
199
+ define_method(identifier) do
200
+ return platform.cell_text(locator.clone)
201
+ end
115
202
 
116
- alias_method :radio_button, :radio
203
+ common_definition_methods(identifier, locator, __method__)
204
+ common_definition_methods(identifier, locator, 'td')
205
+ end
206
+
207
+ alias_method :radio_button, :radio ###
208
+ alias_method :textarea, :text_area ###
209
+ alias_method :textfield, :text_field ###
210
+ alias_method :a, :link ###
211
+ alias_method :ol, :ordered_list
212
+ alias_method :ul, :unordered_list
213
+ alias_method :li, :list_item
214
+ alias_method :td, :cell
117
215
 
118
216
  def common_definition_methods(identifier, locator, method)
119
217
  define_method("#{identifier}_object") do
120
- platform.send(method, locator)
218
+ platform.send(method, locator.clone)
121
219
  end
122
220
 
123
221
  define_method("#{identifier}_exists?") do
124
- platform.send(method, locator).exists?
222
+ platform.send(method, locator.clone).exists?
125
223
  end
126
224
 
127
225
  define_method("#{identifier}_visible?") do
128
- platform.send(method, locator).visible?
226
+ platform.send(method, locator.clone).visible?
129
227
  end
130
228
 
131
229
  alias_method "#{identifier}_#{method}".to_sym, "#{identifier}_object".to_sym
@@ -142,7 +240,7 @@ module Fluent
142
240
 
143
241
  if Fluent.can_be_enabled?(method)
144
242
  define_method("#{identifier}_enabled?") do
145
- platform.send(method, locator).enabled?
243
+ platform.send(method, locator.clone).enabled?
146
244
  end
147
245
 
148
246
  alias_method "#{identifier}!".to_sym, "#{identifier}_enabled?".to_sym