diff --git a/.rubocop.yml b/.rubocop.yml index 08179db7..f545cb27 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,6 +1,9 @@ AllCops: DisabledByDefault: true - + TargetRubyVersion: 2.2.2 + Exclude: + - 'spec/**/*' + - 'lib/capybara/spec/**/*' #################### Lint ################################ Lint/AmbiguousOperator: @@ -70,8 +73,8 @@ Lint/EmptyInterpolation: Lint/EndAlignment: Description: 'Align ends correctly.' - Enabled: true - AlignWith: variable + Enabled: false + EnforcedStyleAlignWith: variable Lint/EndInMethod: Description: 'END blocks should not be placed inside method definitions.' @@ -82,7 +85,7 @@ Lint/EnsureReturn: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-return-ensure' Enabled: true -Lint/Eval: +Security/Eval: Description: 'The use of eval represents a serious security risk.' Enabled: true @@ -93,15 +96,9 @@ Lint/FormatParameterMismatch: Lint/HandleExceptions: Description: "Don't suppress exception." StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#dont-hide-exceptions' - Enabled: true + Enabled: false -Lint/InvalidCharacterLiteral: - Description: >- - Checks for invalid character literals with a non-escaped - whitespace character. - Enabled: true - -Lint/LiteralInCondition: +Lint/LiteralAsCondition: Description: 'Checks of literals used in conditions.' Enabled: true @@ -114,7 +111,7 @@ Lint/Loop: Use Kernel#loop with break rather than begin/end/until or begin/end/while for post-loop tests. StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#loop-with-break' - Enabled: true + Enabled: false Lint/NestedMethodDefinition: Description: 'Do not use nested method definitions.' @@ -174,6 +171,9 @@ Lint/UnusedMethodArgument: Description: 'Checks for unused method arguments.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#underscore-unused-vars' Enabled: true + Exclude: + - 'lib/capybara/driver/base.rb' + - 'lib/capybara/driver/node.rb' Lint/UnreachableCode: Description: 'Unreachable code.' @@ -222,7 +222,7 @@ Metrics/BlockNesting: Metrics/ClassLength: Description: 'Avoid classes longer than 250 lines of code.' - Enabled: true + Enabled: false Max: 250 Metrics/CyclomaticComplexity: @@ -368,12 +368,12 @@ Rails/Validation: ################## Style ################################# -Style/AccessModifierIndentation: +Layout/AccessModifierIndentation: Description: Check indentation of private/protected visibility modifiers. StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#indent-public-private-protected' Enabled: false -Style/AccessorMethodName: +Naming/AccessorMethodName: Description: Check the naming of accessor methods for get_/set_. Enabled: false @@ -382,20 +382,20 @@ Style/Alias: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#alias-method' Enabled: false -Style/AlignArray: +Layout/AlignArray: Description: >- Align the elements of an array literal if they span more than one line. StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#align-multiline-arrays' Enabled: false -Style/AlignHash: +Layout/AlignHash: Description: >- Align the elements of a hash literal if they span more than one line. Enabled: false -Style/AlignParameters: +Layout/AlignParameters: Description: >- Align the parameters of a method call if they span more than one line. @@ -417,7 +417,7 @@ Style/AsciiComments: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#english-comments' Enabled: false -Style/AsciiIdentifiers: +Naming/AsciiIdentifiers: Description: 'Use only ascii symbols in identifiers.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#english-identifiers' Enabled: false @@ -442,7 +442,7 @@ Style/BlockComments: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-block-comments' Enabled: false -Style/BlockEndNewline: +Layout/BlockEndNewline: Description: 'Put end statement of multiline block on its own line.' Enabled: false @@ -463,7 +463,7 @@ Style/CaseEquality: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-case-equality' Enabled: false -Style/CaseIndentation: +Layout/CaseIndentation: Description: 'Indentation of when in a case/when/[else/]end.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#indent-when-to-case' Enabled: false @@ -473,7 +473,7 @@ Style/CharacterLiteral: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-character-literals' Enabled: false -Style/ClassAndModuleCamelCase: +Naming/ClassAndModuleCamelCase: Description: 'Use CamelCase for classes and modules.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#camelcase-classes' Enabled: false @@ -496,7 +496,7 @@ Style/ClassVars: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-class-vars' Enabled: false -Style/ClosingParenthesisIndentation: +Layout/ClosingParenthesisIndentation: Description: 'Checks the indentation of hanging closing parentheses.' Enabled: false @@ -515,11 +515,11 @@ Style/CommentAnnotation: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#annotate-keywords' Enabled: false -Style/CommentIndentation: +Layout/CommentIndentation: Description: 'Indentation of comments.' Enabled: false -Style/ConstantName: +Naming/ConstantName: Description: 'Constants should use SCREAMING_SNAKE_CASE.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#screaming-snake-case' Enabled: false @@ -538,7 +538,7 @@ Style/Documentation: Description: 'Document classes and non-namespace modules.' Enabled: false -Style/DotPosition: +Layout/DotPosition: Description: 'Checks the position of the dot in multi-line method calls.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#consistent-multi-line-chains' Enabled: false @@ -552,7 +552,7 @@ Style/EachWithObject: Description: 'Prefer `each_with_object` over `inject` or `reduce`.' Enabled: false -Style/ElseAlignment: +Layout/ElseAlignment: Description: 'Align elses and elsifs correctly.' Enabled: false @@ -560,32 +560,32 @@ Style/EmptyElse: Description: 'Avoid empty else-clauses.' Enabled: false -Style/EmptyLineBetweenDefs: +Layout/EmptyLineBetweenDefs: Description: 'Use empty lines between defs.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#empty-lines-between-methods' Enabled: false -Style/EmptyLines: +Layout/EmptyLines: Description: "Don't use several empty lines in a row." Enabled: false -Style/EmptyLinesAroundAccessModifier: +Layout/EmptyLinesAroundAccessModifier: Description: "Keep blank lines around access modifiers." Enabled: false -Style/EmptyLinesAroundBlockBody: +Layout/EmptyLinesAroundBlockBody: Description: "Keeps track of empty lines around block bodies." Enabled: false -Style/EmptyLinesAroundClassBody: +Layout/EmptyLinesAroundClassBody: Description: "Keeps track of empty lines around class bodies." Enabled: false -Style/EmptyLinesAroundModuleBody: +Layout/EmptyLinesAroundModuleBody: Description: "Keeps track of empty lines around module bodies." Enabled: false -Style/EmptyLinesAroundMethodBody: +Layout/EmptyLinesAroundMethodBody: Description: "Keeps track of empty lines around method bodies." Enabled: false @@ -599,7 +599,7 @@ Style/EndBlock: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-END-blocks' Enabled: false -Style/EndOfLine: +Layout/EndOfLine: Description: 'Use Unix-style line endings.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#crlf' Enabled: false @@ -609,21 +609,21 @@ Style/EvenOdd: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#predicate-methods' Enabled: false -Style/ExtraSpacing: +Layout/ExtraSpacing: Description: 'Do not use unnecessary spacing.' Enabled: false -Style/FileName: +Naming/FileName: Description: 'Use snake_case for source file names.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#snake-case-files' Enabled: false -Style/InitialIndentation: +Layout/InitialIndentation: Description: >- Checks the indentation of the first non-blank non-comment line in a file. Enabled: false -Style/FirstParameterIndentation: +Layout/FirstParameterIndentation: Description: 'Checks the indentation of the first parameter in a method call.' Enabled: false @@ -672,22 +672,22 @@ Style/IfWithSemicolon: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-semicolon-ifs' Enabled: false -Style/IndentationConsistency: +Layout/IndentationConsistency: Description: 'Keep indentation straight.' Enabled: false -Style/IndentationWidth: +Layout/IndentationWidth: Description: 'Use 2 spaces for indentation.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#spaces-indentation' Enabled: false -Style/IndentArray: +Layout/IndentArray: Description: >- Checks the indentation of the first element in an array literal. Enabled: false -Style/IndentHash: +Layout/IndentHash: Description: 'Checks the indentation of the first key in a hash literal.' Enabled: false @@ -706,7 +706,7 @@ Style/LambdaCall: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#proc-call' Enabled: false -Style/LeadingCommentSpace: +Layout/LeadingCommentSpace: Description: 'Comments should start with a space.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#hash-space' Enabled: false @@ -717,7 +717,7 @@ Style/LineEndConcatenation: line end. Enabled: false -Style/MethodCallParentheses: +Style/MethodCallWithoutArgsParentheses: Description: 'Do not use parentheses for method calls with no arguments.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-args-no-parens' Enabled: false @@ -729,7 +729,7 @@ Style/MethodDefParentheses: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#method-parens' Enabled: false -Style/MethodName: +Naming/MethodName: Description: 'Use the configured style when naming methods.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#snake-case-symbols-methods-vars' Enabled: false @@ -744,7 +744,7 @@ Style/MultilineBlockChain: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#single-line-blocks' Enabled: false -Style/MultilineBlockLayout: +Layout/MultilineBlockLayout: Description: 'Ensures newlines after multiline block do statements.' Enabled: false @@ -753,7 +753,7 @@ Style/MultilineIfThen: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-then' Enabled: false -Style/MultilineOperationIndentation: +Layout/MultilineOperationIndentation: Description: >- Checks indentation of binary operations that span more than one line. @@ -817,7 +817,7 @@ Style/OneLineConditional: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#ternary-operator' Enabled: false -Style/OpMethod: +Naming/BinaryOperatorParameterName: Description: 'When defining binary operators, name the argument other.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#other-arg' Enabled: false @@ -859,7 +859,7 @@ Style/PerlBackrefs: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-perl-regexp-last-matchers' Enabled: false -Style/PredicateName: +Naming/PredicateName: Description: 'Check the names of predicate methods.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#bool-methods-qmark' Enabled: false @@ -899,7 +899,7 @@ Style/RegexpLiteral: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-r' Enabled: false -Style/RescueEnsureAlignment: +Layout/RescueEnsureAlignment: Description: 'Align rescues and ensures correctly.' Enabled: false @@ -935,75 +935,75 @@ Style/SingleLineMethods: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-single-line-methods' Enabled: false -Style/SpaceBeforeFirstArg: +Layout/SpaceBeforeFirstArg: Description: >- Checks that exactly one space is used between a method name and the first argument for method calls without parentheses. Enabled: true -Style/SpaceAfterColon: +Layout/SpaceAfterColon: Description: 'Use spaces after colons.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#spaces-operators' Enabled: false -Style/SpaceAfterComma: +Layout/SpaceAfterComma: Description: 'Use spaces after commas.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#spaces-operators' Enabled: false -Style/SpaceAroundKeyword: +Layout/SpaceAroundKeyword: Description: 'Use spaces around keywords.' Enabled: false -Style/SpaceAfterMethodName: +Layout/SpaceAfterMethodName: Description: >- Do not put a space between a method name and the opening parenthesis in a method definition. StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#parens-no-spaces' Enabled: false -Style/SpaceAfterNot: +Layout/SpaceAfterNot: Description: Tracks redundant space after the ! operator. StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-space-bang' Enabled: false -Style/SpaceAfterSemicolon: +Layout/SpaceAfterSemicolon: Description: 'Use spaces after semicolons.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#spaces-operators' Enabled: false -Style/SpaceBeforeBlockBraces: +Layout/SpaceBeforeBlockBraces: Description: >- Checks that the left block brace has or doesn't have space before it. Enabled: false -Style/SpaceBeforeComma: +Layout/SpaceBeforeComma: Description: 'No spaces before commas.' Enabled: false -Style/SpaceBeforeComment: +Layout/SpaceBeforeComment: Description: >- Checks for missing space between code and a comment on the same line. Enabled: false -Style/SpaceBeforeSemicolon: +Layout/SpaceBeforeSemicolon: Description: 'No spaces before semicolons.' Enabled: false -Style/SpaceInsideBlockBraces: +Layout/SpaceInsideBlockBraces: Description: >- Checks that block braces have or don't have surrounding space. For blocks taking parameters, checks that the left brace has or doesn't have trailing space. Enabled: false -Style/SpaceAroundBlockParameters: +Layout/SpaceAroundBlockParameters: Description: 'Checks the spacing inside and after block parameters pipes.' Enabled: false -Style/SpaceAroundEqualsInParameterDefault: +Layout/SpaceAroundEqualsInParameterDefault: Description: >- Checks that the equals signs in parameter default assignments have or don't have surrounding space depending on @@ -1011,32 +1011,32 @@ Style/SpaceAroundEqualsInParameterDefault: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#spaces-around-equals' Enabled: false -Style/SpaceAroundOperators: +Layout/SpaceAroundOperators: Description: 'Use a single space around operators.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#spaces-operators' Enabled: false -Style/SpaceInsideBrackets: +Layout/SpaceInsideBrackets: Description: 'No spaces after [ or before ].' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-spaces-braces' Enabled: false -Style/SpaceInsideHashLiteralBraces: +Layout/SpaceInsideHashLiteralBraces: Description: "Use spaces inside hash literal braces - or don't." StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#spaces-operators' Enabled: false -Style/SpaceInsideParens: +Layout/SpaceInsideParens: Description: 'No spaces after ( or before ).' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-spaces-braces' Enabled: false -Style/SpaceInsideRangeLiteral: +Layout/SpaceInsideRangeLiteral: Description: 'No spaces inside range literals.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-space-inside-range-literals' Enabled: false -Style/SpaceInsideStringInterpolation: +Layout/SpaceInsideStringInterpolation: Description: 'Checks for padding/surrounding spaces inside string interpolation.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#string-interpolation' Enabled: false @@ -1070,12 +1070,12 @@ Style/SymbolProc: Description: 'Use symbols as procs instead of blocks when possible.' Enabled: false -Style/Tab: +Layout/Tab: Description: 'No hard tabs.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#spaces-indentation' Enabled: false -Style/TrailingBlankLines: +Layout/TrailingBlankLines: Description: 'Checks trailing blank lines and final newline.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#newline-eof' Enabled: false @@ -1090,7 +1090,7 @@ Style/TrailingCommaInLiteral: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas' Enabled: false -Style/TrailingWhitespace: +Layout/TrailingWhitespace: Description: 'Avoid trailing whitespace.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-whitespace' Enabled: false @@ -1129,7 +1129,7 @@ Style/VariableInterpolation: StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#curlies-interpolate' Enabled: false -Style/VariableName: +Naming/VariableName: Description: 'Use the configured style when naming variables.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#snake-case-symbols-methods-vars' Enabled: false diff --git a/Rakefile b/Rakefile index 37416efd..5ccc4338 100644 --- a/Rakefile +++ b/Rakefile @@ -37,7 +37,7 @@ Cucumber::Rake::Task.new(:cucumber) do |task| task.cucumber_opts = ['--format=progress', 'features'] end -task :travis do |t| +task :travis do if ENV['CAPYBARA_FF'] Rake::Task[:spec_marionette].invoke elsif ENV['CAPYBARA_LEGACY_FF'] diff --git a/lib/capybara/minitest.rb b/lib/capybara/minitest.rb index a74a64ca..5fe0096d 100644 --- a/lib/capybara/minitest.rb +++ b/lib/capybara/minitest.rb @@ -98,6 +98,7 @@ module Capybara alias_method :refute_selector, :assert_no_selector alias_method :refute_matches_selector, :assert_not_matches_selector + # rubocop:disable Lint/UnusedBlockArgument %w(xpath css link button field select table).each do |selector_type| define_method "assert_#{selector_type}" do |*args, &optional_filter_block| subject, *args = determine_subject(args) @@ -140,7 +141,7 @@ module Capybara end alias_method "refute_matches_#{selector_type}", "assert_not_matches_#{selector_type}" end - + # rubocop:enable Lint/UnusedBlockArgument ## # Assertion that there is xpath diff --git a/lib/capybara/node/simple.rb b/lib/capybara/node/simple.rb index 5c1d6a55..7a077b8e 100644 --- a/lib/capybara/node/simple.rb +++ b/lib/capybara/node/simple.rb @@ -28,7 +28,7 @@ module Capybara # # @return [String] The text of the element # - def text(type=nil) + def text(_type=nil) native.text end @@ -139,7 +139,7 @@ module Capybara native.has_attribute?('selected') end - def synchronize(seconds=nil) + def synchronize(_seconds=nil) yield # simple nodes don't need to wait end diff --git a/lib/capybara/queries/selector_query.rb b/lib/capybara/queries/selector_query.rb index f4832583..6ebe3177 100644 --- a/lib/capybara/queries/selector_query.rb +++ b/lib/capybara/queries/selector_query.rb @@ -59,27 +59,8 @@ module Capybara end def matches_filters?(node) - if options[:text] - regexp = if options[:text].is_a?(Regexp) - options[:text] - else - if exact_text == true - /\A#{Regexp.escape(options[:text].to_s)}\z/ - else - Regexp.escape(options[:text].to_s) - end - end - text_visible = visible - text_visible = :all if text_visible == :hidden - return false if not node.text(text_visible).match(regexp) - end - - if exact_text.is_a?(String) - regexp = /\A#{Regexp.escape(options[:exact_text])}\z/ - text_visible = visible - text_visible = :all if text_visible == :hidden - return false if not node.text(text_visible).match(regexp) - end + return false unless matches_text_filter(node, options[:text]) if options[:text] + return false unless matches_exact_text_filter(node, exact_text) if exact_text.is_a?(String) case visible when :visible then return false unless node.visible? @@ -103,7 +84,6 @@ module Capybara end unless @filter_block.nil? res - rescue *(node.respond_to?(:session) ? node.session.driver.invalid_element_errors : []) return false end @@ -247,6 +227,28 @@ module Capybara @resolved_node && !(@resolved_node.is_a?(::Capybara::Node::Document) || (@resolved_node.is_a?(::Capybara::Node::Simple) && @resolved_node.path == '/')) end + + def matches_text_filter(node, text_option) + regexp = if text_option.is_a?(Regexp) + text_option + else + if exact_text == true + /\A#{Regexp.escape(text_option.to_s)}\z/ + else + Regexp.escape(text_option.to_s) + end + end + text_visible = visible + text_visible = :all if text_visible == :hidden + node.text(text_visible).match(regexp) + end + + def matches_exact_text_filter(node, exact_text_option) + regexp = /\A#{Regexp.escape(exact_text_option)}\z/ + text_visible = visible + text_visible = :all if text_visible == :hidden + node.text(text_visible).match(regexp) + end end end end diff --git a/lib/capybara/rack_test/form.rb b/lib/capybara/rack_test/form.rb index 91455dd7..48bd5eaf 100644 --- a/lib/capybara/rack_test/form.rb +++ b/lib/capybara/rack_test/form.rb @@ -30,43 +30,11 @@ class Capybara::RackTest::Form < Capybara::RackTest::Node native.xpath(form_elements_xpath).map do |field| case field.name when 'input' - if %w(radio checkbox).include? field['type'] - if field['checked'] - node=Capybara::RackTest::Node.new(self.driver, field) - merge_param!(params, field['name'].to_s, node.value.to_s) - end - elsif %w(submit image).include? field['type'] - # TO DO identify the click button here (in document order, rather - # than leaving until the end of the params) - elsif field['type'] =='file' - if multipart? - file = \ - if (value = field['value']).to_s.empty? - NilUploadedFile.new - else - mime_info = MiniMime.lookup_by_filename(value) - Rack::Test::UploadedFile.new(value, (mime_info && mime_info.content_type).to_s) - end - merge_param!(params, field['name'].to_s, file) - else - merge_param!(params, field['name'].to_s, File.basename(field['value'].to_s)) - end - else - merge_param!(params, field['name'].to_s, field['value'].to_s) - end + add_input_param(field, params) when 'select' - if field['multiple'] == 'multiple' - options = field.xpath(".//option[@selected]") - options.each do |option| - merge_param!(params, field['name'].to_s, (option['value'] || option.text).to_s) - end - else - option = field.xpath(".//option[@selected]").first - option ||= field.xpath('.//option').first - merge_param!(params, field['name'].to_s, (option['value'] || option.text).to_s) if option - end + add_select_param(field, params) when 'textarea' - merge_param!(params, field['name'].to_s, field['_capybara_raw_value'].to_s.gsub(/\n/, "\r\n")) + add_textarea_param(field, params) end end merge_param!(params, button[:name], button[:value] || "") if button[:name] @@ -111,4 +79,48 @@ private ParamsHash.new end end + + def add_input_param(field, params) + if %w(radio checkbox).include? field['type'] + if field['checked'] + node=Capybara::RackTest::Node.new(self.driver, field) + merge_param!(params, field['name'].to_s, node.value.to_s) + end + elsif %w(submit image).include? field['type'] + # TO DO identify the click button here (in document order, rather + # than leaving until the end of the params) + elsif field['type'] =='file' + if multipart? + file = \ + if (value = field['value']).to_s.empty? + NilUploadedFile.new + else + mime_info = MiniMime.lookup_by_filename(value) + Rack::Test::UploadedFile.new(value, (mime_info && mime_info.content_type).to_s) + end + merge_param!(params, field['name'].to_s, file) + else + merge_param!(params, field['name'].to_s, File.basename(field['value'].to_s)) + end + else + merge_param!(params, field['name'].to_s, field['value'].to_s) + end + end + + def add_select_param(field, params) + if field['multiple'] == 'multiple' + options = field.xpath(".//option[@selected]") + options.each do |option| + merge_param!(params, field['name'].to_s, (option['value'] || option.text).to_s) + end + else + option = field.xpath(".//option[@selected]").first + option ||= field.xpath('.//option').first + merge_param!(params, field['name'].to_s, (option['value'] || option.text).to_s) if option + end + end + + def add_textarea_param(field, params) + merge_param!(params, field['name'].to_s, field['_capybara_raw_value'].to_s.gsub(/\n/, "\r\n")) + end end diff --git a/lib/capybara/result.rb b/lib/capybara/result.rb index 8e51cf8a..d01d79c0 100644 --- a/lib/capybara/result.rb +++ b/lib/capybara/result.rb @@ -62,6 +62,7 @@ module Capybara !any? end + # rubocop:disable Metrics/MethodLength def matches_count? # Only check filters for as many elements as necessary to determine result if @query.options[:count] @@ -102,6 +103,7 @@ module Capybara return true end + # rubocop:enable Metrics/MethodLength def failure_message message = @query.failure_message diff --git a/lib/capybara/selector.rb b/lib/capybara/selector.rb index 379075fe..0bd9a9f4 100644 --- a/lib/capybara/selector.rb +++ b/lib/capybara/selector.rb @@ -9,7 +9,7 @@ Capybara::Selector::FilterSet.add(:_field) do expression_filter(:name) { |xpath, val| xpath[XPath.attr(:name).equals(val)] } expression_filter(:placeholder) { |xpath, val| xpath[XPath.attr(:placeholder).equals(val)] } - describe do |checked: nil, unchecked: nil, disabled: nil, multiple: nil, **options| + describe do |checked: nil, unchecked: nil, disabled: nil, multiple: nil, **_options| desc, states = String.new, [] states << 'checked' if checked || (unchecked == false) states << 'not checked' if unchecked || (checked == false) @@ -109,7 +109,7 @@ end # @filter [String, Array] :class Matches the class(es) provided # Capybara.add_selector(:fieldset) do - xpath(:legend) do |locator, legend: nil, **options| + xpath(:legend) do |locator, legend: nil, **_options| xpath = XPath.descendant(:fieldset) xpath = xpath[XPath.attr(:id).equals(locator.to_s).or XPath.child(:legend)[XPath.string.n.is(locator.to_s)]] unless locator.nil? xpath = xpath[XPath.child(:legend)[XPath.string.n.is(legend)]] if legend @@ -130,7 +130,8 @@ end # @filter [String, Regexp,nil] :href Matches the normalized href of the link, if nil will find elements with no href attribute # Capybara.add_selector(:link) do - xpath(:title, :alt) do |locator, href: true, enable_aria_label: false, alt: nil, title: nil, **options| + # rubocop: disable Metrics/ParameterLists: + xpath(:title, :alt) do |locator, href: true, enable_aria_label: false, alt: nil, title: nil, **_options| xpath = XPath.descendant(:a) xpath = if href.nil? xpath[~XPath.attr(:href)] @@ -229,7 +230,7 @@ Capybara.add_selector(:link_or_button) do filter(:disabled, :boolean, default: false, skip_if: :all) { |node, value| node.tag_name == "a" or not(value ^ node.disabled?) } - describe { |disabled: nil, **options| " that is disabled" if disabled == true } + describe { |disabled: nil, **_options| " that is disabled" if disabled == true } end ## @@ -514,7 +515,7 @@ Capybara.add_selector(:table) do xpath end - describe do |caption: nil, **options| + describe do |caption: nil, **_options| desc = String.new desc << " with caption #{caption}" if caption desc @@ -538,7 +539,7 @@ Capybara.add_selector(:frame) do xpath end - describe do |name: nil, **options| + describe do |name: nil, **_options| desc = String.new desc << " with name #{name}" if name desc diff --git a/lib/capybara/selector/selector.rb b/lib/capybara/selector/selector.rb index bfb4384d..2da96810 100644 --- a/lib/capybara/selector/selector.rb +++ b/lib/capybara/selector/selector.rb @@ -233,7 +233,7 @@ module Capybara custom_filters[name] = filter_class.new(name, block, options) end - def locate_field(xpath, locator, enable_aria_label: false, **options) + def locate_field(xpath, locator, enable_aria_label: false, **_options) locate_xpath = xpath #need to save original xpath for the label wrap if locator locator = locator.to_s diff --git a/lib/capybara/selenium/driver.rb b/lib/capybara/selenium/driver.rb index 26a7efbc..98823158 100644 --- a/lib/capybara/selenium/driver.rb +++ b/lib/capybara/selenium/driver.rb @@ -117,20 +117,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base # can trigger an endless series of unload modals begin @browser.manage.delete_all_cookies - if options[:clear_session_storage] - if @browser.respond_to? :session_storage - @browser.session_storage.clear - else - warn "sessionStorage clear requested but is not available for this driver" - end - end - if options[:clear_local_storage] - if @browser.respond_to? :local_storage - @browser.local_storage.clear - else - warn "localStorage clear requested but is not available for this driver" - end - end + clear_storage rescue Selenium::WebDriver::Error::UnhandledError # delete_all_cookies fails when we've previously gone # to about:blank, so we rescue this error and do nothing @@ -322,6 +309,23 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base options[:browser].to_s end + def clear_storage + if options[:clear_session_storage] + if @browser.respond_to? :session_storage + @browser.session_storage.clear + else + warn "sessionStorage clear requested but is not available for this driver" + end + end + if options[:clear_local_storage] + if @browser.respond_to? :local_storage + @browser.local_storage.clear + else + warn "localStorage clear requested but is not available for this driver" + end + end + end + def modal_error if defined?(Selenium::WebDriver::Error::NoSuchAlertError) Selenium::WebDriver::Error::NoSuchAlertError @@ -330,6 +334,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base end end + # rubocop:disable Metrics/MethodLength def insert_modal_handlers(accept, response_text) prompt_response = if accept if response_text.nil? @@ -383,6 +388,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base JS execute_script script end + # rubocop:enable Metrics/MethodLength def within_given_window(handle) original_handle = self.current_window_handle diff --git a/lib/capybara/selenium/node.rb b/lib/capybara/selenium/node.rb index 7e7a73a1..7e0d053b 100644 --- a/lib/capybara/selenium/node.rb +++ b/lib/capybara/selenium/node.rb @@ -52,12 +52,7 @@ class Capybara::Selenium::Node < Capybara::Driver::Node when 'checkbox' click if value ^ native.attribute('checked').to_s.eql?("true") when 'file' - path_names = value.to_s.empty? ? [] : value - if driver.chrome? - native.send_keys(Array(path_names).join("\n")) - else - native.send_keys(*path_names) - end + set_file(value) else set_text(value, options) end @@ -65,27 +60,7 @@ class Capybara::Selenium::Node < Capybara::Driver::Node set_text(value, options) else if content_editable? - #ensure we are focused on the element - click - - script = <<-JS - var range = document.createRange(); - var sel = window.getSelection(); - arguments[0].focus(); - range.selectNodeContents(arguments[0]); - sel.removeAllRanges(); - sel.addRange(range); - JS - driver.execute_script script, self - - if (driver.chrome?) || (driver.firefox? && !driver.marionette?) - # chromedriver raises a can't focus element for child elements if we use native.send_keys - # we've already focused it so just use action api - driver.browser.action.send_keys(value.to_s).perform - else - # action api is really slow here just use native.send_keys - native.send_keys(value.to_s) - end + set_content_editable(value) end end end @@ -199,7 +174,7 @@ class Capybara::Selenium::Node < Capybara::Driver::Node path.unshift self result = [] - while node = path.shift + while (node = path.shift) parent = path.first if parent @@ -259,4 +234,37 @@ private driver.execute_script(script, self) block.call end + + def set_file(value) + path_names = value.to_s.empty? ? [] : value + if driver.chrome? + native.send_keys(Array(path_names).join("\n")) + else + native.send_keys(*path_names) + end + end + + def set_content_editable(value) + #ensure we are focused on the element + click + + script = <<-JS + var range = document.createRange(); + var sel = window.getSelection(); + arguments[0].focus(); + range.selectNodeContents(arguments[0]); + sel.removeAllRanges(); + sel.addRange(range); + JS + driver.execute_script script, self + + if (driver.chrome?) || (driver.firefox? && !driver.marionette?) + # chromedriver raises a can't focus element for child elements if we use native.send_keys + # we've already focused it so just use action api + driver.browser.action.send_keys(value.to_s).perform + else + # action api is really slow here just use native.send_keys + native.send_keys(value.to_s) + end + end end diff --git a/lib/capybara/session.rb b/lib/capybara/session.rb index afd9231c..20a1c14a 100644 --- a/lib/capybara/session.rb +++ b/lib/capybara/session.rb @@ -259,7 +259,7 @@ module Capybara if visit_uri.relative? uri_base.port ||= @server.port if @server && config.always_include_port - visit_uri_parts = visit_uri.to_hash.delete_if { |k,v| v.nil? } + visit_uri_parts = visit_uri.to_hash.delete_if { |_k,v| v.nil? } # Useful to people deploying to a subdirectory # and/or single page apps where only the url fragment changes @@ -753,7 +753,9 @@ module Capybara # @param [Hash] options a customizable set of options # def save_and_open_screenshot(path = nil, **options) + # rubocop:disable Lint/Debugger path = save_screenshot(path, options) + # rubocop:enable Lint/Debugger open_file(path) end diff --git a/lib/capybara/session/config.rb b/lib/capybara/session/config.rb index e96fd30e..9cf63498 100644 --- a/lib/capybara/session/config.rb +++ b/lib/capybara/session/config.rb @@ -88,7 +88,7 @@ module Capybara class ReadOnlySessionConfig < SimpleDelegator SessionConfig::OPTIONS.each do |m| - define_method "#{m}=" do |val| + define_method "#{m}=" do |_| raise "Per session settings are only supported when Capybara.threadsafe == true" end end diff --git a/lib/capybara/spec/session/attach_file_spec.rb b/lib/capybara/spec/session/attach_file_spec.rb index 233666e4..08a20d64 100644 --- a/lib/capybara/spec/session/attach_file_spec.rb +++ b/lib/capybara/spec/session/attach_file_spec.rb @@ -71,7 +71,7 @@ Capybara::SpecHelper.spec "#attach_file" do expect(@session.body).to include("1 | ")#number of files end - it "should not break when using HTML5 multiple file input uploading multiple files" do + it "should not break when using HTML5 multiple file input uploading multiple files" do pending "Selenium is buggy on this, see http://code.google.com/p/selenium/issues/detail?id=2239" if @session.respond_to?(:mode) && @session.mode.to_s =~ /^selenium_(firefox|marionette)/ @session.attach_file "Multiple Documents", [@test_file_path, @another_test_file_path] @session.click_button('Upload Multiple') diff --git a/lib/capybara/spec/session/click_button_spec.rb b/lib/capybara/spec/session/click_button_spec.rb index 41a825ed..6b5826ac 100644 --- a/lib/capybara/spec/session/click_button_spec.rb +++ b/lib/capybara/spec/session/click_button_spec.rb @@ -300,7 +300,7 @@ Capybara::SpecHelper.spec '#click_button' do end end - context "with id given on a button defined by