diff --git a/lib/capybara/selector.rb b/lib/capybara/selector.rb index 3c16f104..b9c51146 100644 --- a/lib/capybara/selector.rb +++ b/lib/capybara/selector.rb @@ -40,6 +40,7 @@ require 'capybara/selector/definition' # * :disabled (Boolean, :all) - Match disabled field? (Default: false) # * :multiple (Boolean) - Match fields that accept multiple values # * :valid (Boolean) - Match fields that are valid/invalid according to HTML5 form validation +# * :validation_message (String, Regexp) - Matches the elements current validationMessage # # * **:fieldset** - Select fieldset elements # * Locator: Matches id, {Capybara.configure test_id}, or contents of wrapped legend @@ -79,6 +80,7 @@ require 'capybara/selector/definition' # * :disabled (Boolean, :all) - Match disabled field? (Default: false) # * :multiple (Boolean) - Match fields that accept multiple values # * :valid (Boolean) - Match fields that are valid/invalid according to HTML5 form validation +# * :validation_message (String, Regexp) - Matches the elements current validationMessage # # * **:radio_button** - Find radio buttons # * Locator: Match id, {Capybara.configure test_id} attribute, name, or associated label text @@ -178,6 +180,12 @@ Capybara::Selector::FilterSet.add(:_field) do node_filter(:valid, :boolean) { |node, value| node.evaluate_script('this.validity.valid') == value } node_filter(:name) { |node, value| !value.is_a?(Regexp) || value.match?(node[:name]) } node_filter(:placeholder) { |node, value| !value.is_a?(Regexp) || value.match?(node[:placeholder]) } + node_filter(:validation_message) do |node, msg| + vm = node[:validationMessage] + (msg.is_a?(Regexp) ? msg.match?(vm) : vm == msg.to_s).tap do |res| + add_error("Expected validation message to be #{msg.inspect} but was #{vm}") unless res + end + end expression_filter(:name) do |xpath, val| builder(xpath).add_attribute_conditions(name: val) @@ -198,7 +206,7 @@ Capybara::Selector::FilterSet.add(:_field) do desc end - describe(:node_filters) do |checked: nil, unchecked: nil, disabled: nil, valid: nil, **| + describe(:node_filters) do |checked: nil, unchecked: nil, disabled: nil, valid: nil, validation_message: nil, **| desc, states = +'', [] states << 'checked' if checked || (unchecked == false) states << 'not checked' if unchecked || (checked == false) @@ -206,6 +214,7 @@ Capybara::Selector::FilterSet.add(:_field) do desc << " that is #{states.join(' and ')}" unless states.empty? desc << ' that is valid' if valid == true desc << ' that is invalid' if valid == false + desc << " with validation message #{validation_message.to_s.inspect}" if validation_message desc end end diff --git a/lib/capybara/selector/definition/fillable_field.rb b/lib/capybara/selector/definition/fillable_field.rb index f04defd3..9a939c33 100644 --- a/lib/capybara/selector/definition/fillable_field.rb +++ b/lib/capybara/selector/definition/fillable_field.rb @@ -18,7 +18,7 @@ Capybara.add_selector(:fillable_field, locator_type: [String, Symbol]) do end end - filter_set(:_field, %i[disabled multiple name placeholder valid]) + filter_set(:_field, %i[disabled multiple name placeholder valid validation_message]) node_filter(:with) do |node, with| val = node.value diff --git a/lib/capybara/spec/session/has_field_spec.rb b/lib/capybara/spec/session/has_field_spec.rb index 8a3e2454..eeabd21b 100644 --- a/lib/capybara/spec/session/has_field_spec.rb +++ b/lib/capybara/spec/session/has_field_spec.rb @@ -60,6 +60,22 @@ Capybara::SpecHelper.spec '#has_field' do end end + context 'with validation message', requires: [:html_validation] do + it 'should accept a regexp' do + @session.fill_in('form_zipcode', with: '1234') + expect(@session).to have_field('form_zipcode', validation_message: /match the requested format/) + expect(@session).not_to have_field('form_zipcode', validation_message: /random/) + end + + it 'should accept a string' do + @session.fill_in('form_zipcode', with: '1234') + expect(@session).to have_field('form_zipcode', validation_message: 'Please match the requested format.') + expect(@session).not_to have_field('form_zipcode', validation_message: 'match the requested format.') + @session.fill_in('form_zipcode', with: '12345') + expect(@session).to have_field('form_zipcode', validation_message: '') + end + end + context 'with type' do it 'should be true if a field with the given type is on the page' do expect(@session).to have_field('First Name', type: 'text') diff --git a/lib/capybara/spec/views/form.erb b/lib/capybara/spec/views/form.erb index 25ac527d..c71a23ce 100644 --- a/lib/capybara/spec/views/form.erb +++ b/lib/capybara/spec/views/form.erb @@ -140,7 +140,7 @@

- +

diff --git a/spec/dsl_spec.rb b/spec/dsl_spec.rb index ac72ea20..17751935 100644 --- a/spec/dsl_spec.rb +++ b/spec/dsl_spec.rb @@ -8,7 +8,7 @@ class TestClass end Capybara::SpecHelper.run_specs TestClass.new, 'DSL', capybara_skip: %i[ - js modals screenshot frames windows send_keys server hover about_scheme psc download css driver scroll spatial + js modals screenshot frames windows send_keys server hover about_scheme psc download css driver scroll spatial html_validation ] do |example| case example.metadata[:full_description] when /has_css\? should support case insensitive :class and :id options/ diff --git a/spec/rack_test_spec.rb b/spec/rack_test_spec.rb index 0395d216..b74b7e3e 100644 --- a/spec/rack_test_spec.rb +++ b/spec/rack_test_spec.rb @@ -26,6 +26,7 @@ skipped_tests = %i[ css scroll spatial + html_validation ] Capybara::SpecHelper.run_specs TestSessions::RackTest, 'RackTest', capybara_skip: skipped_tests do |example| case example.metadata[:full_description]