fixture_kit 0.1.1 → 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.
- checksums.yaml +4 -4
- data/README.md +14 -1
- data/lib/fixture_kit/{fixture_cache.rb → cache.rb} +15 -15
- data/lib/fixture_kit/configuration.rb +2 -0
- data/lib/fixture_kit/{fixture_context.rb → definition_context.rb} +1 -1
- data/lib/fixture_kit/fixture.rb +2 -2
- data/lib/fixture_kit/generator.rb +14 -0
- data/lib/fixture_kit/registry.rb +58 -0
- data/lib/fixture_kit/{fixture_set.rb → repository.rb} +1 -1
- data/lib/fixture_kit/rspec/declaration.rb +17 -0
- data/lib/fixture_kit/rspec/generator.rb +45 -0
- data/lib/fixture_kit/rspec.rb +45 -22
- data/lib/fixture_kit/{fixture_runner.rb → runner.rb} +16 -26
- data/lib/fixture_kit/singleton.rb +4 -5
- data/lib/fixture_kit/test_case/generator.rb +37 -0
- data/lib/fixture_kit/test_case.rb +7 -0
- data/lib/fixture_kit/version.rb +1 -1
- data/lib/fixture_kit.rb +9 -6
- metadata +12 -8
- data/lib/fixture_kit/fixture_registry.rb +0 -54
- data/lib/fixture_kit/transactional_harness.rb +0 -29
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 311fd09f37153fae9d8a09e3e41357c38f18e1e343794a758ae943dfdca3c40a
|
|
4
|
+
data.tar.gz: ee4257fc3c840f809a25204f300c766f872688c5c7417dc22155f001ba424882
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bd8c58de66c08eeceab67e4f0b83a8a95d25291401272e96b51725db2b7a9f2b2592c24f1d6f6cb7b4f6b4716fa93fc768c4fc81afcf1974b9339e14b1b61fa9
|
|
7
|
+
data.tar.gz: 8d335927771e40d35142a69ee9bf911fcfb6c660af6cde28269a16643e86a468c017cf2f54e362f09d90a78bfeffe6320071d0230f6240969fc495de0e91c8f2
|
data/README.md
CHANGED
|
@@ -104,6 +104,8 @@ RSpec.describe Book do
|
|
|
104
104
|
end
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
+
`fixture` returns a `Repository` and exposes records as methods (for example, `fixture.owner`).
|
|
108
|
+
|
|
107
109
|
### 3. Configure RSpec
|
|
108
110
|
|
|
109
111
|
```ruby
|
|
@@ -128,14 +130,25 @@ FixtureKit.configure do |config|
|
|
|
128
130
|
|
|
129
131
|
# Whether to regenerate caches on every run (default: true)
|
|
130
132
|
config.autogenerate = true
|
|
133
|
+
|
|
134
|
+
# Optional: customize how pregeneration is wrapped.
|
|
135
|
+
# Default is FixtureKit::TestCase::Generator.
|
|
136
|
+
# config.generator = FixtureKit::TestCase::Generator
|
|
131
137
|
end
|
|
132
138
|
```
|
|
133
139
|
|
|
140
|
+
Custom generators should subclass `FixtureKit::Generator` and implement `#run`.
|
|
141
|
+
`#run` receives the pregeneration block and should execute it in whatever lifecycle you need.
|
|
142
|
+
|
|
134
143
|
### Autogenerate
|
|
135
144
|
|
|
136
145
|
When `autogenerate` is `true` (the default), FixtureKit clears all caches at the start of each test run, then regenerates them on first use. Subsequent tests that use the same fixture reuse the cache from earlier in the run. This ensures your test data always matches your fixture definitions.
|
|
137
146
|
|
|
138
|
-
When `autogenerate` is `false`, FixtureKit pre-generates all fixture caches at suite start. This
|
|
147
|
+
When `autogenerate` is `false`, FixtureKit pre-generates all fixture caches at suite start. This runs through the configured `generator`, and still rolls back database changes.
|
|
148
|
+
|
|
149
|
+
By default, FixtureKit uses `FixtureKit::TestCase::Generator`, which runs pregeneration inside an internal `ActiveSupport::TestCase` so setup/teardown hooks and transactional fixture behavior run as expected. The internal test case is removed from Minitest runnables, so it does not count toward suite totals.
|
|
150
|
+
|
|
151
|
+
When using `fixture_kit/rspec`, FixtureKit sets `FixtureKit::RSpec::Generator` as the generator. This runs pregeneration inside an internal RSpec example so your normal `before`/`around`/`after` hooks apply. The internal example uses a null reporter, so it does not count toward suite example totals.
|
|
139
152
|
|
|
140
153
|
### Preserving Cache Locally
|
|
141
154
|
|
|
@@ -6,7 +6,7 @@ require "active_support/core_ext/array/wrap"
|
|
|
6
6
|
require "active_support/inflector"
|
|
7
7
|
|
|
8
8
|
module FixtureKit
|
|
9
|
-
class
|
|
9
|
+
class Cache
|
|
10
10
|
# In-memory cache to avoid re-reading/parsing JSON for every test
|
|
11
11
|
@memory_cache = {}
|
|
12
12
|
|
|
@@ -15,7 +15,7 @@ module FixtureKit
|
|
|
15
15
|
|
|
16
16
|
def clear_memory_cache(fixture_name = nil)
|
|
17
17
|
if fixture_name
|
|
18
|
-
@memory_cache.delete(fixture_name
|
|
18
|
+
@memory_cache.delete(fixture_name)
|
|
19
19
|
else
|
|
20
20
|
@memory_cache.clear
|
|
21
21
|
end
|
|
@@ -34,18 +34,18 @@ module FixtureKit
|
|
|
34
34
|
end
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
#
|
|
37
|
+
# Generate caches for all fixtures.
|
|
38
38
|
# Each fixture is generated in a transaction that rolls back, so no data persists.
|
|
39
|
-
def
|
|
40
|
-
|
|
39
|
+
def generate_all
|
|
40
|
+
Registry.load_definitions
|
|
41
|
+
Registry.fixtures.each { |fixture| generate(fixture.name) }
|
|
42
|
+
end
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
def generate(fixture_name)
|
|
45
|
+
clear(fixture_name)
|
|
44
46
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
runner = FixtureRunner.new(name)
|
|
48
|
-
runner.generate_cache_only
|
|
47
|
+
FixtureKit.configuration.generator.run do
|
|
48
|
+
Runner.run(fixture_name, force: true)
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
51
|
end
|
|
@@ -53,7 +53,7 @@ module FixtureKit
|
|
|
53
53
|
attr_reader :records, :exposed
|
|
54
54
|
|
|
55
55
|
def initialize(fixture_name)
|
|
56
|
-
@fixture_name = fixture_name
|
|
56
|
+
@fixture_name = fixture_name
|
|
57
57
|
@records = {}
|
|
58
58
|
@exposed = {}
|
|
59
59
|
end
|
|
@@ -107,15 +107,15 @@ module FixtureKit
|
|
|
107
107
|
File.write(cache_file_path, JSON.pretty_generate(data))
|
|
108
108
|
end
|
|
109
109
|
|
|
110
|
-
# Query exposed records from the database and return a
|
|
111
|
-
def
|
|
110
|
+
# Query exposed records from the database and return a Repository.
|
|
111
|
+
def build_repository
|
|
112
112
|
exposed_records = @exposed.each_with_object({}) do |(name, value), hash|
|
|
113
113
|
was_array = value.is_a?(Array)
|
|
114
114
|
records = Array.wrap(value).map { |record_info| find_exposed_record(record_info.fetch("model"), record_info.fetch("id"), name) }
|
|
115
115
|
hash[name.to_sym] = was_array ? records : records.first
|
|
116
116
|
end
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
Repository.new(exposed_records)
|
|
119
119
|
end
|
|
120
120
|
|
|
121
121
|
private
|
|
@@ -4,11 +4,13 @@ module FixtureKit
|
|
|
4
4
|
class Configuration
|
|
5
5
|
attr_writer :fixture_path
|
|
6
6
|
attr_writer :cache_path
|
|
7
|
+
attr_accessor :generator
|
|
7
8
|
attr_accessor :autogenerate
|
|
8
9
|
|
|
9
10
|
def initialize
|
|
10
11
|
@fixture_path = nil
|
|
11
12
|
@cache_path = nil
|
|
13
|
+
@generator = FixtureKit::TestCase::Generator
|
|
12
14
|
@autogenerate = true
|
|
13
15
|
end
|
|
14
16
|
|
data/lib/fixture_kit/fixture.rb
CHANGED
|
@@ -5,12 +5,12 @@ module FixtureKit
|
|
|
5
5
|
attr_reader :name, :block
|
|
6
6
|
|
|
7
7
|
def initialize(name, &block)
|
|
8
|
-
@name = name
|
|
8
|
+
@name = name
|
|
9
9
|
@block = block
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def execute
|
|
13
|
-
context =
|
|
13
|
+
context = DefinitionContext.new
|
|
14
14
|
context.instance_eval(&block) if block
|
|
15
15
|
context.exposed
|
|
16
16
|
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FixtureKit
|
|
4
|
+
# Base class for fixture cache generators.
|
|
5
|
+
class Generator
|
|
6
|
+
def self.run(&block)
|
|
7
|
+
new.run(&block)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def run
|
|
11
|
+
raise NotImplementedError, "#{self.class} must implement #run"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FixtureKit
|
|
4
|
+
module Registry
|
|
5
|
+
class << self
|
|
6
|
+
def fetch(name)
|
|
7
|
+
fixture = find(name)
|
|
8
|
+
return fixture if fixture
|
|
9
|
+
|
|
10
|
+
file_path = fixture_file_path(name)
|
|
11
|
+
unless File.file?(file_path)
|
|
12
|
+
raise FixtureKit::FixtureDefinitionNotFound,
|
|
13
|
+
"Could not find fixture definition file for '#{name}' at '#{file_path}'"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
load file_path
|
|
17
|
+
find(name)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def find(name)
|
|
21
|
+
registry[name]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def fixtures
|
|
25
|
+
registry.values
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def register(fixture)
|
|
29
|
+
registry[fixture.name] = fixture
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Load all fixture definition files.
|
|
33
|
+
# Uses `load` instead of `require` to ensure fixtures are registered
|
|
34
|
+
# even if the files were previously required (e.g., after a reset).
|
|
35
|
+
def load_definitions
|
|
36
|
+
fixture_path = FixtureKit.configuration.fixture_path
|
|
37
|
+
Dir.glob(File.join(fixture_path, "**/*.rb")).each do |file|
|
|
38
|
+
load file
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def reset
|
|
43
|
+
@registry = nil
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def fixture_file_path(name)
|
|
49
|
+
fixture_path = FixtureKit.configuration.fixture_path
|
|
50
|
+
File.expand_path(File.join(fixture_path, "#{name}.rb"))
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def registry
|
|
54
|
+
@registry ||= {}
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FixtureKit
|
|
4
|
+
module RSpec
|
|
5
|
+
class Generator < FixtureKit::Generator
|
|
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::Generator",
|
|
39
|
+
[],
|
|
40
|
+
[]
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
data/lib/fixture_kit/rspec.rb
CHANGED
|
@@ -4,6 +4,12 @@ require "fixture_kit"
|
|
|
4
4
|
|
|
5
5
|
module FixtureKit
|
|
6
6
|
module RSpec
|
|
7
|
+
autoload :Declaration, File.expand_path("rspec/declaration", __dir__)
|
|
8
|
+
autoload :Generator, File.expand_path("rspec/generator", __dir__)
|
|
9
|
+
|
|
10
|
+
DECLARATION_METADATA_KEY = :fixture_kit_declaration
|
|
11
|
+
PRESERVE_CACHE_ENV_KEY = "FIXTURE_KIT_PRESERVE_CACHE"
|
|
12
|
+
|
|
7
13
|
# Class methods (extended via config.extend)
|
|
8
14
|
module ClassMethods
|
|
9
15
|
# Declare which fixture to use for this example group.
|
|
@@ -26,40 +32,57 @@ module FixtureKit
|
|
|
26
32
|
# end
|
|
27
33
|
# end
|
|
28
34
|
def fixture(name)
|
|
29
|
-
metadata[
|
|
35
|
+
metadata[DECLARATION_METADATA_KEY] = Declaration.new(name)
|
|
30
36
|
end
|
|
31
37
|
end
|
|
32
38
|
|
|
33
39
|
# Instance methods (included via config.include)
|
|
34
40
|
module InstanceMethods
|
|
35
|
-
# Returns the
|
|
41
|
+
# Returns the Repository for the current example's fixture.
|
|
36
42
|
# Access exposed records as methods: fixture.alice, fixture.posts
|
|
37
43
|
def fixture
|
|
38
|
-
@
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
@_fixture_kit_fixture_set || raise("No fixture declared for this example group. Use `fixture \"name\"` in your describe/context block.")
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.configure!(config)
|
|
49
|
+
FixtureKit.configuration.generator = Generator
|
|
50
|
+
config.extend ClassMethods
|
|
51
|
+
config.include InstanceMethods
|
|
52
|
+
|
|
53
|
+
# Load declared fixtures at the beginning of each example.
|
|
54
|
+
# Runs inside transactional fixtures and before user-defined before hooks.
|
|
55
|
+
config.prepend_before(:example, DECLARATION_METADATA_KEY) do |example|
|
|
56
|
+
declaration = example.metadata[DECLARATION_METADATA_KEY]
|
|
57
|
+
@_fixture_kit_fixture_set = declaration.fixture_set
|
|
58
|
+
end
|
|
41
59
|
|
|
42
|
-
|
|
60
|
+
# Setup caches at suite start only when at least one fixture-backed
|
|
61
|
+
# example exists in the loaded suite.
|
|
62
|
+
config.when_first_matching_example_defined(DECLARATION_METADATA_KEY) do
|
|
63
|
+
config.before(:suite) do
|
|
64
|
+
if FixtureKit.configuration.autogenerate
|
|
65
|
+
preserve_cache = ENV[PRESERVE_CACHE_ENV_KEY].to_s.match?(/\A(1|true|yes)\z/i)
|
|
66
|
+
Cache.clear unless preserve_cache
|
|
67
|
+
else
|
|
68
|
+
fixture_names_for_loaded_examples.each do |fixture_name|
|
|
69
|
+
Cache.generate(fixture_name)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
43
72
|
end
|
|
44
73
|
end
|
|
45
74
|
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# Configure RSpec integration
|
|
50
|
-
RSpec.configure do |config|
|
|
51
|
-
config.extend FixtureKit::RSpec::ClassMethods
|
|
52
|
-
config.include FixtureKit::RSpec::InstanceMethods
|
|
53
75
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
else
|
|
62
|
-
FixtureKit::FixtureCache.pregenerate_all
|
|
76
|
+
def self.fixture_names_for_loaded_examples
|
|
77
|
+
::RSpec.world.filtered_examples.each_value.with_object(Set.new) do |examples, names|
|
|
78
|
+
examples.each do |example|
|
|
79
|
+
declaration = example.metadata[DECLARATION_METADATA_KEY]
|
|
80
|
+
names << declaration.name if declaration
|
|
81
|
+
end
|
|
82
|
+
end.to_a
|
|
63
83
|
end
|
|
64
84
|
end
|
|
65
85
|
end
|
|
86
|
+
|
|
87
|
+
# Configure RSpec integration
|
|
88
|
+
FixtureKit::RSpec.configure!(RSpec.configuration)
|
|
@@ -3,14 +3,20 @@
|
|
|
3
3
|
require "active_support/inflector"
|
|
4
4
|
|
|
5
5
|
module FixtureKit
|
|
6
|
-
class
|
|
6
|
+
class Runner
|
|
7
|
+
def self.run(fixture_name, force: false)
|
|
8
|
+
new(fixture_name).run(force: force)
|
|
9
|
+
end
|
|
10
|
+
|
|
7
11
|
def initialize(fixture_name)
|
|
8
|
-
@fixture_name = fixture_name
|
|
9
|
-
@cache =
|
|
12
|
+
@fixture_name = fixture_name
|
|
13
|
+
@cache = Cache.new(@fixture_name)
|
|
10
14
|
end
|
|
11
15
|
|
|
12
|
-
def run
|
|
13
|
-
if
|
|
16
|
+
def run(force: false)
|
|
17
|
+
if force
|
|
18
|
+
execute_and_cache
|
|
19
|
+
elsif @cache.exists?
|
|
14
20
|
execute_from_cache
|
|
15
21
|
elsif FixtureKit.configuration.autogenerate
|
|
16
22
|
execute_and_cache
|
|
@@ -26,26 +32,10 @@ module FixtureKit
|
|
|
26
32
|
end
|
|
27
33
|
end
|
|
28
34
|
|
|
29
|
-
# Generate cache only (used for pregeneration in before(:suite))
|
|
30
|
-
# Wraps execution in ActiveRecord::TestFixtures transactional lifecycle,
|
|
31
|
-
# so no data persists across configured writing pools.
|
|
32
|
-
# Always regenerates the cache, even if one exists
|
|
33
|
-
def generate_cache_only
|
|
34
|
-
# Clear any existing cache for this fixture
|
|
35
|
-
FixtureCache.clear(@fixture_name.to_s)
|
|
36
|
-
|
|
37
|
-
FixtureKit::TransactionalHarness.run do
|
|
38
|
-
execute_and_cache
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
true
|
|
42
|
-
end
|
|
43
|
-
|
|
44
35
|
private
|
|
45
36
|
|
|
46
37
|
def execute_and_cache
|
|
47
|
-
fixture =
|
|
48
|
-
raise ArgumentError, "Fixture '#{@fixture_name}' not found" unless fixture
|
|
38
|
+
fixture = Registry.fetch(@fixture_name)
|
|
49
39
|
|
|
50
40
|
# Start capturing SQL
|
|
51
41
|
capture = SqlCapture.new
|
|
@@ -63,8 +53,8 @@ module FixtureKit
|
|
|
63
53
|
exposed_mapping: build_exposed_mapping(exposed)
|
|
64
54
|
)
|
|
65
55
|
|
|
66
|
-
# Return
|
|
67
|
-
|
|
56
|
+
# Return Repository from the exposed records
|
|
57
|
+
Repository.new(exposed)
|
|
68
58
|
end
|
|
69
59
|
|
|
70
60
|
def execute_from_cache
|
|
@@ -79,8 +69,8 @@ module FixtureKit
|
|
|
79
69
|
connection.execute(sql)
|
|
80
70
|
end
|
|
81
71
|
|
|
82
|
-
# Query exposed records and build
|
|
83
|
-
@cache.
|
|
72
|
+
# Query exposed records and build Repository.
|
|
73
|
+
@cache.build_repository
|
|
84
74
|
end
|
|
85
75
|
|
|
86
76
|
def build_exposed_mapping(exposed)
|
|
@@ -5,8 +5,7 @@ require "pathname"
|
|
|
5
5
|
module FixtureKit
|
|
6
6
|
module Singleton
|
|
7
7
|
def configure
|
|
8
|
-
|
|
9
|
-
yield(@configuration) if block_given?
|
|
8
|
+
yield(configuration) if block_given?
|
|
10
9
|
self
|
|
11
10
|
end
|
|
12
11
|
|
|
@@ -23,14 +22,14 @@ module FixtureKit
|
|
|
23
22
|
name = relative_path.to_s.sub(/\.rb$/, "")
|
|
24
23
|
|
|
25
24
|
fixture = Fixture.new(name, &block)
|
|
26
|
-
|
|
25
|
+
Registry.register(fixture)
|
|
27
26
|
fixture
|
|
28
27
|
end
|
|
29
28
|
|
|
30
29
|
def reset
|
|
31
30
|
@configuration = nil
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
Registry.reset
|
|
32
|
+
Cache.clear_memory_cache
|
|
34
33
|
end
|
|
35
34
|
end
|
|
36
35
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
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 Generator < FixtureKit::Generator
|
|
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
|
data/lib/fixture_kit/version.rb
CHANGED
data/lib/fixture_kit.rb
CHANGED
|
@@ -5,19 +5,22 @@ module FixtureKit
|
|
|
5
5
|
class DuplicateFixtureError < Error; end
|
|
6
6
|
class DuplicateNameError < Error; end
|
|
7
7
|
class CacheMissingError < Error; end
|
|
8
|
+
class PregenerationError < Error; end
|
|
9
|
+
class FixtureDefinitionNotFound < Error; end
|
|
8
10
|
class ExposedRecordNotFound < Error; end
|
|
9
11
|
|
|
10
12
|
autoload :VERSION, File.expand_path("fixture_kit/version", __dir__)
|
|
11
13
|
autoload :Configuration, File.expand_path("fixture_kit/configuration", __dir__)
|
|
12
14
|
autoload :Singleton, File.expand_path("fixture_kit/singleton", __dir__)
|
|
13
15
|
autoload :Fixture, File.expand_path("fixture_kit/fixture", __dir__)
|
|
14
|
-
autoload :
|
|
15
|
-
autoload :
|
|
16
|
-
autoload :
|
|
16
|
+
autoload :DefinitionContext, File.expand_path("fixture_kit/definition_context", __dir__)
|
|
17
|
+
autoload :Registry, File.expand_path("fixture_kit/registry", __dir__)
|
|
18
|
+
autoload :Repository, File.expand_path("fixture_kit/repository", __dir__)
|
|
17
19
|
autoload :SqlCapture, File.expand_path("fixture_kit/sql_capture", __dir__)
|
|
18
|
-
autoload :
|
|
19
|
-
autoload :
|
|
20
|
-
autoload :
|
|
20
|
+
autoload :Cache, File.expand_path("fixture_kit/cache", __dir__)
|
|
21
|
+
autoload :Runner, File.expand_path("fixture_kit/runner", __dir__)
|
|
22
|
+
autoload :Generator, File.expand_path("fixture_kit/generator", __dir__)
|
|
23
|
+
autoload :TestCase, File.expand_path("fixture_kit/test_case", __dir__)
|
|
21
24
|
|
|
22
25
|
extend Singleton
|
|
23
26
|
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.2.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-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -134,17 +134,21 @@ files:
|
|
|
134
134
|
- LICENSE
|
|
135
135
|
- README.md
|
|
136
136
|
- lib/fixture_kit.rb
|
|
137
|
+
- lib/fixture_kit/cache.rb
|
|
137
138
|
- lib/fixture_kit/configuration.rb
|
|
139
|
+
- lib/fixture_kit/definition_context.rb
|
|
138
140
|
- lib/fixture_kit/fixture.rb
|
|
139
|
-
- lib/fixture_kit/
|
|
140
|
-
- lib/fixture_kit/
|
|
141
|
-
- lib/fixture_kit/
|
|
142
|
-
- lib/fixture_kit/fixture_runner.rb
|
|
143
|
-
- lib/fixture_kit/fixture_set.rb
|
|
141
|
+
- lib/fixture_kit/generator.rb
|
|
142
|
+
- lib/fixture_kit/registry.rb
|
|
143
|
+
- lib/fixture_kit/repository.rb
|
|
144
144
|
- lib/fixture_kit/rspec.rb
|
|
145
|
+
- lib/fixture_kit/rspec/declaration.rb
|
|
146
|
+
- lib/fixture_kit/rspec/generator.rb
|
|
147
|
+
- lib/fixture_kit/runner.rb
|
|
145
148
|
- lib/fixture_kit/singleton.rb
|
|
146
149
|
- lib/fixture_kit/sql_capture.rb
|
|
147
|
-
- lib/fixture_kit/
|
|
150
|
+
- lib/fixture_kit/test_case.rb
|
|
151
|
+
- lib/fixture_kit/test_case/generator.rb
|
|
148
152
|
- lib/fixture_kit/version.rb
|
|
149
153
|
homepage: https://github.com/Gusto/fixture_kit
|
|
150
154
|
licenses:
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module FixtureKit
|
|
4
|
-
module FixtureRegistry
|
|
5
|
-
class << self
|
|
6
|
-
def register(fixture)
|
|
7
|
-
fixtures[fixture.name.to_s] = fixture
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def find(name)
|
|
11
|
-
fixtures[name.to_s]
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def all_names
|
|
15
|
-
fixtures.keys
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# Load all fixture definition files from the given path.
|
|
19
|
-
# Uses `load` instead of `require` to ensure fixtures are registered
|
|
20
|
-
# even if the files were previously required (e.g., after a reset).
|
|
21
|
-
def load_definitions(fixture_path)
|
|
22
|
-
Dir.glob(File.join(fixture_path, "**/*.rb")).each do |file|
|
|
23
|
-
load file
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def reset
|
|
28
|
-
@fixtures = nil
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Load a fixture's records into the database and return a FixtureSet.
|
|
32
|
-
# Uses cached INSERT statements if available, otherwise executes fixture and caches.
|
|
33
|
-
def load_fixture(name)
|
|
34
|
-
name = name.to_s
|
|
35
|
-
|
|
36
|
-
# Load the file on-demand if fixture not yet registered
|
|
37
|
-
unless find(name)
|
|
38
|
-
fixture_path = FixtureKit.configuration.fixture_path
|
|
39
|
-
file_path = File.expand_path(File.join(fixture_path, "#{name}.rb"))
|
|
40
|
-
load file_path
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
runner = FixtureRunner.new(name)
|
|
44
|
-
runner.run
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
private
|
|
48
|
-
|
|
49
|
-
def fixtures
|
|
50
|
-
@fixtures ||= {}
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "active_record/fixtures"
|
|
4
|
-
|
|
5
|
-
module FixtureKit
|
|
6
|
-
# Runs arbitrary code inside ActiveRecord::TestFixtures lifecycle without
|
|
7
|
-
# defining a real test example. This gives us Rails' transactional handling
|
|
8
|
-
# across all configured writing pools.
|
|
9
|
-
class TransactionalHarness
|
|
10
|
-
include ActiveRecord::TestFixtures
|
|
11
|
-
|
|
12
|
-
def self.run(&block)
|
|
13
|
-
new.run(&block)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# ActiveRecord::TestFixtures checks `name` to decide whether the current
|
|
17
|
-
# method is marked with `uses_transaction`.
|
|
18
|
-
def name
|
|
19
|
-
"fixture_kit_transactional_harness"
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def run
|
|
23
|
-
setup_fixtures
|
|
24
|
-
yield
|
|
25
|
-
ensure
|
|
26
|
-
teardown_fixtures
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|