From 5b0c2d6f3c33dd6951ea8a3587af6bdd2d6e642e Mon Sep 17 00:00:00 2001 From: Thomas Walpole Date: Wed, 31 Jul 2019 12:32:44 -0700 Subject: [PATCH] Add :valid node filter to :field and :fillable_field selectors --- .rubocop.yml | 1 + History.md | 1 + lib/capybara/selector.rb | 7 ++++++- .../selector/definition/fillable_field.rb | 2 +- lib/capybara/spec/session/has_field_spec.rb | 18 ++++++++++++++++++ lib/capybara/spec/views/form.erb | 7 ++++++- 6 files changed, 33 insertions(+), 3 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index cdae0283..92d5af8a 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -31,6 +31,7 @@ Metrics/BlockLength: - 'capybara.gemspec' ExcludedMethods: - Capybara.add_selector + - Capybara::Selector::FilterSet.add Metrics/AbcSize: Enabled: false diff --git a/History.md b/History.md index 42995cd2..1dd27fc2 100644 --- a/History.md +++ b/History.md @@ -5,6 +5,7 @@ Release date: unreleased * Allow forcing HTML5 or legacy dragging via the `:html5` option to `drag_to` when using Selenium with Chrome or Firefox * Autodetection of drag type interprets not seeing the mousedown event as legacy. +* HTML5 form validation `:valid` node filter added to `:field` and `:fillable_field` selectors # Version 3.27.0 Release date: 2019-07-28 diff --git a/lib/capybara/selector.rb b/lib/capybara/selector.rb index 2b0c0892..ce19d5dd 100644 --- a/lib/capybara/selector.rb +++ b/lib/capybara/selector.rb @@ -34,6 +34,7 @@ require 'capybara/selector/definition' # * :unchecked (Boolean) - Match unchecked fields? # * :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 # # * **:fieldset** - Select fieldset elements # * Locator: Matches id, {Capybara.configure test_id}, or contents of wrapped legend @@ -72,6 +73,7 @@ require 'capybara/selector/definition' # * :type (String) - Matches the type attribute of the field or element type for 'textarea' # * :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 # # * **:radio_button** - Find radio buttons # * Locator: Match id, {Capybara.configure test_id} attribute, name, or associated label text @@ -166,6 +168,7 @@ Capybara::Selector::FilterSet.add(:_field) do node_filter(:checked, :boolean) { |node, value| !(value ^ node.checked?) } node_filter(:unchecked, :boolean) { |node, value| (value ^ node.checked?) } node_filter(:disabled, :boolean, default: false, skip_if: :all) { |node, value| !(value ^ node.disabled?) } + node_filter(:valid, :boolean) { |node, value| node.evaluate_script('this.validity.valid') == value } expression_filter(:name) { |xpath, val| xpath[XPath.attr(:name) == val] } expression_filter(:placeholder) { |xpath, val| xpath[XPath.attr(:placeholder) == val] } @@ -182,12 +185,14 @@ Capybara::Selector::FilterSet.add(:_field) do desc end - describe(:node_filters) do |checked: nil, unchecked: nil, disabled: nil, **| + describe(:node_filters) do |checked: nil, unchecked: nil, disabled: nil, valid: nil, **| desc, states = +'', [] states << 'checked' if checked || (unchecked == false) states << 'not checked' if unchecked || (checked == false) states << 'disabled' if disabled == true desc << " that is #{states.join(' and ')}" unless states.empty? + desc << ' that is valid' if valid == true + desc << ' that is invalid' if valid == false desc end end diff --git a/lib/capybara/selector/definition/fillable_field.rb b/lib/capybara/selector/definition/fillable_field.rb index 98a49ff9..eba9baaa 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]) + filter_set(:_field, %i[disabled multiple name placeholder valid]) 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 0530af77..8a3e2454 100644 --- a/lib/capybara/spec/session/has_field_spec.rb +++ b/lib/capybara/spec/session/has_field_spec.rb @@ -93,6 +93,24 @@ Capybara::SpecHelper.spec '#has_field' do expect(@session).not_to have_field('Html5 Multiple Email', multiple: false) end end + + context 'with valid', requires: [:js] do + it 'should be true if field is valid' do + @session.fill_in 'required', with: 'something' + @session.fill_in 'length', with: 'abcd' + + expect(@session).to have_field('required', valid: true) + expect(@session).to have_field('length', valid: true) + end + + it 'should be false if field is invalid' do + expect(@session).not_to have_field('required', valid: true) + expect(@session).to have_field('required', valid: false) + + @session.fill_in 'length', with: 'abc' + expect(@session).not_to have_field('length', valid: true) + end + end end Capybara::SpecHelper.spec '#has_no_field' do diff --git a/lib/capybara/spec/views/form.erb b/lib/capybara/spec/views/form.erb index 118d72ef..03369d5b 100644 --- a/lib/capybara/spec/views/form.erb +++ b/lib/capybara/spec/views/form.erb @@ -1,7 +1,7 @@

Form

-
+

@@ -460,6 +460,11 @@ New line after and before textarea tag

+ +

+ + +