browsercuke 0.1.0
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/.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
|
+
|