fixture_kit 0.3.0 → 0.4.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/README.md +37 -17
- data/lib/fixture_kit/cache.rb +16 -24
- data/lib/fixture_kit/configuration.rb +3 -17
- data/lib/fixture_kit/configuration_helper.rb +11 -0
- data/lib/fixture_kit/fixture.rb +4 -3
- data/lib/fixture_kit/isolators/minitest_isolator.rb +32 -0
- data/lib/fixture_kit/isolators/rspec_isolator.rb +33 -0
- data/lib/fixture_kit/minitest.rb +43 -0
- data/lib/fixture_kit/registry.rb +4 -3
- data/lib/fixture_kit/rspec.rb +4 -5
- data/lib/fixture_kit/runner.rb +6 -1
- data/lib/fixture_kit/singleton.rb +0 -4
- data/lib/fixture_kit/sql_subscriber.rb +4 -7
- data/lib/fixture_kit/version.rb +1 -1
- data/lib/fixture_kit.rb +14 -14
- metadata +6 -5
- data/lib/fixture_kit/rspec/isolator.rb +0 -45
- data/lib/fixture_kit/test_case/isolator.rb +0 -37
- data/lib/fixture_kit/test_case.rb +0 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b9c12d67129c3c71b587913a62cea49c41f55a7ab9c0f4308961906517f7b6f7
|
|
4
|
+
data.tar.gz: 92e5dec6ccdb3084d5b699fd1f462fb145667dd46caeb7f65aba8d782244bdbd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 75484ce7d299f78263f0c268a39eacb4c33896075b90138ed6741e253b95d312144ced9481ae2e7e6328a4b8817bf8e566c7d56df86975e236b2f2a248643376
|
|
7
|
+
data.tar.gz: c7644edbec83c88df2d5cc24a206ccabd4d3f1077a199fd2317c81e7e128801a58ed86738b229ed679b6ca3c1b979fe0f2b5adbf2334ed4ab16dbd2fa04b3ccf
|
data/README.md
CHANGED
|
@@ -119,22 +119,39 @@ end
|
|
|
119
119
|
|
|
120
120
|
When you call `fixture "name"` in an example group, FixtureKit registers that fixture with its runner.
|
|
121
121
|
|
|
122
|
+
### 4. Configure Minitest
|
|
123
|
+
|
|
124
|
+
```ruby
|
|
125
|
+
# test/test_helper.rb
|
|
126
|
+
require "fixture_kit/minitest"
|
|
127
|
+
|
|
128
|
+
class ActiveSupport::TestCase
|
|
129
|
+
self.use_transactional_tests = true
|
|
130
|
+
end
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
When you call `fixture "name"` in a test class, FixtureKit registers that fixture with its runner and mounts it during test setup.
|
|
134
|
+
|
|
122
135
|
## Configuration
|
|
123
136
|
|
|
124
137
|
```ruby
|
|
125
138
|
# spec/support/fixture_kit.rb
|
|
126
139
|
FixtureKit.configure do |config|
|
|
127
|
-
# Where fixture definitions live (default:
|
|
140
|
+
# Where fixture definitions live (default: fixture_kit).
|
|
141
|
+
# Framework entrypoints set a framework-specific default:
|
|
142
|
+
# - fixture_kit/rspec -> spec/fixture_kit
|
|
143
|
+
# - fixture_kit/minitest -> test/fixture_kit
|
|
128
144
|
config.fixture_path = Rails.root.join("spec/fixture_kit").to_s
|
|
129
145
|
|
|
130
146
|
# Where cache files are stored (default: tmp/cache/fixture_kit)
|
|
131
147
|
config.cache_path = Rails.root.join("tmp/cache/fixture_kit").to_s
|
|
132
148
|
|
|
133
|
-
# Wrapper used to isolate generation work (default: FixtureKit::
|
|
134
|
-
# config.isolator = FixtureKit::
|
|
135
|
-
# config.isolator = FixtureKit::
|
|
149
|
+
# Wrapper used to isolate generation work (default: FixtureKit::MinitestIsolator)
|
|
150
|
+
# config.isolator = FixtureKit::MinitestIsolator
|
|
151
|
+
# config.isolator = FixtureKit::RSpecIsolator
|
|
136
152
|
|
|
137
|
-
# Optional callback, called
|
|
153
|
+
# Optional callback, called right before a fixture cache is generated.
|
|
154
|
+
# Called on first generation and forced regeneration.
|
|
138
155
|
# Receives the fixture name as a String.
|
|
139
156
|
# config.on_cache = ->(fixture_name) { puts "cached #{fixture_name}" }
|
|
140
157
|
end
|
|
@@ -143,26 +160,29 @@ end
|
|
|
143
160
|
Custom isolators should subclass `FixtureKit::Isolator` and implement `#run`.
|
|
144
161
|
`#run` receives the generation block and should execute it in whatever lifecycle you need.
|
|
145
162
|
|
|
146
|
-
By default, FixtureKit uses `FixtureKit::
|
|
163
|
+
By default, FixtureKit uses `FixtureKit::MinitestIsolator`, which runs generation inside an internal `ActiveSupport::TestCase` and removes that harness case from minitest runnables.
|
|
147
164
|
|
|
148
|
-
When using `fixture_kit/rspec`, FixtureKit sets `FixtureKit::
|
|
165
|
+
When using `fixture_kit/rspec`, FixtureKit sets `FixtureKit::RSpecIsolator`. It runs generation inside an internal RSpec example, and uses a null reporter so harness runs do not count toward suite example totals.
|
|
149
166
|
|
|
150
167
|
## Lifecycle
|
|
151
168
|
|
|
152
169
|
Fixture generation is managed by `FixtureKit::Runner`.
|
|
153
170
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
1. `fixture "name"` registers the fixture with the runner during spec file load.
|
|
157
|
-
2. In `before(:suite)`, runner `start`:
|
|
171
|
+
1. Calling `fixture "name"` registers the fixture with the runner.
|
|
172
|
+
2. Runner `start`:
|
|
158
173
|
- clears `cache_path` (unless preserve-cache is enabled),
|
|
159
174
|
- generates caches for all already-registered fixtures.
|
|
160
|
-
3. If new
|
|
161
|
-
4. At
|
|
175
|
+
3. If new tests are loaded after start (for example, queue-mode CI runners), newly registered fixtures are cached immediately.
|
|
176
|
+
4. At test runtime, `fixture` mounts from cache and returns a `Repository`.
|
|
177
|
+
|
|
178
|
+
When runner start happens:
|
|
179
|
+
|
|
180
|
+
- `fixture_kit/rspec`: in `before(:suite)`.
|
|
181
|
+
- `fixture_kit/minitest`: lazily during test setup for the first test class that declares `fixture`.
|
|
162
182
|
|
|
163
183
|
### Preserving Cache Locally
|
|
164
184
|
|
|
165
|
-
If you want to skip cache clearing
|
|
185
|
+
If you want to skip cache clearing when the runner starts (e.g., to reuse caches across test runs during local development), set the `FIXTURE_KIT_PRESERVE_CACHE` environment variable:
|
|
166
186
|
|
|
167
187
|
```bash
|
|
168
188
|
FIXTURE_KIT_PRESERVE_CACHE=1 bundle exec rspec
|
|
@@ -189,13 +209,13 @@ fixture "teams/sales"
|
|
|
189
209
|
|
|
190
210
|
## How It Works
|
|
191
211
|
|
|
192
|
-
1. **Cache generation**: FixtureKit executes your definition block inside the configured isolator, subscribes to `sql.active_record` notifications to track
|
|
212
|
+
1. **Cache generation**: FixtureKit executes your definition block inside the configured isolator, subscribes to `sql.active_record` notifications to track created/updated/deleted models, queries those model tables, and caches INSERT statements for current table contents.
|
|
193
213
|
|
|
194
|
-
2. **Mounting**: FixtureKit loads the cached JSON file and executes the raw SQL INSERT statements directly. No ORM instantiation, no callbacks.
|
|
214
|
+
2. **Mounting**: FixtureKit loads the cached JSON file, clears each tracked table, and executes the raw SQL INSERT statements directly. No ORM instantiation, no callbacks.
|
|
195
215
|
|
|
196
216
|
3. **Repository build**: FixtureKit resolves exposed records by model + id and returns a `Repository` for method-based access.
|
|
197
217
|
|
|
198
|
-
4. **Transaction isolation**:
|
|
218
|
+
4. **Transaction isolation**: Use framework transactions (`use_transactional_fixtures` in RSpec, `use_transactional_tests` in Minitest) so test writes roll back and cached data can be reused safely between tests.
|
|
199
219
|
|
|
200
220
|
### Cache Format
|
|
201
221
|
|
data/lib/fixture_kit/cache.rb
CHANGED
|
@@ -7,6 +7,8 @@ require "active_support/inflector"
|
|
|
7
7
|
|
|
8
8
|
module FixtureKit
|
|
9
9
|
class Cache
|
|
10
|
+
include ConfigurationHelper
|
|
11
|
+
|
|
10
12
|
attr_reader :fixture
|
|
11
13
|
|
|
12
14
|
def initialize(fixture, definition)
|
|
@@ -15,7 +17,7 @@ module FixtureKit
|
|
|
15
17
|
end
|
|
16
18
|
|
|
17
19
|
def path
|
|
18
|
-
File.join(
|
|
20
|
+
File.join(configuration.cache_path, "#{fixture.name}.json")
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
def exists?
|
|
@@ -30,14 +32,19 @@ module FixtureKit
|
|
|
30
32
|
@data ||= JSON.parse(File.read(path))
|
|
31
33
|
@data.fetch("records").each do |model_name, sql|
|
|
32
34
|
model = ActiveSupport::Inflector.constantize(model_name)
|
|
33
|
-
model.connection
|
|
35
|
+
connection = model.connection
|
|
36
|
+
connection.disable_referential_integrity do
|
|
37
|
+
# execute_batch is private in current supported Rails versions.
|
|
38
|
+
# This should be revisited when Rails 8.2 makes it public.
|
|
39
|
+
connection.__send__(:execute_batch, [build_delete_sql(model), sql].compact, "FixtureKit Load")
|
|
40
|
+
end
|
|
34
41
|
end
|
|
35
42
|
|
|
36
43
|
build_repository(@data.fetch("exposed"))
|
|
37
44
|
end
|
|
38
45
|
|
|
39
46
|
def save
|
|
40
|
-
FixtureKit.
|
|
47
|
+
FixtureKit.runner.isolator.run do
|
|
41
48
|
models = SqlSubscriber.capture do
|
|
42
49
|
@definition.evaluate
|
|
43
50
|
end
|
|
@@ -88,37 +95,22 @@ module FixtureKit
|
|
|
88
95
|
rows << "(#{row_values.join(", ")})"
|
|
89
96
|
end
|
|
90
97
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
sql = build_insert_sql(model.table_name, columns, rows, model.connection)
|
|
98
|
+
sql = rows.empty? ? nil : build_insert_sql(model.table_name, columns, rows, model.connection)
|
|
94
99
|
statements_by_model[model.name] = sql
|
|
95
100
|
end
|
|
96
101
|
|
|
97
102
|
statements_by_model
|
|
98
103
|
end
|
|
99
104
|
|
|
105
|
+
def build_delete_sql(model)
|
|
106
|
+
"DELETE FROM #{model.quoted_table_name}"
|
|
107
|
+
end
|
|
108
|
+
|
|
100
109
|
def build_insert_sql(table_name, columns, rows, connection)
|
|
101
110
|
quoted_table = connection.quote_table_name(table_name)
|
|
102
111
|
quoted_columns = columns.map { |c| connection.quote_column_name(c) }
|
|
103
112
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
add_conflict_handling(sql, connection)
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def add_conflict_handling(sql, connection)
|
|
110
|
-
adapter_name = connection.adapter_name.downcase
|
|
111
|
-
|
|
112
|
-
case adapter_name
|
|
113
|
-
when /sqlite/
|
|
114
|
-
sql.sub(/\AINSERT INTO/i, "INSERT OR IGNORE INTO")
|
|
115
|
-
when /postgresql/, /postgis/
|
|
116
|
-
"#{sql} ON CONFLICT DO NOTHING"
|
|
117
|
-
when /mysql/, /trilogy/
|
|
118
|
-
sql.sub(/\AINSERT INTO/i, "INSERT IGNORE INTO")
|
|
119
|
-
else
|
|
120
|
-
sql
|
|
121
|
-
end
|
|
113
|
+
"INSERT INTO #{quoted_table} (#{quoted_columns.join(", ")}) VALUES #{rows.join(", ")}"
|
|
122
114
|
end
|
|
123
115
|
|
|
124
116
|
def build_exposed_mapping(exposed)
|
|
@@ -8,14 +8,14 @@ module FixtureKit
|
|
|
8
8
|
attr_accessor :on_cache
|
|
9
9
|
|
|
10
10
|
def initialize
|
|
11
|
-
@fixture_path =
|
|
11
|
+
@fixture_path = "fixture_kit"
|
|
12
12
|
@cache_path = nil
|
|
13
|
-
@isolator = FixtureKit::
|
|
13
|
+
@isolator = FixtureKit::MinitestIsolator
|
|
14
14
|
@on_cache = nil
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def fixture_path
|
|
18
|
-
@fixture_path
|
|
18
|
+
@fixture_path
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def cache_path
|
|
@@ -24,20 +24,6 @@ module FixtureKit
|
|
|
24
24
|
|
|
25
25
|
private
|
|
26
26
|
|
|
27
|
-
def detect_fixture_path
|
|
28
|
-
if defined?(RSpec)
|
|
29
|
-
"spec/fixture_kit"
|
|
30
|
-
elsif defined?(Minitest)
|
|
31
|
-
"test/fixture_kit"
|
|
32
|
-
elsif Dir.exist?("spec")
|
|
33
|
-
"spec/fixture_kit"
|
|
34
|
-
elsif Dir.exist?("test")
|
|
35
|
-
"test/fixture_kit"
|
|
36
|
-
else
|
|
37
|
-
"spec/fixture_kit"
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
27
|
def detect_cache_path
|
|
42
28
|
"tmp/cache/fixture_kit"
|
|
43
29
|
end
|
data/lib/fixture_kit/fixture.rb
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
module FixtureKit
|
|
4
4
|
class Fixture
|
|
5
|
+
include ConfigurationHelper
|
|
6
|
+
|
|
5
7
|
attr_reader :name, :path
|
|
6
8
|
|
|
7
9
|
def initialize(name, path)
|
|
@@ -11,11 +13,10 @@ module FixtureKit
|
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
def cache(force: false)
|
|
14
|
-
|
|
15
|
-
return if already_cached && !force
|
|
16
|
+
return if @cache.exists? && !force
|
|
16
17
|
|
|
18
|
+
configuration.on_cache&.call(name)
|
|
17
19
|
@cache.save
|
|
18
|
-
FixtureKit.configuration.on_cache&.call(name) unless already_cached
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
def mount
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/test_case"
|
|
4
|
+
require "active_record/fixtures"
|
|
5
|
+
|
|
6
|
+
module FixtureKit
|
|
7
|
+
class MinitestIsolator < FixtureKit::Isolator
|
|
8
|
+
TEST_NAME = "fixture kit cache pregeneration"
|
|
9
|
+
|
|
10
|
+
def run(&block)
|
|
11
|
+
test_class = build_test_class
|
|
12
|
+
test_method = test_class.test(TEST_NAME) do
|
|
13
|
+
block.call
|
|
14
|
+
pass
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
result = test_class.new(test_method).run
|
|
18
|
+
return if result.passed?
|
|
19
|
+
|
|
20
|
+
raise result.failures.first.error
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def build_test_class
|
|
26
|
+
Class.new(ActiveSupport::TestCase) do
|
|
27
|
+
::Minitest::Runnable.runnables.delete(self)
|
|
28
|
+
include(::ActiveRecord::TestFixtures)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FixtureKit
|
|
4
|
+
class RSpecIsolator < FixtureKit::Isolator
|
|
5
|
+
def run(&block)
|
|
6
|
+
previous_example = ::RSpec.current_example
|
|
7
|
+
previous_scope = ::RSpec.current_scope
|
|
8
|
+
example_group = build_example_group
|
|
9
|
+
example = example_group.example { block.call }
|
|
10
|
+
instance = example_group.new
|
|
11
|
+
succeeded =
|
|
12
|
+
begin
|
|
13
|
+
example.run(instance, ::RSpec::Core::NullReporter)
|
|
14
|
+
ensure
|
|
15
|
+
::RSpec.current_example = previous_example
|
|
16
|
+
::RSpec.current_scope = previous_scope
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
raise example.exception unless succeeded
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def build_example_group
|
|
25
|
+
::RSpec::Core::ExampleGroup.subclass(
|
|
26
|
+
::RSpec::Core::ExampleGroup,
|
|
27
|
+
"FixtureKit",
|
|
28
|
+
[],
|
|
29
|
+
[]
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fixture_kit"
|
|
4
|
+
require "active_support/lazy_load_hooks"
|
|
5
|
+
|
|
6
|
+
module FixtureKit
|
|
7
|
+
module Minitest
|
|
8
|
+
DECLARATION_CLASS_ATTRIBUTE = :fixture_kit_declaration
|
|
9
|
+
|
|
10
|
+
module ClassMethods
|
|
11
|
+
def fixture(name)
|
|
12
|
+
self.fixture_kit_declaration = FixtureKit.runner.register(name)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
module InstanceMethods
|
|
17
|
+
def fixture
|
|
18
|
+
@_fixture_kit_repository || raise("No fixture declared for this test class. Use `fixture \"name\"` in your test class.")
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.configure!(test_case)
|
|
23
|
+
FixtureKit.runner.configuration.fixture_path = "test/fixture_kit"
|
|
24
|
+
FixtureKit.runner.configuration.isolator = FixtureKit::MinitestIsolator
|
|
25
|
+
|
|
26
|
+
test_case.class_attribute DECLARATION_CLASS_ATTRIBUTE, instance_accessor: false
|
|
27
|
+
test_case.extend ClassMethods
|
|
28
|
+
test_case.include InstanceMethods
|
|
29
|
+
|
|
30
|
+
test_case.setup do
|
|
31
|
+
declaration = self.class.fixture_kit_declaration
|
|
32
|
+
next unless declaration
|
|
33
|
+
|
|
34
|
+
FixtureKit.runner.start unless FixtureKit.runner.started?
|
|
35
|
+
@_fixture_kit_repository = declaration.mount
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
ActiveSupport.on_load(:active_support_test_case) do
|
|
42
|
+
FixtureKit::Minitest.configure!(self)
|
|
43
|
+
end
|
data/lib/fixture_kit/registry.rb
CHANGED
|
@@ -4,8 +4,9 @@ require "pathname"
|
|
|
4
4
|
|
|
5
5
|
module FixtureKit
|
|
6
6
|
class Registry
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
include ConfigurationHelper
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
9
10
|
@registry = {}
|
|
10
11
|
end
|
|
11
12
|
|
|
@@ -28,7 +29,7 @@ module FixtureKit
|
|
|
28
29
|
private
|
|
29
30
|
|
|
30
31
|
def fixture_file_path(name)
|
|
31
|
-
File.expand_path(File.join(
|
|
32
|
+
File.expand_path(File.join(configuration.fixture_path, "#{name}.rb"))
|
|
32
33
|
end
|
|
33
34
|
end
|
|
34
35
|
end
|
data/lib/fixture_kit/rspec.rb
CHANGED
|
@@ -4,8 +4,6 @@ require "fixture_kit"
|
|
|
4
4
|
|
|
5
5
|
module FixtureKit
|
|
6
6
|
module RSpec
|
|
7
|
-
autoload :Isolator, File.expand_path("rspec/isolator", __dir__)
|
|
8
|
-
|
|
9
7
|
DECLARATION_METADATA_KEY = :fixture_kit_declaration
|
|
10
8
|
|
|
11
9
|
# Class methods (extended via config.extend)
|
|
@@ -39,13 +37,14 @@ module FixtureKit
|
|
|
39
37
|
# Returns the Repository for the current example's fixture.
|
|
40
38
|
# Access exposed records as methods: fixture.alice, fixture.posts
|
|
41
39
|
def fixture
|
|
42
|
-
@
|
|
40
|
+
@_fixture_kit_repository || raise("No fixture declared for this example group. Use `fixture \"name\"` in your describe/context block.")
|
|
43
41
|
end
|
|
44
42
|
end
|
|
45
43
|
|
|
46
44
|
def self.configure!(config)
|
|
45
|
+
FixtureKit.runner.configuration.fixture_path = "spec/fixture_kit"
|
|
47
46
|
config.add_setting(:fixture_kit, default: FixtureKit.runner)
|
|
48
|
-
FixtureKit.configuration.isolator =
|
|
47
|
+
FixtureKit.runner.configuration.isolator = FixtureKit::RSpecIsolator
|
|
49
48
|
|
|
50
49
|
config.extend ClassMethods
|
|
51
50
|
config.include InstanceMethods, DECLARATION_METADATA_KEY
|
|
@@ -53,7 +52,7 @@ module FixtureKit
|
|
|
53
52
|
# Load declared fixtures at the beginning of each example.
|
|
54
53
|
# Runs inside transactional fixtures and before user-defined before hooks.
|
|
55
54
|
config.prepend_before(:example, DECLARATION_METADATA_KEY) do |example|
|
|
56
|
-
@
|
|
55
|
+
@_fixture_kit_repository = example.metadata[DECLARATION_METADATA_KEY].mount
|
|
57
56
|
end
|
|
58
57
|
|
|
59
58
|
config.append_before(:suite) do
|
data/lib/fixture_kit/runner.rb
CHANGED
|
@@ -10,7 +10,8 @@ module FixtureKit
|
|
|
10
10
|
|
|
11
11
|
def initialize
|
|
12
12
|
@configuration = Configuration.new
|
|
13
|
-
@registry = Registry.new
|
|
13
|
+
@registry = Registry.new
|
|
14
|
+
@isolator = nil
|
|
14
15
|
@started = false
|
|
15
16
|
end
|
|
16
17
|
|
|
@@ -28,6 +29,10 @@ module FixtureKit
|
|
|
28
29
|
registry.fixtures.each(&:cache)
|
|
29
30
|
end
|
|
30
31
|
|
|
32
|
+
def isolator
|
|
33
|
+
@isolator ||= configuration.isolator.new
|
|
34
|
+
end
|
|
35
|
+
|
|
31
36
|
def started?
|
|
32
37
|
@started
|
|
33
38
|
end
|
|
@@ -6,18 +6,15 @@ require "active_support/inflector"
|
|
|
6
6
|
module FixtureKit
|
|
7
7
|
class SqlSubscriber
|
|
8
8
|
EVENT = "sql.active_record"
|
|
9
|
+
NAME_PATTERN = /\A(?<model_name>.+?) (?:(?:Bulk )?(?:Insert|Upsert)|Create|Destroy|(?:Update|Delete)(?: All)?)\z/
|
|
9
10
|
|
|
10
11
|
def self.capture(&block)
|
|
11
12
|
models = Set.new
|
|
12
13
|
subscriber = lambda do |_event_name, _start, _finish, _id, payload|
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
name = payload[:name].to_s
|
|
15
|
+
model_name = name[NAME_PATTERN, :model_name]
|
|
16
|
+
next unless model_name
|
|
15
17
|
|
|
16
|
-
# payload[:name] is like "User Create" - extract model name
|
|
17
|
-
name = payload[:name]
|
|
18
|
-
next unless name&.end_with?(" Create")
|
|
19
|
-
|
|
20
|
-
model_name = name.sub(/ Create\z/, "")
|
|
21
18
|
models.add(ActiveSupport::Inflector.constantize(model_name))
|
|
22
19
|
end
|
|
23
20
|
|
data/lib/fixture_kit/version.rb
CHANGED
data/lib/fixture_kit.rb
CHANGED
|
@@ -2,26 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
module FixtureKit
|
|
4
4
|
class Error < StandardError; end
|
|
5
|
-
class DuplicateFixtureError < Error; end
|
|
6
5
|
class DuplicateNameError < Error; end
|
|
7
6
|
class CacheMissingError < Error; end
|
|
8
|
-
class PregenerationError < Error; end
|
|
9
7
|
class FixtureDefinitionNotFound < Error; end
|
|
10
8
|
class ExposedRecordNotFound < Error; end
|
|
11
9
|
class RunnerAlreadyStartedError < Error; end
|
|
12
10
|
|
|
13
|
-
autoload :VERSION,
|
|
14
|
-
autoload :Configuration,
|
|
15
|
-
autoload :
|
|
16
|
-
autoload :
|
|
17
|
-
autoload :
|
|
18
|
-
autoload :
|
|
19
|
-
autoload :
|
|
20
|
-
autoload :
|
|
21
|
-
autoload :
|
|
22
|
-
autoload :
|
|
23
|
-
autoload :
|
|
24
|
-
autoload :
|
|
11
|
+
autoload :VERSION, File.expand_path("fixture_kit/version", __dir__)
|
|
12
|
+
autoload :Configuration, File.expand_path("fixture_kit/configuration", __dir__)
|
|
13
|
+
autoload :ConfigurationHelper, File.expand_path("fixture_kit/configuration_helper", __dir__)
|
|
14
|
+
autoload :Singleton, File.expand_path("fixture_kit/singleton", __dir__)
|
|
15
|
+
autoload :Fixture, File.expand_path("fixture_kit/fixture", __dir__)
|
|
16
|
+
autoload :Definition, File.expand_path("fixture_kit/definition", __dir__)
|
|
17
|
+
autoload :Registry, File.expand_path("fixture_kit/registry", __dir__)
|
|
18
|
+
autoload :Repository, File.expand_path("fixture_kit/repository", __dir__)
|
|
19
|
+
autoload :SqlSubscriber, File.expand_path("fixture_kit/sql_subscriber", __dir__)
|
|
20
|
+
autoload :Cache, File.expand_path("fixture_kit/cache", __dir__)
|
|
21
|
+
autoload :Runner, File.expand_path("fixture_kit/runner", __dir__)
|
|
22
|
+
autoload :Isolator, File.expand_path("fixture_kit/isolator", __dir__)
|
|
23
|
+
autoload :MinitestIsolator, File.expand_path("fixture_kit/isolators/minitest_isolator", __dir__)
|
|
24
|
+
autoload :RSpecIsolator, File.expand_path("fixture_kit/isolators/rspec_isolator", __dir__)
|
|
25
25
|
|
|
26
26
|
extend Singleton
|
|
27
27
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fixture_kit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ngan Pham
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-02-
|
|
11
|
+
date: 2026-02-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -136,18 +136,19 @@ files:
|
|
|
136
136
|
- lib/fixture_kit.rb
|
|
137
137
|
- lib/fixture_kit/cache.rb
|
|
138
138
|
- lib/fixture_kit/configuration.rb
|
|
139
|
+
- lib/fixture_kit/configuration_helper.rb
|
|
139
140
|
- lib/fixture_kit/definition.rb
|
|
140
141
|
- lib/fixture_kit/fixture.rb
|
|
141
142
|
- lib/fixture_kit/isolator.rb
|
|
143
|
+
- lib/fixture_kit/isolators/minitest_isolator.rb
|
|
144
|
+
- lib/fixture_kit/isolators/rspec_isolator.rb
|
|
145
|
+
- lib/fixture_kit/minitest.rb
|
|
142
146
|
- lib/fixture_kit/registry.rb
|
|
143
147
|
- lib/fixture_kit/repository.rb
|
|
144
148
|
- lib/fixture_kit/rspec.rb
|
|
145
|
-
- lib/fixture_kit/rspec/isolator.rb
|
|
146
149
|
- lib/fixture_kit/runner.rb
|
|
147
150
|
- lib/fixture_kit/singleton.rb
|
|
148
151
|
- lib/fixture_kit/sql_subscriber.rb
|
|
149
|
-
- lib/fixture_kit/test_case.rb
|
|
150
|
-
- lib/fixture_kit/test_case/isolator.rb
|
|
151
152
|
- lib/fixture_kit/version.rb
|
|
152
153
|
homepage: https://github.com/Gusto/fixture_kit
|
|
153
154
|
licenses:
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module FixtureKit
|
|
4
|
-
module RSpec
|
|
5
|
-
class Isolator < FixtureKit::Isolator
|
|
6
|
-
def run(&block)
|
|
7
|
-
previous_example = ::RSpec.current_example
|
|
8
|
-
previous_scope = ::RSpec.current_scope
|
|
9
|
-
example_group = build_example_group
|
|
10
|
-
example = build_example(example_group, &block)
|
|
11
|
-
instance = example_group.new(example.inspect_output)
|
|
12
|
-
succeeded =
|
|
13
|
-
begin
|
|
14
|
-
example.run(instance, ::RSpec::Core::NullReporter)
|
|
15
|
-
ensure
|
|
16
|
-
example_group.remove_example(example)
|
|
17
|
-
::RSpec.current_example = previous_example
|
|
18
|
-
::RSpec.current_scope = previous_scope
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
unless succeeded
|
|
22
|
-
raise example.exception if example.exception
|
|
23
|
-
raise FixtureKit::PregenerationError, "FixtureKit pregeneration failed"
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
private
|
|
28
|
-
|
|
29
|
-
def build_example(example_group, &block)
|
|
30
|
-
example_group.example(
|
|
31
|
-
"FixtureKit cache pregeneration"
|
|
32
|
-
) { block.call }
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def build_example_group
|
|
36
|
-
::RSpec::Core::ExampleGroup.subclass(
|
|
37
|
-
::RSpec::Core::ExampleGroup,
|
|
38
|
-
"FixtureKit::RSpec::Isolator",
|
|
39
|
-
[],
|
|
40
|
-
[]
|
|
41
|
-
)
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "active_support/test_case"
|
|
4
|
-
require "active_record/fixtures"
|
|
5
|
-
|
|
6
|
-
module FixtureKit
|
|
7
|
-
module TestCase
|
|
8
|
-
class Isolator < FixtureKit::Isolator
|
|
9
|
-
TEST_METHOD_NAME = "test_fixture_kit_cache_pregeneration"
|
|
10
|
-
|
|
11
|
-
def run(&block)
|
|
12
|
-
result = build_test_class(&block).run
|
|
13
|
-
return if result.passed?
|
|
14
|
-
|
|
15
|
-
failure = result.failures.first
|
|
16
|
-
raise failure.error if failure.respond_to?(:error)
|
|
17
|
-
raise failure if failure
|
|
18
|
-
|
|
19
|
-
raise FixtureKit::PregenerationError, "FixtureKit pregeneration failed"
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
private
|
|
23
|
-
|
|
24
|
-
def build_test_class(&block)
|
|
25
|
-
Class.new(ActiveSupport::TestCase) do
|
|
26
|
-
::Minitest::Runnable.runnables.delete(self)
|
|
27
|
-
include(::ActiveRecord::TestFixtures)
|
|
28
|
-
|
|
29
|
-
define_method(TEST_METHOD_NAME) do
|
|
30
|
-
block.call
|
|
31
|
-
pass
|
|
32
|
-
end
|
|
33
|
-
end.new(TEST_METHOD_NAME)
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|