capybara 2.9.0 → 2.9.1
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.
- 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
|