carwow_rubocop 6.4.0 → 6.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/config/default.yml +1 -0
- data/config/rubocop-carwow.yml +9 -0
- data/lib/rubocop/carwow/version.rb +1 -1
- data/lib/rubocop/cop/carwow/no_change_matcher_with_browser_action.rb +90 -0
- data/lib/rubocop/cop/carwow/no_vehicle_brand_model_sideload.rb +58 -0
- metadata +8 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e3188042457455f9b00b2eba182c978d7687a7324c02bf2df68dd72a353e5a72
|
|
4
|
+
data.tar.gz: 15b8d392add3a85e05b87a6acb705d3c1a8cd54f906d7021a5c5a854387a863a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e156ae2a9536b74791994e18aa3e708c9dc083b6018613e696fb564bfb8b0b7aab64a4611b97ab7d9b8149942a975f6846e6a789c4cfa8d8debe10a2e45b8f74
|
|
7
|
+
data.tar.gz: 7853d1d241b1d1be66719736a202bfb83a68ebb7677e04b5b4775113c29225a233671cb002b98b5e13e007d50b92b9b89ee5be9eaf0acaf5c8c8e9156c50095d
|
data/Gemfile.lock
CHANGED
data/config/default.yml
CHANGED
data/config/rubocop-carwow.yml
CHANGED
|
@@ -36,3 +36,12 @@ Carwow/AddColumnWithComment:
|
|
|
36
36
|
Enabled: true
|
|
37
37
|
Include: &migrations_only
|
|
38
38
|
- "**/db/migrate/**/*.rb"
|
|
39
|
+
|
|
40
|
+
Carwow/NoVehicleBrandModelSideload:
|
|
41
|
+
Enabled: true
|
|
42
|
+
|
|
43
|
+
Carwow/NoChangeMatcherWithBrowserAction:
|
|
44
|
+
Enabled: true
|
|
45
|
+
Include:
|
|
46
|
+
- "**/*_spec.rb"
|
|
47
|
+
- "**/spec/**/*"
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Carwow
|
|
6
|
+
# Detects the use of `expect { browser_action }.to change { db_access }`
|
|
7
|
+
# in feature/system specs. This pattern is racy because `change{}` takes
|
|
8
|
+
# DB snapshots before and after the block with no guarantee the browser
|
|
9
|
+
# has finished processing the action.
|
|
10
|
+
#
|
|
11
|
+
# @example Bad
|
|
12
|
+
# expect { submit }.not_to(change { listing.reload.state })
|
|
13
|
+
# expect { click_button('Save') }.to change { User.count }.by(1)
|
|
14
|
+
#
|
|
15
|
+
# @example Good
|
|
16
|
+
# submit
|
|
17
|
+
# expect(page).to have_content('Success')
|
|
18
|
+
# expect(listing.reload.state).to eq('complete')
|
|
19
|
+
#
|
|
20
|
+
# click_button('Save')
|
|
21
|
+
# expect(page).to have_current_path(success_path)
|
|
22
|
+
# expect(User.count).to eq(2)
|
|
23
|
+
#
|
|
24
|
+
class NoChangeMatcherWithBrowserAction < Base
|
|
25
|
+
MSG = 'Avoid wrapping Capybara browser actions in `expect { }.to change { }`. ' \
|
|
26
|
+
'The DB snapshot races the async browser. Instead: call the action, ' \
|
|
27
|
+
'wait with `expect(page).to have_*`, then assert the DB state.'
|
|
28
|
+
|
|
29
|
+
CAPYBARA_ACTIONS = %i[
|
|
30
|
+
visit
|
|
31
|
+
click_button click_link click_on click
|
|
32
|
+
fill_in choose check uncheck select attach_file
|
|
33
|
+
find find_field find_button find_by_id find_link
|
|
34
|
+
within within_frame within_window
|
|
35
|
+
execute_script evaluate_script
|
|
36
|
+
scroll_to scroll_by
|
|
37
|
+
hover drag_to drop
|
|
38
|
+
dismiss_confirm accept_confirm dismiss_prompt accept_prompt
|
|
39
|
+
submit
|
|
40
|
+
].to_set.freeze
|
|
41
|
+
|
|
42
|
+
# AST shape for `expect { ... }.to change { ... }`
|
|
43
|
+
# (possibly chained with .by / .by_at_least etc., which wraps the whole thing)
|
|
44
|
+
#
|
|
45
|
+
# The `.to`/`.not_to` send node:
|
|
46
|
+
# (send
|
|
47
|
+
# (block (send nil :expect) (args) <body>) <- expect { body }
|
|
48
|
+
# {:to :not_to :to_not}
|
|
49
|
+
# {
|
|
50
|
+
# (block (send nil :change) (args) _) <- change { ... }
|
|
51
|
+
# (send (block (send nil :change) ...) _) <- change { }.by(n)
|
|
52
|
+
# }
|
|
53
|
+
# )
|
|
54
|
+
#
|
|
55
|
+
# We also handle the parenthesised form: .not_to(change { ... })
|
|
56
|
+
# which produces identical AST.
|
|
57
|
+
def_node_matcher :expect_to_change?, <<~PATTERN
|
|
58
|
+
(send
|
|
59
|
+
(block
|
|
60
|
+
(send nil? :expect)
|
|
61
|
+
(args)
|
|
62
|
+
...)
|
|
63
|
+
{:to :not_to :to_not}
|
|
64
|
+
{
|
|
65
|
+
(block (send nil? :change) ...)
|
|
66
|
+
(send (block (send nil? :change) ...) ...)
|
|
67
|
+
}
|
|
68
|
+
)
|
|
69
|
+
PATTERN
|
|
70
|
+
|
|
71
|
+
def on_send(node)
|
|
72
|
+
return unless expect_to_change?(node)
|
|
73
|
+
|
|
74
|
+
expect_block = node.receiver
|
|
75
|
+
return unless block_contains_capybara_action?(expect_block)
|
|
76
|
+
|
|
77
|
+
add_offense(node)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
def block_contains_capybara_action?(block_node)
|
|
83
|
+
block_node.each_descendant(:send).any? do |send_node|
|
|
84
|
+
CAPYBARA_ACTIONS.include?(send_node.method_name)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Carwow
|
|
6
|
+
class NoVehicleBrandModelSideload < Base
|
|
7
|
+
MSG = 'Do not sideload vehicle brand/model with includes.' \
|
|
8
|
+
'Request brand/model via extra_fields(vehicles: ...).'
|
|
9
|
+
|
|
10
|
+
RESTRICT_ON_SEND = %i[includes].freeze
|
|
11
|
+
|
|
12
|
+
DEAL_CONST = 'DealsServiceApiClient::Deal'
|
|
13
|
+
VEHICLE_CONST = 'DealsServiceApiClient::Vehicle'
|
|
14
|
+
|
|
15
|
+
def_node_matcher :brand_or_model_sym?, <<~PATTERN
|
|
16
|
+
(sym {:brand :model})
|
|
17
|
+
PATTERN
|
|
18
|
+
|
|
19
|
+
def_node_matcher :vehicle_with_brand_or_model?, <<~PATTERN
|
|
20
|
+
(pair (sym :vehicle) (array <#brand_or_model_sym? ...>))
|
|
21
|
+
PATTERN
|
|
22
|
+
|
|
23
|
+
def on_send(node)
|
|
24
|
+
offending_sideloads(node).each { |sideload| add_offense(sideload) }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def offending_sideloads(node)
|
|
30
|
+
case root_receiver_const(node.receiver)
|
|
31
|
+
when DEAL_CONST then deal_offenses(node.arguments)
|
|
32
|
+
when VEHICLE_CONST then vehicle_offenses(node.arguments)
|
|
33
|
+
else []
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def deal_offenses(arguments)
|
|
38
|
+
arguments.flat_map do |arg|
|
|
39
|
+
next [] unless arg.hash_type?
|
|
40
|
+
|
|
41
|
+
arg.pairs.filter_map { |pair| pair.value if vehicle_with_brand_or_model?(pair) }
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def vehicle_offenses(arguments)
|
|
46
|
+
arguments.select { |arg| brand_or_model_sym?(arg) }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def root_receiver_const(node)
|
|
50
|
+
return unless node
|
|
51
|
+
return node.const_name if node.const_type?
|
|
52
|
+
|
|
53
|
+
root_receiver_const(node.receiver) if node.send_type?
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: carwow_rubocop
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 6.
|
|
4
|
+
version: 6.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- carwow Developers
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: exe
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date: 2026-
|
|
11
|
+
date: 2026-05-15 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: bundler
|
|
@@ -168,12 +169,15 @@ files:
|
|
|
168
169
|
- lib/rubocop/cop/carwow/jobs.rb
|
|
169
170
|
- lib/rubocop/cop/carwow/jobs_must_define_queue.rb
|
|
170
171
|
- lib/rubocop/cop/carwow/jobs_queue_name_style.rb
|
|
172
|
+
- lib/rubocop/cop/carwow/no_change_matcher_with_browser_action.rb
|
|
171
173
|
- lib/rubocop/cop/carwow/no_stubbing_business_event.rb
|
|
174
|
+
- lib/rubocop/cop/carwow/no_vehicle_brand_model_sideload.rb
|
|
172
175
|
homepage: https://github.com/carwow/carwow_rubocop
|
|
173
176
|
licenses:
|
|
174
177
|
- MIT
|
|
175
178
|
metadata:
|
|
176
179
|
rubygems_mfa_required: 'true'
|
|
180
|
+
post_install_message:
|
|
177
181
|
rdoc_options: []
|
|
178
182
|
require_paths:
|
|
179
183
|
- lib
|
|
@@ -188,7 +192,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
188
192
|
- !ruby/object:Gem::Version
|
|
189
193
|
version: '0'
|
|
190
194
|
requirements: []
|
|
191
|
-
rubygems_version: 3.
|
|
195
|
+
rubygems_version: 3.4.19
|
|
196
|
+
signing_key:
|
|
192
197
|
specification_version: 4
|
|
193
198
|
summary: carwow's rubocop configuration
|
|
194
199
|
test_files: []
|