page-object 0.6.1 → 0.6.2

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