browsercuke 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/README.md +227 -0
- data/bin/browsercuke +29 -0
- data/bin/browsercuke-setup +31 -0
- data/bin/sapphirecuke +16 -0
- data/step_definitions/browser/README.md +38 -0
- data/step_definitions/browser/ajax.rb +83 -0
- data/step_definitions/browser/buttons.rb +33 -0
- data/step_definitions/browser/checkboxes.rb +26 -0
- data/step_definitions/browser/expectations.rb +29 -0
- data/step_definitions/browser/images.rb +26 -0
- data/step_definitions/browser/links.rb +26 -0
- data/step_definitions/browser/pages.rb +17 -0
- data/step_definitions/browser/popups.rb +32 -0
- data/step_definitions/browser/radio_buttons.rb +26 -0
- data/step_definitions/browser/select_lists.rb +31 -0
- data/step_definitions/browser/text_fields.rb +71 -0
- data/support/env.rb +104 -0
- data/support/firewatir-mods.rb +46 -0
- data/support/safariwatir-mods.rb +167 -0
- metadata +136 -0
data/.gitignore
ADDED
data/README.md
ADDED
@@ -0,0 +1,227 @@
|
|
1
|
+
= BrowserCuke
|
2
|
+
|
3
|
+
http://github.com/sminnee/browsercuke
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
BrowserCuke is a layer of browser-based testing on top of Cucumber. It provides an intuitive way of
|
8
|
+
writing business-readable tests for your web applications, that use real web browsers to test. Your
|
9
|
+
test scripts can now be a way of communicating with your client how you have tested the application
|
10
|
+
and how it should work.
|
11
|
+
|
12
|
+
For more information about Cucumber, see [the cucumber website](http://cukes.info).
|
13
|
+
|
14
|
+
BrowserCuke currently uses Watir to perform the browser automation, although it may be extended in
|
15
|
+
the future to use something like WebRat to test applications sans-JavaScript.
|
16
|
+
|
17
|
+
== FEATURES
|
18
|
+
|
19
|
+
* Tests Safari and Firefox
|
20
|
+
* Looks for page elements like a human would: e.g. ignores hidden elements, and you can use form element labels as identifiers.
|
21
|
+
* Automatically wait for ajax requests to complete.
|
22
|
+
|
23
|
+
It currently has the following limitations:
|
24
|
+
|
25
|
+
* No known Windows and IE support
|
26
|
+
* No ability to test with JavaScript
|
27
|
+
* Ajax auto-wait only works with Prototype and jQuery generated Ajax requests.
|
28
|
+
* Testing of iframes and multiple windows is untested.
|
29
|
+
* No drag & drop tests.
|
30
|
+
|
31
|
+
Roadmap:
|
32
|
+
|
33
|
+
* Make it work in Windows/OSX/Linux and Firefox/Safari/IE
|
34
|
+
* Add JS-disabled testing using WebRat
|
35
|
+
* Ensure that you can test iframes and multiple windows intuitively
|
36
|
+
* Add tests for drag & drop
|
37
|
+
* Add tests for colour and image changes
|
38
|
+
* Get the FireWatir and SafariWatir monkey patches submitted to those upstream projects.
|
39
|
+
|
40
|
+
== INSTALL:
|
41
|
+
|
42
|
+
BrowserCuke is packaged as a gem, so the easiest way of installing BrowserCuke is by running this
|
43
|
+
command:
|
44
|
+
|
45
|
+
$ gem install browsercuke
|
46
|
+
|
47
|
+
After you have installed the gem, you should run this command to set up your browsers properly:
|
48
|
+
|
49
|
+
$ browsercuke-setup
|
50
|
+
|
51
|
+
== SYNOPSIS:
|
52
|
+
|
53
|
+
Run something like this to execute a test freature.
|
54
|
+
|
55
|
+
browsercuke http://localhost/yoursite create-page.feature
|
56
|
+
|
57
|
+
=== Using BrowserCuke to run tests from another project
|
58
|
+
|
59
|
+
BrowserCuke doesn't come bundled with any actual tests, so usually you have to write tests as part
|
60
|
+
of your project.
|
61
|
+
|
62
|
+
|
63
|
+
This example runs a copy of BrowserCuke installed in ~/browsercuke to execute the features
|
64
|
+
contained in a Sapphire project. `sake SapphireURL/baseurl` return the URL of the current Sapphire
|
65
|
+
project.
|
66
|
+
|
67
|
+
browsercuke firefox `sake SapphireInfo/baseurl` */tests/cuke/*.feature
|
68
|
+
|
69
|
+
Because BrowserCuke was written in order to support testing of Sapphire projects, we have a special
|
70
|
+
script for this particular example. This will probably go away as BrowserCuke matures
|
71
|
+
|
72
|
+
sapphirecuke firefox
|
73
|
+
|
74
|
+
=== Rules
|
75
|
+
|
76
|
+
Please see [the cucumber website](http://cukes.info) for information about the exact cucumber
|
77
|
+
syntax.
|
78
|
+
|
79
|
+
Actions
|
80
|
+
-------
|
81
|
+
|
82
|
+
### When I click the "(identifier)" button
|
83
|
+
|
84
|
+
### When I click the "(identifier)" checkbox
|
85
|
+
|
86
|
+
### When I click the "(identifier)" image
|
87
|
+
|
88
|
+
### When I click the "(identifier)" link
|
89
|
+
|
90
|
+
### When I click the "(identifier)" radio button
|
91
|
+
|
92
|
+
### When I visit (url)
|
93
|
+
|
94
|
+
### When I select "(value)" from "(dropdown identfier)"
|
95
|
+
|
96
|
+
### When I put "(value)" in the "(field identifier)" field / When I set "(field)" to "(value)"
|
97
|
+
|
98
|
+
Assertions
|
99
|
+
----------
|
100
|
+
|
101
|
+
### Then I see "(text)"
|
102
|
+
|
103
|
+
### Then I don't see "(text)"
|
104
|
+
|
105
|
+
### Then I am at (url) / Then I am sent to (url)
|
106
|
+
|
107
|
+
### Then the url (url) does not exist
|
108
|
+
|
109
|
+
### Then "(value)" is selected in "(dropdown identfier)"
|
110
|
+
|
111
|
+
### Then the "(identifier)" field is "(value)" / Then the "(identifier)" field becomes "(value)"
|
112
|
+
|
113
|
+
### Then the "(identifier)" field is blank
|
114
|
+
|
115
|
+
|
116
|
+
|
117
|
+
Waiting
|
118
|
+
-------
|
119
|
+
|
120
|
+
### I wait for "(text)"
|
121
|
+
|
122
|
+
### I wait for HTML ("html")
|
123
|
+
|
124
|
+
Misc
|
125
|
+
----
|
126
|
+
|
127
|
+
### I cancel pop-ups
|
128
|
+
|
129
|
+
### I confirm pop-ups
|
130
|
+
|
131
|
+
### I put "(text)" in the pop-up
|
132
|
+
|
133
|
+
-----
|
134
|
+
|
135
|
+
Recommended amendment - we should alter the rules to operate this way:
|
136
|
+
|
137
|
+
Actions
|
138
|
+
-------
|
139
|
+
|
140
|
+
### When I click "(button/image/link/checkbox/radiobutton)"
|
141
|
+
|
142
|
+
### When I visit "(url)"
|
143
|
+
|
144
|
+
### When I set "(dropdown/textfield)" to "(value)"
|
145
|
+
|
146
|
+
Assertions
|
147
|
+
----------
|
148
|
+
|
149
|
+
### Then I see "(text)"
|
150
|
+
|
151
|
+
### Then I don't see "(text)"
|
152
|
+
|
153
|
+
### Then I am at (url)
|
154
|
+
|
155
|
+
### Then the url (url) doesn't exist
|
156
|
+
|
157
|
+
### Then "(field/dropdown)" is "(value)"
|
158
|
+
|
159
|
+
### Then "(checkbox/radio)" is selected
|
160
|
+
|
161
|
+
### Then "(checkbox/radio)" isn't selected
|
162
|
+
|
163
|
+
### Then "(identifier)" is blank
|
164
|
+
|
165
|
+
|
166
|
+
Waiting
|
167
|
+
-------
|
168
|
+
|
169
|
+
### I wait for "(text)"
|
170
|
+
|
171
|
+
### I wait for HTML ("html")
|
172
|
+
|
173
|
+
Misc
|
174
|
+
----
|
175
|
+
|
176
|
+
### I cancel pop-ups
|
177
|
+
|
178
|
+
### I confirm pop-ups
|
179
|
+
|
180
|
+
### I put "(text)" in pop-ups
|
181
|
+
|
182
|
+
== REQUIREMENTS:
|
183
|
+
|
184
|
+
Currently browsercuke works with the following browsers.
|
185
|
+
|
186
|
+
* Firefox 3.5
|
187
|
+
* Safari
|
188
|
+
|
189
|
+
It has been tested on OS X only; Windows and IE support coming soon!
|
190
|
+
|
191
|
+
== DEVELOPERS:
|
192
|
+
|
193
|
+
After checking out the source, run:
|
194
|
+
|
195
|
+
$ rake newb
|
196
|
+
|
197
|
+
This task will install any missing dependencies, run the tests/specs,
|
198
|
+
and generate the RDoc.
|
199
|
+
|
200
|
+
== LICENSE:
|
201
|
+
|
202
|
+
Browsercuke is licensed under the BSD license
|
203
|
+
|
204
|
+
Copyright (c) 2009, Sam Minnée
|
205
|
+
All rights reserved.
|
206
|
+
|
207
|
+
Redistribution and use in source and binary forms, with or without
|
208
|
+
modification, are permitted provided that the following conditions are met:
|
209
|
+
* Redistributions of source code must retain the above copyright
|
210
|
+
notice, this list of conditions and the following disclaimer.
|
211
|
+
* Redistributions in binary form must reproduce the above copyright
|
212
|
+
notice, this list of conditions and the following disclaimer in the
|
213
|
+
documentation and/or other materials provided with the distribution.
|
214
|
+
* Neither the name of the <organization> nor the
|
215
|
+
names of its contributors may be used to endorse or promote products
|
216
|
+
derived from this software without specific prior written permission.
|
217
|
+
|
218
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
219
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
220
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
221
|
+
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
222
|
+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
223
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
224
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
225
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
226
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
227
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/bin/browsercuke
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
if [ "$2" = "" ]; then
|
3
|
+
echo "Usage: $0 (browser) (url) (feature-file) (other cucumber args)
|
4
|
+
|
5
|
+
Run the given feature file using the URL has the test site, on the given browser.
|
6
|
+
|
7
|
+
Supported browsers:
|
8
|
+
firefox
|
9
|
+
safari
|
10
|
+
|
11
|
+
"
|
12
|
+
exit 1
|
13
|
+
fi
|
14
|
+
|
15
|
+
basedir=`dirname $0`
|
16
|
+
|
17
|
+
export BROWSERSALAD_BROWSER=$1
|
18
|
+
export BROWSERSALAD_URL=$2
|
19
|
+
|
20
|
+
|
21
|
+
# Special case for Sapphire applications - collect all the step_definitions from the modules
|
22
|
+
if [ -d sapphire/tests/cuke ]; then
|
23
|
+
for file in `ls -1d */tests/cuke/step_definitions`; do
|
24
|
+
extras="$extras -r $file"
|
25
|
+
done
|
26
|
+
fi
|
27
|
+
|
28
|
+
echo "cucumber -r $basedir/support -r $basedir/step_definitions $extras $3 $4 $5 $6 $7 $8 $9"
|
29
|
+
cucumber -r $basedir/support -r $basedir/step_definitions $extras $3 $4 $5 $6 $7 $8 $9
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
echo "Browsercuke OS X installer
|
3
|
+
===========================
|
4
|
+
"
|
5
|
+
|
6
|
+
ffbin=/Applications/Firefox.app/Contents/MacOS/firefox-bin
|
7
|
+
|
8
|
+
|
9
|
+
if [ ! -f jssh-3.5.x-Darwin-param.xpi ]; then
|
10
|
+
echo "> Downloading Firefox 3.5 JSSH plugin"
|
11
|
+
wget http://wiki.openqa.org/download/attachments/13893658/jssh-3.5.x-Darwin-param.xpi
|
12
|
+
fi
|
13
|
+
|
14
|
+
echo "> Installing Firefox 3.5 JSSH plugin"
|
15
|
+
open ./jssh-3.5.x-Darwin-param.xpi
|
16
|
+
|
17
|
+
echo "> Please go to System Prefences -> Universal Access and check the box labelled 'Enable access for assistive devices'
|
18
|
+
|
19
|
+
When you're done, press enter to continue."
|
20
|
+
|
21
|
+
read -s -n1
|
22
|
+
|
23
|
+
echo "
|
24
|
+
Done!
|
25
|
+
|
26
|
+
You should be able to run one of these commands now:
|
27
|
+
|
28
|
+
browsercuke firefox http://localhost/yourtestsite create-page.feature
|
29
|
+
browsercuke safari http://localhost/yourtestsite create-page.feature
|
30
|
+
|
31
|
+
"
|
data/bin/sapphirecuke
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
if [ "$1" = "" ]; then
|
3
|
+
echo "Usage: $0 (browser)
|
4
|
+
"
|
5
|
+
exit 1
|
6
|
+
fi
|
7
|
+
|
8
|
+
if [ ! -f sapphire/main.php ]; then
|
9
|
+
echo "Please run $0 from within your sapphire project root.
|
10
|
+
I couldn't find ./sapphire/main.php.
|
11
|
+
"
|
12
|
+
exit 2
|
13
|
+
fi
|
14
|
+
|
15
|
+
dirname=`dirname $0`
|
16
|
+
$dirname/browsercuke $1 `./sapphire/sake SapphireInfo/baseurl` */tests/cuke/*.feature
|
@@ -0,0 +1,38 @@
|
|
1
|
+
Web Application Testing Kit
|
2
|
+
===========================
|
3
|
+
|
4
|
+
These step definitions are intended to provide a generic, intuitive and powerful mechanism for
|
5
|
+
building web application tests in Cucumber. They have been originally developed for the
|
6
|
+
SilverStripe CMS but should be able to be used anywhere you find Ajax and HTML.
|
7
|
+
|
8
|
+
|
9
|
+
To do
|
10
|
+
-----
|
11
|
+
|
12
|
+
### Soon
|
13
|
+
|
14
|
+
* [x] Wait for ajax
|
15
|
+
* [x] Use <label for="X"> tags to find fields by label
|
16
|
+
* [x] Exclude hidden fields from the search; find the first visible tab
|
17
|
+
* [ ] Make label matchers case-insensitive
|
18
|
+
* [ ] Drag & drop testing (incl. SiteTree)
|
19
|
+
* [ ] ComplexTableField, pop-up, iframe testing
|
20
|
+
* [ ] Content-identification testing
|
21
|
+
* [ ] Multi-window testing (incl. checking the front-end site)
|
22
|
+
* [ ] TinyMCE testing
|
23
|
+
|
24
|
+
### Later
|
25
|
+
|
26
|
+
* Allow detection of an element's colour - The "New Page" link is green.
|
27
|
+
|
28
|
+
Origin
|
29
|
+
------
|
30
|
+
|
31
|
+
These step definitions came from [Watircuke](http://github.com/richdownie/watircuke),
|
32
|
+
by Rich Downie. They have been modified quite a bit.
|
33
|
+
|
34
|
+
No license was provided with them, so we've included this credit and our thanks. :-)
|
35
|
+
|
36
|
+
Sam Minnée
|
37
|
+
SilverStripe
|
38
|
+
|
@@ -0,0 +1,83 @@
|
|
1
|
+
=begin
|
2
|
+
Ajax Handling
|
3
|
+
This pair of methods lets us wait for ajax actions to complete before proceeding.
|
4
|
+
|
5
|
+
To use:
|
6
|
+
* Call ajax_before_action prior to the action - e.g. button/link click
|
7
|
+
* Call ajax_after_action after the action
|
8
|
+
|
9
|
+
What happens:
|
10
|
+
* If the action didn't trigger an ajax call, then it won't wait
|
11
|
+
* If the action did trigger an ajax call, then it will wait until after the success handler is
|
12
|
+
completed
|
13
|
+
|
14
|
+
Because the handler does nothing if there wasn't an ajax call, it's safe to be wrapped around all
|
15
|
+
button/link clicks.
|
16
|
+
=end
|
17
|
+
|
18
|
+
def ajax_before_action(browser)
|
19
|
+
|
20
|
+
# Warning: don't use // comments in the JS, only /* */, because newlines are removed
|
21
|
+
|
22
|
+
js = <<-eos
|
23
|
+
window.__ajaxStatus = function() { return 'no ajax'; };
|
24
|
+
|
25
|
+
if(typeof window.__ajaxPatch == 'undefined') {
|
26
|
+
window.__ajaxPatch = 1;
|
27
|
+
|
28
|
+
var patchedList = "";
|
29
|
+
|
30
|
+
/* Monkey-patch Prototype */
|
31
|
+
if(typeof window.Ajax!='undefined' && typeof window.Ajax.Request!='undefined') {
|
32
|
+
window.Ajax.Request.prototype.initialize = function(url, options) {
|
33
|
+
this.transport = window.Ajax.getTransport();
|
34
|
+
|
35
|
+
var __activeTransport = this.transport;
|
36
|
+
window.__ajaxStatus = function() {
|
37
|
+
return (__activeTransport.readyState == 4) ? 'success' : 'waiting';
|
38
|
+
};
|
39
|
+
|
40
|
+
this.setOptions(options);
|
41
|
+
this.request(url);
|
42
|
+
};
|
43
|
+
patchedList += " prototype";
|
44
|
+
}
|
45
|
+
|
46
|
+
/* Monkey-patch jQuery */
|
47
|
+
if(typeof window.jQuery!='undefined') {
|
48
|
+
var _orig_ajax = window.jQuery.ajax;
|
49
|
+
|
50
|
+
window.jQuery(window).ajaxStop(function() {
|
51
|
+
window.__ajaxStatus = function() { return 'success'; };
|
52
|
+
});
|
53
|
+
|
54
|
+
window.jQuery.ajax = function(s) {
|
55
|
+
window.__ajaxStatus = function() { return 'waiting'; };
|
56
|
+
_orig_ajax(s);
|
57
|
+
};
|
58
|
+
patchedList += " jquery";
|
59
|
+
}
|
60
|
+
return "patched" + patchedList;
|
61
|
+
} else {
|
62
|
+
return "already patched: " + window.__ajaxPatch;
|
63
|
+
}
|
64
|
+
eos
|
65
|
+
|
66
|
+
browser.evaluate_script(js)
|
67
|
+
|
68
|
+
#js = js.gsub(/[\n\r]/, "; ")
|
69
|
+
#browser.js_eval(js)
|
70
|
+
|
71
|
+
# For debugging
|
72
|
+
#puts "Patching:"
|
73
|
+
#puts browser.js_eval(js)
|
74
|
+
end
|
75
|
+
|
76
|
+
def ajax_after_action(browser)
|
77
|
+
Watir::Waiter::wait_until {
|
78
|
+
status = browser.evaluate_script("return window.__ajaxStatus ? window.__ajaxStatus() : 'no ajax'")
|
79
|
+
# For debugging
|
80
|
+
# puts "Waiting for ajax: #{status}"
|
81
|
+
status != "waiting"
|
82
|
+
}
|
83
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Try running with the button ":id", ":name", ":value", ":text", ":index" or ":class" element attribute.
|
2
|
+
# Does not matter what you select!
|
3
|
+
# The proper watir code will be executed regardless.
|
4
|
+
|
5
|
+
Given /click the "(.*)" button/i do |type|
|
6
|
+
btn = getButton(@browser, type)
|
7
|
+
|
8
|
+
if(btn) then
|
9
|
+
ajax_before_action @browser
|
10
|
+
btn.click
|
11
|
+
ajax_after_action @browser
|
12
|
+
else
|
13
|
+
fail("could not find the '#{type}'button on #{@browser.url}")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def getButton(browser, type)
|
18
|
+
button = browser.button(:id, type)
|
19
|
+
button = browser.button(:value, type) unless button.exists?
|
20
|
+
|
21
|
+
# :text used for Firefox suport
|
22
|
+
if browser.instance_of?(FireWatir::Firefox)
|
23
|
+
button = browser.button(:text, type) unless button.exists?
|
24
|
+
end
|
25
|
+
# :xpath used for Safari suport
|
26
|
+
button = browser.button(:xpath, "//button[.='#{type}']") unless button.exists?
|
27
|
+
|
28
|
+
button = browser.button(:index, type) unless button.exists?
|
29
|
+
button = browser.button(:class, type) unless button.exists?
|
30
|
+
|
31
|
+
button = nil unless button.exists?
|
32
|
+
return button
|
33
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Try running with the checkbox ":id", ":name", ":value", ":text", ":index" or ":class" element attribute.
|
2
|
+
# Does not matter what you select!
|
3
|
+
# The proper watir code will be executed regardless.
|
4
|
+
|
5
|
+
Given /click the "(.*)" checkbox/i do |type|
|
6
|
+
if @browser.checkbox(:id, type).exists? then
|
7
|
+
@browser.checkbox(:id, type).click
|
8
|
+
elsif
|
9
|
+
@browser.checkbox(:name, type).exists? then
|
10
|
+
@browser.checkbox(:name, type).click
|
11
|
+
elsif
|
12
|
+
@browser.checkbox(:value, type).exists? then
|
13
|
+
@browser.checkbox(:value, type).click
|
14
|
+
elsif
|
15
|
+
@browser.checkbox(:text, type).exists? then
|
16
|
+
@browser.checkbox(:text, type).click
|
17
|
+
elsif
|
18
|
+
@browser.checkbox(:index, type).exists? then
|
19
|
+
@browser.checkbox(:index, type).click
|
20
|
+
elsif
|
21
|
+
@browser.checkbox(:class, type).exists? then
|
22
|
+
@browser.checkbox(:class, type).click
|
23
|
+
else
|
24
|
+
fail("could not find what you asked for")
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
Given /I see "(.*)"/ do |text|
|
2
|
+
describe "Matcher" do
|
3
|
+
it "should have text" do
|
4
|
+
@browser.should have_text(text)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
Given /I don't see "(.*)"/ do |text|
|
10
|
+
describe "Matcher" do
|
11
|
+
it "shouldn't have text" do
|
12
|
+
@browser.should_not have_text(text)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Given /I wait for "(.*)"/ do |text|
|
18
|
+
Watir::Waiter::wait_until { @browser.text.include? text}
|
19
|
+
end
|
20
|
+
|
21
|
+
Given /I wait for html "(.*)"/ do |text|
|
22
|
+
Watir::Waiter::wait_until { @browser.html.include? text}
|
23
|
+
end
|
24
|
+
|
25
|
+
# Wait for time
|
26
|
+
Given /Wait ([0-9]+)s$/i do |seconds|
|
27
|
+
sleep seconds.to_i
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Try running with the image ":src", ":id", ":name", ":index", ":class" element attribute.
|
2
|
+
# Does not matter what you select!
|
3
|
+
# The proper watir code will be executed regardless.
|
4
|
+
|
5
|
+
Given /click the "(.*)" image/i do |type|
|
6
|
+
if @browser.image(:src, type).exists? then
|
7
|
+
@browser.image(:src, type).click
|
8
|
+
elsif
|
9
|
+
@browser.image(:id, type).exists? then
|
10
|
+
@browser.image(:id, type).click
|
11
|
+
elsif
|
12
|
+
@browser.image(:name, type).exists? then
|
13
|
+
@browser.image(:name, type).click
|
14
|
+
elsif
|
15
|
+
@browser.image(:text, type).exists? then
|
16
|
+
@browser.image(:text, type).click
|
17
|
+
elsif
|
18
|
+
@browser.image(:index, type).exists? then
|
19
|
+
@browser.image(:index, type).click
|
20
|
+
elsif
|
21
|
+
@browser.image(:class, type).exists? then
|
22
|
+
@browser.image(:class, type).click
|
23
|
+
else
|
24
|
+
fail("could not find what you asked for")
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Try running with the link ":id", ":text", ":class" element attribute.
|
2
|
+
# Does not matter what you select!
|
3
|
+
# The proper watir code will be executed regardless.
|
4
|
+
|
5
|
+
Given /click the "(.*)" link/i do |type|
|
6
|
+
if link = getLink(@browser, type) then
|
7
|
+
ajax_before_action @browser
|
8
|
+
link.click
|
9
|
+
ajax_after_action @browser
|
10
|
+
else
|
11
|
+
fail("could not find the '#{type}' link on #{@browser.url}")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def getLink(browser, match)
|
16
|
+
link = browser.link(:id, match)
|
17
|
+
if not link.exists? then link = browser.link(:text, match) end
|
18
|
+
if not link.exists? then link = browser.link(:class, match) end
|
19
|
+
# Try the URL with both the baseURL prefix and without it
|
20
|
+
if not link.exists? then link = browser.link(:url, @baseURL + match) end
|
21
|
+
if not link.exists? then link = browser.link(:url, match) end
|
22
|
+
if not link.exists? then link = browser.link(:xpath, match) end
|
23
|
+
if not link.exists? then link = nil end
|
24
|
+
|
25
|
+
return link
|
26
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Given /visit (.*)/o do |url|
|
2
|
+
@browser.goto(@baseURL + url)
|
3
|
+
end
|
4
|
+
|
5
|
+
Given /I am at (.*)/i do |url|
|
6
|
+
@browser.url.should =~ /^#{@baseURL}#{url}/
|
7
|
+
end
|
8
|
+
|
9
|
+
Given /I am sent to (.*)/i do |url|
|
10
|
+
Given "I am at #{url}"
|
11
|
+
end
|
12
|
+
|
13
|
+
Given /url (.*) does not exist/ do |url|
|
14
|
+
Given "I visit #{url}"
|
15
|
+
# Brittle - needs to check that actual 404 status, but that's hard
|
16
|
+
And "I see \"The requested page couldn't be found.\""
|
17
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
Given /cancel pop-ups/i do
|
2
|
+
script = "window.confirm=window.alert=window.prompt=function(){ return false; };"
|
3
|
+
|
4
|
+
# Special case for FireWatir
|
5
|
+
if @browser.respond_to?('evaluate_script_alternate')
|
6
|
+
@browser.evaluate_script_alternate(script)
|
7
|
+
else
|
8
|
+
@browser.evaluate_script(script)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
Given /confirm pop-ups/i do
|
13
|
+
script ="window.confirm=window.alert=function(){ return true; }; window.prompt=function(){ return false; }";
|
14
|
+
|
15
|
+
# Special case for FireWatir
|
16
|
+
if @browser.respond_to?('evaluate_script_alternate')
|
17
|
+
@browser.evaluate_script_alternate(script)
|
18
|
+
else
|
19
|
+
@browser.evaluate_script(script)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
Given /put "(.*)" in the pop-up/i do | value |
|
24
|
+
script = "window.confirm=window.alert=function(){ return true; }; window.prompt=function(){ return \"#{value}\"; }"
|
25
|
+
|
26
|
+
# Special case for FireWatir
|
27
|
+
if @browser.respond_to?('evaluate_script_alternate')
|
28
|
+
@browser.evaluate_script_alternate(script)
|
29
|
+
else
|
30
|
+
@browser.evaluate_script(script)
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Try running with the radio ":id", ":name", ":value", ":text", ":index" or ":class" element attribute.
|
2
|
+
# Does not matter what you select!
|
3
|
+
# The proper watir code will be executed regardless.
|
4
|
+
|
5
|
+
Given /click the "(.*)" radio button/i do |type|
|
6
|
+
if @browser.radio(:id, type).exists? then
|
7
|
+
@browser.radio(:id, type).click
|
8
|
+
elsif
|
9
|
+
@browser.radio(:name, type).exists? then
|
10
|
+
@browser.radio(:name, type).click
|
11
|
+
elsif
|
12
|
+
@browser.radio(:value, type).exists? then
|
13
|
+
@browser.radio(:value, type).click
|
14
|
+
elsif
|
15
|
+
@browser.radio(:text, type).exists? then
|
16
|
+
@browser.radio(:text, type).click
|
17
|
+
elsif
|
18
|
+
@browser.radio(:index, type).exists? then
|
19
|
+
@browser.radio(:index, type).click
|
20
|
+
elsif
|
21
|
+
@browser.radio(:class, type).exists? then
|
22
|
+
@browser.radio(:class, type).click
|
23
|
+
else
|
24
|
+
fail("could not find what you asked for")
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# Try running with the select-list ":id", ":name", ":value", ":text", ":index" or ":class" element attribute.
|
2
|
+
# Does not matter what you select!
|
3
|
+
# The proper watir code will be executed regardless.
|
4
|
+
|
5
|
+
Given /select "(.*)" from "(.*)"/i do |text, type|
|
6
|
+
if @browser.select_list(:id, type).exists? then
|
7
|
+
@browser.select_list(:id, type).select(text)
|
8
|
+
|
9
|
+
elsif @browser.select_list(:name, type).exists? then
|
10
|
+
@browser.select_list(:name, type).select(text)
|
11
|
+
|
12
|
+
elsif @browser.select_list(:value, type).exists? then
|
13
|
+
@browser.select_list(:value, type).select(text)
|
14
|
+
|
15
|
+
elsif @browser.select_list(:text, type).exists? then
|
16
|
+
@browser.select_list(:text, type).select(text)
|
17
|
+
|
18
|
+
elsif @browser.select_list(:index, type).exists? then
|
19
|
+
@browser.select_list(:index, type).select(text)
|
20
|
+
|
21
|
+
elsif @browser.select_list(:class, /(^|\s)#{type}(\s|$)/).exists? then
|
22
|
+
@browser.select_list(:class, /(^|\s)#{type}(\s|$)/).set(text)
|
23
|
+
else
|
24
|
+
fail("could not find what you asked for")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Given /"(.*)" is selected in "(.*)"/i do |text, field|
|
29
|
+
pending
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,71 @@
|
|
1
|
+
Given /put "(.*)" in the "(.*)" field/i do |text,type|
|
2
|
+
field = getTextField(@browser, type)
|
3
|
+
if field then
|
4
|
+
field.set(text)
|
5
|
+
else
|
6
|
+
fail("could not find the '#{type}' field to write '#{text}' into on #{@browser.url}")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
Given /The "(.*)" field is "(.*)"/i do |name, value|
|
12
|
+
field = getTextField(@browser, name)
|
13
|
+
|
14
|
+
if field then
|
15
|
+
field.value.should == value
|
16
|
+
else
|
17
|
+
fail("could not find the '#{name}' field on #{@browser.url}")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Synonyms
|
22
|
+
Given /set "(.*)" to "(.*)"/i do |type,text|
|
23
|
+
Given "I put \"#{text}\" in the \"#{type}\" field"
|
24
|
+
end
|
25
|
+
|
26
|
+
Given /The "(.*)" field is blank/i do |field|
|
27
|
+
Given "The \"#{field}\" field is \"\""
|
28
|
+
end
|
29
|
+
|
30
|
+
Given /The value of "(.*)" becomes "(.*)"/i do |field, value|
|
31
|
+
Given "The \"#{field}\" field is \"#{value}\""
|
32
|
+
end
|
33
|
+
|
34
|
+
# Try running with the text_field ":id", ":name", ":value", ":index" or ":class" element attribute.
|
35
|
+
# Does not matter what you select!
|
36
|
+
# The proper watir code will be executed regardless.
|
37
|
+
|
38
|
+
def getTextField(browser, type)
|
39
|
+
# Build an array of all potential fields
|
40
|
+
fields = []
|
41
|
+
# By ID
|
42
|
+
browser.text_fields().each { | field |
|
43
|
+
if field.id == type then fields.push field end
|
44
|
+
}
|
45
|
+
# By Name
|
46
|
+
browser.text_fields().each { | field |
|
47
|
+
if field.respond_to?('htmlname') then
|
48
|
+
if field.htmlname == type then fields.push field end
|
49
|
+
else
|
50
|
+
if field.name == type then fields.push field end
|
51
|
+
end
|
52
|
+
}
|
53
|
+
# By the associated <label>
|
54
|
+
browser.elements_by_xpath("//label[.='#{type}']").each { | label |
|
55
|
+
if label.for then
|
56
|
+
browser.text_fields().each { | field |
|
57
|
+
if field.id == label.for then fields.push field end
|
58
|
+
}
|
59
|
+
end
|
60
|
+
}
|
61
|
+
# By value
|
62
|
+
#fields += browser.text_fields(:value, type)
|
63
|
+
# By CSS Class
|
64
|
+
#fields += browser.text_fields(:class, type)
|
65
|
+
|
66
|
+
# Return the first visible one
|
67
|
+
fields.each { | field |
|
68
|
+
if field.visible? then return field end
|
69
|
+
}
|
70
|
+
return nil
|
71
|
+
end
|
data/support/env.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'spec'
|
2
|
+
VERSION = "0.1.0"
|
3
|
+
|
4
|
+
|
5
|
+
$killFF = false
|
6
|
+
|
7
|
+
if ENV['BROWSERSALAD_BROWSER'] and ENV['BROWSERSALAD_BROWSER'].downcase == 'safari'
|
8
|
+
require 'safariwatir'
|
9
|
+
Browser = Watir::Safari
|
10
|
+
else
|
11
|
+
case RUBY_PLATFORM
|
12
|
+
when /darwin/
|
13
|
+
require 'firewatir'
|
14
|
+
|
15
|
+
class FireWatir::Firefox
|
16
|
+
# Modified implementation of Firewatir start-up to give it up to 30 seconds to get things sorted
|
17
|
+
def initialize(options = {})
|
18
|
+
if(options.kind_of?(Integer))
|
19
|
+
options = {:waitTime => options}
|
20
|
+
end
|
21
|
+
|
22
|
+
# check for jssh not running, firefox may be open but not with -jssh
|
23
|
+
# if its not open at all, regardless of the :suppress_launch_process option start it
|
24
|
+
# error if running without jssh, we don't want to kill their current window (mac only)
|
25
|
+
jssh_down = false
|
26
|
+
begin
|
27
|
+
set_defaults()
|
28
|
+
rescue Watir::Exception::UnableToStartJSShException
|
29
|
+
jssh_down = true
|
30
|
+
end
|
31
|
+
|
32
|
+
if current_os == :macosx && !%x{ps x | grep firefox-bin | grep -v grep}.empty?
|
33
|
+
raise "Firefox is running without -jssh" if jssh_down
|
34
|
+
open_window unless options[:suppress_launch_process]
|
35
|
+
elsif not options[:suppress_launch_process]
|
36
|
+
launch_browser(options)
|
37
|
+
end
|
38
|
+
|
39
|
+
set_defaults(300)
|
40
|
+
get_window_number()
|
41
|
+
set_browser_document()
|
42
|
+
end
|
43
|
+
|
44
|
+
def set_defaults(no_of_tries = 3)
|
45
|
+
no_of_tries_so_far = 0
|
46
|
+
# JSSH listens on port 9997. Create a new socket to connect to port 9997.
|
47
|
+
begin
|
48
|
+
$jssh_socket = TCPSocket::new(MACHINE_IP, "9997")
|
49
|
+
$jssh_socket.sync = true
|
50
|
+
read_socket()
|
51
|
+
rescue
|
52
|
+
no_of_tries_so_far += 1
|
53
|
+
sleep 0.1
|
54
|
+
retry if no_of_tries_so_far < no_of_tries
|
55
|
+
raise UnableToStartJSShException, "Unable to connect to machine : #{MACHINE_IP} on port 9997. Make sure that JSSh is properly installed and Firefox is running with '-jssh' option"
|
56
|
+
end
|
57
|
+
@error_checkers = []
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
Watir::Browser.default = 'firefox'
|
62
|
+
Browser = Watir::Browser
|
63
|
+
$killFF = true
|
64
|
+
when /win32|mingw/
|
65
|
+
require 'watir'
|
66
|
+
Browser = Watir::IE
|
67
|
+
when /java/
|
68
|
+
require 'celerity'
|
69
|
+
Browser = Celerity::Browser
|
70
|
+
else
|
71
|
+
raise "This platform is not supported (#{PLATFORM})"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Set up
|
76
|
+
$browser = Browser.new
|
77
|
+
|
78
|
+
if ENV['BROWSERSALAD_URL'] then
|
79
|
+
$baseURL = ENV['BROWSERSALAD_URL']
|
80
|
+
if not $baseURL.match(/\/$/) then
|
81
|
+
$baseURL += '/'
|
82
|
+
end
|
83
|
+
else
|
84
|
+
$baseURL = "http://demo.silverstripe.com/"
|
85
|
+
end
|
86
|
+
|
87
|
+
# Make it go fast - IE only
|
88
|
+
# $browser.speed = :zippy
|
89
|
+
|
90
|
+
# Before each scenario, load in the globals
|
91
|
+
Before do
|
92
|
+
@browser = $browser
|
93
|
+
@baseURL = $baseURL
|
94
|
+
end
|
95
|
+
|
96
|
+
at_exit do
|
97
|
+
# Let us see the aftermath for 10 seconds
|
98
|
+
sleep 10
|
99
|
+
|
100
|
+
# Kill database
|
101
|
+
$browser.goto $baseURL + 'dev/tests/endsession'
|
102
|
+
|
103
|
+
if $killFF then `killall -9 firefox-bin` end
|
104
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'firewatir'
|
2
|
+
|
3
|
+
class Element
|
4
|
+
# Returns true if the current elements returns true
|
5
|
+
# Feature missing from FireWatir
|
6
|
+
def visible?
|
7
|
+
js = "(function(el) {
|
8
|
+
var w = getWindows()[#{$browser.window_index}].content;
|
9
|
+
while(el && el != w.document) {
|
10
|
+
var s = w.getComputedStyle(el, null);
|
11
|
+
if(s.getPropertyValue('display') == 'none' || s.getPropertyValue('visibility') == 'hidden') return false;
|
12
|
+
el = el.parentNode;
|
13
|
+
};
|
14
|
+
return true;
|
15
|
+
})(#{element_object});"
|
16
|
+
return js_eval(js) == 'true'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class FireWatir::Firefox
|
21
|
+
def evaluate_script(script)
|
22
|
+
# Warning: don't use // comments in the JS, only /* */, because newlines are removed
|
23
|
+
|
24
|
+
outerScript = <<-eos
|
25
|
+
(function(window) {
|
26
|
+
#{script};
|
27
|
+
})(getWindows()[#{@window_index}].content);
|
28
|
+
eos
|
29
|
+
|
30
|
+
return self.js_eval(outerScript)
|
31
|
+
end
|
32
|
+
|
33
|
+
def evaluate_script_alternate(script)
|
34
|
+
# Warning: don't use // comments in the JS, only /* */, because newlines are removed
|
35
|
+
|
36
|
+
outerScript = <<-eos
|
37
|
+
var _old_window = window;
|
38
|
+
var window = getWindows()[#{@window_index}].content;
|
39
|
+
#{script};
|
40
|
+
window = _old_window;
|
41
|
+
delete _old_window;
|
42
|
+
eos
|
43
|
+
|
44
|
+
return self.js_eval(outerScript)
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This is a collection of modifications to SafariWatir to get it to work more consistently with the
|
4
|
+
Watir API
|
5
|
+
|
6
|
+
=end
|
7
|
+
|
8
|
+
require 'safariwatir'
|
9
|
+
|
10
|
+
module Watir
|
11
|
+
module Container
|
12
|
+
# Implement missing API method - all text fields
|
13
|
+
def text_fields()
|
14
|
+
return @scripter.get_all_text_fields
|
15
|
+
end
|
16
|
+
|
17
|
+
# Implement missing API method - all elements matching an xpath
|
18
|
+
def elements_by_xpath(xpath)
|
19
|
+
return @scripter.get_all_by_xpath(xpath)
|
20
|
+
end
|
21
|
+
|
22
|
+
class HtmlElement
|
23
|
+
# Implement missing API methods - id, for, and name on all HTML elements
|
24
|
+
def id
|
25
|
+
return attr('id') || ''
|
26
|
+
end
|
27
|
+
def for
|
28
|
+
return attr('for') || ''
|
29
|
+
end
|
30
|
+
# This htmlname rather than name because name seems to have a special meaning in some versions of Ruby.
|
31
|
+
def htmlname
|
32
|
+
return @scripter.get_attribute('name', self) || ''
|
33
|
+
end
|
34
|
+
def value
|
35
|
+
return @scripter.get_value_for(self) || ''
|
36
|
+
end
|
37
|
+
|
38
|
+
# Implement missing API method - is the element visible?
|
39
|
+
def visible?
|
40
|
+
return @scripter.eval_on_element("return (function(el) {
|
41
|
+
while(el && el != document) {
|
42
|
+
var s = window.getComputedStyle(el, null);
|
43
|
+
if(s.getPropertyValue('display') == 'none' || s.getPropertyValue('visibility') == 'hidden') return false;
|
44
|
+
el = el.parentNode;
|
45
|
+
};
|
46
|
+
return true;
|
47
|
+
})(element);", self)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class TextField
|
52
|
+
# Altered API method for consistency - char-by-char setting of the value mucked with onchange
|
53
|
+
# handlers
|
54
|
+
def set(value)
|
55
|
+
@scripter.focus(self)
|
56
|
+
@scripter.highlight(self) do
|
57
|
+
clear_text_input
|
58
|
+
append_text_input(value.to_s)
|
59
|
+
end
|
60
|
+
@scripter.blur(self)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class Safari
|
66
|
+
# Added missing API method - evaluate an arbitrary script
|
67
|
+
def evaluate_script(script)
|
68
|
+
return @scripter.evaluate_script(script)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class AppleScripter
|
73
|
+
# Internal handler for Safari class to access
|
74
|
+
def evaluate_script(script)
|
75
|
+
return execute(script)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Internal handler for Safari class to access
|
79
|
+
def get_all_text_fields()
|
80
|
+
ids = get_ids_from_js("document.getElementsByTagName('input')", "item.type == 'text' || item.type == 'password'") + get_ids_from_js("document.getElementsByTagName('textarea')")
|
81
|
+
return ids.map { |id|
|
82
|
+
Container::TextField.new(self, :id, id)
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
# Internal handler for Safari class to access
|
87
|
+
def get_all_by_xpath(xpath)
|
88
|
+
xpath = xpath.gsub("'","\'")
|
89
|
+
ids = get_ids_from_js("document.evaluate(\"#{xpath}\", document.documentElement, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)",
|
90
|
+
nil,
|
91
|
+
"items.snapshotLength",
|
92
|
+
"items.snapshotItem(i)")
|
93
|
+
return ids.map { |id|
|
94
|
+
Container::HtmlElement.new(self, :id, id)
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
# Return the IDs of the elements returned by the given JS expression
|
99
|
+
# js: The JavaScript that returns a list of items
|
100
|
+
# filter: The JavaScript to evaluate on each item (variable name will be 'item') to filter the
|
101
|
+
# list. This is optional
|
102
|
+
# getLength: Expression to get the length of the JS var 'items'
|
103
|
+
# getItem: Expression to get the 'i'th of the JS var 'items'
|
104
|
+
def get_ids_from_js(js, filter = nil, getLength = "items.length", getItem = "items[i]")
|
105
|
+
if filter == nil
|
106
|
+
filter = "true"
|
107
|
+
end
|
108
|
+
|
109
|
+
fullJS = <<-eos
|
110
|
+
return (function() {
|
111
|
+
var items = #{js};
|
112
|
+
var i, item;
|
113
|
+
var output = [];
|
114
|
+
for(i=0;i<#{getLength};i++) {
|
115
|
+
item = #{getItem};
|
116
|
+
if(#{filter}) {
|
117
|
+
// Adding a random ID is a little clumsy but will do, for now
|
118
|
+
if(!item.id) item.id = 'safariwatir-' + parseInt(Math.random()*1000000000);
|
119
|
+
output.push(item.id);
|
120
|
+
}
|
121
|
+
}
|
122
|
+
return output;
|
123
|
+
})()
|
124
|
+
eos
|
125
|
+
|
126
|
+
return eval_js(fullJS)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Internal handler for HtmlElement class - Evaluate JS on a particular element
|
130
|
+
def eval_on_element(js, element)
|
131
|
+
execute(element.operate { js }, element)
|
132
|
+
end
|
133
|
+
|
134
|
+
# Altered API methdo - fix bugs in match by ID and Value
|
135
|
+
def handle_match(element, how = nil)
|
136
|
+
how = {:text => "text", :url => "href", :id => 'id', :value => 'value', :xpath => 'xpath'}[element.how] unless how
|
137
|
+
case element.what
|
138
|
+
when Regexp
|
139
|
+
%|#{how}.match(/#{element.what.source}/#{element.what.casefold? ? "i":nil})|
|
140
|
+
when String
|
141
|
+
%|#{how} == '#{element.what}'|
|
142
|
+
else
|
143
|
+
raise RuntimeError, "Unable to locate #{element.element_name} with #{element.how}"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Altered internal API method - need to wait for the URL displayed to actually change, so that
|
148
|
+
# we can handle slow-loading pages better
|
149
|
+
def navigate_to(url, &extra_action)
|
150
|
+
page_load(extra_action) do
|
151
|
+
currentURL = @document.URL.get
|
152
|
+
@document.URL.set(url)
|
153
|
+
|
154
|
+
if currentURL != url
|
155
|
+
60.times do |tries|
|
156
|
+
if @document.URL.get != currentURL
|
157
|
+
break
|
158
|
+
else
|
159
|
+
sleep 0.5
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
end
|
metadata
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: browsercuke
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- "Sam Minn\xC3\xA9e"
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-07 00:00:00 +13:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: cucumber
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.4.4
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: firewatir>= 1.6.5
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: safariwatir>= 0.3.7
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: rb-appscript>= 0.5.3
|
47
|
+
type: :runtime
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: hoe
|
57
|
+
type: :development
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 2.4.0
|
64
|
+
version:
|
65
|
+
description: |-
|
66
|
+
BrowserCuke is a layer of browser-based testing on top of Cucumber. It provides an intuitive way of
|
67
|
+
writing business-readable tests for your web applications, that use real web browsers to test. Your
|
68
|
+
test scripts can now be a way of communicating with your client how you have tested the application
|
69
|
+
and how it should work.
|
70
|
+
|
71
|
+
For more information about Cucumber, see [the cucumber website](http://cukes.info).
|
72
|
+
|
73
|
+
BrowserCuke currently uses Watir to perform the browser automation, although it may be extended in
|
74
|
+
the future to use something like WebRat to test applications sans-JavaScript.
|
75
|
+
email:
|
76
|
+
- sam@silverstripe.com
|
77
|
+
executables:
|
78
|
+
- browsercuke
|
79
|
+
- browsercuke-setup
|
80
|
+
- sapphirecuke
|
81
|
+
extensions: []
|
82
|
+
|
83
|
+
extra_rdoc_files: []
|
84
|
+
|
85
|
+
files:
|
86
|
+
- .gitignore
|
87
|
+
- README.md
|
88
|
+
- bin/browsercuke
|
89
|
+
- bin/browsercuke-setup
|
90
|
+
- bin/sapphirecuke
|
91
|
+
- step_definitions/browser/README.md
|
92
|
+
- step_definitions/browser/ajax.rb
|
93
|
+
- step_definitions/browser/buttons.rb
|
94
|
+
- step_definitions/browser/checkboxes.rb
|
95
|
+
- step_definitions/browser/expectations.rb
|
96
|
+
- step_definitions/browser/images.rb
|
97
|
+
- step_definitions/browser/links.rb
|
98
|
+
- step_definitions/browser/pages.rb
|
99
|
+
- step_definitions/browser/popups.rb
|
100
|
+
- step_definitions/browser/radio_buttons.rb
|
101
|
+
- step_definitions/browser/select_lists.rb
|
102
|
+
- step_definitions/browser/text_fields.rb
|
103
|
+
- support/env.rb
|
104
|
+
- support/firewatir-mods.rb
|
105
|
+
- support/safariwatir-mods.rb
|
106
|
+
has_rdoc: true
|
107
|
+
homepage: http://github.com/sminnee/browsercuke
|
108
|
+
licenses: []
|
109
|
+
|
110
|
+
post_install_message:
|
111
|
+
rdoc_options:
|
112
|
+
- --main
|
113
|
+
- README.md
|
114
|
+
require_paths:
|
115
|
+
- lib
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: "0"
|
121
|
+
version:
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: "0"
|
127
|
+
version:
|
128
|
+
requirements: []
|
129
|
+
|
130
|
+
rubyforge_project: browsercuke
|
131
|
+
rubygems_version: 1.3.5
|
132
|
+
signing_key:
|
133
|
+
specification_version: 3
|
134
|
+
summary: BrowserCuke is a layer of browser-based testing on top of Cucumber
|
135
|
+
test_files: []
|
136
|
+
|