page-object 0.6.1 → 0.6.2

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.
Files changed (31) hide show
  1. data/ChangeLog +11 -0
  2. data/features/html/nested_elements.html +20 -0
  3. data/features/javascript.feature +14 -0
  4. data/features/nested_elements.feature +11 -0
  5. data/features/sample-app/public/jquery-1.3.2.js +4376 -0
  6. data/features/sample-app/public/jquery.html +30 -0
  7. data/features/sample-app/public/prototype-1.6.0.3.js +4320 -0
  8. data/features/sample-app/public/prototype.html +34 -0
  9. data/features/sample-app/sample_app.rb +36 -0
  10. data/features/step_definitions/javascript_steps.rb +30 -0
  11. data/features/step_definitions/nested_elements_steps.rb +15 -0
  12. data/features/support/ajax_text_environment.rb +26 -0
  13. data/lib/page-object.rb +45 -1
  14. data/lib/page-object/javascript/jquery.rb +14 -0
  15. data/lib/page-object/javascript/prototype.rb +14 -0
  16. data/lib/page-object/javascript_framework_facade.rb +76 -0
  17. data/lib/page-object/platforms/selenium_webdriver/ordered_list.rb +10 -4
  18. data/lib/page-object/platforms/selenium_webdriver/unordered_list.rb +10 -4
  19. data/lib/page-object/platforms/watir_webdriver/ordered_list.rb +8 -5
  20. data/lib/page-object/platforms/watir_webdriver/page_object.rb +1 -1
  21. data/lib/page-object/platforms/watir_webdriver/select_list.rb +1 -1
  22. data/lib/page-object/platforms/watir_webdriver/text_area.rb +1 -1
  23. data/lib/page-object/platforms/watir_webdriver/unordered_list.rb +8 -5
  24. data/lib/page-object/version.rb +1 -1
  25. data/page-object.gemspec +3 -2
  26. data/spec/page-object/elements/ordered_list_spec.rb +26 -15
  27. data/spec/page-object/elements/select_list_spec.rb +1 -0
  28. data/spec/page-object/elements/unordered_list_spec.rb +22 -10
  29. data/spec/page-object/javascript_framework_facade_spec.rb +61 -0
  30. data/spec/page-object/page-object_spec.rb +26 -1
  31. metadata +46 -14
@@ -0,0 +1,34 @@
1
+ <htmL>
2
+ <head>
3
+ <title>Prototype - Sample App</title>
4
+ <script type="application/x-javascript" src="/prototype-1.6.0.3.js"></script>
5
+ </head>
6
+ <body>
7
+ <div id="ajax-demo">
8
+ <h2>AJAX Calculator</h2>
9
+ <form id="calculator-form" action="#" method="post" onSubmit="return false;">
10
+ <input id="calculator-expression" name="calculator-expression"/>
11
+ <input type="submit" id="calculator-button" value="Compute" />
12
+ <br/><br/>
13
+ <div>Result: <input id="calculator-result" disabled /></div>
14
+ </form>
15
+
16
+ <script type="text/javascript" language="javascript">
17
+ Event.observe(window, 'load', function() {
18
+
19
+ Event.observe('calculator-button', 'click', function (event) {
20
+ new Ajax.Request('/compute', {
21
+ method: 'post',
22
+ parameters: $('calculator-form').serialize(true),
23
+ onSuccess: function(transport) {
24
+ $('calculator-result').value = transport.responseText;
25
+ },
26
+ });
27
+ return false;
28
+ });
29
+
30
+ });
31
+ </script>
32
+ </div>
33
+
34
+ </body>
@@ -0,0 +1,36 @@
1
+ require 'rubygems'
2
+ require 'rack'
3
+ require 'webrick'
4
+
5
+
6
+ class SampleApp
7
+
8
+ def self.start(host, port)
9
+ Rack::Handler::WEBrick.run(new,
10
+ :Host => host,
11
+ :Port => port,
12
+ :Logger => ::WEBrick::Log.new('/dev/null'),
13
+ :AccessLog => [nil, nil],)
14
+ end
15
+
16
+ def initialize
17
+ @public = Rack::File.new(File.expand_path("../public", __FILE__))
18
+ end
19
+
20
+ def call(env)
21
+ req = Rack::Request.new(env)
22
+
23
+ case req.path
24
+ when "/"
25
+ [200, {}, ["Sample Application"]]
26
+ when "/compute"
27
+ sleep 3
28
+ resp = eval(req.params['calculator-expression']).to_s
29
+ [200, {}, [resp]]
30
+ else
31
+ @public.call(env)
32
+ end
33
+ end
34
+
35
+ end
36
+
@@ -0,0 +1,30 @@
1
+ class JavascriptPage
2
+ include PageObject
3
+
4
+ text_field(:expression, :id => 'calculator-expression')
5
+ text_field(:results, :id => 'calculator-result')
6
+ button(:compute, :value => 'Compute')
7
+
8
+ end
9
+
10
+ Given /^I am on jQuery example page$/ do
11
+ PageObject.javascript_framework = :jquery
12
+ @page = JavascriptPage.new(@browser)
13
+ @page.navigate_to "http://localhost:4567/jquery.html"
14
+ end
15
+
16
+ Given /^I am on the Prototype example page$/ do
17
+ PageObject.javascript_framework = :prototype
18
+ @page = JavascriptPage.new(@browser)
19
+ @page.navigate_to "http://localhost:4567/prototype.html"
20
+ end
21
+
22
+ When /^I ask to compute "([^\"]*)"$/ do |expression|
23
+ @page.expression = expression
24
+ @page.compute
25
+ end
26
+
27
+ Then /^I should be able to wait for the answer "([^\"]*)"$/ do |answer|
28
+ @page.wait_for_ajax
29
+ @page.results.should == answer
30
+ end
@@ -27,6 +27,9 @@ class NestedElementsPage
27
27
  h6(:nested_h6) { |page| page.outer_div_element.h6_element }
28
28
  paragraph(:nested_paragraph) { |page| page.outer_div_element.paragraph_element }
29
29
  file_field(:nested_file_field) { |page| page.outer_div_element.file_field_element }
30
+
31
+ unordered_list(:outer_list, :id => 'outer')
32
+ ordered_list(:ordered_outer, :id => 'ol-outer')
30
33
  end
31
34
 
32
35
  Given /^I am on the nested elements page$/ do
@@ -195,3 +198,15 @@ end
195
198
  Then /^I should be able to set the nested file field$/ do
196
199
  @ff.value = __FILE__
197
200
  end
201
+
202
+ When /^I get the outter unordered list$/ do
203
+ @list = @page.outer_list_element
204
+ end
205
+
206
+ When /^I get the outter ordered list$/ do
207
+ @list = @page.ordered_outer_element
208
+ end
209
+
210
+ Then /^I should see "([^\"]*)" for list item (\d+)$/ do |text, item_number|
211
+ @list[item_number.to_i - 1].text.should == text
212
+ end
@@ -0,0 +1,26 @@
1
+ require_relative "../sample-app/sample_app"
2
+
3
+ class AjaxTestEnvironment
4
+ def run
5
+ Thread.abort_on_exception = true
6
+ @example_app = Thread.new { SampleApp.start("127.0.0.1", 4567) }
7
+ poller = Selenium::WebDriver::SocketPoller.new("127.0.0.1", 4567, 60)
8
+ unless poller.connected?
9
+ raise "timed out waiting for SampleApp to launch"
10
+ end
11
+
12
+ self
13
+ end
14
+
15
+ def stop
16
+ @example_app.kill
17
+ end
18
+
19
+ end
20
+
21
+ @server = AjaxTestEnvironment.new
22
+ @server.run
23
+
24
+ at_exit do
25
+ @server.stop
26
+ end
@@ -4,7 +4,9 @@ require 'page-object/platforms'
4
4
  require 'page-object/element_locators'
5
5
  require 'page-object/nested_elements'
6
6
  require 'page-object/page_populator'
7
+ require 'page-object/javascript_framework_facade'
7
8
 
9
+ require 'selenium/webdriver/common/error'
8
10
  #
9
11
  # Module that when included adds functionality to a page object. This module
10
12
  # will add numerous class and instance methods that you use to define and
@@ -62,6 +64,29 @@ module PageObject
62
64
  cls.extend PageObject::Accessors
63
65
  end
64
66
 
67
+ #
68
+ # Set the javascript framework to use when determining number of
69
+ # ajax requests. Valid frameworks are :jquery, :prototype, and
70
+ # :dojo
71
+ #
72
+ def self.javascript_framework=(framework)
73
+ PageObject::JavascriptFrameworkFacade.framework = framework
74
+ end
75
+
76
+ #
77
+ # Add a new javascript framework to page-object. The module passed
78
+ # in must adhere to the same prototype as the JQuery and Prototype
79
+ # modules.
80
+ #
81
+ # @param [Symbol] the name used to reference the framework in
82
+ # subsequent calls
83
+ # @param [Module] a module that has the necessary methods to perform
84
+ # the required actions.
85
+ #
86
+ def self.add_framework(key, framework)
87
+ PageObject::JavascriptFrameworkFacade.add_framework(key, framework)
88
+ end
89
+
65
90
  #
66
91
  # get the current page url
67
92
  #
@@ -115,6 +140,25 @@ module PageObject
115
140
  platform.wait_until(timeout, message, &block)
116
141
  end
117
142
 
143
+
144
+ #
145
+ # Wait until there are no pending ajax requests. This requires you
146
+ # to set the javascript framework in advance.
147
+ #
148
+ # @param [Numeric] the amount of time to wait for the block to return true.
149
+ # @param [String] the message to include with the error if we exceed
150
+ # the timeout duration.
151
+ #
152
+ def wait_for_ajax(timeout = 30, message = nil)
153
+ end_time = ::Time.now + timeout
154
+ until ::Time.now > end_time
155
+ return if browser.execute_script(::PageObject::JavascriptFrameworkFacade.pending_requests) == 0
156
+ sleep 0.5
157
+ end
158
+ message = "Timed out waiting for ajax requests to complete" unless message
159
+ raise message
160
+ end
161
+
118
162
  #
119
163
  # Override the normal alert popup so it does not occurr.
120
164
  #
@@ -277,6 +321,6 @@ module PageObject
277
321
  end
278
322
 
279
323
  def call_block(&block)
280
- block.arity == 1 ? block.call(self) : self.instance_eval(&block)
324
+ block.arity == 1 ? block.call(self) : self.instance_eval(&block)
281
325
  end
282
326
  end
@@ -0,0 +1,14 @@
1
+ module PageObject
2
+ module Javascript
3
+
4
+ module JQuery
5
+ #
6
+ # return the number of pending ajax requests
7
+ #
8
+ def self.pending_requests
9
+ 'return jQuery.active'
10
+ end
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module PageObject
2
+ module Javascript
3
+
4
+ module Prototype
5
+ #
6
+ # return the number of pending ajax requests
7
+ #
8
+ def self.pending_requests
9
+ 'return Ajax.activeRequestCount'
10
+ end
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,76 @@
1
+ require 'page-object/javascript/jquery'
2
+ require 'page-object/javascript/prototype'
3
+
4
+
5
+ module PageObject
6
+ #
7
+ # Provide hooks into different common Javascript Frameworks.
8
+ # Currently this module only supports jQuery and Prototype but it
9
+ # has the ability for you to plug your own framework into it and
10
+ # therefore have it work with this gem. You do this by calling the
11
+ # #add_framework method. The module you provide must implement the
12
+ # necessary methods. Please look at the jQuery or Prototype
13
+ # implementations to determine the necessary methods
14
+ #
15
+ module JavascriptFrameworkFacade
16
+
17
+ class << self
18
+ #
19
+ # Set the framework to use.
20
+ #
21
+ # @param[Symbol] the framework to use. :jquery and :prototype
22
+ # are supported
23
+ #
24
+ def framework=(framework)
25
+ initialize_script_builder unless @builder
26
+ raise unknown_framework(framework) unless @builder[framework]
27
+ @framework = framework
28
+ end
29
+
30
+ #
31
+ # Get the framework that will be used
32
+ #
33
+ def framework
34
+ @framework
35
+ end
36
+
37
+ #
38
+ # Add a framework and make it available to the system.
39
+ #
40
+ def add_framework(key, value)
41
+ raise invalid_framework unless value.respond_to? :pending_requests
42
+ initialize_script_builder unless @builder
43
+ @builder[key] = value
44
+ end
45
+
46
+ #
47
+ # get the javascript to determine number of pending requests
48
+ #
49
+ def pending_requests
50
+ script_builder.pending_requests
51
+ end
52
+
53
+ def script_builder
54
+ initialize_script_builder unless @builder
55
+ @builder[@framework]
56
+ end
57
+
58
+ private
59
+
60
+ def initialize_script_builder
61
+ @builder = {
62
+ :jquery => ::PageObject::Javascript::JQuery,
63
+ :prototype => ::PageObject::Javascript::Prototype,
64
+ }
65
+ end
66
+
67
+ def unknown_framework(framework)
68
+ "You specified the Javascript framework #{framework} and it is unknow to the system"
69
+ end
70
+
71
+ def invalid_framework
72
+ "The Javascript framework you provided does not implement the necessary methods"
73
+ end
74
+ end
75
+ end
76
+ end
@@ -10,19 +10,25 @@ module PageObject
10
10
  # @return [PageObject::Elements::ListItem]
11
11
  #
12
12
  def [](idx)
13
- eles = list_items
14
- Object::PageObject::Elements::ListItem.new(eles[idx], :platform => :selenium_webdriver)
13
+ children[idx]
15
14
  end
16
15
 
17
16
  #
18
17
  # Return the number of items contained in the ordered list
19
18
  #
20
19
  def items
21
- list_items.size
20
+ children.size
22
21
  end
23
22
 
24
23
  private
25
24
 
25
+ def children
26
+ items = list_items.map do |item|
27
+ ::PageObject::Elements::ListItem.new(item, :platform => :selenium_webdriver)
28
+ end
29
+ items.find_all { |item| item.parent.element == element }
30
+ end
31
+
26
32
  def list_items
27
33
  element.find_elements(:xpath, child_xpath)
28
34
  end
@@ -30,4 +36,4 @@ module PageObject
30
36
  end
31
37
  end
32
38
  end
33
- end
39
+ end
@@ -10,19 +10,25 @@ module PageObject
10
10
  # @return [PageObject::Elements::ListItem]
11
11
  #
12
12
  def [](idx)
13
- eles = list_items
14
- Object::PageObject::Elements::ListItem.new(eles[idx], :platform => :selenium_webdriver)
13
+ children[idx]
15
14
  end
16
15
 
17
16
  #
18
17
  # Return the number of items contained in the unordered list
19
18
  #
20
19
  def items
21
- list_items.size
20
+ children.size
22
21
  end
23
22
 
24
23
  private
25
24
 
25
+ def children
26
+ items = list_items.map do |item|
27
+ ::PageObject::Elements::ListItem.new(item, :platform => :selenium_webdriver)
28
+ end
29
+ items.find_all { |item| item.parent.element == element }
30
+ end
31
+
26
32
  def list_items
27
33
  element.find_elements(:xpath, child_xpath)
28
34
  end
@@ -30,4 +36,4 @@ module PageObject
30
36
  end
31
37
  end
32
38
  end
33
- end
39
+ end
@@ -10,23 +10,26 @@ module PageObject
10
10
  # @return [PageObject::Elements::ListItem]
11
11
  #
12
12
  def [](idx)
13
- eles = list_items
14
- Object::PageObject::Elements::ListItem.new(eles[idx], :platform => :watir_webdriver)
13
+ Object::PageObject::Elements::ListItem.new(children[idx], :platform => :watir_webdriver)
15
14
  end
16
15
 
17
16
  #
18
17
  # Return the number of items contained in the ordered list
19
18
  #
20
19
  def items
21
- list_items.size
20
+ children.size
22
21
  end
23
22
 
24
23
  private
25
24
 
25
+ def children
26
+ list_items.find_all { |item| item.parent == element }
27
+ end
28
+
26
29
  def list_items
27
- element.wd.find_elements(:xpath, child_xpath)
30
+ element.ols(:xpath => child_xpath)
28
31
  end
29
32
  end
30
33
  end
31
34
  end
32
- end
35
+ end
@@ -154,7 +154,7 @@ module PageObject
154
154
  # See PageObject#clear_cookies
155
155
  #
156
156
  def clear_cookies
157
- @browser.clear_cookies
157
+ @browser.cookies.clear
158
158
  end
159
159
 
160
160
  #