diff_test 0.2.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.
Files changed (33) hide show
  1. checksums.yaml +7 -0
  2. data/.standard.yml +3 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +208 -0
  5. data/Rakefile +10 -0
  6. data/lib/diff_test/api_client.rb +38 -0
  7. data/lib/diff_test/configuration.rb +178 -0
  8. data/lib/diff_test/file_hash_computer.rb +21 -0
  9. data/lib/diff_test/helper.rb +37 -0
  10. data/lib/diff_test/impacted_file_tracker.rb +34 -0
  11. data/lib/diff_test/integrations/integration.rb +29 -0
  12. data/lib/diff_test/integrations/minitest/integration.rb +26 -0
  13. data/lib/diff_test/integrations/minitest/lifecycle.rb +77 -0
  14. data/lib/diff_test/integrations/rails_js/annotator.rb +43 -0
  15. data/lib/diff_test/integrations/rails_js/body_processor.rb +69 -0
  16. data/lib/diff_test/integrations/rails_js/integration.rb +25 -0
  17. data/lib/diff_test/integrations/rails_js/js_files.rake +48 -0
  18. data/lib/diff_test/integrations/rails_js/middleware.rb +43 -0
  19. data/lib/diff_test/integrations/rails_js/processing_skip_analyzer.rb +31 -0
  20. data/lib/diff_test/integrations/rails_js/railtie.rb +17 -0
  21. data/lib/diff_test/js_version_hash_computer.rb +24 -0
  22. data/lib/diff_test/project_version_hash_computer.rb +26 -0
  23. data/lib/diff_test/should_run_decider.rb +44 -0
  24. data/lib/diff_test/test_execution.rb +92 -0
  25. data/lib/diff_test/test_suite_execution.rb +114 -0
  26. data/lib/diff_test/trackers/base.rb +23 -0
  27. data/lib/diff_test/trackers/js_file.rb +7 -0
  28. data/lib/diff_test/trackers/ruby_file.rb +50 -0
  29. data/lib/diff_test/trackers/singleton_base.rb +43 -0
  30. data/lib/diff_test/version.rb +5 -0
  31. data/lib/diff_test.rb +32 -0
  32. data/sig/diff_test.rbs +4 -0
  33. metadata +107 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: cac8148799f86b799f536964cbaf80ee3b77d99f915f33eb3c4e54c76cafd465
4
+ data.tar.gz: 52332e3b52034d18dd9572b85e9f2d4cf807000fd2049c27d6177a6f48caf1c5
5
+ SHA512:
6
+ metadata.gz: c9059223409cd8347bfe233adf8d65d19577d90cefa72e1b1cacd3a660cb33a018d0609d75710154f9addcbb057e207cbbb449b3c8d8cc7f7fd695fd3ae210f1
7
+ data.tar.gz: 89a3b42a009650ea1a6cd970627c40474b563d8afafa24371103dbfd933287b601359c220afeb6af19a52b2f78e19478290c343bd6c9cb14df115956664b624a
data/.standard.yml ADDED
@@ -0,0 +1,3 @@
1
+ # For available configuration options, see:
2
+ # https://github.com/standardrb/standard
3
+ ruby_version: 3.0
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Owais
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,208 @@
1
+ # DiffTest
2
+
3
+ ## Configuration
4
+
5
+ ### enabled
6
+ ```ruby
7
+ DiffTest.configure do |config|
8
+ config.enabled = ENV['CI'].present?
9
+
10
+ config.project_root = Rails.root
11
+
12
+ config.vendor_bundle_path = File.join(Rails.root, 'vendor')
13
+
14
+ # Default: All files generated by git
15
+ config.project_files = [
16
+ -> { `git -C "#{Rails.root}" ls-files`.split("\n") }
17
+ ]
18
+
19
+ # These paths don't factor into determining if tests should be run at all.
20
+ # Its as if they aren't even there.
21
+ config.ignored_paths = [
22
+ 'db/migrate/**/*',
23
+ '**/*.md',
24
+ # 'doc/**/*',
25
+ # 'services/video_encoding/**/*
26
+ # 'simplero-mobile-app/**/*
27
+ # **/*.css
28
+ # **/*.scss
29
+ ]
30
+
31
+ # Add patterns where you ruby/template files live.
32
+ # If you change any file that does not match these patterns, we will run all the tests.
33
+ config.tracked_paths = [
34
+ 'app/**/*.rb',
35
+ 'app/**/*.html.erb',
36
+ 'lib/**/*.rb',
37
+ 'lib/**/*.html.erb',
38
+ 'test/**/*.rb',
39
+ ]
40
+
41
+ # For this to work correctly,
42
+ # You need to ensure that these files are annotated
43
+ # You can automatically annotate your files with
44
+ # rake diff_test:annotate
45
+ # This also happens automatically when you run RAILS_ENV=test rails assets:precompile
46
+ config.tracked_js_paths = [
47
+ 'app/javascript/**/*.{js,jsx,ts,tsx,mjs,cjs,coffee}',
48
+ 'app/assets/javascripts/**/*.{js,jsx,ts,tsx,mjs,cjs,coffee}',
49
+ ]
50
+
51
+ end
52
+ ```
53
+
54
+ # TODO
55
+ * Testing strategy
56
+ * Documentation
57
+ --
58
+ * Fixture tracker
59
+ * Factory tracker
60
+ * CSS tracker
61
+
62
+ - TracePointTracker
63
+ - ConstantTracker (depends_on TracePointTracker)
64
+ - FileTracker
65
+ - FixtureTracker
66
+ - JavascriptTracker
67
+ -
68
+
69
+ - ImpactedFileTracker
70
+ - FileTracker
71
+ - ConstantTracker
72
+ - TracePointTracker
73
+
74
+
75
+
76
+
77
+
78
+
79
+
80
+ Number of commits (out of last 2000) with any changes NOT matching allowed patterns:
81
+ base_only => 592
82
+ with_factories_fixtures => 583
83
+ with_js_ts => 422
84
+ with_js_ts_css => 325
85
+ with_js_css_db_except_schema => 298
86
+ with_factories_fixtures_js_css => 316
87
+ with_factories_fixtures_js_css_db_except_schema => 288
88
+ with_factories_fixtures_except_schema => 558
89
+ with_factories_fixtures_css_except_schema => 487
90
+ with_css => 521
91
+ with_css_except_schema => 497
92
+ ruby cookbooks/track_non_matching.rb 1000 23.75s user 8.41s system 95% cpu 33.642 total
93
+
94
+
95
+
96
+
97
+
98
+
99
+ ######
100
+
101
+ * Write tests on diff_test_web
102
+ * These are all system tests.
103
+ * Creates test suite executions
104
+ * Creates test executions
105
+ * Runs tests when impacted files change
106
+ * Runs tests when project files change
107
+ * Runs system test when js version change (in unrelated file) but no previous js run
108
+ * Skips system test when no js version change
109
+ * Runs system test when related js file changes
110
+ * Skip system test when related js file changes after a succesful run
111
+
112
+ * ImpactedFileTracker
113
+ - Ruby
114
+ - HTML
115
+ - Javascript
116
+
117
+
118
+ ### Test TODO
119
+
120
+ Test rails app
121
+ [ ] UserTest model
122
+ - class access
123
+ [ ] AccountTest model
124
+ - calls searchable
125
+ - uses fixtures for users and accounts
126
+ [ ] Controller/Integration test
127
+ [ ] System test
128
+ - AccountController#index - views, controller, js, css, fixtures
129
+ - AccountController#partial
130
+ - AccountController#stream
131
+ - AccountController#components
132
+ - AccountController#layouts
133
+ - AccountController#helpers
134
+ [ ] Mailer test
135
+ [ ] Job test
136
+
137
+
138
+ # Tasks
139
+ X Allow login
140
+ X Allow signup
141
+ xpassword confirmation controller
142
+ X Allow account creation
143
+ xhandle check controller
144
+ xinherit from controller
145
+ X Account#show
146
+ xMake account#show view render a user_card partial
147
+ X Allow customer creation (assoc to user & account)
148
+ x Write model unit tests for User
149
+ x Write model unit tests for Account
150
+ x View component with html
151
+ x View component with call
152
+ x Write integration tests for AccountController around the handle_connect helper
153
+ x Make a mailer that sends a email about the details of a newly created account
154
+ x Make a job that runs every hour deleting accounts with invalid users
155
+ x View comopnent test
156
+ x Write system test for signup
157
+ password mismatch test
158
+ x Write system test for login
159
+ x Write system test for account creation
160
+ - handle check
161
+ - currency (USD)
162
+ - user
163
+ x Write system test for customer creation
164
+ -
165
+
166
+
167
+
168
+ DiffTestWeb
169
+ [ ] Test each test written above
170
+ assert impacted file.
171
+ run it again
172
+ assert skipped
173
+ change some unrelated files
174
+ run it again
175
+ change some related files
176
+ assert not skipped
177
+
178
+ [ ] Test various configurations
179
+ Changing JS version hash
180
+ Changing project version hash
181
+ All JS files annotated tracking
182
+
183
+
184
+
185
+
186
+ # Works locally
187
+ # Won't auto-annotate files locally
188
+ # Annotate files in CI through precompile or db:prepare
189
+
190
+
191
+ ### LAter
192
+ # config.enabled = Rails.env.test?
193
+ # config.enabled = Rails.env.test? && ENV['CI'].present?
194
+
195
+
196
+ # Annotates JS files so they are be able to tracked as well.
197
+ # By default, we only do this in CI env.
198
+ # As an alternative, you can run `bundle exec rake diff_test:annotate` manually.
199
+ # To unannotate, simply run `bundle exec rake diff_test:unannoate`
200
+ # config.auto_annotate_js_files = :ci
201
+
202
+
203
+
204
+ # TODO
205
+ - Initialier/install script
206
+ - Set unskippable
207
+ - Skip from branch/commit/author name
208
+ - Unskippable branches
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "minitest/test_task"
5
+
6
+ Minitest::TestTask.create
7
+
8
+ require "standard/rake"
9
+
10
+ task default: %i[test standard]
@@ -0,0 +1,38 @@
1
+ require 'httparty'
2
+
3
+ module DiffTest
4
+ class ApiClient
5
+ include HTTParty
6
+
7
+ def self.get(path, options = {}, &block)
8
+ set_api_key_in_headers(options)
9
+ super
10
+ end
11
+
12
+ def self.post(path, options = {}, &block)
13
+ set_api_key_in_headers(options)
14
+ super
15
+ end
16
+
17
+ def self.put(path, options = {}, &block)
18
+ set_api_key_in_headers(options)
19
+ super
20
+ end
21
+
22
+ def self.patch(path, options = {}, &block)
23
+ set_api_key_in_headers(options)
24
+ super
25
+ end
26
+
27
+ def self.delete(path, options = {}, &block)
28
+ set_api_key_in_headers(options)
29
+ super
30
+ end
31
+
32
+ def self.set_api_key_in_headers(options)
33
+ base_uri "http://localhost:#{DiffTest.configuration.port}"
34
+ options[:headers] ||= {}
35
+ options[:headers]['X-Diff-Test-Api-Key'] = DiffTest.configuration.api_key
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,178 @@
1
+ module DiffTest
2
+ class Configuration
3
+ attr_writer \
4
+ :api_key,
5
+ :port,
6
+ :project_root,
7
+ :vendor_bundle_path,
8
+ :project_files,
9
+ :ignored_files,
10
+ :tracked_files,
11
+ :tracked_js_files
12
+
13
+ def api_key
14
+ @api_key || ENV['DIFF_TEST_API_KEY']
15
+ end
16
+
17
+ def port
18
+ @port || 8085
19
+ end
20
+
21
+ def project_root
22
+ return @project_root if @project_root
23
+
24
+ @project_root = ::Rails.root.to_s if defined?(::Rails)
25
+
26
+ unless @project_root
27
+ raise "Please specify a project root in config/environments/test.rb using
28
+ DiffTest.configure do |config|
29
+ config.project_root = '/path/to/your/project'
30
+ end
31
+ "
32
+ end
33
+
34
+ @project_root
35
+ end
36
+
37
+ def vendor_bundle_path
38
+ return @vendor_bundle_path if @vendor_bundle_path
39
+
40
+ @vendor_bundle_path = File.join(project_root, 'vendor', 'bundle').to_s if defined?(::Rails)
41
+ end
42
+
43
+ def project_files
44
+ @expanded_project_files ||=
45
+ begin
46
+ @project_files ||= [-> { `git -C "#{project_root}" ls-files`.split("\n") }]
47
+
48
+ expand_files(@project_files)
49
+ end
50
+ end
51
+
52
+ def ignored_files
53
+ @expanded_ignored_files ||=
54
+ begin
55
+ @ignored_files ||= ['db/migrate/**/*', '**/*.md']
56
+ filter_from_project_files(@ignored_files)
57
+ end
58
+ end
59
+
60
+ def tracked_files
61
+ @expanded_tracked_files ||=
62
+ begin
63
+ @tracked_files ||= [
64
+ 'app/**/*.rb',
65
+ 'app/**/*.html.erb',
66
+ 'lib/**/*.rb',
67
+ 'lib/**/*.html.erb',
68
+ 'test/**/*.rb',
69
+ '!test/fixtures/**/*',
70
+ '!test/factories/**/*',
71
+ '!test/factories.rb',
72
+ ]
73
+ filter_from_project_files(@tracked_files)
74
+ end
75
+ end
76
+
77
+ def tracked_js_files
78
+ @expanded_js_files ||=
79
+ begin
80
+ @tracked_js_files ||= [
81
+ 'app/components/**/*.{js,jsx,ts,tsx,mjs,cjs,coffee}',
82
+ 'app/javascript/**/*.{js,jsx,ts,tsx,mjs,cjs,coffee}',
83
+ 'app/assets/javascripts/**/*.{js,jsx,ts,tsx,mjs,cjs,coffee}'
84
+ ]
85
+ filter_from_project_files(@tracked_js_files)
86
+ end
87
+ end
88
+
89
+ def system_test_paths
90
+ @expanded_system_test_paths ||=
91
+ begin
92
+ @system_test_paths ||= [
93
+ 'test/system/**/*.rb',
94
+ 'test/system/**/*.html.erb'
95
+ ]
96
+ filter_from_project_files(@system_test_paths)
97
+ end
98
+ end
99
+
100
+ def ci_platform
101
+ if ENV['CIRCLECI']
102
+ 'circleci'
103
+ elsif ENV['GITHUB_ACTIONS']
104
+ 'github-actions'
105
+ elsif ENV['TRAVIS']
106
+ 'travis'
107
+ elsif ENV['BUILDKITE']
108
+ 'buildkite'
109
+ elsif ENV['JENKINS_URL']
110
+ 'jenkins'
111
+ end
112
+ end
113
+
114
+ def auto_annotate_js_files?
115
+ case auto_annotate_js_files
116
+ when :ci
117
+ !!ci_platform
118
+ else
119
+ auto_annotate_js_files
120
+ end
121
+ end
122
+
123
+ def auto_annotate_js_files
124
+ return :ci if @auto_annotate_js_files.nil?
125
+ @auto_annotate_js_files
126
+ end
127
+
128
+ def auto_annotate_js_files=(value)
129
+ @auto_annotate_js_files = value.nil? ? !!value : value
130
+ end
131
+
132
+ private
133
+
134
+ def file_matches_pattern?(file_path, pattern)
135
+ File.fnmatch?(pattern, file_path, File::Constants::FNM_PATHNAME | File::Constants::FNM_EXTGLOB)
136
+ end
137
+
138
+ def file_matches_any_patterns?(file_path, patterns)
139
+ patterns.any? { |pattern| file_matches_pattern?(file_path, pattern) }
140
+ end
141
+
142
+ def file_matches_any_negative_patterns?(file_path, negative_patterns)
143
+ negative_patterns.any? { |pattern| file_matches_pattern?(file_path, pattern[1..-1]) }
144
+ end
145
+
146
+ def filter_from_project_files(patterns)
147
+ negative_patterns, positive_patterns = patterns.partition { |pattern| pattern.start_with?('!') }
148
+
149
+ project_files.select do |file_path|
150
+ file_matches_any_patterns?(file_path, positive_patterns) &&
151
+ !file_matches_any_negative_patterns?(file_path, negative_patterns)
152
+ end.to_set
153
+ end
154
+
155
+ def expand_files(files)
156
+ files = files.flat_map do |file|
157
+ if file.is_a?(Proc)
158
+ file.call
159
+ elsif file.is_a?(String) && file.start_with?('!')
160
+ file
161
+ else
162
+ Dir.glob(file, base: project_root)
163
+ end
164
+ end
165
+
166
+ negative_patterns, files = files.partition { |file| file.is_a?(String) && file.start_with?('!') }
167
+
168
+ files = files.reject do |file|
169
+ file_matches_any_negative_patterns?(file, negative_patterns)
170
+ end unless negative_patterns.empty?
171
+
172
+ files.select do |file_path|
173
+ File.file?(DiffTest::Helper.expand_path(file_path))
174
+ end.to_set
175
+ end
176
+
177
+ end
178
+ end
@@ -0,0 +1,21 @@
1
+ require 'xxhash'
2
+
3
+ module DiffTest
4
+ class FileHashComputer
5
+ # Save hashesh in a global cache. If available use it, otherwise compute it.
6
+ #
7
+ def self.compute(file_path)
8
+ return @cache[file_path] if @cache&.key?(file_path)
9
+
10
+ content = File.read(file_path)
11
+ content = DiffTest::Integrations::RailsJs::Annotator.unannotate(content)
12
+
13
+ @cache ||= {}
14
+ @cache[file_path] = XXhash.xxh64(content).to_s
15
+ end
16
+
17
+ def self.compute_relative(file_path)
18
+ self.compute(DiffTest::Helper.absolute_path_from_project_root(file_path))
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,37 @@
1
+ module DiffTest
2
+ module Helper
3
+ module_function
4
+
5
+ def test_id(test_file_path, test_name)
6
+ [test_file_path, test_name].join(':')
7
+ end
8
+
9
+ def relative_path_from_project_root(file_path)
10
+ raise 'Expected file_path to be an absolute path' unless file_path.start_with?('/')
11
+
12
+ Pathname.new(file_path).relative_path_from(DiffTest.configuration.project_root).to_s
13
+ end
14
+
15
+ def relative_const_source_path_from_project_root(const_name)
16
+ relative_path_from_project_root(const_source_path(const_name))
17
+ end
18
+
19
+ def const_source_path(const_name)
20
+ Module.const_source_location(const_name).first
21
+ end
22
+
23
+ def absolute_path_from_project_root(file_path)
24
+ File.join(DiffTest.configuration.project_root, file_path)
25
+ end
26
+
27
+ def file_in_project?(file_path)
28
+ file_path &&
29
+ file_path.start_with?(DiffTest.configuration.project_root) &&
30
+ !file_path.start_with?(DiffTest.configuration.vendor_bundle_path)
31
+ end
32
+
33
+ def expand_path(file_path)
34
+ File.expand_path(file_path, DiffTest.configuration.project_root)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,34 @@
1
+ require_relative 'file_hash_computer'
2
+ require_relative 'trackers/ruby_file'
3
+ require_relative 'trackers/js_file'
4
+
5
+ module DiffTest
6
+ class ImpactedFileTracker
7
+ attr_reader :trackers
8
+
9
+ def initialize
10
+ @trackers = [
11
+ DiffTest::Trackers::RubyFile.new,
12
+ DiffTest::Trackers::JsFile.new
13
+ ]
14
+ end
15
+
16
+ def save_payload
17
+ impacted_files.each_with_object({}) do |file_path, payload|
18
+ payload[file_path] = FileHashComputer.compute(file_path)
19
+ end
20
+ end
21
+
22
+ def impacted_files
23
+ trackers.map(&:impacted_files).reduce(Set.new, :|)
24
+ end
25
+
26
+ def start
27
+ trackers.each(&:enable)
28
+ end
29
+
30
+ def stop
31
+ trackers.each(&:disable)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,29 @@
1
+ module DiffTest
2
+ module Integrations
3
+ class Integration
4
+ def supported?
5
+ Gem.loaded_specs[gem_name]&.version > minimum_compatible_version
6
+ end
7
+
8
+ def gem_name
9
+ raise NotImplementedError
10
+ end
11
+
12
+ def loaded?
13
+ raise NotImplementedError
14
+ end
15
+
16
+ def integrate
17
+ raise NotImplementedError
18
+ end
19
+
20
+ def integrate_if_ready
21
+ integrate if supported? && loaded?
22
+ end
23
+
24
+ def self.instance
25
+ @instance ||= new
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,26 @@
1
+ require_relative '../integration'
2
+ require_relative 'lifecycle'
3
+
4
+ module DiffTest
5
+ module Integrations
6
+ module Minitest
7
+ class Integration < DiffTest::Integrations::Integration
8
+ def gem_name
9
+ 'minitest'
10
+ end
11
+
12
+ def minimum_compatible_version
13
+ '5.0.0'
14
+ end
15
+
16
+ def loaded?
17
+ supported? && defined?(::Minitest) && defined?(::Minitest::Test)
18
+ end
19
+
20
+ def integrate
21
+ ::Minitest::Test.include(DiffTest::Integrations::Minitest::Lifecycle)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,77 @@
1
+ module DiffTest
2
+ module Integrations
3
+ module Minitest
4
+ module Lifecycle
5
+ def self.included(base)
6
+ base.prepend(InstanceMethods)
7
+ end
8
+
9
+ module InstanceMethods
10
+ def before_setup
11
+ super
12
+
13
+ unless DiffTest::TestSuiteExecution.current
14
+ tests = ::Minitest::Test.runnables.flat_map do |runnable|
15
+ next if runnable.runnable_methods.empty?
16
+
17
+ test_file_path = Helper.relative_const_source_path_from_project_root(runnable.name)
18
+
19
+ runnable.runnable_methods.map do |test_name|
20
+ DiffTest::Helper.test_id(test_file_path, test_name)
21
+ end
22
+ end.compact
23
+
24
+ test_suite_execution = DiffTest::TestSuiteExecution.find_or_create(tests)
25
+
26
+ at_exit do
27
+ DiffTest::TestSuiteExecution.current.save
28
+ end
29
+ end
30
+
31
+ raise "Expected DiffTest::TestExecution to be nil. Please report this issue." if DiffTest::TestExecution.current
32
+
33
+ test_file_path = Helper.relative_const_source_path_from_project_root(self.class.name)
34
+ test_name = self.name
35
+
36
+ DiffTest::TestExecution.current = execution = DiffTest::TestExecution.new(test_file_path:, test_name:)
37
+
38
+ if execution.should_run?
39
+ DiffTest::TestSuiteExecution.current.ensure_application_eager_loaded!
40
+ else
41
+ if defined?(ActiveSupport::TestCase) && respond_to?(:run_callbacks)
42
+ # ActionMailer::TestCase has setup/teardown hook
43
+ # Since we call skip here, the setup hook won't be called.
44
+ # This is cause the ActiveSupport::Testcase's before_setup is higher up in the call chain and is invoked first
45
+ # But if calls super before run_callbacks. which leads to this method being called.
46
+ # But then since we skip here, we never reach the run_callbacks call because skip raises an exception.
47
+ run_callbacks(:setup)
48
+ end
49
+ skip("Impacted files have not changed. Skipping...")
50
+ end
51
+ ensure
52
+ execution.start
53
+ end
54
+
55
+ def after_teardown
56
+ execution = DiffTest::TestExecution.current
57
+
58
+ if execution.should_run?
59
+ if skipped?
60
+ execution.skipped!
61
+ elsif passed?
62
+ execution.passed!
63
+ else
64
+ execution.failed!
65
+ end
66
+ else
67
+ execution.not_run!
68
+ end
69
+ execution.stop
70
+ DiffTest::TestExecution.current = nil
71
+ super
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end