fixture_kit 0.1.0 → 0.1.2
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 +16 -3
- data/lib/fixture_kit/configuration.rb +2 -0
- data/lib/fixture_kit/fixture_runner.rb +4 -3
- data/lib/fixture_kit/fixture_set.rb +1 -8
- data/lib/fixture_kit/generator.rb +14 -0
- data/lib/fixture_kit/rspec/declaration.rb +17 -0
- data/lib/fixture_kit/rspec/generator.rb +45 -0
- data/lib/fixture_kit/rspec.rb +18 -8
- data/lib/fixture_kit/singleton.rb +1 -2
- 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 +3 -0
- metadata +21 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2e0215c05b7885a41bf05f4ecd197b5df0d2bec66a8994b9ffe3c5310523d7c2
|
|
4
|
+
data.tar.gz: 41f8326c8e2b24094d977127da376efcec101471d61a3da009cbb61a8683cce8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5315136c139de91a4d6a7bf325fdd9710a0583928b1f0dccdee0d8584afc9be050083ee174a0ddc3d538650d8509e4fd764731c4e547d5f9dacc2651690a454a
|
|
7
|
+
data.tar.gz: f7212cae51606a7e9ef8c80f7c27d9a95e6091b02f0873d2786241780bbd2a961d0f94a1e8cb0bc42cdd188276fc56526b2f1cba1136edeba66384824e255ab4
|
data/README.md
CHANGED
|
@@ -98,12 +98,14 @@ RSpec.describe Book do
|
|
|
98
98
|
expect(fixture.books.size).to eq(3)
|
|
99
99
|
end
|
|
100
100
|
|
|
101
|
-
it "
|
|
102
|
-
expect(fixture
|
|
101
|
+
it "exposes records as methods" do
|
|
102
|
+
expect(fixture.owner.email).to eq("alice@example.com")
|
|
103
103
|
end
|
|
104
104
|
end
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
+
`fixture` returns a `FixtureSet` 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
|
|
|
@@ -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
|
|
|
@@ -27,15 +27,16 @@ module FixtureKit
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
# Generate cache only (used for pregeneration in before(:suite))
|
|
30
|
-
# Wraps execution in
|
|
30
|
+
# Wraps execution in the configured generator lifecycle.
|
|
31
|
+
# The default generator uses ActiveRecord::TestFixtures transactions.
|
|
32
|
+
# Entry points (like `fixture_kit/rspec`) can install richer generators.
|
|
31
33
|
# Always regenerates the cache, even if one exists
|
|
32
34
|
def generate_cache_only
|
|
33
35
|
# Clear any existing cache for this fixture
|
|
34
36
|
FixtureCache.clear(@fixture_name.to_s)
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
FixtureKit.configuration.generator.run do
|
|
37
39
|
execute_and_cache
|
|
38
|
-
raise ActiveRecord::Rollback
|
|
39
40
|
end
|
|
40
41
|
|
|
41
42
|
true
|
|
@@ -4,17 +4,10 @@ module FixtureKit
|
|
|
4
4
|
class FixtureSet
|
|
5
5
|
def initialize(exposed_records)
|
|
6
6
|
@records = exposed_records
|
|
7
|
+
@records.each_value { |value| value.freeze if value.is_a?(Array) }
|
|
7
8
|
define_accessors
|
|
8
9
|
end
|
|
9
10
|
|
|
10
|
-
def [](name)
|
|
11
|
-
@records[name.to_sym]
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def to_h
|
|
15
|
-
@records.dup
|
|
16
|
-
end
|
|
17
|
-
|
|
18
11
|
private
|
|
19
12
|
|
|
20
13
|
def define_accessors
|
|
@@ -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,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FixtureKit
|
|
4
|
+
module RSpec
|
|
5
|
+
class Declaration
|
|
6
|
+
attr_reader :name
|
|
7
|
+
|
|
8
|
+
def initialize(name)
|
|
9
|
+
@name = name.to_s
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def fixture_set
|
|
13
|
+
FixtureKit::FixtureRegistry.load_fixture(name)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
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
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "fixture_kit"
|
|
4
|
+
require_relative "rspec/declaration"
|
|
5
|
+
require_relative "rspec/generator"
|
|
4
6
|
|
|
5
7
|
module FixtureKit
|
|
6
8
|
module RSpec
|
|
9
|
+
DECLARATION_METADATA_KEY = :fixture_kit_declaration
|
|
10
|
+
PRESERVE_CACHE_ENV_KEY = "FIXTURE_KIT_PRESERVE_CACHE"
|
|
11
|
+
|
|
7
12
|
# Class methods (extended via config.extend)
|
|
8
13
|
module ClassMethods
|
|
9
14
|
# Declare which fixture to use for this example group.
|
|
@@ -26,7 +31,7 @@ module FixtureKit
|
|
|
26
31
|
# end
|
|
27
32
|
# end
|
|
28
33
|
def fixture(name)
|
|
29
|
-
metadata[
|
|
34
|
+
metadata[FixtureKit::RSpec::DECLARATION_METADATA_KEY] = FixtureKit::RSpec::Declaration.new(name)
|
|
30
35
|
end
|
|
31
36
|
end
|
|
32
37
|
|
|
@@ -35,28 +40,33 @@ module FixtureKit
|
|
|
35
40
|
# Returns the FixtureSet for the current example's fixture.
|
|
36
41
|
# Access exposed records as methods: fixture.alice, fixture.posts
|
|
37
42
|
def fixture
|
|
38
|
-
@
|
|
39
|
-
fixture_name = self.class.metadata[:fixture_name]
|
|
40
|
-
raise "No fixture declared for this example group. Use `fixture \"name\"` in your describe/context block." unless fixture_name
|
|
41
|
-
|
|
42
|
-
FixtureKit::FixtureRegistry.load_fixture(fixture_name)
|
|
43
|
-
end
|
|
43
|
+
@_fixture_kit_fixture_set || raise("No fixture declared for this example group. Use `fixture \"name\"` in your describe/context block.")
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
+
# Install the RSpec generator by default for this entrypoint.
|
|
50
|
+
FixtureKit.configuration.generator = FixtureKit::RSpec::Generator
|
|
51
|
+
|
|
49
52
|
# Configure RSpec integration
|
|
50
53
|
RSpec.configure do |config|
|
|
51
54
|
config.extend FixtureKit::RSpec::ClassMethods
|
|
52
55
|
config.include FixtureKit::RSpec::InstanceMethods
|
|
53
56
|
|
|
57
|
+
# Load declared fixtures at the beginning of each example.
|
|
58
|
+
# Runs inside transactional fixtures and before user-defined before hooks.
|
|
59
|
+
config.prepend_before(:example, FixtureKit::RSpec::DECLARATION_METADATA_KEY) do |example|
|
|
60
|
+
declaration = example.metadata[FixtureKit::RSpec::DECLARATION_METADATA_KEY]
|
|
61
|
+
@_fixture_kit_fixture_set = declaration.fixture_set
|
|
62
|
+
end
|
|
63
|
+
|
|
54
64
|
# Setup caches at suite start based on autogenerate setting
|
|
55
65
|
# - autogenerate=true: Clear all caches (unless FIXTURE_KIT_PRESERVE_CACHE is set)
|
|
56
66
|
# - autogenerate=false: Pre-generate all caches so tests don't fail
|
|
57
67
|
config.before(:suite) do
|
|
58
68
|
if FixtureKit.configuration.autogenerate
|
|
59
|
-
preserve_cache = ENV[
|
|
69
|
+
preserve_cache = ENV[FixtureKit::RSpec::PRESERVE_CACHE_ENV_KEY].to_s.match?(/\A(1|true|yes)\z/i)
|
|
60
70
|
FixtureKit::FixtureCache.clear unless preserve_cache
|
|
61
71
|
else
|
|
62
72
|
FixtureKit::FixtureCache.pregenerate_all
|
|
@@ -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,6 +5,7 @@ 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
|
|
8
9
|
class ExposedRecordNotFound < Error; end
|
|
9
10
|
|
|
10
11
|
autoload :VERSION, File.expand_path("fixture_kit/version", __dir__)
|
|
@@ -17,6 +18,8 @@ module FixtureKit
|
|
|
17
18
|
autoload :SqlCapture, File.expand_path("fixture_kit/sql_capture", __dir__)
|
|
18
19
|
autoload :FixtureCache, File.expand_path("fixture_kit/fixture_cache", __dir__)
|
|
19
20
|
autoload :FixtureRunner, File.expand_path("fixture_kit/fixture_runner", __dir__)
|
|
21
|
+
autoload :Generator, File.expand_path("fixture_kit/generator", __dir__)
|
|
22
|
+
autoload :TestCase, File.expand_path("fixture_kit/test_case", __dir__)
|
|
20
23
|
|
|
21
24
|
extend Singleton
|
|
22
25
|
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.1.
|
|
4
|
+
version: 0.1.2
|
|
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-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -52,6 +52,20 @@ dependencies:
|
|
|
52
52
|
- - ">="
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: appraisal
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
55
69
|
- !ruby/object:Gem::Dependency
|
|
56
70
|
name: rake
|
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -127,9 +141,14 @@ files:
|
|
|
127
141
|
- lib/fixture_kit/fixture_registry.rb
|
|
128
142
|
- lib/fixture_kit/fixture_runner.rb
|
|
129
143
|
- lib/fixture_kit/fixture_set.rb
|
|
144
|
+
- lib/fixture_kit/generator.rb
|
|
130
145
|
- lib/fixture_kit/rspec.rb
|
|
146
|
+
- lib/fixture_kit/rspec/declaration.rb
|
|
147
|
+
- lib/fixture_kit/rspec/generator.rb
|
|
131
148
|
- lib/fixture_kit/singleton.rb
|
|
132
149
|
- lib/fixture_kit/sql_capture.rb
|
|
150
|
+
- lib/fixture_kit/test_case.rb
|
|
151
|
+
- lib/fixture_kit/test_case/generator.rb
|
|
133
152
|
- lib/fixture_kit/version.rb
|
|
134
153
|
homepage: https://github.com/Gusto/fixture_kit
|
|
135
154
|
licenses:
|