capybara 2.9.0 → 2.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +7 -0
- data/README.md +2 -2
- data/lib/capybara/node/actions.rb +15 -12
- data/lib/capybara/queries/match_query.rb +1 -3
- data/lib/capybara/queries/selector_query.rb +33 -4
- data/lib/capybara/selector.rb +12 -17
- data/lib/capybara/selector/css.rb +30 -0
- data/lib/capybara/selector/selector.rb +2 -1
- data/lib/capybara/spec/session/check_spec.rb +14 -5
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +6 -0
- data/lib/capybara/spec/session/selectors_spec.rb +1 -1
- data/lib/capybara/spec/views/form.erb +5 -3
- data/lib/capybara/version.rb +1 -1
- data/spec/selector_spec.rb +81 -3
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc4841dedf9ca38322cb47a786b24f8628e62fd2
|
4
|
+
data.tar.gz: be5ea00f82b66a46769eab36218b26be66dda267
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 266ef0ca4cec47b1692544d070b6cf467f366d52d4675dae21b2e2cce3985f9ea8a5b268f70d71e290cabe4f0fbf7134b39283e2ea180cabd7610d7c34ec06f7
|
7
|
+
data.tar.gz: d4ec85892ef15b4f1fee2b51b8b52a51119baaaf2a09b0abb096621197608e545036c0146cbcb64d860736cf014bb375186fec6d4f13d66e04e79959e174470c
|
data/History.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
#Version 2.9.1
|
2
|
+
Release date: 2016-09-23
|
3
|
+
|
4
|
+
### Fixed
|
5
|
+
* allow_label_click option did not work in some cases with Poltergeist - Issue #1762 [Thomas Walpole]
|
6
|
+
* matches_selector? should have access to all of a selectors options except the count options [Thomas Walpole]
|
7
|
+
|
1
8
|
#Version 2.9.0
|
2
9
|
Release date: 2016-09-19
|
3
10
|
|
data/README.md
CHANGED
@@ -781,7 +781,7 @@ module MyModule
|
|
781
781
|
include Capybara::DSL
|
782
782
|
|
783
783
|
def login!
|
784
|
-
within("//form[@id='session']") do
|
784
|
+
within(:xpath, "//form[@id='session']") do
|
785
785
|
fill_in 'Email', :with => 'user@example.com'
|
786
786
|
fill_in 'Password', :with => 'password'
|
787
787
|
end
|
@@ -852,7 +852,7 @@ manually.
|
|
852
852
|
require 'capybara'
|
853
853
|
|
854
854
|
session = Capybara::Session.new(:webkit, my_rack_app)
|
855
|
-
session.within("
|
855
|
+
session.within("form#session") do
|
856
856
|
session.fill_in 'Email', :with => 'user@example.com'
|
857
857
|
session.fill_in 'Password', :with => 'password'
|
858
858
|
end
|
@@ -109,11 +109,12 @@ module Capybara
|
|
109
109
|
allow_label_click = options.delete(:allow_label_click) { Capybara.automatic_label_click }
|
110
110
|
|
111
111
|
begin
|
112
|
-
find(:radio_button, locator, options)
|
113
|
-
|
114
|
-
|
112
|
+
radio = find(:radio_button, locator, options)
|
113
|
+
radio.set(true)
|
114
|
+
rescue => e
|
115
|
+
raise unless allow_label_click && catch_error?(e)
|
115
116
|
begin
|
116
|
-
radio
|
117
|
+
radio ||= find(:radio_button, locator, options.merge({wait: 0, visible: :all}))
|
117
118
|
label = find(:label, for: radio, wait: 0, visible: true)
|
118
119
|
label.click unless radio.checked?
|
119
120
|
rescue
|
@@ -145,11 +146,12 @@ module Capybara
|
|
145
146
|
allow_label_click = options.delete(:allow_label_click) { Capybara.automatic_label_click }
|
146
147
|
|
147
148
|
begin
|
148
|
-
find(:checkbox, locator, options)
|
149
|
-
|
150
|
-
|
149
|
+
cbox = find(:checkbox, locator, options)
|
150
|
+
cbox.set(true)
|
151
|
+
rescue => e
|
152
|
+
raise unless allow_label_click && catch_error?(e)
|
151
153
|
begin
|
152
|
-
cbox
|
154
|
+
cbox ||= find(:checkbox, locator, options.merge({wait: 0, visible: :all}))
|
153
155
|
label = find(:label, for: cbox, wait: 0, visible: true)
|
154
156
|
label.click unless cbox.checked?
|
155
157
|
rescue
|
@@ -181,11 +183,12 @@ module Capybara
|
|
181
183
|
allow_label_click = options.delete(:allow_label_click) { Capybara.automatic_label_click }
|
182
184
|
|
183
185
|
begin
|
184
|
-
find(:checkbox, locator, options)
|
185
|
-
|
186
|
-
|
186
|
+
cbox = find(:checkbox, locator, options)
|
187
|
+
cbox.set(false)
|
188
|
+
rescue => e
|
189
|
+
raise unless allow_label_click && catch_error?(e)
|
187
190
|
begin
|
188
|
-
cbox
|
191
|
+
cbox ||= find(:checkbox, locator, options.merge({wait: 0, visible: :all}))
|
189
192
|
label = find(:label, for: cbox, wait: 0, visible: true)
|
190
193
|
label.click if cbox.checked?
|
191
194
|
rescue
|
@@ -1,8 +1,6 @@
|
|
1
1
|
module Capybara
|
2
2
|
module Queries
|
3
3
|
class MatchQuery < Capybara::Queries::SelectorQuery
|
4
|
-
VALID_KEYS = [:text, :visible, :exact, :wait]
|
5
|
-
|
6
4
|
def visible
|
7
5
|
if options.has_key?(:visible)
|
8
6
|
super
|
@@ -14,7 +12,7 @@ module Capybara
|
|
14
12
|
private
|
15
13
|
|
16
14
|
def valid_keys
|
17
|
-
|
15
|
+
super - COUNT_KEYS
|
18
16
|
end
|
19
17
|
end
|
20
18
|
end
|
@@ -4,7 +4,7 @@ module Capybara
|
|
4
4
|
class SelectorQuery < Queries::BaseQuery
|
5
5
|
attr_accessor :selector, :locator, :options, :expression, :find, :negative
|
6
6
|
|
7
|
-
VALID_KEYS = COUNT_KEYS + [:text, :visible, :exact, :match, :wait, :filter_set]
|
7
|
+
VALID_KEYS = COUNT_KEYS + [:text, :id, :class, :visible, :exact, :match, :wait, :filter_set]
|
8
8
|
VALID_MATCH = [:first, :smart, :prefer_exact, :one]
|
9
9
|
|
10
10
|
def initialize(*args)
|
@@ -39,6 +39,8 @@ module Capybara
|
|
39
39
|
def description
|
40
40
|
@description = String.new("#{label} #{locator.inspect}")
|
41
41
|
@description << " with text #{options[:text].inspect}" if options[:text]
|
42
|
+
@description << " with id #{options[:id]}" if options[:id]
|
43
|
+
@description << " with classes #{Array(options[:class]).join(',')}]" if options[:class]
|
42
44
|
@description << selector.description(options)
|
43
45
|
@description
|
44
46
|
end
|
@@ -92,15 +94,16 @@ module Capybara
|
|
92
94
|
|
93
95
|
def xpath(exact=nil)
|
94
96
|
exact = self.exact? if exact.nil?
|
95
|
-
if @expression.respond_to?(:to_xpath) and exact
|
97
|
+
expr = if @expression.respond_to?(:to_xpath) and exact
|
96
98
|
@expression.to_xpath(:exact)
|
97
99
|
else
|
98
100
|
@expression.to_s
|
99
101
|
end
|
102
|
+
filtered_xpath(expr)
|
100
103
|
end
|
101
104
|
|
102
105
|
def css
|
103
|
-
@expression
|
106
|
+
filtered_css(@expression)
|
104
107
|
end
|
105
108
|
|
106
109
|
# @api private
|
@@ -141,7 +144,7 @@ module Capybara
|
|
141
144
|
end
|
142
145
|
|
143
146
|
def custom_keys
|
144
|
-
query_filters.keys + @selector.expression_filters
|
147
|
+
@custom_keys ||= query_filters.keys + @selector.expression_filters
|
145
148
|
end
|
146
149
|
|
147
150
|
def assert_valid_keys
|
@@ -151,6 +154,32 @@ module Capybara
|
|
151
154
|
end
|
152
155
|
end
|
153
156
|
|
157
|
+
def filtered_xpath(expr)
|
158
|
+
if options.has_key?(:id) || options.has_key?(:class)
|
159
|
+
expr = "(#{expr})"
|
160
|
+
expr = "#{expr}[#{XPath.attr(:id) == options[:id]}]" if options.has_key?(:id) && !custom_keys.include?(:id)
|
161
|
+
if options.has_key?(:class) && !custom_keys.include?(:class)
|
162
|
+
class_xpath = Array(options[:class]).map do |klass|
|
163
|
+
"contains(concat(' ',normalize-space(@class),' '),' #{klass} ')"
|
164
|
+
end.join(" and ")
|
165
|
+
expr = "#{expr}[#{class_xpath}]"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
expr
|
169
|
+
end
|
170
|
+
|
171
|
+
def filtered_css(expr)
|
172
|
+
if options.has_key?(:id) || options.has_key?(:class)
|
173
|
+
css_selectors = expr.split(',').map(&:rstrip)
|
174
|
+
expr = css_selectors.map do |sel|
|
175
|
+
sel += "##{Capybara::Selector::CSS.escape(options[:id])}" if options.has_key?(:id) && !custom_keys.include?(:id)
|
176
|
+
sel += Array(options[:class]).map { |k| ".#{Capybara::Selector::CSS.escape(k)}"}.join if options.has_key?(:class) && !custom_keys.include?(:class)
|
177
|
+
sel
|
178
|
+
end.join(", ")
|
179
|
+
end
|
180
|
+
expr
|
181
|
+
end
|
182
|
+
|
154
183
|
def warn_exact_usage
|
155
184
|
if options.has_key?(:exact) && !supports_exact?
|
156
185
|
warn "The :exact option only has an effect on queries using the XPath#is method. Using it with the query \"#{expression.to_s}\" has no effect."
|
data/lib/capybara/selector.rb
CHANGED
@@ -65,7 +65,7 @@ end
|
|
65
65
|
# @filter [Boolean] :disabled Match disabled field?
|
66
66
|
# @filter [Boolean] :multiple Match fields that accept multiple values
|
67
67
|
Capybara.add_selector(:field) do
|
68
|
-
xpath(:
|
68
|
+
xpath(:name, :placeholder, :type) do |locator, options|
|
69
69
|
xpath = XPath.descendant(:input, :textarea, :select)[~XPath.attr(:type).one_of('submit', 'image', 'hidden')]
|
70
70
|
if options[:type]
|
71
71
|
type=options[:type].to_s
|
@@ -105,12 +105,10 @@ end
|
|
105
105
|
# @filter [String, Array<String>] :class Matches the class(es) provided
|
106
106
|
#
|
107
107
|
Capybara.add_selector(:fieldset) do
|
108
|
-
xpath(:
|
108
|
+
xpath(:legend) do |locator, options|
|
109
109
|
xpath = XPath.descendant(:fieldset)
|
110
110
|
xpath = xpath[XPath.attr(:id).equals(locator.to_s) | XPath.child(:legend)[XPath.string.n.is(locator.to_s)]] unless locator.nil?
|
111
|
-
xpath = xpath[XPath.attr(:id).equals(options[:id])] if options[:id]
|
112
111
|
xpath = xpath[XPath.child(:legend)[XPath.string.n.is(options[:legend])]] if options[:legend]
|
113
|
-
xpath = xpath[find_by_attr(:class, options[:class])]
|
114
112
|
xpath
|
115
113
|
end
|
116
114
|
end
|
@@ -128,7 +126,7 @@ end
|
|
128
126
|
# @filter [String, Regexp] :href Matches the normalized href of the link
|
129
127
|
#
|
130
128
|
Capybara.add_selector(:link) do
|
131
|
-
xpath(:
|
129
|
+
xpath(:title, :alt) do |locator, options={}|
|
132
130
|
xpath = XPath.descendant(:a)[XPath.attr(:href)]
|
133
131
|
unless locator.nil?
|
134
132
|
locator = locator.to_s
|
@@ -139,7 +137,7 @@ Capybara.add_selector(:link) do
|
|
139
137
|
matchers |= XPath.attr(:'aria-label').is(locator) if Capybara.enable_aria_label
|
140
138
|
xpath = xpath[matchers]
|
141
139
|
end
|
142
|
-
xpath = [:
|
140
|
+
xpath = [:title].inject(xpath) { |memo, ef| memo[find_by_attr(ef, options[ef])] }
|
143
141
|
xpath = xpath[XPath.descendant(:img)[XPath.attr(:alt).equals(options[:alt])]] if options[:alt]
|
144
142
|
xpath
|
145
143
|
end
|
@@ -167,7 +165,7 @@ end
|
|
167
165
|
# @filter [String] :value Matches the value of an input button
|
168
166
|
#
|
169
167
|
Capybara.add_selector(:button) do
|
170
|
-
xpath(:
|
168
|
+
xpath(:value, :title) do |locator, options={}|
|
171
169
|
input_btn_xpath = XPath.descendant(:input)[XPath.attr(:type).one_of('submit', 'reset', 'image', 'button')]
|
172
170
|
btn_xpath = XPath.descendant(:button)
|
173
171
|
image_btn_xpath = XPath.descendant(:input)[XPath.attr(:type).equals('image')]
|
@@ -233,7 +231,7 @@ end
|
|
233
231
|
#
|
234
232
|
Capybara.add_selector(:fillable_field) do
|
235
233
|
label "field"
|
236
|
-
xpath(:
|
234
|
+
xpath(:name, :placeholder) do |locator, options|
|
237
235
|
xpath = XPath.descendant(:input, :textarea)[~XPath.attr(:type).one_of('submit', 'image', 'radio', 'checkbox', 'hidden', 'file')]
|
238
236
|
locate_field(xpath, locator, options)
|
239
237
|
end
|
@@ -267,7 +265,7 @@ end
|
|
267
265
|
#
|
268
266
|
Capybara.add_selector(:radio_button) do
|
269
267
|
label "radio button"
|
270
|
-
xpath(:
|
268
|
+
xpath(:name) do |locator, options|
|
271
269
|
xpath = XPath.descendant(:input)[XPath.attr(:type).equals('radio')]
|
272
270
|
locate_field(xpath, locator, options)
|
273
271
|
end
|
@@ -298,7 +296,7 @@ end
|
|
298
296
|
# @filter [String] :option Match the value
|
299
297
|
#
|
300
298
|
Capybara.add_selector(:checkbox) do
|
301
|
-
xpath(:
|
299
|
+
xpath(:name) do |locator, options|
|
302
300
|
xpath = XPath.descendant(:input)[XPath.attr(:type).equals('checkbox')]
|
303
301
|
locate_field(xpath, locator, options)
|
304
302
|
end
|
@@ -332,7 +330,7 @@ end
|
|
332
330
|
#
|
333
331
|
Capybara.add_selector(:select) do
|
334
332
|
label "select box"
|
335
|
-
xpath(:
|
333
|
+
xpath(:name, :placeholder) do |locator, options|
|
336
334
|
xpath = XPath.descendant(:select)
|
337
335
|
locate_field(xpath, locator, options)
|
338
336
|
end
|
@@ -408,7 +406,7 @@ end
|
|
408
406
|
#
|
409
407
|
Capybara.add_selector(:file_field) do
|
410
408
|
label "file field"
|
411
|
-
xpath(:
|
409
|
+
xpath(:name) do |locator, options|
|
412
410
|
xpath = XPath.descendant(:input)[XPath.attr(:type).equals('file')]
|
413
411
|
locate_field(xpath, locator, options)
|
414
412
|
end
|
@@ -466,17 +464,15 @@ end
|
|
466
464
|
# @filter [String, Array<String>] :class Matches the class(es) provided
|
467
465
|
#
|
468
466
|
Capybara.add_selector(:table) do
|
469
|
-
xpath(:
|
467
|
+
xpath(:caption) do |locator, options|
|
470
468
|
xpath = XPath.descendant(:table)
|
471
469
|
xpath = xpath[XPath.attr(:id).equals(locator.to_s) | XPath.descendant(:caption).is(locator.to_s)] unless locator.nil?
|
472
470
|
xpath = xpath[XPath.descendant(:caption).equals(options[:caption])] if options[:caption]
|
473
|
-
xpath = [:id, :class].inject(xpath) { |memo, ef| memo[find_by_attr(ef, options[ef])] }
|
474
471
|
xpath
|
475
472
|
end
|
476
473
|
|
477
474
|
describe do |options|
|
478
475
|
desc = String.new
|
479
|
-
desc << " with id #{options[:id]}" if options[:id]
|
480
476
|
desc << " with caption #{options[:caption]}" if options[:caption]
|
481
477
|
desc
|
482
478
|
end
|
@@ -492,7 +488,7 @@ end
|
|
492
488
|
# @filter [String, Array<String>] :class Matches the class(es) provided
|
493
489
|
#
|
494
490
|
Capybara.add_selector(:frame) do
|
495
|
-
xpath(:
|
491
|
+
xpath(:name) do |locator, options|
|
496
492
|
xpath = XPath.descendant(:iframe) + XPath.descendant(:frame)
|
497
493
|
xpath = xpath[XPath.attr(:id).equals(locator.to_s) | XPath.attr(:name).equals(locator)] unless locator.nil?
|
498
494
|
xpath = expression_filters.inject(xpath) { |memo, ef| memo[find_by_attr(ef, options[ef])] }
|
@@ -501,7 +497,6 @@ Capybara.add_selector(:frame) do
|
|
501
497
|
|
502
498
|
describe do |options|
|
503
499
|
desc = String.new
|
504
|
-
desc << " with id #{options[:id]}" if options[:id]
|
505
500
|
desc << " with name #{options[:name]}" if options[:name]
|
506
501
|
desc
|
507
502
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Capybara
|
2
|
+
class Selector
|
3
|
+
class CSS
|
4
|
+
def self.escape(str)
|
5
|
+
out = String.new("")
|
6
|
+
value = str.dup
|
7
|
+
out << value.slice!(0...1) if value =~ /^[-_]/
|
8
|
+
out << if value[0] =~ NMSTART
|
9
|
+
value.slice!(0...1)
|
10
|
+
else
|
11
|
+
escape_char(value.slice!(0...1))
|
12
|
+
end
|
13
|
+
out << value.gsub(/[^a-zA-Z0-9_-]/) {|c| escape_char c}
|
14
|
+
out
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.escape_char(c)
|
18
|
+
return "\\%06x" % c.ord() unless c =~ %r{[ -/:-~]}
|
19
|
+
"\\#{c}"
|
20
|
+
end
|
21
|
+
|
22
|
+
S = '\u{80}-\u{D7FF}\u{E000}-\u{FFFD}\u{10000}-\u{10FFFF}'
|
23
|
+
H = /[0-9a-fA-F]/
|
24
|
+
UNICODE = /\\#{H}{1,6}[ \t\r\n\f]?/
|
25
|
+
NONASCII = /[#{S}]/
|
26
|
+
ESCAPE = /#{UNICODE}|\\[ -~#{S}]/
|
27
|
+
NMSTART = /[_a-zA-Z]|#{NONASCII}|#{ESCAPE}/
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require 'capybara/selector/filter_set'
|
3
|
+
require 'capybara/selector/css'
|
3
4
|
require 'xpath'
|
4
5
|
|
5
6
|
#Patch XPath to allow a nil condition in where
|
@@ -201,7 +202,7 @@ module Capybara
|
|
201
202
|
locate_xpath += XPath.descendant(:label)[XPath.string.n.is(locator)].descendant(xpath)
|
202
203
|
end
|
203
204
|
|
204
|
-
locate_xpath = [:
|
205
|
+
locate_xpath = [:name, :placeholder].inject(locate_xpath) { |memo, ef| memo[find_by_attr(ef, options[ef])] }
|
205
206
|
locate_xpath
|
206
207
|
end
|
207
208
|
|
@@ -161,11 +161,20 @@ Capybara::SpecHelper.spec "#check" do
|
|
161
161
|
expect{@session.check('form_cars_mclaren')}.to raise_error(Capybara::ElementNotFound, 'Unable to find checkbox "form_cars_mclaren"')
|
162
162
|
end
|
163
163
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
164
|
+
context "with allow_label_click == true" do
|
165
|
+
it "should check via the label if input is hidden" do
|
166
|
+
expect(@session.find(:checkbox, 'form_cars_tesla', unchecked: true, visible: :hidden)).to be
|
167
|
+
@session.check('form_cars_tesla', allow_label_click: true)
|
168
|
+
@session.click_button('awesome')
|
169
|
+
expect(extract_results(@session)['cars']).to include('tesla')
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should check via the label if input is moved off the left edge of the page" do
|
173
|
+
expect(@session.find(:checkbox, 'form_cars_pagani', unchecked: true, visible: :all)).to be
|
174
|
+
@session.check('form_cars_pagani', allow_label_click: true)
|
175
|
+
@session.click_button('awesome')
|
176
|
+
expect(extract_results(@session)['cars']).to include('pagani')
|
177
|
+
end
|
169
178
|
end
|
170
179
|
end
|
171
180
|
end
|
@@ -42,6 +42,12 @@ Capybara::SpecHelper.spec '#match_selector?' do
|
|
42
42
|
expect(@element.matches_xpath?("//span", text: '42')).to be true
|
43
43
|
expect(@element.matches_xpath?("//span", text: 'Nope')).to be false
|
44
44
|
end
|
45
|
+
|
46
|
+
it 'should accept selector filters' do
|
47
|
+
@session.visit('/form')
|
48
|
+
cbox = @session.find(:css, '#form_pets_dog')
|
49
|
+
expect(cbox.matches_selector?(:checkbox, id: 'form_pets_dog', option: 'dog', name: 'form[pets][]', checked: true)).to be true
|
50
|
+
end
|
45
51
|
end
|
46
52
|
|
47
53
|
Capybara::SpecHelper.spec '#not_matches_selector?' do
|
@@ -33,7 +33,7 @@ Capybara::SpecHelper.spec Capybara::Selector do
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
describe "
|
36
|
+
describe "field selectors" do
|
37
37
|
it "can find specifically by id" do
|
38
38
|
expect(@session.find(:field, id: 'customer_email').value).to eq "ben@ben.com"
|
39
39
|
end
|
@@ -5,9 +5,9 @@
|
|
5
5
|
|
6
6
|
<p>
|
7
7
|
<label for="form_title">Title</label>
|
8
|
-
<select name="form[title]" id="form_title">
|
9
|
-
<option>Mrs</option>
|
10
|
-
<option>Mr</option>
|
8
|
+
<select name="form[title]" id="form_title" class="title">
|
9
|
+
<option class="title">Mrs</option>
|
10
|
+
<option class="title">Mr</option>
|
11
11
|
<option>Miss</option>
|
12
12
|
<option disabled="disabled">Other</option>
|
13
13
|
</select>
|
@@ -183,6 +183,8 @@ New line after and before textarea tag
|
|
183
183
|
<label for="form_cars_tesla">Tesla</label>
|
184
184
|
<input type="checkbox" value="ferrari" name="form[cars][]" id="form_cars_ferrari" checked="checked" style="display: none"/>
|
185
185
|
<label for="form_cars_ferrari">Ferrari</label>
|
186
|
+
<input type="checkbox" value="pagani" name="form[cars][]" id="form_cars_pagani" style="position: absolute; left: -9999px"/>
|
187
|
+
<label for="form_cars_pagani">Pagani</label>
|
186
188
|
<input type="checkbox" value="ariel" name="form[cars][]" id="form_cars_ariel" style="display: none"/>
|
187
189
|
<label>
|
188
190
|
McLaren
|
data/lib/capybara/version.rb
CHANGED
data/spec/selector_spec.rb
CHANGED
@@ -18,10 +18,13 @@ RSpec.describe Capybara do
|
|
18
18
|
<p class="b">Some Content</p>
|
19
19
|
<p class="b"></p>
|
20
20
|
</div>
|
21
|
-
<
|
21
|
+
<div id="#special">
|
22
|
+
</div>
|
23
|
+
<input id="2checkbox" class="2checkbox" type="checkbox"/>
|
22
24
|
<input type="radio"/>
|
23
|
-
<
|
24
|
-
<input type="
|
25
|
+
<label for="my_text_input">My Text Input</label>
|
26
|
+
<input type="text" name="form[my_text_input]" placeholder="my text" id="my_text_input"/>
|
27
|
+
<input type="file" id="file" class=".special file"/>
|
25
28
|
<a href="#">link</a>
|
26
29
|
<fieldset></fieldset>
|
27
30
|
<select>
|
@@ -42,6 +45,10 @@ RSpec.describe Capybara do
|
|
42
45
|
css { |css_class| "div.#{css_class}" }
|
43
46
|
filter(:not_empty, boolean: true, default: true, skip_if: :all) { |node, value| value ^ (node.text == '') }
|
44
47
|
end
|
48
|
+
|
49
|
+
Capybara.add_selector :custom_css_selector do
|
50
|
+
css { |selector| selector }
|
51
|
+
end
|
45
52
|
end
|
46
53
|
|
47
54
|
describe "modify_selector" do
|
@@ -89,6 +96,77 @@ RSpec.describe Capybara do
|
|
89
96
|
end
|
90
97
|
end
|
91
98
|
|
99
|
+
context "with :id option" do
|
100
|
+
it "works with compound css selectors" do
|
101
|
+
expect(string.all(:custom_css_selector, "div, h1", id: 'page').size).to eq 1
|
102
|
+
expect(string.all(:custom_css_selector, "h1, div", id: 'page').size).to eq 1
|
103
|
+
end
|
104
|
+
|
105
|
+
it "works with 'special' characters" do
|
106
|
+
skip "We support old Nokogiris but they have their limits" if Gem::Version.new(Nokogiri::VERSION) < Gem::Version.new('1.6.8')
|
107
|
+
expect(string.find(:custom_css_selector, "div", id: "#special")[:id]).to eq '#special'
|
108
|
+
expect(string.find(:custom_css_selector, "input", id: "2checkbox")[:id]).to eq '2checkbox'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context "with :class option" do
|
113
|
+
it "works with compound css selectors" do
|
114
|
+
expect(string.all(:custom_css_selector, "div, h1", class: 'a').size).to eq 2
|
115
|
+
expect(string.all(:custom_css_selector, "h1, div", class: 'a').size).to eq 2
|
116
|
+
end
|
117
|
+
|
118
|
+
it "works with 'special' characters" do
|
119
|
+
skip "We support old Nokogiris but they have their limits" if Gem::Version.new(Nokogiri::VERSION) < Gem::Version.new('1.6.8')
|
120
|
+
expect(string.find(:custom_css_selector, "input", class: ".special")[:id]).to eq 'file'
|
121
|
+
expect(string.find(:custom_css_selector, "input", class: "2checkbox")[:id]).to eq '2checkbox'
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# :css, :xpath, :id, :field, :fieldset, :link, :button, :link_or_button, :fillable_field, :radio_button, :checkbox, :select,
|
126
|
+
# :option, :file_field, :label, :table, :frame
|
127
|
+
|
128
|
+
describe ":css selector" do
|
129
|
+
it "finds by CSS locator" do
|
130
|
+
expect(string.find(:css, "input#my_text_input")[:name]).to eq 'form[my_text_input]'
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe ":xpath selector" do
|
135
|
+
it "finds by XPath locator" do
|
136
|
+
expect(string.find(:xpath, './/input[@id="my_text_input"]')[:name]).to eq 'form[my_text_input]'
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe ":id selector" do
|
141
|
+
it "finds by locator" do
|
142
|
+
expect(string.find(:id, "my_text_input")[:name]).to eq 'form[my_text_input]'
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe ":field selector" do
|
147
|
+
it "finds by locator" do
|
148
|
+
expect(string.find(:field, 'My Text Input')[:id]).to eq 'my_text_input'
|
149
|
+
expect(string.find(:field, 'my_text_input')[:id]).to eq 'my_text_input'
|
150
|
+
expect(string.find(:field, 'form[my_text_input]')[:id]).to eq 'my_text_input'
|
151
|
+
end
|
152
|
+
|
153
|
+
it "finds by id" do
|
154
|
+
expect(string.find(:field, id: 'my_text_input')[:name]).to eq 'form[my_text_input]'
|
155
|
+
end
|
156
|
+
|
157
|
+
it "finds by name" do
|
158
|
+
expect(string.find(:field, name: 'form[my_text_input]')[:id]).to eq 'my_text_input'
|
159
|
+
end
|
160
|
+
|
161
|
+
it "finds by placeholder" do
|
162
|
+
expect(string.find(:field, placeholder: 'my text')[:id]).to eq 'my_text_input'
|
163
|
+
end
|
164
|
+
|
165
|
+
it "finds by type" do
|
166
|
+
expect(string.find(:field, type: 'file')[:id]).to eq 'file'
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
92
170
|
describe ":option selector" do
|
93
171
|
it "finds disabled options" do
|
94
172
|
expect(string.find(:option, disabled: true).value).to eq 'b'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: capybara
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.9.
|
4
|
+
version: 2.9.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Walpole
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain:
|
12
12
|
- gem-public_cert.pem
|
13
|
-
date: 2016-09-
|
13
|
+
date: 2016-09-23 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: nokogiri
|
@@ -284,6 +284,7 @@ files:
|
|
284
284
|
- lib/capybara/rspec/features.rb
|
285
285
|
- lib/capybara/rspec/matchers.rb
|
286
286
|
- lib/capybara/selector.rb
|
287
|
+
- lib/capybara/selector/css.rb
|
287
288
|
- lib/capybara/selector/filter.rb
|
288
289
|
- lib/capybara/selector/filter_set.rb
|
289
290
|
- lib/capybara/selector/selector.rb
|