Skip to content

Commit cea510a

Browse files
committed
Move the department associated with Capybara::RSpecMatchers to Capybara/RSpec/*
1 parent 6c8deaf commit cea510a

16 files changed

+492
-367
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Edge (Unreleased)
44

5+
- **breaking** Move the department associated with `Capybara::RSpecMatchers` to `Capybara/RSpec/*`. ([@ydah])
56
- Fix a false negative for `Capybara/NegationMatcher` when using `to_not`. ([@ydah])
67

78
## 2.20.0 (2024-01-03)

config/default.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Capybara/CurrentPathExpectation:
2626
VersionAdded: '1.18'
2727
VersionChanged: '2.0'
2828
Reference: https://www.rubydoc.info/gems/rubocop-capybara/RuboCop/Cop/Capybara/CurrentPathExpectation
29+
VersionRemoved: '3.0'
2930

3031
Capybara/MatchStyle:
3132
Description: Checks for usage of deprecated style methods.
@@ -43,6 +44,7 @@ Capybara/NegationMatcher:
4344
- have_no
4445
- not_to
4546
Reference: https://www.rubydoc.info/gems/rubocop-capybara/RuboCop/Cop/Capybara/NegationMatcher
47+
VersionRemoved: '3.0'
4648

4749
Capybara/RedundantWithinFind:
4850
Description: Checks for redundant `within find(...)` calls.
@@ -67,25 +69,45 @@ Capybara/SpecificMatcher:
6769
Enabled: pending
6870
VersionAdded: '2.12'
6971
Reference: https://www.rubydoc.info/gems/rubocop-capybara/RuboCop/Cop/Capybara/SpecificMatcher
72+
VersionRemoved: '3.0'
7073

7174
Capybara/VisibilityMatcher:
7275
Description: Checks for boolean visibility in Capybara finders.
7376
Enabled: true
7477
VersionAdded: '1.39'
7578
VersionChanged: '2.0'
7679
Reference: https://www.rubydoc.info/gems/rubocop-capybara/RuboCop/Cop/Capybara/VisibilityMatcher
80+
VersionRemoved: '3.0'
7781

7882
Capybara/RSpec:
7983
Enabled: true
8084
Include: *1
8185

86+
Capybara/RSpec/CurrentPathExpectation:
87+
Description: Checks that no expectations are set on Capybara's `current_path`.
88+
Enabled: true
89+
VersionAdded: '1.18'
90+
VersionChanged: '2.0'
91+
Reference: https://www.rubydoc.info/gems/rubocop-capybara/RuboCop/Cop/Capybara/CurrentPathExpectation
92+
8293
Capybara/RSpec/HaveSelector:
8394
Description: Use `have_css` or `have_xpath` instead of `have_selector`.
8495
Enabled: pending
8596
DefaultSelector: css
8697
VersionAdded: '2.19'
8798
Reference: https://www.rubydoc.info/gems/rubocop-capybara/RuboCop/Cop/Capybara/RSpec/HaveSelector
8899

100+
Capybara/RSpec/NegationMatcher:
101+
Description: Enforces use of `have_no_*` or `not_to` for negated expectations.
102+
Enabled: pending
103+
VersionAdded: '2.14'
104+
VersionChanged: '2.20'
105+
EnforcedStyle: have_no
106+
SupportedStyles:
107+
- have_no
108+
- not_to
109+
Reference: https://www.rubydoc.info/gems/rubocop-capybara/RuboCop/Cop/Capybara/NegationMatcher
110+
89111
Capybara/RSpec/PredicateMatcher:
90112
Description: Prefer using predicate matcher over using predicate method directly.
91113
Enabled: pending
@@ -97,3 +119,16 @@ Capybara/RSpec/PredicateMatcher:
97119
- explicit
98120
VersionAdded: '2.19'
99121
Reference: https://www.rubydoc.info/gems/rubocop-capybara/RuboCop/Cop/Capybara/RSpec/PredicateMatcher
122+
123+
Capybara/RSpec/SpecificMatcher:
124+
Description: Checks for there is a more specific matcher offered by Capybara.
125+
Enabled: pending
126+
VersionAdded: '2.12'
127+
Reference: https://www.rubydoc.info/gems/rubocop-capybara/RuboCop/Cop/Capybara/SpecificMatcher
128+
129+
Capybara/RSpec/VisibilityMatcher:
130+
Description: Checks for boolean visibility in Capybara finders.
131+
Enabled: true
132+
VersionAdded: '1.39'
133+
VersionChanged: '2.0'
134+
Reference: https://www.rubydoc.info/gems/rubocop-capybara/RuboCop/Cop/Capybara/VisibilityMatcher

lib/rubocop-capybara.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
require 'rubocop'
77

8+
require_relative 'rubocop/capybara/'
89
require_relative 'rubocop/cop/capybara/mixin/capybara_help'
910
require_relative 'rubocop/cop/capybara/mixin/css_attributes_parser'
1011
require_relative 'rubocop/cop/capybara/mixin/css_selector'

lib/rubocop/cop/capybara/current_path_expectation.rb

Lines changed: 7 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,140 +1,18 @@
11
# frozen_string_literal: true
22

3+
require_relative './rspec/current_path_expectation'
4+
35
module RuboCop
46
module Cop
57
module Capybara
68
# Checks that no expectations are set on Capybara's `current_path`.
79
#
8-
# The
9-
# https://www.rubydoc.info/github/teamcapybara/capybara/master/Capybara/RSpecMatchers#have_current_path-instance_method[`have_current_path` matcher]
10-
# should be used on `page` to set expectations on Capybara's
11-
# current path, since it uses
12-
# https://github.com/teamcapybara/capybara/blob/master/README.md#asynchronous-javascript-ajax-and-friends[Capybara's waiting functionality]
13-
# which ensures that preceding actions (like `click_link`) have
14-
# completed.
15-
#
16-
# This cop does not support autocorrection in some cases.
17-
#
18-
# @example
19-
# # bad
20-
# expect(current_path).to eq('/callback')
21-
# expect(page.current_path).to eq('/callback')
10+
# IMPORTANT: This cop is deprecated and will be removed in
11+
# RuboCop Capybara 3.0.
12+
# Please use `Capybara/RSpec/CurrentPathExpectation` instead.
2213
#
23-
# # good
24-
# expect(page).to have_current_path('/callback', ignore_query: true)
25-
#
26-
# # bad (does not support autocorrection when `match` with a variable)
27-
# expect(page).to match(variable)
28-
#
29-
class CurrentPathExpectation < ::RuboCop::Cop::Base
30-
extend AutoCorrector
31-
include RangeHelp
32-
33-
MSG = 'Do not set an RSpec expectation on `current_path` in ' \
34-
'Capybara feature specs - instead, use the ' \
35-
'`have_current_path` matcher on `page`'
36-
37-
RESTRICT_ON_SEND = %i[expect].freeze
38-
39-
# @!method expectation_set_on_current_path(node)
40-
def_node_matcher :expectation_set_on_current_path, <<~PATTERN
41-
(send nil? :expect (send {(send nil? :page) nil?} :current_path))
42-
PATTERN
43-
44-
# Supported matchers: eq(...) / match(/regexp/) / match('regexp')
45-
# @!method as_is_matcher(node)
46-
def_node_matcher :as_is_matcher, <<~PATTERN
47-
(send
48-
#expectation_set_on_current_path ${:to :to_not :not_to}
49-
${(send nil? :eq ...) (send nil? :match (regexp ...))})
50-
PATTERN
51-
52-
# @!method regexp_node_matcher(node)
53-
def_node_matcher :regexp_node_matcher, <<~PATTERN
54-
(send
55-
#expectation_set_on_current_path ${:to :to_not :not_to}
56-
$(send nil? :match ${str dstr xstr}))
57-
PATTERN
58-
59-
def self.autocorrect_incompatible_with
60-
[Style::TrailingCommaInArguments]
61-
end
62-
63-
def on_send(node)
64-
expectation_set_on_current_path(node) do
65-
add_offense(node.loc.selector) do |corrector|
66-
next unless node.chained?
67-
68-
autocorrect(corrector, node)
69-
end
70-
end
71-
end
72-
73-
private
74-
75-
def autocorrect(corrector, node)
76-
as_is_matcher(node.parent) do |to_sym, matcher_node|
77-
rewrite_expectation(corrector, node, to_sym, matcher_node)
78-
end
79-
80-
regexp_node_matcher(node.parent) do |to_sym, matcher_node, regexp|
81-
rewrite_expectation(corrector, node, to_sym, matcher_node)
82-
convert_regexp_node_to_literal(corrector, matcher_node, regexp)
83-
end
84-
end
85-
86-
def rewrite_expectation(corrector, node, to_symbol, matcher_node)
87-
corrector.replace(node.first_argument, 'page')
88-
corrector.replace(node.parent.loc.selector, 'to')
89-
matcher_method = if to_symbol == :to
90-
'have_current_path'
91-
else
92-
'have_no_current_path'
93-
end
94-
corrector.replace(matcher_node.loc.selector, matcher_method)
95-
add_argument_parentheses(corrector, matcher_node.first_argument)
96-
add_ignore_query_options(corrector, node, matcher_node)
97-
end
98-
99-
def convert_regexp_node_to_literal(corrector, matcher_node, regexp_node)
100-
str_node = matcher_node.first_argument
101-
regexp_expr = regexp_node_to_regexp_expr(regexp_node)
102-
corrector.replace(str_node, regexp_expr)
103-
end
104-
105-
def regexp_node_to_regexp_expr(regexp_node)
106-
if regexp_node.xstr_type?
107-
"/\#{`#{regexp_node.value.value}`}/"
108-
else
109-
Regexp.new(regexp_node.value).inspect
110-
end
111-
end
112-
113-
def add_argument_parentheses(corrector, arg_node)
114-
return unless method_call_with_no_parentheses?(arg_node)
115-
116-
first_argument_range = range_with_surrounding_space(
117-
arg_node.first_argument.source_range, side: :left
118-
)
119-
corrector.insert_before(first_argument_range, '(')
120-
corrector.insert_after(arg_node.last_argument, ')')
121-
end
122-
123-
def method_call_with_no_parentheses?(arg_node)
124-
arg_node.send_type? && arg_node.arguments? && !arg_node.parenthesized?
125-
end
126-
127-
# `have_current_path` with no options will include the querystring
128-
# while `page.current_path` does not.
129-
# This ensures the option `ignore_query: true` is added
130-
# except when `match` matcher.
131-
def add_ignore_query_options(corrector, node, matcher_node)
132-
return if matcher_node.method?(:match)
133-
134-
expectation_node = node.parent.last_argument
135-
expectation_last_child = expectation_node.children.last
136-
corrector.insert_after(expectation_last_child, ', ignore_query: true')
137-
end
14+
class CurrentPathExpectation <
15+
RuboCop::Cop::Capybara::RSpec::CurrentPathExpectation
13816
end
13917
end
14018
end

lib/rubocop/cop/capybara/negation_matcher.rb

Lines changed: 6 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,104 +1,17 @@
11
# frozen_string_literal: true
22

3+
require_relative './rspec/negation_matcher'
4+
35
module RuboCop
46
module Cop
57
module Capybara
68
# Enforces use of `have_no_*` or `not_to` for negated expectations.
79
#
8-
# @example EnforcedStyle: have_no (default)
9-
# # bad
10-
# expect(page).not_to have_selector 'a'
11-
# expect(page).not_to have_css('a')
12-
#
13-
# # good
14-
# expect(page).to have_no_selector 'a'
15-
# expect(page).to have_no_css('a')
16-
#
17-
# @example EnforcedStyle: not_to
18-
# # bad
19-
# expect(page).to have_no_selector 'a'
20-
# expect(page).to have_no_css('a')
21-
#
22-
# # good
23-
# expect(page).not_to have_selector 'a'
24-
# expect(page).not_to have_css('a')
10+
# IMPORTANT: This cop is deprecated and will be removed in
11+
# RuboCop Capybara 3.0.
12+
# Please use `Capybara/RSpec/NegationMatcher` instead.
2513
#
26-
class NegationMatcher < ::RuboCop::Cop::Base
27-
extend AutoCorrector
28-
include ConfigurableEnforcedStyle
29-
30-
MSG = 'Use `expect(...).%<runner>s %<matcher>s`.'
31-
CAPYBARA_MATCHERS = %w[
32-
selector css xpath text title current_path link button
33-
field checked_field unchecked_field select table
34-
sibling ancestor content
35-
].freeze
36-
POSITIVE_MATCHERS =
37-
Set.new(CAPYBARA_MATCHERS) { |element| :"have_#{element}" }.freeze
38-
NEGATIVE_MATCHERS =
39-
Set.new(CAPYBARA_MATCHERS) { |element| :"have_no_#{element}" }
40-
.freeze
41-
RESTRICT_ON_SEND = (POSITIVE_MATCHERS + NEGATIVE_MATCHERS).freeze
42-
43-
# @!method not_to?(node)
44-
def_node_matcher :not_to?, <<~PATTERN
45-
(send ... {:not_to :to_not}
46-
(send nil? %POSITIVE_MATCHERS ...))
47-
PATTERN
48-
49-
# @!method have_no?(node)
50-
def_node_matcher :have_no?, <<~PATTERN
51-
(send ... :to
52-
(send nil? %NEGATIVE_MATCHERS ...))
53-
PATTERN
54-
55-
def on_send(node)
56-
return unless offense?(node)
57-
58-
matcher = node.method_name.to_s
59-
add_offense(offense_range(node),
60-
message: message(matcher)) do |corrector|
61-
corrector.replace(node.parent.loc.selector, replaced_runner)
62-
corrector.replace(node.loc.selector,
63-
replaced_matcher(matcher))
64-
end
65-
end
66-
67-
private
68-
69-
def offense?(node)
70-
node.arguments? &&
71-
((style == :have_no && not_to?(node.parent)) ||
72-
(style == :not_to && have_no?(node.parent)))
73-
end
74-
75-
def offense_range(node)
76-
node.parent.loc.selector.with(end_pos: node.loc.selector.end_pos)
77-
end
78-
79-
def message(matcher)
80-
format(MSG,
81-
runner: replaced_runner,
82-
matcher: replaced_matcher(matcher))
83-
end
84-
85-
def replaced_runner
86-
case style
87-
when :have_no
88-
'to'
89-
when :not_to
90-
'not_to'
91-
end
92-
end
93-
94-
def replaced_matcher(matcher)
95-
case style
96-
when :have_no
97-
matcher.sub('have_', 'have_no_')
98-
when :not_to
99-
matcher.sub('have_no_', 'have_')
100-
end
101-
end
14+
class NegationMatcher < RuboCop::Cop::Capybara::RSpec::NegationMatcher
10215
end
10316
end
10417
end

0 commit comments

Comments
 (0)