diff options
Diffstat (limited to 'rubocop/cop')
-rw-r--r-- | rubocop/cop/rspec/have_gitlab_http_status.rb | 86 |
1 files changed, 61 insertions, 25 deletions
diff --git a/rubocop/cop/rspec/have_gitlab_http_status.rb b/rubocop/cop/rspec/have_gitlab_http_status.rb index 6b179720060..d61fb9f2368 100644 --- a/rubocop/cop/rspec/have_gitlab_http_status.rb +++ b/rubocop/cop/rspec/have_gitlab_http_status.rb @@ -15,39 +15,67 @@ module RuboCop # expect(response).to have_http_status(200) # expect(response).to have_http_status(:ok) # expect(response).to have_gitlab_http_status(200) + # expect(response.status).to eq(200) + # expect(response.status).not_to eq(200) # # # good # expect(response).to have_gitlab_http_status(:ok) + # expect(response).not_to have_gitlab_http_status(:ok) # class HaveGitlabHttpStatus < RuboCop::Cop::Cop CODE_TO_SYMBOL = Rack::Utils::SYMBOL_TO_STATUS_CODE.invert MSG_MATCHER_NAME = - 'Use `have_gitlab_http_status` instead of `have_http_status`.' + 'Prefer `have_gitlab_http_status` over `have_http_status`.' - MSG_STATUS = + MSG_NUMERIC_STATUS = 'Prefer named HTTP status `%{name}` over ' \ 'its numeric representation `%{code}`.' - MSG_UNKNOWN = 'HTTP status `%{code}` is unknown. ' \ + MSG_RESPONSE_STATUS = + 'Prefer `have_gitlab_http_status` matcher over ' \ + '`response.status`.' + + MSG_UNKNOWN_STATUS = 'HTTP status `%{code}` is unknown. ' \ 'Please provide a valid one or disable this cop.' MSG_DOCS_LINK = 'https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#have_gitlab_http_status' REPLACEMENT = 'have_gitlab_http_status(%{arg})' + REPLACEMENT_RESPONSE_STATUS = + 'expect(response).%{expectation} have_gitlab_http_status(%{arg})' + def_node_matcher :have_http_status?, <<~PATTERN - ( - send nil? - { - :have_http_status - :have_gitlab_http_status - } + (send nil? + { :have_http_status :have_gitlab_http_status } _ ) PATTERN + def_node_matcher :response_status_eq?, <<~PATTERN + (send + (send nil? :expect + (send + (send nil? :response) :status)) ${ :to :not_to } + (send nil? :eq + (int $_))) + PATTERN + def on_send(node) + offense_for_matcher(node) || offense_for_response_status(node) + end + + def autocorrect(node) + lambda do |corrector| + replacement = replace_matcher(node) || replace_response_status(node) + corrector.replace(node.source_range, replacement) + end + end + + private + + def offense_for_matcher(node) return unless have_http_status?(node) offenses = [ @@ -57,16 +85,31 @@ module RuboCop return if offenses.empty? - add_offense(node, message: message_for(offenses)) + add_offense(node, message: message_for(*offenses)) end - def autocorrect(node) - lambda do |corrector| - corrector.replace(node.source_range, replacement(node)) - end + def offense_for_response_status(node) + return unless response_status_eq?(node) + + add_offense(node, message: message_for(MSG_RESPONSE_STATUS)) end - private + def replace_matcher(node) + return unless have_http_status?(node) + + code = extract_numeric_code(node) + arg = code_to_symbol(code) || argument(node).source + + format(REPLACEMENT, arg: arg) + end + + def replace_response_status(node) + expectation, code = response_status_eq?(node) + return unless code + + arg = code_to_symbol(code) + format(REPLACEMENT_RESPONSE_STATUS, expectation: expectation, arg: arg) + end def offense_for_name(node) return if method_name(node) == :have_gitlab_http_status @@ -79,22 +122,15 @@ module RuboCop return unless code symbol = code_to_symbol(code) - return format(MSG_UNKNOWN, code: code) unless symbol + return format(MSG_UNKNOWN_STATUS, code: code) unless symbol - format(MSG_STATUS, name: symbol, code: code) + format(MSG_NUMERIC_STATUS, name: symbol, code: code) end - def message_for(offenses) + def message_for(*offenses) (offenses + [MSG_DOCS_LINK]).join(' ') end - def replacement(node) - code = extract_numeric_code(node) - arg = code_to_symbol(code) || argument(node).source - - format(REPLACEMENT, arg: arg) - end - def code_to_symbol(code) CODE_TO_SYMBOL[code]&.inspect end |