fixture_farm 0.1.6 → 0.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c681a08bddfef41bec83f8fc4693fc299f5b0f750d1904a652d2adac306aad51
4
- data.tar.gz: b1a19637eab90fe234dc45eba360963a5342b1923f7085d75a19df4678829669
3
+ metadata.gz: aff981f1a6701eb197d0a067391143ce166d4c64de2d3c449cfac8400bb48dd2
4
+ data.tar.gz: 49d489ca4b85708d285db668ca2dcde57ac4a3aa52b394403ad82ccde4841196
5
5
  SHA512:
6
- metadata.gz: 194b052b53935e3e74c7f16818b83f8536c836ac09d3911a966f50591b0931348d75a4448fafcfaa657295855c016902df0bed068a798e90ff478d841f0a5427
7
- data.tar.gz: d1da130e48e0fa0802edb690600482b897985fa8928be6189b5c13c3b74401df67d5963e9c183387e6dd309826e1fc20b989b7b8c4348ec3cf0394b3e9beb075
6
+ metadata.gz: 138bcbab569d27a49c332ac24b814392aab3888e2cd49cf3b64e3f46b3b5a6f6c780d6f7aa355ceba410c900611b31c16dc7ead35af6d74431043391fb34cbce
7
+ data.tar.gz: 22170db6fd9112ea4d67d6de74f270f4615a2d2ab07b02af913c2de516c952d4045685c19a1f382679046939ccf7425dc05c6742f934c58cddc4c7afa116f7b1
data/README.md CHANGED
@@ -65,7 +65,7 @@ To record in tests, wrap some code in `record_new_fixtures` block. For example:
65
65
  include FixtureFarm::TestHelper
66
66
 
67
67
  test 'some stuff does the right thing' do
68
- record_new_fixtures('some_stuff') do |stop_recording|
68
+ record_new_fixtures do |stop_recording|
69
69
  user = User.create!(name: 'Bob')
70
70
  post = user.posts.create!(title: 'Stuff')
71
71
 
@@ -82,7 +82,7 @@ Running this test generates user and post fixtures. Now you can rewrite this tes
82
82
 
83
83
  ```ruby
84
84
  test 'some stuff does the right thing' do
85
- user = users('some_stuff_user_1')
85
+ user = users('user_1')
86
86
 
87
87
  assert_difference 'user.published_posts.size' do
88
88
  user.posts.first.publish!
@@ -90,5 +90,41 @@ test 'some stuff does the right thing' do
90
90
  end
91
91
  ```
92
92
 
93
+ `record_new_fixtures` accepts optional name prefix, that applies to all new fixture names.
94
+
95
+ A more robust approach is to have dedicated fixture tests that normally fail, but can be optionally run in "record mode" (think VCR).
96
+
97
+ For example, let's say we have `Author` model that `has_many :posts` and we require authors to have at least one post. Here's the test to enforce `authors` fixtures to comply with this rule:
98
+
99
+ ```ruby
100
+ test 'authors fixtures must have at least one post' do
101
+ offending_records = Author.where.missing(:posts)
102
+
103
+ assert_empty offending_records
104
+ end
105
+ ```
106
+
107
+ Let's say this test is currently failing.
108
+
109
+ Now let's add the option to automatically record missing fixtures:
110
+
111
+ ```ruby
112
+ test 'authors fixtures must have at least one post' do
113
+ offending_records = Author.where.missing(:posts)
114
+
115
+ if ENV['RECORD_FIXTURES']
116
+ record_new_fixtures do
117
+ offending_records.each do |author|
118
+ author.posts.create!(text: 'some text')
119
+ end
120
+ end
121
+ end
122
+
123
+ assert_empty offending_records
124
+ end
125
+ ```
126
+
127
+ Running this test with `RECORD_FIXTURES=1` will generate missing fixture entries in `test/fixtures/posts.yml`. Now re-run the test again and it's passing.
128
+
93
129
  ## License
94
130
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/bin/fixture_farm.rb CHANGED
@@ -10,9 +10,8 @@ end
10
10
 
11
11
  case ARGV[0]
12
12
  when 'record'
13
- usage unless ARGV[1]
14
13
  FixtureFarm::FixtureRecorder.start_recording_session!(ARGV[1])
15
- puts "Recording fixtures with prefix #{ARGV[1]}"
14
+ puts 'Recording fixtures' + ARGV[1].nil? ? '' : " with prefix #{ARGV[1]}"
16
15
  when 'status'
17
16
  puts "Recording is #{FixtureFarm::FixtureRecorder.recording_session_in_progress? ? 'on' : 'off'}"
18
17
  when 'stop'
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FixtureFarm
4
+ mattr_accessor :parent_models_to_ignore_when_naming_fixtures, default: []
5
+
4
6
  class FixtureRecorder
5
7
  STORE_PATH = Rails.root.join('tmp', 'fixture_farm_store.json')
6
8
 
@@ -8,6 +10,7 @@ module FixtureFarm
8
10
  @fixture_name_prefix = fixture_name_prefix
9
11
  @new_models = new_models
10
12
  @initial_now = Time.zone.now
13
+ @ignore_while_tree_walking = Set.new
11
14
  end
12
15
 
13
16
  def self.resume_recording_session
@@ -92,15 +95,41 @@ module FixtureFarm
92
95
  end
93
96
 
94
97
  def named_new_fixtures
95
- @new_models.uniq(&:id).each_with_object({}) do |model_instance, named_new_fixtures|
96
- new_fixture_name = "#{@fixture_name_prefix}_#{model_instance.class.name.underscore.gsub('/', '_')}_1"
98
+ @named_new_fixtures ||= begin
99
+ (@new_models - @ignore_while_tree_walking.to_a).uniq(&:id).each_with_object({}) do |model_instance, named_new_fixtures|
100
+ @ignore_while_tree_walking.add(model_instance)
97
101
 
98
- while named_new_fixtures[new_fixture_name]
99
- new_fixture_name = new_fixture_name.sub(/_(\d+)$/, "_#{Regexp.last_match(1).to_i + 1}")
100
- end
102
+ new_fixture_name = [
103
+ @fixture_name_prefix,
104
+ first_belongs_to_fixture_name(model_instance),
105
+ "#{model_instance.class.name.underscore.split('/').last}_1"
106
+ ].select(&:present?).join('_')
107
+
108
+ while named_new_fixtures[new_fixture_name]
109
+ new_fixture_name = new_fixture_name.sub(/_(\d+)$/, "_#{Regexp.last_match(1).to_i + 1}")
110
+ end
111
+
112
+ named_new_fixtures[new_fixture_name] = model_instance
113
+
114
+ @ignore_while_tree_walking.delete(model_instance)
115
+ end
116
+ end
117
+ end
118
+
119
+ def first_belongs_to_fixture_name(model_instance)
120
+ model_instance.class.reflect_on_all_associations.filter(&:belongs_to?).each do |association|
121
+ associated_model_instance = find_associated_model_instance(model_instance, association)
122
+
123
+ next unless associated_model_instance
101
124
 
102
- named_new_fixtures[new_fixture_name] = model_instance
125
+ next if FixtureFarm.parent_models_to_ignore_when_naming_fixtures.any? { _1.call(associated_model_instance) }
126
+
127
+ if (associated_model_instance_fixture_name = fixture_name(associated_model_instance))
128
+ return associated_model_instance_fixture_name
129
+ end
103
130
  end
131
+
132
+ nil
104
133
  end
105
134
 
106
135
  def update_fixture_files(named_new_fixtures)
@@ -113,15 +142,11 @@ module FixtureFarm
113
142
  end
114
143
 
115
144
  if belongs_to_association
116
- associated_model_instance = find_assiciated_model_instance(model_instance, belongs_to_association)
145
+ associated_model_instance = find_associated_model_instance(model_instance, belongs_to_association)
117
146
 
118
147
  next unless associated_model_instance
119
148
 
120
- associated_fixture_name = named_new_fixtures.find do |_, fixture_model|
121
- fixture_model.id == associated_model_instance.id
122
- end&.first || associated_model_instance.fixture_name
123
-
124
- [belongs_to_association.name.to_s, associated_fixture_name]
149
+ [belongs_to_association.name.to_s, fixture_name(associated_model_instance)]
125
150
  elsif model_instance.column_for_attribute(k).type
126
151
  [k, serialize_attributes(v)]
127
152
  end
@@ -147,7 +172,7 @@ module FixtureFarm
147
172
  # Clear default_scope before finding associated model record.
148
173
  # This, in particular, turns off ActsAsTenant, that otherwise
149
174
  # might return no record if the tenant has changed by this point.
150
- def find_assiciated_model_instance(model_instance, association)
175
+ def find_associated_model_instance(model_instance, association)
151
176
  associated_model_class = if association.polymorphic?
152
177
  model_instance.public_send(association.foreign_type).safe_constantize
153
178
  else
@@ -238,5 +263,11 @@ module FixtureFarm
238
263
  end
239
264
  end.except(:value_rest)
240
265
  end
266
+
267
+ def fixture_name(model_instance)
268
+ named_new_fixtures.find do |_, fixture_model|
269
+ fixture_model.id == model_instance.id
270
+ end&.first || model_instance.fixture_name
271
+ end
241
272
  end
242
273
  end
@@ -4,7 +4,7 @@ require "fixture_farm/fixture_recorder"
4
4
 
5
5
  module FixtureFarm
6
6
  module TestHelper
7
- def record_new_fixtures(fixture_name_prefix, &block)
7
+ def record_new_fixtures(fixture_name_prefix = nil, &block)
8
8
  FixtureRecorder.new(fixture_name_prefix).record_new_fixtures(&block)
9
9
  end
10
10
  end
@@ -1,3 +1,3 @@
1
1
  module FixtureFarm
2
- VERSION = '0.1.6'
2
+ VERSION = '0.2.1'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fixture_farm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - artemave
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-08-21 00:00:00.000000000 Z
11
+ date: 2025-03-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -67,7 +67,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  requirements: []
70
- rubygems_version: 3.4.10
70
+ rubygems_version: 3.5.22
71
71
  signing_key:
72
72
  specification_version: 4
73
73
  summary: Generate rails fixutures while browsing