wrapybara 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +20 -0
- data/README.rdoc +19 -0
- data/lib/wrapybara.rb +2 -0
- data/lib/wrapybara/element.rb +150 -0
- data/lib/wrapybara/elements/attribute.rb +32 -0
- data/lib/wrapybara/elements/button.rb +27 -0
- data/lib/wrapybara/elements/checkbox.rb +49 -0
- data/lib/wrapybara/elements/content.rb +33 -0
- data/lib/wrapybara/elements/file_field.rb +27 -0
- data/lib/wrapybara/elements/fillable_field.rb +46 -0
- data/lib/wrapybara/elements/form.rb +21 -0
- data/lib/wrapybara/elements/image.rb +23 -0
- data/lib/wrapybara/elements/label.rb +21 -0
- data/lib/wrapybara/elements/link.rb +29 -0
- data/lib/wrapybara/elements/option.rb +48 -0
- data/lib/wrapybara/elements/password_field.rb +22 -0
- data/lib/wrapybara/elements/radio_button.rb +49 -0
- data/lib/wrapybara/elements/select.rb +67 -0
- data/lib/wrapybara/elements/table.rb +51 -0
- data/lib/wrapybara/elements/table_body.rb +40 -0
- data/lib/wrapybara/elements/table_cell.rb +87 -0
- data/lib/wrapybara/elements/table_head.rb +40 -0
- data/lib/wrapybara/elements/text_area.rb +22 -0
- data/lib/wrapybara/elements/text_field.rb +22 -0
- data/lib/wrapybara/ext/focus_tracking.js +68 -0
- data/lib/wrapybara/ext/focus_tracking.rb +45 -0
- data/lib/wrapybara/methods.rb +57 -0
- data/lib/wrapybara/steps.rb +139 -0
- metadata +92 -0
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Phillip Koebbe
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
= wrapybara
|
2
|
+
|
3
|
+
Description goes here.
|
4
|
+
|
5
|
+
== Contributing to wrapybara
|
6
|
+
|
7
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
8
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
9
|
+
* Fork the project
|
10
|
+
* Start a feature/bugfix branch
|
11
|
+
* Commit and push until you are happy with your contribution
|
12
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
13
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
14
|
+
|
15
|
+
== Copyright
|
16
|
+
|
17
|
+
Copyright (c) 2011 Phillip Koebbe. See LICENSE.txt for
|
18
|
+
further details.
|
19
|
+
|
data/lib/wrapybara.rb
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
module Wrapybara
|
2
|
+
module Element
|
3
|
+
def get_element(xpath, scope)
|
4
|
+
if scope
|
5
|
+
# if scope starts with '/html', let's assume (for now) that it's already an xpath
|
6
|
+
unless scope =~ /^\/html/
|
7
|
+
# if there are multiple scopes (ie, "div1 div2 para1"), the following makes
|
8
|
+
# xpath look like "id('div1')/*[@id='div2']/*[@id='para1']"
|
9
|
+
|
10
|
+
scope = scope.split(' ')
|
11
|
+
id = scope.shift
|
12
|
+
scope = "id('#{id}')" + scope.inject('') { |output, s| output += "//*[@id='#{s}']" }
|
13
|
+
end
|
14
|
+
|
15
|
+
# xpath might come in like //something, and since we would be looking for an element
|
16
|
+
# in the scope of another element, we need to make sure we aren't looking at the whole
|
17
|
+
# document by adding the dot at the beginning
|
18
|
+
xpath = ".#{xpath}" if xpath[0..1] == '//'
|
19
|
+
Capybara.find(scope).find(xpath) rescue nil
|
20
|
+
else
|
21
|
+
Capybara.find(xpath) rescue nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def element
|
26
|
+
@element
|
27
|
+
end
|
28
|
+
|
29
|
+
def path
|
30
|
+
element.path
|
31
|
+
end
|
32
|
+
|
33
|
+
def style
|
34
|
+
element[:style] || ''
|
35
|
+
end
|
36
|
+
|
37
|
+
def click
|
38
|
+
element.click
|
39
|
+
end
|
40
|
+
|
41
|
+
def exists?
|
42
|
+
!@element.nil?
|
43
|
+
end
|
44
|
+
|
45
|
+
def should_exist(message = nil)
|
46
|
+
message ||= "Expected element #{self.element_identifier} to exist"
|
47
|
+
raise UnmetExpectation, message unless self.exists?
|
48
|
+
end
|
49
|
+
|
50
|
+
def should_not_exist(message = nil)
|
51
|
+
message ||= "Did not expect element #{self.element_identifier} to exist"
|
52
|
+
raise UnmetExpectation, message if self.exists?
|
53
|
+
end
|
54
|
+
|
55
|
+
def should_have_attribute(attribute, value = nil)
|
56
|
+
the_attribute = Attribute.new(self, attribute)
|
57
|
+
the_attribute.should_exist
|
58
|
+
the_attribute.value.should_be value if value
|
59
|
+
end
|
60
|
+
|
61
|
+
def should_not_have_attribute(attribute, value = nil)
|
62
|
+
the_attribute = Attribute.new(self, attribute)
|
63
|
+
if value
|
64
|
+
the_attribute.should_exist
|
65
|
+
the_attribute.value.should_not_be value
|
66
|
+
else
|
67
|
+
the_attribute.should_not_exist
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def enabled?
|
72
|
+
!disabled?
|
73
|
+
end
|
74
|
+
|
75
|
+
def disabled?
|
76
|
+
self.should_exist
|
77
|
+
['true', 'disabled'].include?(@element[:disabled])
|
78
|
+
end
|
79
|
+
|
80
|
+
def should_be_enabled
|
81
|
+
message = "Expected element #{self.element_identifier} to be enabled"
|
82
|
+
raise UnmetExpectation, message unless self.enabled?
|
83
|
+
end
|
84
|
+
|
85
|
+
def should_not_be_enabled
|
86
|
+
message = "Did not expect element #{self.element_identifier} to be enabled"
|
87
|
+
raise UnmetExpectation, message if self.enabled?
|
88
|
+
end
|
89
|
+
|
90
|
+
def should_be_disabled
|
91
|
+
message = "Expected element #{self.element_identifier} to be disabled"
|
92
|
+
raise UnmetExpectation, message unless self.disabled?
|
93
|
+
end
|
94
|
+
|
95
|
+
def should_not_be_disabled
|
96
|
+
message = "Did not expect element #{self.element_identifier} to be disabled"
|
97
|
+
raise UnmetExpectation, message if self.disabled?
|
98
|
+
end
|
99
|
+
|
100
|
+
def visible?
|
101
|
+
self.should_exist
|
102
|
+
|
103
|
+
# determining visibility of something is challenging, to say the least. this approach is to start with the subject element
|
104
|
+
# and check its style attribute for display: none or visibility: hidden. if neither is found, work backward up the
|
105
|
+
# object hierarchy checking each parent.
|
106
|
+
|
107
|
+
return false if self.style.downcase.gsub(' ', '') =~ /(display:none|visibility:hidden)/
|
108
|
+
|
109
|
+
parent = get_element(self.path + '/..', nil)
|
110
|
+
while parent && parent.path != '/html'
|
111
|
+
style = parent[:style] || ''
|
112
|
+
return false if style.downcase.gsub(' ', '') =~ /(display:none|visibility:hidden)/
|
113
|
+
parent = get_element(parent.path + '/..', nil)
|
114
|
+
end
|
115
|
+
|
116
|
+
return true
|
117
|
+
end
|
118
|
+
|
119
|
+
def should_be_visible
|
120
|
+
message = "Expected content #{self.element_identifier} to be visible"
|
121
|
+
raise UnmetExpectation, message unless self.visible?
|
122
|
+
end
|
123
|
+
|
124
|
+
def should_not_be_visible
|
125
|
+
message = "Did not expect content #{self.element_identifier} to be visible"
|
126
|
+
raise UnmetExpectation, message if self.visible?
|
127
|
+
end
|
128
|
+
|
129
|
+
def within(scope)
|
130
|
+
scope ? " within '#{scope}'" : ''
|
131
|
+
end
|
132
|
+
|
133
|
+
def element_identifier
|
134
|
+
"#{@how} '#{@identifier}'#{self.within(@scope)}"
|
135
|
+
end
|
136
|
+
|
137
|
+
def parent_identifier
|
138
|
+
return '' unless @parent
|
139
|
+
"#{@parent.how} '#{@parent.identifier}'#{self.within(@parent.scope)}"
|
140
|
+
end
|
141
|
+
|
142
|
+
def default_scope
|
143
|
+
nil
|
144
|
+
end
|
145
|
+
|
146
|
+
def default_how
|
147
|
+
'labeled'
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Wrapybara
|
2
|
+
class Attribute
|
3
|
+
include Element
|
4
|
+
|
5
|
+
def initialize(parent, attribute)
|
6
|
+
@parent = parent
|
7
|
+
@attribute = attribute
|
8
|
+
end
|
9
|
+
|
10
|
+
def value
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def should_exist
|
15
|
+
raise UnmetExpectation, "Expected element #{self.parent_identifier} to have attribute '#{@attribute}'" if @parent.element[@attribute].nil?
|
16
|
+
end
|
17
|
+
|
18
|
+
def should_not_exist
|
19
|
+
raise UnmetExpectation, "Did not expect element #{self.parent_identifier} to have attribute '#{@attribute}'" unless @parent.element[@attribute].nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
def should_be(value)
|
23
|
+
message = "Expected element #{self.parent_identifier} to have attribute '#{@attribute}' with value '#{value}'"
|
24
|
+
raise UnmetExpectation, message unless @parent.element[@attribute] == value
|
25
|
+
end
|
26
|
+
|
27
|
+
def should_not_be(value)
|
28
|
+
message = "Did not expect element #{self.parent_identifier} to have attribute '#{@attribute}' with value '#{value}'"
|
29
|
+
raise UnmetExpectation, message if @parent.element[@attribute] == value
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Wrapybara
|
2
|
+
class Button
|
3
|
+
include Element
|
4
|
+
|
5
|
+
def initialize(identifier, scope = default_scope, how = default_how)
|
6
|
+
@identifier = identifier
|
7
|
+
@how = how
|
8
|
+
@scope = scope
|
9
|
+
xpath = XPath::HTML.button(identifier)
|
10
|
+
@element = get_element(xpath, scope)
|
11
|
+
end
|
12
|
+
|
13
|
+
def should_exist
|
14
|
+
super "Expected a button #{self.element_identifier} to exist"
|
15
|
+
end
|
16
|
+
|
17
|
+
def should_not_exist
|
18
|
+
super "Did not expect a button #{self.element_identifier}' to exist"
|
19
|
+
end
|
20
|
+
|
21
|
+
def click
|
22
|
+
self.should_exist
|
23
|
+
# Capybara method
|
24
|
+
@element.click
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Wrapybara
|
2
|
+
class Checkbox
|
3
|
+
include Element
|
4
|
+
|
5
|
+
def initialize(identifier, scope = default_scope, how = default_how)
|
6
|
+
@identifier = identifier
|
7
|
+
@how = how
|
8
|
+
@scope = scope
|
9
|
+
xpath = XPath::HTML.checkbox(identifier)
|
10
|
+
@element = get_element(xpath, scope)
|
11
|
+
end
|
12
|
+
|
13
|
+
def should_exist
|
14
|
+
super "Expected a checkbox #{self.element_identifier} to exist"
|
15
|
+
end
|
16
|
+
|
17
|
+
def should_not_exist
|
18
|
+
super "Did not expect a checkbox #{self.element_identifier}' to exist"
|
19
|
+
end
|
20
|
+
|
21
|
+
def set(state)
|
22
|
+
self.should_exist
|
23
|
+
# Capybara method
|
24
|
+
@element.set(state)
|
25
|
+
end
|
26
|
+
|
27
|
+
def check
|
28
|
+
self.set(true)
|
29
|
+
end
|
30
|
+
|
31
|
+
def uncheck
|
32
|
+
self.set(false)
|
33
|
+
end
|
34
|
+
|
35
|
+
def checked?
|
36
|
+
self.should_exist
|
37
|
+
# Capybara method
|
38
|
+
@element.checked?
|
39
|
+
end
|
40
|
+
|
41
|
+
def should_be_checked
|
42
|
+
raise UnmetExpectation, "Expected a checkbox #{self.element_identifier} to be checked" unless self.checked?
|
43
|
+
end
|
44
|
+
|
45
|
+
def should_not_be_checked
|
46
|
+
raise UnmetExpectation, "Did not expect a checkbox #{self.element_identifier} to be checked" if self.checked?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Wrapybara
|
2
|
+
class Content
|
3
|
+
include Element
|
4
|
+
|
5
|
+
def initialize(identifier, scope = default_scope)
|
6
|
+
@identifier = identifier
|
7
|
+
@scope = scope
|
8
|
+
#xpath = XPath::HTML.content(identifier)
|
9
|
+
# the %{} string notation is used so double quotes can offset identifier, allowing identifier to contain single quotes/apostrophes.
|
10
|
+
# also important to note is that this xpath requires text to be contained in something (div, p, span). any text just floating around
|
11
|
+
# on the page will show up with a path of //html, which is not terribly useful later on.
|
12
|
+
xpath = %{//*[contains(text(), "#{identifier}")]}
|
13
|
+
@element = get_element(xpath, scope)
|
14
|
+
end
|
15
|
+
|
16
|
+
def click
|
17
|
+
self.should_be_visible
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
def should_exist
|
22
|
+
super "Expected content #{self.element_identifier} to exist"
|
23
|
+
end
|
24
|
+
|
25
|
+
def should_not_exist
|
26
|
+
super "Did not expect content #{self.element_identifier} to exist"
|
27
|
+
end
|
28
|
+
|
29
|
+
def element_identifier
|
30
|
+
"'#{@identifier}'#{self.within(@scope)}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Wrapybara
|
2
|
+
class FileField
|
3
|
+
include Element
|
4
|
+
|
5
|
+
def initialize(identifier, scope = default_scope, how = default_how)
|
6
|
+
@identifier = identifier
|
7
|
+
@how = how
|
8
|
+
@scope = scope
|
9
|
+
xpath = XPath::HTML.file_field(identifier)
|
10
|
+
@element = get_element(xpath, scope)
|
11
|
+
end
|
12
|
+
|
13
|
+
def attach_file(path)
|
14
|
+
self.should_exist
|
15
|
+
# Capybara method
|
16
|
+
@element.set(path)
|
17
|
+
end
|
18
|
+
|
19
|
+
def should_exist
|
20
|
+
super "Expected a file field #{self.element_identifier} to exist"
|
21
|
+
end
|
22
|
+
|
23
|
+
def should_not_exist
|
24
|
+
super "Did not expect a file field #{self.element_identifier}' to exist"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Wrapybara
|
2
|
+
module FillableField
|
3
|
+
def fill_in(value)
|
4
|
+
self.should_exist
|
5
|
+
# Capybara method
|
6
|
+
@element.set(value)
|
7
|
+
end
|
8
|
+
|
9
|
+
def value
|
10
|
+
self.should_exist
|
11
|
+
(@element.value || '').strip
|
12
|
+
end
|
13
|
+
|
14
|
+
def empty?
|
15
|
+
self.value == ''
|
16
|
+
end
|
17
|
+
|
18
|
+
def should_be_empty
|
19
|
+
raise UnmetExpectation, "Expected text field #{self.element_identifier} to be empty" unless self.empty?
|
20
|
+
end
|
21
|
+
|
22
|
+
def should_not_be_empty
|
23
|
+
raise UnmetExpectation, "Did not expect text field #{self.element_identifier} to be empty" if self.empty?
|
24
|
+
end
|
25
|
+
|
26
|
+
def has_content?(content)
|
27
|
+
self.value =~ /#{content}/
|
28
|
+
end
|
29
|
+
|
30
|
+
def should_have_content(content)
|
31
|
+
if content.blank?
|
32
|
+
self.should_be_empty
|
33
|
+
else
|
34
|
+
raise UnmetExpectation, "Expected text field #{self.element_identifier} to have content '#{content}'" unless self.has_content?(content)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def should_not_have_content(content)
|
39
|
+
if content.blank?
|
40
|
+
self.should_not_be_empty
|
41
|
+
else
|
42
|
+
raise UnmetExpectation, "Did not expect text field #{self.element_identifier} to have content '#{content}'" if self.has_content?(content)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Wrapybara
|
2
|
+
class Form
|
3
|
+
include Element
|
4
|
+
|
5
|
+
def initialize(identifier, scope = default_scope, how = default_how)
|
6
|
+
@identifier = identifier
|
7
|
+
@how = how
|
8
|
+
@scope = scope
|
9
|
+
xpath = "id('#{identifier}') | id(//label[contains(normalize-space(string(.)), '#{identifier}')]/@for)"
|
10
|
+
@element = get_element(xpath, scope)
|
11
|
+
end
|
12
|
+
|
13
|
+
def should_exist
|
14
|
+
super "Expected a form #{self.element_identifier} to exist"
|
15
|
+
end
|
16
|
+
|
17
|
+
def should_not_exist
|
18
|
+
super "Did not expect a form #{self.element_identifier}' to exist"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Wrapybara
|
2
|
+
class Image
|
3
|
+
include Element
|
4
|
+
|
5
|
+
attr_reader :element, :identifier, :how, :scope
|
6
|
+
|
7
|
+
def initialize(identifier, scope = default_scope, how = default_how)
|
8
|
+
@identifier = identifier
|
9
|
+
@how = how
|
10
|
+
@scope = scope
|
11
|
+
xpath = "//img[@src='#{identifier}' or @id='#{identifier}' or @title='#{identifier}' or @alt='#{identifier}']"
|
12
|
+
@element = get_element(xpath, scope)
|
13
|
+
end
|
14
|
+
|
15
|
+
def should_exist
|
16
|
+
super "Expected an image #{self.element_identifier} to exist"
|
17
|
+
end
|
18
|
+
|
19
|
+
def should_not_exist
|
20
|
+
super "Did not expect an image #{self.element_identifier}' to exist"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|