rsel 0.0.4 → 0.0.5
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/docs/development.md +8 -3
- data/docs/examples.md +119 -0
- data/docs/history.md +9 -0
- data/docs/index.md +3 -1
- data/docs/locators.md +72 -0
- data/docs/scoping.md +19 -5
- data/docs/todo.md +4 -2
- data/docs/usage.md +2 -2
- data/lib/rsel/exceptions.rb +1 -1
- data/lib/rsel/selenium_test.rb +37 -132
- data/lib/rsel/support.rb +138 -0
- data/rsel.gemspec +1 -1
- data/spec/selenium_test_spec.rb +103 -12
- data/spec/spec_helper.rb +1 -10
- data/spec/support_spec.rb +48 -0
- data/test/app.rb +6 -6
- metadata +8 -39
- data/vendor/rubyslim-0.1.1/.gitignore +0 -7
- data/vendor/rubyslim-0.1.1/README.md +0 -159
- data/vendor/rubyslim-0.1.1/Rakefile +0 -21
- data/vendor/rubyslim-0.1.1/bin/rubyslim +0 -10
- data/vendor/rubyslim-0.1.1/lib/rubyslim/list_deserializer.rb +0 -69
- data/vendor/rubyslim-0.1.1/lib/rubyslim/list_executor.rb +0 -12
- data/vendor/rubyslim-0.1.1/lib/rubyslim/list_serializer.rb +0 -45
- data/vendor/rubyslim-0.1.1/lib/rubyslim/ruby_slim.rb +0 -61
- data/vendor/rubyslim-0.1.1/lib/rubyslim/slim_error.rb +0 -3
- data/vendor/rubyslim-0.1.1/lib/rubyslim/slim_helper_library.rb +0 -23
- data/vendor/rubyslim-0.1.1/lib/rubyslim/socket_service.rb +0 -53
- data/vendor/rubyslim-0.1.1/lib/rubyslim/statement.rb +0 -79
- data/vendor/rubyslim-0.1.1/lib/rubyslim/statement_executor.rb +0 -174
- data/vendor/rubyslim-0.1.1/lib/rubyslim/table_to_hash_converter.rb +0 -32
- data/vendor/rubyslim-0.1.1/lib/test_module/library_new.rb +0 -13
- data/vendor/rubyslim-0.1.1/lib/test_module/library_old.rb +0 -12
- data/vendor/rubyslim-0.1.1/lib/test_module/should_not_find_test_slim_in_here/test_slim.rb +0 -7
- data/vendor/rubyslim-0.1.1/lib/test_module/simple_script.rb +0 -9
- data/vendor/rubyslim-0.1.1/lib/test_module/test_chain.rb +0 -5
- data/vendor/rubyslim-0.1.1/lib/test_module/test_slim.rb +0 -86
- data/vendor/rubyslim-0.1.1/lib/test_module/test_slim_with_arguments.rb +0 -23
- data/vendor/rubyslim-0.1.1/lib/test_module/test_slim_with_no_sut.rb +0 -5
- data/vendor/rubyslim-0.1.1/rubyslim.gemspec +0 -22
- data/vendor/rubyslim-0.1.1/spec/instance_creation_spec.rb +0 -40
- data/vendor/rubyslim-0.1.1/spec/it8f_spec.rb +0 -8
- data/vendor/rubyslim-0.1.1/spec/list_deserializer_spec.rb +0 -66
- data/vendor/rubyslim-0.1.1/spec/list_executor_spec.rb +0 -187
- data/vendor/rubyslim-0.1.1/spec/list_serialzer_spec.rb +0 -38
- data/vendor/rubyslim-0.1.1/spec/method_invocation_spec.rb +0 -127
- data/vendor/rubyslim-0.1.1/spec/slim_helper_library_spec.rb +0 -80
- data/vendor/rubyslim-0.1.1/spec/socket_service_spec.rb +0 -98
- data/vendor/rubyslim-0.1.1/spec/spec_helper.rb +0 -6
- data/vendor/rubyslim-0.1.1/spec/statement_executor_spec.rb +0 -50
- data/vendor/rubyslim-0.1.1/spec/statement_spec.rb +0 -17
- data/vendor/rubyslim-0.1.1/spec/table_to_hash_converter_spec.rb +0 -31
data/docs/development.md
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
Development
|
2
|
-
|
2
|
+
===========
|
3
3
|
|
4
4
|
If you would like to contribute to development of Rsel, create a fork of the
|
5
5
|
[Github repository](https://github.com/a-e/rsel), clone your fork, and submit
|
6
6
|
pull requests for any improvements you would like to share.
|
7
7
|
|
8
|
+
|
9
|
+
Testing
|
10
|
+
-------
|
11
|
+
|
8
12
|
While developing, you should run the RSpec tests frequently to ensure nothing
|
9
13
|
gets broken. You can do this with a single `rake` command:
|
10
14
|
|
@@ -42,7 +46,8 @@ and stop them:
|
|
42
46
|
$ rake selenium:rc:stop
|
43
47
|
$ rake testapp:stop
|
44
48
|
|
45
|
-
|
46
|
-
|
49
|
+
When the test application is running, you can view the site in your browser by
|
50
|
+
visiting http://localhost:8070/. If you are developing new features, please add
|
51
|
+
spec tests in the `spec` directory!
|
47
52
|
|
48
53
|
Next: [To-do list](todo.md)
|
data/docs/examples.md
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
Examples
|
2
|
+
========
|
3
|
+
|
4
|
+
This page presents some example Rsel tests, illustrating how you might use many
|
5
|
+
of the built-in methods from a FitNesse wiki page. All of these are based on
|
6
|
+
the example web application that you can find in the Rsel `test` directory;
|
7
|
+
it's the same one used for running the spec tests in the `spec` directory. See
|
8
|
+
[Development](development.md) for instructions on running the server if you'd
|
9
|
+
like to execute these examples.
|
10
|
+
|
11
|
+
|
12
|
+
Links
|
13
|
+
-------------
|
14
|
+
|
15
|
+
| script | selenium test | !-http://localhost:8070-! |
|
16
|
+
| Open browser |
|
17
|
+
| Maximize browser |
|
18
|
+
| Visit | / |
|
19
|
+
| See | Welcome |
|
20
|
+
| See | This is a Sinatra webapp for unit testing Rsel |
|
21
|
+
| Link | About this site | exists |
|
22
|
+
| Click link | About this site |
|
23
|
+
| See | This site is really cool |
|
24
|
+
| See title | About this site |
|
25
|
+
| Click back |
|
26
|
+
| See | This is a Sinatra webapp for unit testing Rsel |
|
27
|
+
| Do not see | This site is really cool |
|
28
|
+
| Close browser |
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
Buttons
|
33
|
+
-------------
|
34
|
+
|
35
|
+
| script | selenium test | !-http://localhost:8070-! |
|
36
|
+
| Open browser |
|
37
|
+
| Maximize browser |
|
38
|
+
| Visit | /form |
|
39
|
+
| Button | Submit person form | exists |
|
40
|
+
| Click | Submit person form | button |
|
41
|
+
| See | We appreciate your feedback |
|
42
|
+
| Visit | /form |
|
43
|
+
| Button | Submit spouse form | exists | !{within:spouse_form} |
|
44
|
+
| Click | Submit spouse form | button | !{within:spouse_form} |
|
45
|
+
| See | We appreciate your feedback |
|
46
|
+
| Close browser |
|
47
|
+
|
48
|
+
|
49
|
+
Checkboxes
|
50
|
+
-------------
|
51
|
+
|
52
|
+
| script | selenium test | !-http://localhost:8070-! |
|
53
|
+
| Open browser |
|
54
|
+
| Maximize browser |
|
55
|
+
| Visit | /form |
|
56
|
+
| Enable | I like cheese | checkbox |
|
57
|
+
| Checkbox | I like cheese | is enabled |
|
58
|
+
| Disable | I like cheese | checkbox |
|
59
|
+
| Checkbox | I like cheese | is disabled |
|
60
|
+
| Enable | I like salami | checkbox | !{within:salami_checkbox} |
|
61
|
+
| Checkbox | I like salami | is enabled | !{within:salami_checkbox} |
|
62
|
+
| Disable | I like salami | checkbox | !{within:salami_checkbox} |
|
63
|
+
| Checkbox | I like salami | is disabled | !{within:salami_checkbox} |
|
64
|
+
| Close browser |
|
65
|
+
|
66
|
+
|
67
|
+
Dropdowns
|
68
|
+
-------------
|
69
|
+
|
70
|
+
| script | selenium test | !-http://localhost:8070-! |
|
71
|
+
| Open browser |
|
72
|
+
| Maximize browser |
|
73
|
+
| Visit | /form |
|
74
|
+
| Dropdown | Height | includes | Short |
|
75
|
+
| Dropdown | Height | includes | Average |
|
76
|
+
| Dropdown | Height | includes | Tall |
|
77
|
+
| Select | Tall | from | Height | dropdown |
|
78
|
+
| Dropdown | Height | equals | Tall |
|
79
|
+
| Select | Short | from | Height | dropdown |
|
80
|
+
| Dropdown | Height | equals | Short |
|
81
|
+
| Close browser |
|
82
|
+
|
83
|
+
|
84
|
+
Radiobuttons
|
85
|
+
-------------
|
86
|
+
|
87
|
+
| script | selenium test | !-http://localhost:8070-! |
|
88
|
+
| Open browser |
|
89
|
+
| Maximize browser |
|
90
|
+
| Visit | /form |
|
91
|
+
| Select | Briefs | radio |
|
92
|
+
| Radio | Briefs | is enabled |
|
93
|
+
| Radio | Boxers | is disabled |
|
94
|
+
| Select | Boxers | radio | !{within:clothing} |
|
95
|
+
| Radio | Boxers | is enabled | !{within:clothing} |
|
96
|
+
| Radio | Briefs | is disabled | !{within:clothing} |
|
97
|
+
| Close browser |
|
98
|
+
|
99
|
+
|
100
|
+
Tables
|
101
|
+
-------------
|
102
|
+
|
103
|
+
| script | selenium test | !-http://localhost:8070-! |
|
104
|
+
| Open browser |
|
105
|
+
| Maximize browser |
|
106
|
+
| Visit | /table |
|
107
|
+
| Row | First name, Last name, Email, Actions | exists |
|
108
|
+
| Row | !-Eric, Pierce, epierce@example.com-! | exists |
|
109
|
+
| Enable | Like | checkbox | !{in_row:Marcus} |
|
110
|
+
| Checkbox | Like | is enabled | !{in_row:Marcus} |
|
111
|
+
| Disable | Like | checkbox | !{in_row:Marcus} |
|
112
|
+
| Checkbox | Like | is disabled | !{in_row:Marcus} |
|
113
|
+
| Select | Male | from | Gender | dropdown | !{in_row:Eric} |
|
114
|
+
| Click | Edit | link | !{in_row:Eric} |
|
115
|
+
| See title | Editing Eric |
|
116
|
+
| Close browser |
|
117
|
+
|
118
|
+
|
119
|
+
Next: [Customization](custom.md)
|
data/docs/history.md
CHANGED
@@ -1,6 +1,15 @@
|
|
1
1
|
Rsel History
|
2
2
|
============
|
3
3
|
|
4
|
+
0.0.5
|
5
|
+
-----
|
6
|
+
|
7
|
+
- Allow Selenium-style locators beginning with id=, name=, xpath=, css= etc.
|
8
|
+
- Raise a StopTest exception when Selenium is not running (requires updated rubyslim)
|
9
|
+
- Locators are now documented
|
10
|
+
- Example FitNesse tables are now included
|
11
|
+
|
12
|
+
|
4
13
|
0.0.4
|
5
14
|
-----
|
6
15
|
|
data/docs/index.md
CHANGED
@@ -5,9 +5,11 @@ Rsel connects [FitNesse](http://fitnesse.org) to
|
|
5
5
|
[Selenium](http://seleniumhq.org) via [Ruby](http://ruby-lang.org). It allows
|
6
6
|
you to use a natural English syntax to write web application tests.
|
7
7
|
|
8
|
-
- [Installation
|
8
|
+
- [Installation](install.md)
|
9
9
|
- [Usage](usage.md)
|
10
|
+
- [Locators](locators.md)
|
10
11
|
- [Scoping](scoping.md)
|
12
|
+
- [Examples](examples.md)
|
11
13
|
- [Customization](custom.md)
|
12
14
|
- [Development](development.md)
|
13
15
|
- [To-do list](todo.md)
|
data/docs/locators.md
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
Locators
|
2
|
+
========
|
3
|
+
|
4
|
+
By default, Selenium accepts a [variety of locator strings](http://release.seleniumhq.org/selenium-remote-control/0.9.2/doc/dotnet/Selenium.html)
|
5
|
+
for specifying the element you want to inspect or interact with. While these
|
6
|
+
are suitable for programmers and web developers with intimate knowledge of
|
7
|
+
their webpages' structure, they are often not intuitive to the average user.
|
8
|
+
|
9
|
+
For example, the default behavior of Selenium is to match elements based on
|
10
|
+
their `name` attribute. Given this HTML:
|
11
|
+
|
12
|
+
<a name="contact_us_link" href="/contact">Contact Us</a>
|
13
|
+
|
14
|
+
To click on the "Concact Us" link using a standard Selenium locator, you'd have
|
15
|
+
to do one of the following:
|
16
|
+
|
17
|
+
| click | contact_us_link |
|
18
|
+
| click | link=Contact Us |
|
19
|
+
|
20
|
+
This is easy enough, but what if the target element does not have a `name`
|
21
|
+
attribute defined? What if the link is an image instead of a piece of text? In
|
22
|
+
those cases, you'd have to use a locator string based on `id` (if the element
|
23
|
+
has one), `dom`, `xpath`, or `css`. Again, all of these are
|
24
|
+
programmer-oriented, and would not make much sense to the average user looking
|
25
|
+
at the webpage. While this scheme allows selecting HTML elements with great
|
26
|
+
precision, it can become cumbersome to read and write.
|
27
|
+
|
28
|
+
The situation becomes even more complex with HTML form elements--text fields,
|
29
|
+
dropdowns, checkboxes and the like. While HTML provides a way to semantically
|
30
|
+
label these fields, Selenium provides no way to select those fields based on
|
31
|
+
their label, aside from using a rather long and complex `xpath` expression.
|
32
|
+
For instance, given this HTML:
|
33
|
+
|
34
|
+
<label for="first_name_text_field">First name</label>
|
35
|
+
<input id="first_name_text_field" type="text" />
|
36
|
+
|
37
|
+
With Selenium's default selectors, you could do:
|
38
|
+
|
39
|
+
| type | id=first_name_text_field | Eric |
|
40
|
+
| type | xpath=.//input[@id = ../label[.='First name']/@for] | Eric |
|
41
|
+
|
42
|
+
Neither of these solutions is very attractive.
|
43
|
+
|
44
|
+
For these reasons, Rsel has a simpler locator scheme that matches elements
|
45
|
+
based on several likely attributes. Links are matched on `id`, link text, or
|
46
|
+
the `alt` text in the case of an image link. Form fields are matched on their
|
47
|
+
plain-text label, `name` or `id` attribute. In Rsel, the above examples become
|
48
|
+
much easier:
|
49
|
+
|
50
|
+
| click | Contact Us |
|
51
|
+
| Type | Eric | into field | First name |
|
52
|
+
|
53
|
+
This allows you to use human-readable locator strings for most HTML elements,
|
54
|
+
keeping your test steps free of ugly markup. Refer to the `SeleniumTest` method
|
55
|
+
documentation for details on what locator strings are expected for each element.
|
56
|
+
|
57
|
+
If you like, you can still pass explicit Selenium-style locators, as long as
|
58
|
+
they are prefixed with `id=`, `name=`, `dom=`, `xpath=`, `link=`, or `css=`. If
|
59
|
+
you do this, it's up to you to make sure you're using a suitable locator for
|
60
|
+
the kind of element you're interacting with. For example, it doesn't make much
|
61
|
+
sense to write:
|
62
|
+
|
63
|
+
| Type | Eric | into field | link=Contact Us |
|
64
|
+
|
65
|
+
But Rsel won't stop you from trying! One drawback to this approach is that any
|
66
|
+
[scoping](scoping.md) clause is ignored. In most cases, it's easier, safer, and
|
67
|
+
more readable to use the plain text locator, and rely on Rsel's internal logic
|
68
|
+
to find the correct element. This feature is only provided as a workaround for
|
69
|
+
the possibility that Rsel's locator scheme is too restrictive for your needs.
|
70
|
+
|
71
|
+
Next: [Scoping](scoping.md)
|
72
|
+
|
data/docs/scoping.md
CHANGED
@@ -79,10 +79,24 @@ operate on checkboxes, dropdowns, or text fields as well.
|
|
79
79
|
Caveat
|
80
80
|
------
|
81
81
|
|
82
|
-
|
83
|
-
|
84
|
-
of
|
85
|
-
|
82
|
+
The first thing you need to remember when using a scoping hash is that your tables
|
83
|
+
must not be fully escaped. This just means you should not include a `!` at the
|
84
|
+
beginning of your table, otherwise the hash syntax will be interpreted
|
85
|
+
literally, instead of as an embedded hash.
|
86
|
+
|
87
|
+
This means you will need to manually escape any cells in your table that
|
88
|
+
contain URLs, email addresses, or other auto-interpreted text:
|
89
|
+
|
90
|
+
| script | selenium test | !-http://www.example.com-! |
|
91
|
+
| Open browser |
|
92
|
+
| See | Welcome |
|
93
|
+
| Click | About | link | !{within:footer} |
|
94
|
+
| Close browser |
|
95
|
+
|
96
|
+
Another important thing to note is that due to the way FitNesse Slim script
|
97
|
+
tables are evaluated, the scoping hash must be added after a cell that contains
|
98
|
+
part of the method name. Cells in these tables must contain alternating
|
99
|
+
(function, argument) chunks; the way the above example breaks down is:
|
86
100
|
|
87
101
|
| Type | | into | | field | |
|
88
102
|
| | 111-222-3333 | | Phone number | | !{within:work} |
|
@@ -104,5 +118,5 @@ have a use case that isn't covered by the existing scopes, please [submit an
|
|
104
118
|
issue](http://github.com/a-e/rsel/issues), or better yet, implement it yourself
|
105
119
|
and submit a pull request. See [Development](development.md) for more info.
|
106
120
|
|
107
|
-
Next: [
|
121
|
+
Next: [Examples](examples.md)
|
108
122
|
|
data/docs/todo.md
CHANGED
@@ -5,8 +5,10 @@ To-do list
|
|
5
5
|
only support true/false results, with no clear way to report on what went
|
6
6
|
wrong (aside from raising an exception, which even then curiously does not
|
7
7
|
mark the step as failed)
|
8
|
-
- Find a way to abort a test if
|
9
|
-
|
8
|
+
- Find a way to abort a test if a step fails (will probably require more
|
9
|
+
hacking on rubyslim)
|
10
10
|
- Verify the presence of images, allow clicking on images
|
11
|
+
- Create a Selenium IDE plugin to generate FitNesse-formatted output for
|
12
|
+
recorded scripts
|
11
13
|
|
12
14
|
Next: [History](history.md)
|
data/docs/usage.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
Usage
|
2
|
-
|
2
|
+
=====
|
3
3
|
|
4
4
|
Once you have created your `SetUp` page, you can create sibling pages with
|
5
5
|
tests in them. For instance, continuing with the example from
|
@@ -46,5 +46,5 @@ driver frowns upon it.)
|
|
46
46
|
See the `SeleniumTest` class documentation for a full list of available methods
|
47
47
|
and how to use them.
|
48
48
|
|
49
|
-
Next: [
|
49
|
+
Next: [Locators](locators.md)
|
50
50
|
|
data/lib/rsel/exceptions.rb
CHANGED
data/lib/rsel/selenium_test.rb
CHANGED
@@ -1,31 +1,29 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'exceptions')
|
1
|
+
#require File.join(File.dirname(__FILE__), 'exceptions')
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'xpath'
|
5
5
|
require 'selenium/client'
|
6
|
+
require 'rsel/support'
|
7
|
+
require 'rsel/exceptions'
|
6
8
|
|
7
9
|
module Rsel
|
8
10
|
|
9
|
-
# Main Selenium-test class.
|
11
|
+
# Main Selenium-test class, and wrapper for all Selenium method calls. This
|
12
|
+
# class is intended to be instantiated in a FitNesse / Slim script table.
|
13
|
+
# May be customized or extended using a subclass.
|
14
|
+
#
|
15
|
+
# @note: Function names beginning with the words 'check', 'ensure', 'reject',
|
16
|
+
# 'note', 'show', or 'start' cannot be called from a Slim script table, since
|
17
|
+
# these are keywords that receive special handling by Slim.
|
10
18
|
#
|
11
19
|
# @example
|
12
20
|
# !| script | selenium test | http://www.example.com/ |
|
13
|
-
#
|
14
|
-
# NOTE: Function names beginning with these words are forbidden:
|
15
|
-
#
|
16
|
-
# - check
|
17
|
-
# - ensure
|
18
|
-
# - reject
|
19
|
-
# - note
|
20
|
-
# - show
|
21
|
-
# - start
|
22
|
-
#
|
23
|
-
# This is because the above words are keywords in Slim script tables; if
|
24
|
-
# the first cell of a script table begins with any of these words, Slim tries
|
25
|
-
# to apply special handling to them, which usually doesn't do what you want.
|
21
|
+
# | script | selenium test | !-http://www.example.com/-! |
|
26
22
|
#
|
27
23
|
class SeleniumTest
|
28
24
|
|
25
|
+
include Support
|
26
|
+
|
29
27
|
# Initialize a test, connecting to the given Selenium server.
|
30
28
|
#
|
31
29
|
# @param [String] url
|
@@ -59,14 +57,13 @@ module Rsel
|
|
59
57
|
# @example
|
60
58
|
# | Open browser |
|
61
59
|
#
|
62
|
-
# @raise [
|
60
|
+
# @raise [StopTestSeleniumNotRunning] if Selenium connection cannot be made
|
63
61
|
#
|
64
62
|
def open_browser
|
65
63
|
begin
|
66
64
|
@browser.start_new_browser_session
|
67
65
|
rescue
|
68
|
-
|
69
|
-
raise SeleniumNotRunning, "Could not start Selenium."
|
66
|
+
raise StopTestSeleniumNotRunning, "Could not start Selenium."
|
70
67
|
else
|
71
68
|
visit @url
|
72
69
|
end
|
@@ -204,7 +201,7 @@ module Rsel
|
|
204
201
|
# @since 0.0.2
|
205
202
|
#
|
206
203
|
def link_exists(locator, scope={})
|
207
|
-
return @browser.element?(
|
204
|
+
return @browser.element?(loc(locator, 'link', scope))
|
208
205
|
end
|
209
206
|
|
210
207
|
|
@@ -222,7 +219,7 @@ module Rsel
|
|
222
219
|
# @since 0.0.2
|
223
220
|
#
|
224
221
|
def button_exists(locator, scope={})
|
225
|
-
return @browser.element?(
|
222
|
+
return @browser.element?(loc(locator, 'button', scope))
|
226
223
|
end
|
227
224
|
|
228
225
|
|
@@ -258,7 +255,7 @@ module Rsel
|
|
258
255
|
#
|
259
256
|
def type_into_field(text, locator, scope={})
|
260
257
|
return_error_status do
|
261
|
-
@browser.type(
|
258
|
+
@browser.type(loc(locator, 'field', scope), text)
|
262
259
|
end
|
263
260
|
end
|
264
261
|
|
@@ -269,12 +266,14 @@ module Rsel
|
|
269
266
|
# Label, name, or id of the field you want to type into
|
270
267
|
# @param [String] text
|
271
268
|
# What to type into the field
|
269
|
+
# @param [Hash] scope
|
270
|
+
# Scoping keywords as understood by {#xpath}
|
272
271
|
#
|
273
272
|
# @example
|
274
273
|
# | Fill in | First name | with | Eric |
|
275
274
|
#
|
276
|
-
def fill_in_with(locator, text)
|
277
|
-
type_into_field(text, locator)
|
275
|
+
def fill_in_with(locator, text, scope={})
|
276
|
+
type_into_field(text, locator, scope)
|
278
277
|
end
|
279
278
|
|
280
279
|
|
@@ -290,8 +289,8 @@ module Rsel
|
|
290
289
|
# @example
|
291
290
|
# | Field | First name | contains | Eric |
|
292
291
|
#
|
293
|
-
def field_contains(locator, text)
|
294
|
-
@browser.field(
|
292
|
+
def field_contains(locator, text, scope={})
|
293
|
+
@browser.field(loc(locator, 'field', scope)).include?(text)
|
295
294
|
end
|
296
295
|
|
297
296
|
|
@@ -308,7 +307,7 @@ module Rsel
|
|
308
307
|
# | Field | First name | equals; | Eric | !{within:contact} |
|
309
308
|
#
|
310
309
|
def field_equals(locator, text, scope={})
|
311
|
-
@browser.field(
|
310
|
+
@browser.field(loc(locator, 'field', scope)) == text
|
312
311
|
end
|
313
312
|
|
314
313
|
|
@@ -324,7 +323,7 @@ module Rsel
|
|
324
323
|
#
|
325
324
|
def click(locator, scope={})
|
326
325
|
return_error_status do
|
327
|
-
@browser.click(
|
326
|
+
@browser.click(loc(locator, 'link_or_button', scope))
|
328
327
|
end
|
329
328
|
end
|
330
329
|
|
@@ -344,7 +343,7 @@ module Rsel
|
|
344
343
|
#
|
345
344
|
def click_link(locator, scope={})
|
346
345
|
return_error_status do
|
347
|
-
@browser.click(
|
346
|
+
@browser.click(loc(locator, 'link', scope))
|
348
347
|
end
|
349
348
|
end
|
350
349
|
alias_method :follow, :click_link
|
@@ -365,7 +364,7 @@ module Rsel
|
|
365
364
|
def click_button(locator, scope={})
|
366
365
|
# TODO: Make this fail when the button is disabled
|
367
366
|
return_error_status do
|
368
|
-
@browser.click(
|
367
|
+
@browser.click(loc(locator, 'button', scope))
|
369
368
|
end
|
370
369
|
end
|
371
370
|
alias_method :press, :click_button
|
@@ -386,7 +385,7 @@ module Rsel
|
|
386
385
|
def enable_checkbox(locator, scope={})
|
387
386
|
return true if checkbox_is_enabled(locator, scope)
|
388
387
|
return_error_status do
|
389
|
-
@browser.click(
|
388
|
+
@browser.click(loc(locator, 'checkbox', scope))
|
390
389
|
end
|
391
390
|
end
|
392
391
|
|
@@ -406,7 +405,7 @@ module Rsel
|
|
406
405
|
def disable_checkbox(locator, scope={})
|
407
406
|
return true if checkbox_is_disabled(locator, scope)
|
408
407
|
return_error_status do
|
409
|
-
@browser.click(
|
408
|
+
@browser.click(loc(locator, 'checkbox', scope))
|
410
409
|
end
|
411
410
|
end
|
412
411
|
|
@@ -423,7 +422,7 @@ module Rsel
|
|
423
422
|
# | Checkbox | send me spam | is enabled | !{within:opt_in} |
|
424
423
|
#
|
425
424
|
def checkbox_is_enabled(locator, scope={})
|
426
|
-
xp =
|
425
|
+
xp = loc(locator, 'checkbox', scope)
|
427
426
|
begin
|
428
427
|
enabled = @browser.checked?(xp)
|
429
428
|
rescue
|
@@ -448,7 +447,7 @@ module Rsel
|
|
448
447
|
# @since 0.0.4
|
449
448
|
#
|
450
449
|
def radio_is_enabled(locator, scope={})
|
451
|
-
xp =
|
450
|
+
xp = loc(locator, 'radio_button', scope)
|
452
451
|
begin
|
453
452
|
enabled = @browser.checked?(xp)
|
454
453
|
rescue
|
@@ -471,7 +470,7 @@ module Rsel
|
|
471
470
|
# | Checkbox | send me spam | is disabled | !{within:opt_in} |
|
472
471
|
#
|
473
472
|
def checkbox_is_disabled(locator, scope={})
|
474
|
-
xp =
|
473
|
+
xp = loc(locator, 'checkbox', scope)
|
475
474
|
begin
|
476
475
|
enabled = @browser.checked?(xp)
|
477
476
|
rescue
|
@@ -496,7 +495,7 @@ module Rsel
|
|
496
495
|
# @since 0.0.4
|
497
496
|
#
|
498
497
|
def radio_is_disabled(locator, scope={})
|
499
|
-
xp =
|
498
|
+
xp = loc(locator, 'radio_button', scope)
|
500
499
|
begin
|
501
500
|
enabled = @browser.checked?(xp)
|
502
501
|
rescue
|
@@ -520,7 +519,7 @@ module Rsel
|
|
520
519
|
#
|
521
520
|
def select_radio(locator, scope={})
|
522
521
|
return_error_status do
|
523
|
-
@browser.click(
|
522
|
+
@browser.click(loc(locator, 'radio_button', scope))
|
524
523
|
end
|
525
524
|
end
|
526
525
|
|
@@ -538,7 +537,7 @@ module Rsel
|
|
538
537
|
#
|
539
538
|
def select_from_dropdown(option, locator, scope={})
|
540
539
|
return_error_status do
|
541
|
-
@browser.select(
|
540
|
+
@browser.select(loc(locator, 'select', scope), option)
|
542
541
|
end
|
543
542
|
end
|
544
543
|
|
@@ -577,9 +576,8 @@ module Rsel
|
|
577
576
|
# @since 0.0.2
|
578
577
|
#
|
579
578
|
def dropdown_equals(locator, option, scope={})
|
580
|
-
# TODO: Apply scope
|
581
579
|
begin
|
582
|
-
selected = @browser.get_selected_label(
|
580
|
+
selected = @browser.get_selected_label(loc(locator, 'select', scope))
|
583
581
|
rescue
|
584
582
|
return false
|
585
583
|
else
|
@@ -618,99 +616,6 @@ module Rsel
|
|
618
616
|
end
|
619
617
|
end
|
620
618
|
|
621
|
-
|
622
|
-
# Execute the given block, and return false if it raises an exception.
|
623
|
-
# Otherwise, return true.
|
624
|
-
#
|
625
|
-
# @example
|
626
|
-
# return_error_status do
|
627
|
-
# # some code that might raise an exception
|
628
|
-
# end
|
629
|
-
#
|
630
|
-
def return_error_status
|
631
|
-
begin
|
632
|
-
yield
|
633
|
-
rescue => e
|
634
|
-
#puts e.message
|
635
|
-
#puts e.backtrace
|
636
|
-
return false
|
637
|
-
else
|
638
|
-
return true
|
639
|
-
end
|
640
|
-
end
|
641
|
-
|
642
|
-
|
643
|
-
# Return a Selenium-style xpath generated by calling `XPath::HTML.<kind>`
|
644
|
-
# with the given `locator`.
|
645
|
-
#
|
646
|
-
# @param [String] kind
|
647
|
-
# What kind of locator you're using (link, button, checkbox, field etc.).
|
648
|
-
# This must correspond to a method name in `XPath::HTML`.
|
649
|
-
# @param [String] locator
|
650
|
-
# Name, id, value, label or whatever other locators are accepted by
|
651
|
-
# `XPath::HTML.<kind>`
|
652
|
-
# @param [Hash] scope
|
653
|
-
# Keywords to restrict the scope of matching elements
|
654
|
-
# @option scope [String] :within
|
655
|
-
# Restrict scope to elements having this id, matching `locator` only if
|
656
|
-
# it's contained within an element with this id.
|
657
|
-
# @option scope [String] :in_row
|
658
|
-
# Restrict scope to a table row containing this text, matching `locator`
|
659
|
-
# only if that locator is in the same row as the given text.
|
660
|
-
#
|
661
|
-
# @example
|
662
|
-
# xpath('link', 'Log in')
|
663
|
-
# xpath('button', 'Submit')
|
664
|
-
# xpath('field', 'First name')
|
665
|
-
# xpath('table_row', ['First', 'Last'])
|
666
|
-
#
|
667
|
-
def xpath(kind, locator, scope={})
|
668
|
-
loc_xp = XPath::HTML.send(kind, locator)
|
669
|
-
if scope[:within]
|
670
|
-
parent = XPath.descendant[XPath.attr(:id).equals(scope[:within])]
|
671
|
-
result = apply_scope(parent, loc_xp)
|
672
|
-
elsif scope[:in_row]
|
673
|
-
row = XPath.descendant(:tr)[XPath.contains(scope[:in_row])]
|
674
|
-
result = apply_scope(row, loc_xp)
|
675
|
-
else
|
676
|
-
result = loc_xp.to_s
|
677
|
-
end
|
678
|
-
return "xpath=#{result}"
|
679
|
-
end
|
680
|
-
|
681
|
-
|
682
|
-
# Restrict the scope of all XPath expressions in `inner` by prepending
|
683
|
-
# `container` to each of them, and return new union expression where
|
684
|
-
# `inner` matches only if it's a child of `container`.
|
685
|
-
#
|
686
|
-
def apply_scope(container, inner)
|
687
|
-
scoped_expressions = xpath_expressions(inner).collect do |expr|
|
688
|
-
container.child(expr)
|
689
|
-
end
|
690
|
-
return XPath::Union.new(*scoped_expressions).to_s
|
691
|
-
end
|
692
|
-
|
693
|
-
|
694
|
-
# Return an array of individual Expressions in the given XPath::Union, or
|
695
|
-
# just `[union]` if it has no sub-expressions. This is an ugly recursive
|
696
|
-
# hack, designed to allow splitting up unions into their constituents for
|
697
|
-
# the purpose of modifying them individually and re-combining them.
|
698
|
-
#
|
699
|
-
# @param [XPath::Union, XPath::Expression] union
|
700
|
-
# The xpath you want to break down into individual expressions
|
701
|
-
#
|
702
|
-
# @since 0.0.3
|
703
|
-
#
|
704
|
-
def xpath_expressions(union)
|
705
|
-
if union.respond_to?(:expressions)
|
706
|
-
return union.expressions.collect do |expr|
|
707
|
-
xpath_expressions(expr)
|
708
|
-
end.flatten
|
709
|
-
else
|
710
|
-
return [union]
|
711
|
-
end
|
712
|
-
end
|
713
|
-
|
714
619
|
end
|
715
620
|
end
|
716
621
|
|