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.
- data/ChangeLog +11 -0
- data/features/html/nested_elements.html +20 -0
- data/features/javascript.feature +14 -0
- data/features/nested_elements.feature +11 -0
- data/features/sample-app/public/jquery-1.3.2.js +4376 -0
- data/features/sample-app/public/jquery.html +30 -0
- data/features/sample-app/public/prototype-1.6.0.3.js +4320 -0
- data/features/sample-app/public/prototype.html +34 -0
- data/features/sample-app/sample_app.rb +36 -0
- data/features/step_definitions/javascript_steps.rb +30 -0
- data/features/step_definitions/nested_elements_steps.rb +15 -0
- data/features/support/ajax_text_environment.rb +26 -0
- data/lib/page-object.rb +45 -1
- data/lib/page-object/javascript/jquery.rb +14 -0
- data/lib/page-object/javascript/prototype.rb +14 -0
- data/lib/page-object/javascript_framework_facade.rb +76 -0
- data/lib/page-object/platforms/selenium_webdriver/ordered_list.rb +10 -4
- data/lib/page-object/platforms/selenium_webdriver/unordered_list.rb +10 -4
- data/lib/page-object/platforms/watir_webdriver/ordered_list.rb +8 -5
- data/lib/page-object/platforms/watir_webdriver/page_object.rb +1 -1
- data/lib/page-object/platforms/watir_webdriver/select_list.rb +1 -1
- data/lib/page-object/platforms/watir_webdriver/text_area.rb +1 -1
- data/lib/page-object/platforms/watir_webdriver/unordered_list.rb +8 -5
- data/lib/page-object/version.rb +1 -1
- data/page-object.gemspec +3 -2
- data/spec/page-object/elements/ordered_list_spec.rb +26 -15
- data/spec/page-object/elements/select_list_spec.rb +1 -0
- data/spec/page-object/elements/unordered_list_spec.rb +22 -10
- data/spec/page-object/javascript_framework_facade_spec.rb +61 -0
- data/spec/page-object/page-object_spec.rb +26 -1
- 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
|
data/lib/page-object.rb
CHANGED
@@ -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
|
-
|
324
|
+
block.arity == 1 ? block.call(self) : self.instance_eval(&block)
|
281
325
|
end
|
282
326
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
30
|
+
element.ols(:xpath => child_xpath)
|
28
31
|
end
|
29
32
|
end
|
30
33
|
end
|
31
34
|
end
|
32
|
-
end
|
35
|
+
end
|