xpath 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/xpath.rb +4 -0
- data/lib/xpath/expression.rb +6 -0
- data/lib/xpath/html.rb +7 -10
- data/lib/xpath/version.rb +1 -1
- data/spec/fixtures/form.html +19 -253
- data/spec/html_spec.rb +126 -158
- data/spec/xpath_spec.rb +8 -0
- metadata +3 -9
data/lib/xpath.rb
CHANGED
@@ -51,6 +51,10 @@ module XPath
|
|
51
51
|
Expression::StringFunction.new(current)
|
52
52
|
end
|
53
53
|
|
54
|
+
def tag(name)
|
55
|
+
Expression::Tag.new(name)
|
56
|
+
end
|
57
|
+
|
54
58
|
def css(selector)
|
55
59
|
paths = Nokogiri::CSS.xpath_for(selector).map do |selector|
|
56
60
|
Expression::CSS.new(current, Expression::Literal.new(selector))
|
data/lib/xpath/expression.rb
CHANGED
data/lib/xpath/html.rb
CHANGED
@@ -27,15 +27,12 @@ module XPath
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def field(locator, options={})
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
xpath = xpath[~attr(:checked)] if options[:unchecked]
|
37
|
-
xpath
|
38
|
-
end
|
30
|
+
xpath = descendant(:input, :textarea, :select)[~attr(:type).one_of('submit', 'image', 'hidden')]
|
31
|
+
xpath = locate_field(xpath, locator)
|
32
|
+
xpath = xpath[attr(:checked)] if options[:checked]
|
33
|
+
xpath = xpath[~attr(:checked)] if options[:unchecked]
|
34
|
+
xpath = xpath[field_value(options[:with])] if options.has_key?(:with)
|
35
|
+
xpath
|
39
36
|
end
|
40
37
|
|
41
38
|
def fillable_field(locator, options={})
|
@@ -105,7 +102,7 @@ module XPath
|
|
105
102
|
end
|
106
103
|
|
107
104
|
def field_value(value)
|
108
|
-
(text.is(value) &
|
105
|
+
(text.is(value) & tag(:textarea)) | (attr(:value).equals(value) & ~tag(:textarea))
|
109
106
|
end
|
110
107
|
|
111
108
|
end
|
data/lib/xpath/version.rb
CHANGED
data/spec/fixtures/form.html
CHANGED
@@ -1,20 +1,20 @@
|
|
1
1
|
<h1>Form</h1>
|
2
2
|
|
3
3
|
<p>
|
4
|
-
<a id="awesome-link" href="#link">An awesome link</a>
|
5
|
-
<a id="some-id" href="#id">With id</a>
|
6
|
-
<a title="My title" href="#title">A cool title</a>
|
7
|
-
<a href="#image"><img src="foo.png" alt="Alt link"/></a>
|
8
|
-
<a title="This title is too long" href="#bar">A link at a time</a>
|
9
|
-
<a title="This title" href="#foo">A link</a>
|
10
|
-
<a href="#bar"><img src="foo.png" alt="An image that is beautiful"/></a>
|
11
|
-
<a href="#foo"><img src="foo.ong" alt="An image"/></a>
|
4
|
+
<a id="awesome-link" data="link-text" href="#link">An awesome link</a>
|
5
|
+
<a id="some-id" data="link-id" href="#id">With id</a>
|
6
|
+
<a title="My title" data="link-title" href="#title">A cool title</a>
|
7
|
+
<a href="#image" data="link-img"><img src="foo.png" alt="Alt link"/></a>
|
8
|
+
<a title="This title is too long" data="link-fuzzy" href="#bar">A link at a time</a>
|
9
|
+
<a title="This title" data="link-exact" href="#foo">A link</a>
|
10
|
+
<a href="#bar" data="link-img-fuzzy"><img src="foo.png" alt="An image that is beautiful"/></a>
|
11
|
+
<a href="#foo" data="link-img-exact"><img src="foo.ong" alt="An image"/></a>
|
12
12
|
<a>Wrong Link</a>
|
13
|
-
<a href="#spacey"> My
|
13
|
+
<a href="#spacey" data="link-whitespace"> My
|
14
14
|
|
15
15
|
whitespaced
|
16
16
|
link</a>
|
17
|
-
<a href="#has-children">
|
17
|
+
<a href="#has-children" data="link-children">
|
18
18
|
An <em>emphatic</em> link with some children
|
19
19
|
</a>
|
20
20
|
</p>
|
@@ -49,254 +49,20 @@
|
|
49
49
|
|
50
50
|
whitespaced
|
51
51
|
button</button>
|
52
|
-
<button
|
52
|
+
<button data="btag-with-children">
|
53
53
|
An <em>emphatic</em> button with some children
|
54
54
|
</button>
|
55
55
|
|
56
56
|
<input type="schmoo" value="schmoo button" data="schmoo"/>
|
57
57
|
</p>
|
58
58
|
|
59
|
+
<p>
|
60
|
+
<fieldset id="some-fieldset-id" data="fieldset-id"></fieldset>
|
61
|
+
<fieldset data="fieldset-legend"><legend>Some Legend</legend></fieldset>
|
62
|
+
<fieldset data="fieldset-fuzzy"><legend>Long legend yo</legend></fieldset>
|
63
|
+
<fieldset data="fieldset-exact"><legend>Long legend</legend></fieldset>
|
64
|
+
</p>
|
59
65
|
|
60
|
-
<
|
61
|
-
|
62
|
-
<p>
|
63
|
-
<label for="form_title">Title</label>
|
64
|
-
<select name="form[title]" id="form_title">
|
65
|
-
<option>Mrs</option>
|
66
|
-
<option>Mr</option>
|
67
|
-
<option>Miss</option>
|
68
|
-
</select>
|
69
|
-
</p>
|
70
|
-
|
71
|
-
|
72
|
-
<p>
|
73
|
-
<label for="form_other_title">Other title</label>
|
74
|
-
<select name="form[other_title]" id="form_other_title">
|
75
|
-
<option>Mrs</option>
|
76
|
-
<option>Mr</option>
|
77
|
-
<option>Miss</option>
|
78
|
-
</select>
|
79
|
-
</p>
|
80
|
-
|
81
|
-
<p>
|
82
|
-
<label for="form_first_name">
|
83
|
-
First Name
|
84
|
-
<input type="text" name="form[first_name]" value="John" id="form_first_name"/>
|
85
|
-
</label>
|
86
|
-
</p>
|
87
|
-
|
88
|
-
<p>
|
89
|
-
<label for="form_last_name">Last Name</label>
|
90
|
-
<input type="text" name="form[last_name]" value="Smith" id="form_last_name"/>
|
91
|
-
</p>
|
92
|
-
|
93
|
-
<p>
|
94
|
-
<label for="form_name_explanation">Explanation of Name</label>
|
95
|
-
<textarea name="form[name_explanation]" id="form_name_explanation"></textarea>
|
96
|
-
</p>
|
97
|
-
|
98
|
-
<p>
|
99
|
-
<label for="form_name">Name</label>
|
100
|
-
<input type="text" name="form[name]" value="John Smith" id="form_name"/>
|
101
|
-
</p>
|
102
|
-
|
103
|
-
<p>
|
104
|
-
<label for="form_schmooo">Schmooo</label>
|
105
|
-
<input type="schmooo" name="form[schmooo]" value="This is Schmooo!" id="form_schmooo"/>
|
106
|
-
</p>
|
107
|
-
|
108
|
-
<p>
|
109
|
-
<label>Street<br/>
|
110
|
-
<input type="text" name="form[street]" value="Sesame street 66"/>
|
111
|
-
</label>
|
112
|
-
</p>
|
113
|
-
|
114
|
-
<p>
|
115
|
-
<label for="form_phone">Phone</label>
|
116
|
-
<input name="form[phone]" value="+1 555 7021" id="form_phone"/>
|
117
|
-
</p>
|
118
|
-
|
119
|
-
<p>
|
120
|
-
<label for="form_password">Password</label>
|
121
|
-
<input type="password" name="form[password]" value="seeekrit" id="form_password"/>
|
122
|
-
</p>
|
123
|
-
|
124
|
-
<p>
|
125
|
-
<label for="form_terms_of_use">Terms of Use</label>
|
126
|
-
<input type="hidden" name="form[terms_of_use]" value="0" id="form_terms_of_use_default">
|
127
|
-
<input type="checkbox" name="form[terms_of_use]" value="1" id="form_terms_of_use">
|
128
|
-
</p>
|
129
|
-
|
130
|
-
<p>
|
131
|
-
<label for="form_image">Image</label>
|
132
|
-
<input type="file" name="form[image]" id="form_image"/>
|
133
|
-
</p>
|
134
|
-
|
135
|
-
<p>
|
136
|
-
<input type="hidden" name="form[token]" value="12345" id="form_token"/>
|
137
|
-
</p>
|
138
|
-
|
139
|
-
<p>
|
140
|
-
<label for="form_locale">Locale</label>
|
141
|
-
<select name="form[locale]" id="form_locale">
|
142
|
-
<option value="sv">Swedish</option>
|
143
|
-
<option selected="selected" value="en">English</option>
|
144
|
-
<option value="fi">Finish</option>
|
145
|
-
<option value="no">Norwegian</option>
|
146
|
-
<option value="jo">John's made-up language</option>
|
147
|
-
<option value="jbo"> Lojban </option>
|
148
|
-
</select>
|
149
|
-
</p>
|
150
|
-
|
151
|
-
<p>
|
152
|
-
<label for="form_region">Region</label>
|
153
|
-
<select name="form[region]" id="form_region">
|
154
|
-
<option>Sweden</option>
|
155
|
-
<option selected="selected">Norway</option>
|
156
|
-
<option>Finland</option>
|
157
|
-
</select>
|
158
|
-
</p>
|
159
|
-
|
160
|
-
<p>
|
161
|
-
<label for="form_city">City</label>
|
162
|
-
<select name="form[city]" id="form_city">
|
163
|
-
<option>London</option>
|
164
|
-
<option>Stockholm</option>
|
165
|
-
<option>Paris</option>
|
166
|
-
</select>
|
167
|
-
</p>
|
168
|
-
|
169
|
-
<p>
|
170
|
-
<label for="form_tendency">Tendency</label>
|
171
|
-
<select name="form[tendency]" id="form_tendency"></select>
|
172
|
-
</p>
|
173
|
-
|
174
|
-
<p>
|
175
|
-
<label for="form_description">Description</label></br>
|
176
|
-
<textarea name="form[description]" id="form_description">Descriptive text goes here</textarea>
|
177
|
-
<p>
|
178
|
-
|
179
|
-
<p>
|
180
|
-
<input type="radio" name="form[gender]" value="male" id="gender_male"/>
|
181
|
-
<label for="gender_male">Male</label>
|
182
|
-
<input type="radio" name="form[gender]" value="female" id="gender_female" checked="checked"/>
|
183
|
-
<label for="gender_female">Female</label>
|
184
|
-
<input type="radio" name="form[gender]" value="both" id="gender_both"/>
|
185
|
-
<label for="gender_both">Both</label>
|
186
|
-
</p>
|
187
|
-
|
188
|
-
<p>
|
189
|
-
<input type="checkbox" value="dog" name="form[pets][]" id="form_pets_dog" checked="checked"/>
|
190
|
-
<label for="form_pets_dog">Dog</label>
|
191
|
-
<input type="checkbox" value="cat" name="form[pets][]" id="form_pets_cat"/>
|
192
|
-
<label for="form_pets_cat">Cat</label>
|
193
|
-
<input type="checkbox" value="hamster" name="form[pets][]" id="form_pets_hamster" checked="checked"/>
|
194
|
-
<label for="form_pets_hamster">Hamster</label>
|
195
|
-
</p>
|
196
|
-
|
197
|
-
<p>
|
198
|
-
<label for="form_languages">Languages</label>
|
199
|
-
<select name="form[languages][]" id="form_languages" multiple="multiple">
|
200
|
-
<option>Ruby</option>
|
201
|
-
<option>SQL</option>
|
202
|
-
<option>HTML</option>
|
203
|
-
<option>Javascript</option>
|
204
|
-
</select>
|
205
|
-
</p>
|
206
|
-
|
207
|
-
<p>
|
208
|
-
<label for="form_underwear">Underwear</label>
|
209
|
-
<select name="form[underwear][]" id="form_underwear" multiple="multiple">
|
210
|
-
<option selected="selected">Boxer Briefs</option>
|
211
|
-
<option>Boxers</option>
|
212
|
-
<option selected="selected">Briefs</option>
|
213
|
-
<option selected="selected">Commando</option>
|
214
|
-
<option selected="selected">Frenchman's Pantalons</option>
|
215
|
-
</select>
|
216
|
-
</p>
|
217
|
-
|
218
|
-
<div style="display:none;">
|
219
|
-
<label for="form_first_name_hidden">
|
220
|
-
Super Secret
|
221
|
-
<input type="text" name="form[super_secret]" value="test123" id="form_super_secret"/>
|
222
|
-
</label>
|
223
|
-
</div>
|
224
|
-
|
225
|
-
<p>
|
226
|
-
<input type="button" name="form[fresh]" id="fresh_btn" value="i am fresh"/>
|
227
|
-
<input type="submit" name="form[awesome]" id="awe123" value="awesome"/>
|
228
|
-
<input type="submit" name="form[crappy]" id="crap321" value="crappy"/>
|
229
|
-
<input type="image" name="form[okay]" id="okay556" value="okay" alt="oh hai thar"/>
|
230
|
-
<button type="submit" id="click_me_123" value="click_me">Click me!</button>
|
231
|
-
<button type="submit" name="form[no_value]">No Value!</button>
|
232
|
-
</p>
|
233
|
-
</form>
|
234
|
-
|
235
|
-
<form id="get-form" action="/form/get?foo=bar" method="get">
|
236
|
-
<p>
|
237
|
-
<label for="form_middle_name">Middle Name</label>
|
238
|
-
<input type="text" name="form[middle_name]" value="Darren" id="form_middle_name"/>
|
239
|
-
</p>
|
240
|
-
|
241
|
-
<p>
|
242
|
-
<input type="submit" name="form[mediocre]" id="mediocre" value="med"/>
|
243
|
-
<p>
|
244
|
-
</form>
|
245
|
-
|
246
|
-
<form action="/upload" method="post" enctype="multipart/form-data">
|
247
|
-
<p>
|
248
|
-
<label for="form_file_name">File Name</label>
|
249
|
-
<input type="file" name="form[file_name]" id="form_file_name"/>
|
250
|
-
</p>
|
251
|
-
|
252
|
-
<p>
|
253
|
-
<label for="form_document">Document</label>
|
254
|
-
<input type="file" name="form[document]" id="form_document"/>
|
255
|
-
</p>
|
256
|
-
|
257
|
-
<p>
|
258
|
-
<input type="submit" value="Upload"/>
|
259
|
-
<p>
|
260
|
-
</form>
|
261
|
-
|
262
|
-
<form action="/redirect" method="post">
|
263
|
-
<p>
|
264
|
-
<input type="submit" value="Go FAR"/>
|
265
|
-
</p>
|
266
|
-
</form>
|
267
|
-
|
268
|
-
<form action="/form" method="post">
|
269
|
-
<p>
|
270
|
-
<label for="html5_email">Html5 Email</label>
|
271
|
-
<input type="email" name="form[html5_email]" value="person@email.com" id="html5_email"/>
|
272
|
-
</p>
|
273
|
-
<p>
|
274
|
-
<label for="html5_url">Html5 Url</label>
|
275
|
-
<input type="url" name="form[html5_url]" value="http://www.example.com" id="html5_url"/>
|
276
|
-
</p>
|
277
|
-
<p>
|
278
|
-
<label for="html5_search">Html5 Search</label>
|
279
|
-
<input type="search" name="form[html5_search]" value="what are you looking for" id="html5_search"/>
|
280
|
-
</p>
|
281
|
-
<p>
|
282
|
-
<label for="html5_tel">Html5 Tel</label>
|
283
|
-
<input type="tel" name="form[html5_tel]" value="911" id="html5_tel"/>
|
284
|
-
</p>
|
285
|
-
<p>
|
286
|
-
<label for="html5_color">Html5 Color</label>
|
287
|
-
<input type="color" name="form[html5_color]" value="#FFF" id="html5_color"/>
|
288
|
-
</p>
|
289
|
-
|
290
|
-
<p>
|
291
|
-
<input type="submit" name="form[html5_submit]" value="html5_submit"/>
|
292
|
-
</p>
|
293
|
-
</form>
|
66
|
+
<p>
|
294
67
|
|
295
|
-
|
296
|
-
<p>
|
297
|
-
<button type="submit" name="form[button]" value="button_first">Just an input that came first</button>
|
298
|
-
<button type="submit" name="form[button]" value="button_second">Just an input</button>
|
299
|
-
<input type="submit" name="form[button]" value="Just a button that came first"/>
|
300
|
-
<input type="submit" name="form[button]" value="Just a button"/>
|
301
|
-
</p>
|
302
|
-
</form>
|
68
|
+
</p>
|
data/spec/html_spec.rb
CHANGED
@@ -6,190 +6,158 @@ describe XPath::HTML do
|
|
6
6
|
let(:template_path) { File.read(File.expand_path("fixtures/#{template}.html", File.dirname(__FILE__))) }
|
7
7
|
let(:doc) { Nokogiri::HTML(template_path) }
|
8
8
|
|
9
|
-
def get(
|
10
|
-
all(
|
9
|
+
def get(*args)
|
10
|
+
all(*args).first
|
11
11
|
end
|
12
12
|
|
13
|
-
def all(
|
14
|
-
|
13
|
+
def all(*args)
|
14
|
+
XPath::HTML.send(subject, *args).to_xpaths.map do |xpath|
|
15
15
|
doc.xpath(xpath)
|
16
|
-
end.flatten
|
16
|
+
end.flatten.uniq.map { |node| node[:data] }
|
17
17
|
end
|
18
18
|
|
19
19
|
describe '#link' do
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
it
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
it
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
it
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
it "finds links by approximate content" do
|
38
|
-
get(XPath::HTML.link('awesome'))[:href].should == '#link'
|
39
|
-
end
|
40
|
-
|
41
|
-
it "prefers exact matches of content" do
|
42
|
-
result = all(XPath::HTML.link('A link'))
|
43
|
-
result[0][:href].should == '#foo'
|
44
|
-
result[1][:href].should == '#bar'
|
45
|
-
end
|
46
|
-
|
47
|
-
it "finds links by title" do
|
48
|
-
get(XPath::HTML.link('My title'))[:href].should == '#title'
|
49
|
-
end
|
50
|
-
|
51
|
-
it "finds links by approximate title" do
|
52
|
-
get(XPath::HTML.link('title'))[:href].should == '#title'
|
53
|
-
end
|
54
|
-
|
55
|
-
it "prefers exact matches of title" do
|
56
|
-
result = all(XPath::HTML.link('This title'))
|
57
|
-
result[0][:href].should == '#foo'
|
58
|
-
result[1][:href].should == '#bar'
|
59
|
-
end
|
60
|
-
|
61
|
-
it "finds links by an image's alt attribute" do
|
62
|
-
get(XPath::HTML.link('Alt link'))[:href].should == '#image'
|
63
|
-
end
|
64
|
-
|
65
|
-
it "finds links by an image's approximate alt attribute" do
|
66
|
-
get(XPath::HTML.link('Alt'))[:href].should == '#image'
|
67
|
-
end
|
68
|
-
|
69
|
-
it "prefers exact matches of image's alt attribute" do
|
70
|
-
result = all(XPath::HTML.link('An image'))
|
71
|
-
result[0][:href].should == '#foo'
|
72
|
-
result[1][:href].should == '#bar'
|
73
|
-
end
|
74
|
-
|
75
|
-
it "does not find links without href attriutes" do
|
76
|
-
get(XPath::HTML.link('Wrong Link')).should be_nil
|
77
|
-
end
|
20
|
+
subject { :link }
|
21
|
+
|
22
|
+
it("finds links by id") { get('some-id').should == 'link-id' }
|
23
|
+
it("finds links by content") { get('An awesome link').should == 'link-text' }
|
24
|
+
it("finds links by content regardless of whitespace") { get('My whitespaced link').should == 'link-whitespace' }
|
25
|
+
it("finds links with child tags by content") { get('An emphatic link').should == 'link-children' }
|
26
|
+
it("finds links by the content of theur child tags") { get('emphatic').should == 'link-children' }
|
27
|
+
it("finds links by approximate content") { get('awesome').should == 'link-text' }
|
28
|
+
it("prefers exact matches of content") { all('A link').should == ['link-exact', 'link-fuzzy'] }
|
29
|
+
it("finds links by title") { get('My title').should == 'link-title' }
|
30
|
+
it("finds links by approximate title") { get('title').should == 'link-title' }
|
31
|
+
it("prefers exact matches of title") { all('This title').should == ['link-exact', 'link-fuzzy'] }
|
32
|
+
it("finds links by image's alt attribute") { get('Alt link').should == 'link-img' }
|
33
|
+
it("finds links by image's approximate alt attribute") { get('Alt').should == 'link-img' }
|
34
|
+
it("prefers exact matches of image's alt attribute") { all('An image').should == ['link-img-exact', 'link-img-fuzzy'] }
|
35
|
+
it("does not find links without href attriutes") { get('Wrong Link').should be_nil }
|
78
36
|
end
|
79
37
|
|
80
38
|
describe '#button' do
|
81
|
-
|
82
|
-
it "finds buttons by id" do
|
83
|
-
get(XPath::HTML.button('submit-with-id'))[:data].should == 'id-submit'
|
84
|
-
end
|
39
|
+
subject { :button }
|
85
40
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
it
|
91
|
-
get(XPath::HTML.button('mit-with-val'))[:data].should == 'value-submit'
|
92
|
-
end
|
93
|
-
|
94
|
-
it "finds prefers buttons with exact value " do
|
95
|
-
results = all(XPath::HTML.button('exact value submit'))
|
96
|
-
results[0][:data].should == 'exact-value-submit'
|
97
|
-
results[1][:data].should == 'not-exact-value-submit'
|
98
|
-
end
|
41
|
+
context "with submit type" do
|
42
|
+
it("finds buttons by id") { get('submit-with-id').should == 'id-submit' }
|
43
|
+
it("finds buttons by value") { get('submit-with-value').should == 'value-submit' }
|
44
|
+
it("finds buttons by approximate value") { get('mit-with-val').should == 'value-submit' }
|
45
|
+
it("prefers buttons with exact value") { all('exact value submit').should == ['exact-value-submit', 'not-exact-value-submit'] }
|
99
46
|
end
|
100
47
|
|
101
48
|
context "with button type" do
|
102
|
-
it
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
it "finds buttons by value" do
|
107
|
-
get(XPath::HTML.button('button-with-value'))[:data].should == 'value-button'
|
108
|
-
end
|
109
|
-
|
110
|
-
it "finds buttons by approximate value " do
|
111
|
-
get(XPath::HTML.button('ton-with-val'))[:data].should == 'value-button'
|
112
|
-
end
|
113
|
-
|
114
|
-
it "finds prefers buttons with exact value " do
|
115
|
-
results = all(XPath::HTML.button('exact value button'))
|
116
|
-
results[0][:data].should == 'exact-value-button'
|
117
|
-
results[1][:data].should == 'not-exact-value-button'
|
118
|
-
end
|
49
|
+
it("finds buttons by id") { get('button-with-id').should == 'id-button' }
|
50
|
+
it("finds buttons by value") { get('button-with-value').should == 'value-button' }
|
51
|
+
it("finds buttons by approximate value") { get('ton-with-val').should == 'value-button' }
|
52
|
+
it("prefers buttons with exact value") { all('exact value button').should == ['exact-value-button', 'not-exact-value-button'] }
|
119
53
|
end
|
120
54
|
|
121
55
|
context "with image type" do
|
122
|
-
it
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
it
|
127
|
-
get(XPath::HTML.button('imgbut-with-value'))[:data].should == 'value-imgbut'
|
128
|
-
end
|
129
|
-
|
130
|
-
it "finds buttons by approximate value " do
|
131
|
-
get(XPath::HTML.button('gbut-with-val'))[:data].should == 'value-imgbut'
|
132
|
-
end
|
133
|
-
|
134
|
-
it "finds buttons by alt attribute" do
|
135
|
-
get(XPath::HTML.button('imgbut-with-alt'))[:data].should == 'alt-imgbut'
|
136
|
-
end
|
137
|
-
|
138
|
-
it "prefers buttons with exact value " do
|
139
|
-
results = all(XPath::HTML.button('exact value imgbut'))
|
140
|
-
results[0][:data].should == 'exact-value-imgbut'
|
141
|
-
results[1][:data].should == 'not-exact-value-imgbut'
|
142
|
-
end
|
56
|
+
it("finds buttons by id") { get('imgbut-with-id').should == 'id-imgbut' }
|
57
|
+
it("finds buttons by value") { get('imgbut-with-value').should == 'value-imgbut' }
|
58
|
+
it("finds buttons by approximate value") { get('gbut-with-val').should == 'value-imgbut' }
|
59
|
+
it("finds buttons by alt attribute") { get('imgbut-with-alt').should == 'alt-imgbut' }
|
60
|
+
it("prefers buttons with exact value") { all('exact value imgbut').should == ['exact-value-imgbut', 'not-exact-value-imgbut'] }
|
143
61
|
end
|
144
62
|
|
145
63
|
context "with button tag" do
|
146
|
-
it
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
it
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
it
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
it "finds prefers buttons with exact value " do
|
159
|
-
results = all(XPath::HTML.button('exact value btag'))
|
160
|
-
results[0][:data].should == 'exact-value-btag'
|
161
|
-
results[1][:data].should == 'not-exact-value-btag'
|
162
|
-
end
|
163
|
-
|
164
|
-
it "finds buttons by text" do
|
165
|
-
get(XPath::HTML.button('btag-with-text'))[:data].should == 'text-btag'
|
166
|
-
end
|
64
|
+
it("finds buttons by id") { get('btag-with-id').should == 'id-btag' }
|
65
|
+
it("finds buttons by value") { get('btag-with-value').should == 'value-btag' }
|
66
|
+
it("finds buttons by approximate value") { get('tag-with-val').should == 'value-btag' }
|
67
|
+
it("finds prefers buttons with exact value") { all('exact value btag').should == ['exact-value-btag', 'not-exact-value-btag'] }
|
68
|
+
it("finds buttons by text") { get('btag-with-text').should == 'text-btag' }
|
69
|
+
it("finds buttons by text ignoring whitespace") { get('My whitespaced button').should == 'btag-with-whitespace' }
|
70
|
+
it("finds buttons by approximate text ") { get('tag-with-tex').should == 'text-btag' }
|
71
|
+
it("finds buttons with child tags by text") { get('An emphatic button').should == 'btag-with-children' }
|
72
|
+
it("finds buttons by text of their children") { get('emphatic').should == 'btag-with-children' }
|
73
|
+
it("prefers buttons with exact text") { all('exact text btag').should == ['exact-text-btag', 'not-exact-text-btag'] }
|
74
|
+
end
|
167
75
|
|
168
|
-
|
169
|
-
|
170
|
-
|
76
|
+
context "with unkown type" do
|
77
|
+
it("does not find the button") { get('schmoo button').should be_nil }
|
78
|
+
end
|
79
|
+
end
|
171
80
|
|
172
|
-
|
173
|
-
|
174
|
-
end
|
81
|
+
describe '#fieldset' do
|
82
|
+
subject { :fieldset }
|
175
83
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
84
|
+
it("finds fieldsets by id") { get('some-fieldset-id').should == 'fieldset-id' }
|
85
|
+
it("finds fieldsets by legend") { get('Some Legend').should == 'fieldset-legend' }
|
86
|
+
it("accepts approximate legends") { get('Legend').should == 'fieldset-legend' }
|
87
|
+
it("prefers exact legend") { all('Long legend').should == ['fieldset-exact', 'fieldset-fuzzy'] }
|
88
|
+
end
|
180
89
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
90
|
+
describe '#field' do
|
91
|
+
subject { :field }
|
92
|
+
|
93
|
+
context "by id" do
|
94
|
+
it("finds inputs with text type") {}
|
95
|
+
it("finds inputs with password type") {}
|
96
|
+
it("finds inputs with custom type") {}
|
97
|
+
it("finds textareas") {}
|
98
|
+
it("finds select boxes") {}
|
99
|
+
it("does not find submit buttons") {}
|
100
|
+
it("does not find image buttons") {}
|
101
|
+
it("does not find hidden fields") {}
|
102
|
+
end
|
103
|
+
|
104
|
+
context "by name" do
|
105
|
+
it("finds inputs with text type") {}
|
106
|
+
it("finds inputs with password type") {}
|
107
|
+
it("finds inputs with custom type") {}
|
108
|
+
it("finds textareas") {}
|
109
|
+
it("finds select boxes") {}
|
110
|
+
it("does not find submit buttons") {}
|
111
|
+
it("does not find image buttons") {}
|
112
|
+
it("does not find hidden fields") {}
|
113
|
+
end
|
114
|
+
|
115
|
+
context "by referenced label" do
|
116
|
+
it("finds inputs with text type") {}
|
117
|
+
it("finds inputs with password type") {}
|
118
|
+
it("finds inputs with custom type") {}
|
119
|
+
it("finds textareas") {}
|
120
|
+
it("finds select boxes") {}
|
121
|
+
it("does not find submit buttons") {}
|
122
|
+
it("does not find image buttons") {}
|
123
|
+
it("does not find hidden fields") {}
|
124
|
+
end
|
125
|
+
|
126
|
+
context "by parent label" do
|
127
|
+
it("finds inputs with text type") {}
|
128
|
+
it("finds inputs with password type") {}
|
129
|
+
it("finds inputs with custom type") {}
|
130
|
+
it("finds textareas") {}
|
131
|
+
it("finds select boxes") {}
|
132
|
+
it("does not find submit buttons") {}
|
133
|
+
it("does not find image buttons") {}
|
134
|
+
it("does not find hidden fields") {}
|
135
|
+
end
|
136
|
+
|
137
|
+
context "with :with option" do
|
138
|
+
it("finds inputs that match option") {}
|
139
|
+
it("omits inputs that don't match option") {}
|
140
|
+
it("finds textareas that match option") {}
|
141
|
+
it("omits textareas that don't match option") {}
|
142
|
+
end
|
143
|
+
|
144
|
+
context "with :checked option" do
|
145
|
+
context "when true" do
|
146
|
+
it("finds checked fields") {}
|
147
|
+
it("omits unchecked fields") {}
|
148
|
+
end
|
149
|
+
context "when false" do
|
150
|
+
it("finds unchecked fields") {}
|
151
|
+
it("omits checked fields") {}
|
152
|
+
end
|
153
|
+
context "when ommitted" do
|
154
|
+
it("finds unchecked fields") {}
|
155
|
+
it("finds checked fields") {}
|
185
156
|
end
|
186
157
|
end
|
158
|
+
end
|
187
159
|
|
188
|
-
|
189
|
-
it "does not find the button" do
|
190
|
-
get(XPath::HTML.button('schmoo button')).should be_nil
|
191
|
-
end
|
192
|
-
end
|
160
|
+
describe '#fillable_field' do
|
193
161
|
|
194
162
|
end
|
195
163
|
end
|
data/spec/xpath_spec.rb
CHANGED
@@ -96,6 +96,14 @@ describe XPath do
|
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
|
+
describe '#tag' do
|
100
|
+
it "should filter elements by tag" do
|
101
|
+
@results = xpath { |x| x.descendant[x.tag(:p) | x.tag(:li)] }
|
102
|
+
@results[0].text.should == 'Blah'
|
103
|
+
@results[3].text.should == 'A list'
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
99
107
|
describe '#contains' do
|
100
108
|
it "should find nodes that contain the given string" do
|
101
109
|
@results = xpath do |x|
|
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xpath
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: 25
|
5
4
|
prerelease: false
|
6
5
|
segments:
|
7
6
|
- 0
|
8
7
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
8
|
+
- 2
|
9
|
+
version: 0.1.2
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- Jonas Nicklas
|
@@ -15,7 +14,7 @@ autorequire:
|
|
15
14
|
bindir: bin
|
16
15
|
cert_chain: []
|
17
16
|
|
18
|
-
date: 2010-10-
|
17
|
+
date: 2010-10-08 00:00:00 +02:00
|
19
18
|
default_executable:
|
20
19
|
dependencies:
|
21
20
|
- !ruby/object:Gem::Dependency
|
@@ -26,7 +25,6 @@ dependencies:
|
|
26
25
|
requirements:
|
27
26
|
- - ~>
|
28
27
|
- !ruby/object:Gem::Version
|
29
|
-
hash: 9
|
30
28
|
segments:
|
31
29
|
- 1
|
32
30
|
- 3
|
@@ -41,7 +39,6 @@ dependencies:
|
|
41
39
|
requirements:
|
42
40
|
- - ">="
|
43
41
|
- !ruby/object:Gem::Version
|
44
|
-
hash: 13
|
45
42
|
segments:
|
46
43
|
- 1
|
47
44
|
- 2
|
@@ -57,7 +54,6 @@ dependencies:
|
|
57
54
|
requirements:
|
58
55
|
- - ">="
|
59
56
|
- !ruby/object:Gem::Version
|
60
|
-
hash: 27
|
61
57
|
segments:
|
62
58
|
- 0
|
63
59
|
- 5
|
@@ -103,7 +99,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
103
99
|
requirements:
|
104
100
|
- - ">="
|
105
101
|
- !ruby/object:Gem::Version
|
106
|
-
hash: 3
|
107
102
|
segments:
|
108
103
|
- 0
|
109
104
|
version: "0"
|
@@ -112,7 +107,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
112
107
|
requirements:
|
113
108
|
- - ">="
|
114
109
|
- !ruby/object:Gem::Version
|
115
|
-
hash: 3
|
116
110
|
segments:
|
117
111
|
- 0
|
118
112
|
version: "0"
|