├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── dependabot.yml └── workflows │ ├── build.yml │ ├── dynamic-readme.yml │ └── dynamic-security.yml ├── .gitignore ├── .hound.yml ├── .rspec ├── .tool-versions ├── Appraisals ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── NEWS.md ├── README.md ├── RELEASING.md ├── Rakefile ├── SECURITY.md ├── bin └── setup ├── cucumber.yml ├── factory_bot_rails.gemspec ├── features ├── fixture_replacement_config.feature ├── generators.feature ├── initializers.feature ├── load_definitions.feature ├── reloading.feature ├── step_definitions │ ├── appraisal.rb │ └── rails_steps.rb └── support │ ├── env.rb │ └── rails_template ├── gemfiles ├── rails5.0.gemfile ├── rails5.1.gemfile ├── rails5.2.gemfile ├── rails6.0.gemfile ├── rails6.1.gemfile ├── rails7.0.gemfile ├── rails7.1.gemfile ├── rails7.2.gemfile └── rails8.0.gemfile ├── lib ├── factory_bot_rails.rb ├── factory_bot_rails │ ├── definition_file_paths.rb │ ├── factory_validator.rb │ ├── file_fixture_support.rb │ ├── generator.rb │ ├── generators │ │ ├── non_rspec_generator.rb │ │ ├── null_generator.rb │ │ └── rspec_generator.rb │ ├── railtie.rb │ ├── reloader.rb │ └── version.rb ├── generators │ ├── factory_bot.rb │ └── factory_bot │ │ └── model │ │ ├── model_generator.rb │ │ └── templates │ │ └── factories.erb └── rails │ └── projections.json ├── spec ├── factory_bot_rails │ ├── definition_file_paths_spec.rb │ ├── factory_spec.rb │ ├── railtie_spec.rb │ └── reloader_spec.rb ├── fake_app.rb ├── fixtures │ ├── factories.rb │ ├── factories │ │ └── definitions.rb │ └── files │ │ └── file.txt ├── spec_helper.rb └── support │ └── active_record │ └── migrations.rb └── test ├── factory_bot_rails └── factory_test.rb ├── fixtures └── files │ └── file.txt └── test_helper.rb /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: 'bug' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 12 | 13 | ### Description 14 | 15 | 16 | 17 | 21 | 22 | ### Reproduction Steps 23 | 24 | 26 | 27 | ### Expected behavior 28 | 29 | 30 | 31 | ### Actual behavior 32 | 33 | 34 | 35 | ### System configuration 36 | **factory_bot_rails version**: 37 | **factory_bot version**: 38 | **rails version**: 39 | **ruby version**: 40 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: 'feature' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 12 | 13 | ### Problem this feature will solve 14 | 15 | 17 | 18 | 22 | 23 | ### Desired solution 24 | 25 | 26 | 27 | ## Alternatives considered 28 | 29 | 30 | 31 | ## Additional context 32 | 33 | 34 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | 4 | updates: 5 | - package-ecosystem: "bundler" 6 | directory: "/" 7 | schedule: 8 | interval: weekly 9 | time: "02:00" 10 | timezone: "Etc/UTC" 11 | - package-ecosystem: "github-actions" 12 | directory: "/" 13 | schedule: 14 | interval: weekly 15 | time: "02:00" 16 | timezone: "Etc/UTC" 17 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | pull_request: 4 | push: 5 | branches: [ main ] 6 | 7 | jobs: 8 | build: 9 | name: Ruby ${{ matrix.ruby }} / Rails ${{ matrix.rails }} 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | rails: ["8.0", "7.2", "7.1", "7.0", "6.1"] 14 | ruby: ["3.4", "3.3", "3.2", "3.1"] 15 | exclude: 16 | # Rails >= 8.0 requires Ruby 3.2 17 | - ruby: "3.1" 18 | rails: "8.0" 19 | 20 | 21 | runs-on: 'ubuntu-latest' 22 | 23 | env: 24 | ARUBA_TIMEOUT: 240 25 | BUNDLE_GEMFILE: gemfiles/rails${{ matrix.rails }}.gemfile 26 | 27 | steps: 28 | - uses: actions/checkout@v4 29 | - uses: ruby/setup-ruby@v1 30 | with: 31 | ruby-version: ${{ matrix.ruby }} 32 | - name: Setup project 33 | run: bundle install 34 | - name: RSpec specs 35 | run: bundle exec rake spec 36 | - name: Minitest tests 37 | run: bundle exec rake test 38 | - name: Cucumber tests 39 | run: bundle exec rake cucumber 40 | 41 | standard: 42 | name: Run standard 43 | runs-on: 'ubuntu-latest' 44 | steps: 45 | - uses: actions/checkout@v4 46 | - uses: ruby/setup-ruby@v1 47 | with: 48 | ruby-version: "3.4" 49 | - name: Setup project 50 | run: bundle install 51 | - name: Run test 52 | run: bundle exec rake standard 53 | -------------------------------------------------------------------------------- /.github/workflows/dynamic-readme.yml: -------------------------------------------------------------------------------- 1 | name: update-templates 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | workflow_dispatch: 8 | 9 | jobs: 10 | update-templates: 11 | permissions: 12 | contents: write 13 | pull-requests: write 14 | pages: write 15 | uses: thoughtbot/templates/.github/workflows/dynamic-readme.yaml@main 16 | secrets: 17 | token: ${{ secrets.GITHUB_TOKEN }} 18 | -------------------------------------------------------------------------------- /.github/workflows/dynamic-security.yml: -------------------------------------------------------------------------------- 1 | name: update-security 2 | 3 | on: 4 | push: 5 | paths: 6 | - SECURITY.md 7 | branches: 8 | - main 9 | workflow_dispatch: 10 | 11 | jobs: 12 | update-security: 13 | permissions: 14 | contents: write 15 | pull-requests: write 16 | pages: write 17 | uses: thoughtbot/templates/.github/workflows/dynamic-security.yaml@main 18 | secrets: 19 | token: ${{ secrets.GITHUB_TOKEN }} 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .bundle 3 | gemfiles/*.lock 4 | coverage 5 | factory_girl_rails-*.gem 6 | pkg 7 | rdoc 8 | test.db 9 | tmp 10 | .rubocop-https* 11 | factory_bot_rails-*.gem 12 | -------------------------------------------------------------------------------- /.hound.yml: -------------------------------------------------------------------------------- 1 | rubocop: 2 | config_file: .rubocop.yml 3 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --format progress 3 | --require spec_helper 4 | -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | ruby 3.4.1 2 | -------------------------------------------------------------------------------- /Appraisals: -------------------------------------------------------------------------------- 1 | appraise "rails6.1" do 2 | gem "bigdecimal" 3 | gem "byebug" 4 | gem "concurrent-ruby", "< 1.3.5" 5 | gem "drb" 6 | gem "listen", "~> 3.2" 7 | gem "puma", "~> 5.0" 8 | gem "rails", "~> 6.1.0", ">= 6.1.0.0" 9 | gem "spring", "!= 2.1.1" 10 | gem "spring-watcher-listen", "~> 2.0.0" 11 | gem "sqlite3", "~> 1.4" 12 | end 13 | 14 | appraise "rails7.0" do 15 | gem "bigdecimal" 16 | gem "byebug" 17 | gem "concurrent-ruby", "< 1.3.5" 18 | gem "drb" 19 | gem "listen", "~> 3.2" 20 | gem "puma", "~> 5.0" 21 | gem "rails", "~> 7.0.1", ">= 7.0.1" 22 | gem "spring", "!= 2.1.1" 23 | gem "spring-watcher-listen", "~> 2.0.0" 24 | gem "sqlite3", "~> 1.4" 25 | end 26 | 27 | appraise "rails7.1" do 28 | gem "byebug" 29 | gem "listen", "~> 3.2" 30 | gem "puma", "~> 6.0" 31 | gem "rails", "~> 7.1.0" 32 | gem "spring", "!= 2.1.1" 33 | gem "spring-watcher-listen", "~> 2.0.0" 34 | gem "sqlite3", "~> 1.4" 35 | end 36 | 37 | appraise "rails7.2" do 38 | gem "byebug" 39 | gem "listen", "~> 3.2" 40 | gem "puma", "~> 6.0" 41 | gem "rails", "~> 7.2.0" 42 | gem "spring", "!= 2.1.1" 43 | gem "spring-watcher-listen", "~> 2.0.0" 44 | gem "sqlite3", "~> 1.4" 45 | end 46 | 47 | appraise "rails8.0" do 48 | gem "brakeman" 49 | gem "byebug" 50 | gem "kamal" 51 | gem "listen", "~> 3.2" 52 | gem "puma", "~> 6.0" 53 | gem "rails", "~> 8.0.0" 54 | gem "rubocop-rails-omakase" 55 | gem "solid_queue" 56 | gem "spring", "!= 2.1.1" 57 | gem "spring-watcher-listen", "~> 2.0.0" 58 | gem "sqlite3", ">= 2.1" 59 | gem "thruster" 60 | end 61 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lines starting with '#' are comments. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # More details are here: https://help.github.com/articles/about-codeowners/ 5 | 6 | # The '*' pattern is global owners. 7 | 8 | # Order is important. The last matching pattern has the most precedence. 9 | # The folders are ordered as follows: 10 | 11 | # In each subsection folders are ordered first by depth, then alphabetically. 12 | # This should make it easy to add new rules without breaking existing ones. 13 | 14 | # Global rule: 15 | * @neilvcarvalho @DoodlingDev 16 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of conduct 2 | 3 | By participating in this project, you agree to abide by the 4 | [thoughtbot code of conduct][1]. 5 | 6 | [1]: https://thoughtbot.com/open-source-code-of-conduct 7 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We love pull requests from everyone. By participating in this project, you 4 | agree to abide by the thoughtbot [code of conduct]. 5 | 6 | [code of conduct]: https://thoughtbot.com/open-source-code-of-conduct 7 | 8 | Fork, then clone the repo: 9 | 10 | git clone git@github.com:your-username/factory_bot_rails.git 11 | 12 | Set up your machine: 13 | 14 | ./bin/setup 15 | 16 | Make sure the tests pass: 17 | 18 | rake 19 | 20 | Make your change. Add tests for your change. Make the tests pass: 21 | 22 | rake 23 | 24 | Push to your fork and [submit a pull request][pr]. 25 | 26 | [pr]: https://github.com/thoughtbot/factory_bot_rails/compare/ 27 | 28 | At this point you're waiting on us. We like to at least comment on pull requests 29 | within three business days (and, typically, one business day). We may suggest 30 | some changes or improvements or alternatives. 31 | 32 | Some things that will increase the chance that your pull request is accepted: 33 | 34 | * Write tests. 35 | * Follow our [style guide][style]. 36 | * Write a [good commit message][commit]. 37 | 38 | [style]: https://github.com/thoughtbot/guides/tree/main/general 39 | [commit]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html 40 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gemspec name: "factory_bot_rails" 4 | 5 | gem "appraisal" 6 | gem "aruba" 7 | gem "cucumber" 8 | gem "rake" 9 | gem "rspec-rails" 10 | gem "standard" 11 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | factory_bot_rails (6.4.4) 5 | factory_bot (~> 6.5) 6 | railties (>= 6.1.0) 7 | 8 | GEM 9 | remote: https://rubygems.org/ 10 | specs: 11 | actionpack (8.0.1) 12 | actionview (= 8.0.1) 13 | activesupport (= 8.0.1) 14 | nokogiri (>= 1.8.5) 15 | rack (>= 2.2.4) 16 | rack-session (>= 1.0.1) 17 | rack-test (>= 0.6.3) 18 | rails-dom-testing (~> 2.2) 19 | rails-html-sanitizer (~> 1.6) 20 | useragent (~> 0.16) 21 | actionview (8.0.1) 22 | activesupport (= 8.0.1) 23 | builder (~> 3.1) 24 | erubi (~> 1.11) 25 | rails-dom-testing (~> 2.2) 26 | rails-html-sanitizer (~> 1.6) 27 | activejob (8.0.1) 28 | activesupport (= 8.0.1) 29 | globalid (>= 0.3.6) 30 | activemodel (8.0.1) 31 | activesupport (= 8.0.1) 32 | activerecord (8.0.1) 33 | activemodel (= 8.0.1) 34 | activesupport (= 8.0.1) 35 | timeout (>= 0.4.0) 36 | activestorage (8.0.1) 37 | actionpack (= 8.0.1) 38 | activejob (= 8.0.1) 39 | activerecord (= 8.0.1) 40 | activesupport (= 8.0.1) 41 | marcel (~> 1.0) 42 | activesupport (8.0.1) 43 | base64 44 | benchmark (>= 0.3) 45 | bigdecimal 46 | concurrent-ruby (~> 1.0, >= 1.3.1) 47 | connection_pool (>= 2.2.5) 48 | drb 49 | i18n (>= 1.6, < 2) 50 | logger (>= 1.4.2) 51 | minitest (>= 5.1) 52 | securerandom (>= 0.3) 53 | tzinfo (~> 2.0, >= 2.0.5) 54 | uri (>= 0.13.1) 55 | appraisal (2.5.0) 56 | bundler 57 | rake 58 | thor (>= 0.14.0) 59 | aruba (2.3.0) 60 | bundler (>= 1.17, < 3.0) 61 | contracts (>= 0.16.0, < 0.18.0) 62 | cucumber (>= 8.0, < 10.0) 63 | rspec-expectations (~> 3.4) 64 | thor (~> 1.0) 65 | ast (2.4.2) 66 | base64 (0.2.0) 67 | benchmark (0.4.0) 68 | bigdecimal (3.1.9) 69 | bigdecimal (3.1.9-java) 70 | builder (3.3.0) 71 | concurrent-ruby (1.3.5) 72 | connection_pool (2.5.0) 73 | contracts (0.17.2) 74 | crass (1.0.6) 75 | cucumber (9.2.1) 76 | builder (~> 3.2) 77 | cucumber-ci-environment (> 9, < 11) 78 | cucumber-core (> 13, < 14) 79 | cucumber-cucumber-expressions (~> 17.0) 80 | cucumber-gherkin (> 24, < 28) 81 | cucumber-html-formatter (> 20.3, < 22) 82 | cucumber-messages (> 19, < 25) 83 | diff-lcs (~> 1.5) 84 | mini_mime (~> 1.1) 85 | multi_test (~> 1.1) 86 | sys-uname (~> 1.2) 87 | cucumber-ci-environment (10.0.1) 88 | cucumber-core (13.0.3) 89 | cucumber-gherkin (>= 27, < 28) 90 | cucumber-messages (>= 20, < 23) 91 | cucumber-tag-expressions (> 5, < 7) 92 | cucumber-cucumber-expressions (17.1.0) 93 | bigdecimal 94 | cucumber-gherkin (27.0.0) 95 | cucumber-messages (>= 19.1.4, < 23) 96 | cucumber-html-formatter (21.9.0) 97 | cucumber-messages (> 19, < 28) 98 | cucumber-messages (22.0.0) 99 | cucumber-tag-expressions (6.1.2) 100 | date (3.4.1) 101 | date (3.4.1-java) 102 | diff-lcs (1.5.1) 103 | drb (2.2.1) 104 | erubi (1.13.1) 105 | factory_bot (6.5.1) 106 | activesupport (>= 6.1.0) 107 | ffi (1.17.1) 108 | ffi (1.17.1-java) 109 | globalid (1.2.1) 110 | activesupport (>= 6.1) 111 | i18n (1.14.7) 112 | concurrent-ruby (~> 1.0) 113 | io-console (0.8.0) 114 | io-console (0.8.0-java) 115 | irb (1.15.1) 116 | pp (>= 0.6.0) 117 | rdoc (>= 4.0.0) 118 | reline (>= 0.4.2) 119 | jar-dependencies (0.5.4) 120 | json (2.9.1) 121 | json (2.9.1-java) 122 | language_server-protocol (3.17.0.4) 123 | lint_roller (1.1.0) 124 | logger (1.6.5) 125 | loofah (2.24.0) 126 | crass (~> 1.0.2) 127 | nokogiri (>= 1.12.0) 128 | marcel (1.0.4) 129 | mini_mime (1.1.5) 130 | mini_portile2 (2.8.8) 131 | minitest (5.25.4) 132 | multi_test (1.1.0) 133 | mutex_m (0.3.0) 134 | nokogiri (1.18.2) 135 | mini_portile2 (~> 2.8.2) 136 | racc (~> 1.4) 137 | nokogiri (1.18.2-java) 138 | racc (~> 1.4) 139 | parallel (1.26.3) 140 | parser (3.3.7.1) 141 | ast (~> 2.4.1) 142 | racc 143 | pp (0.6.2) 144 | prettyprint 145 | prettyprint (0.2.0) 146 | psych (5.2.3) 147 | date 148 | stringio 149 | psych (5.2.3-java) 150 | date 151 | jar-dependencies (>= 0.1.7) 152 | racc (1.8.1) 153 | racc (1.8.1-java) 154 | rack (3.1.9) 155 | rack-session (2.1.0) 156 | base64 (>= 0.1.0) 157 | rack (>= 3.0.0) 158 | rack-test (2.2.0) 159 | rack (>= 1.3) 160 | rackup (2.2.1) 161 | rack (>= 3) 162 | rails-dom-testing (2.2.0) 163 | activesupport (>= 5.0.0) 164 | minitest 165 | nokogiri (>= 1.6) 166 | rails-html-sanitizer (1.6.2) 167 | loofah (~> 2.21) 168 | nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) 169 | railties (8.0.1) 170 | actionpack (= 8.0.1) 171 | activesupport (= 8.0.1) 172 | irb (~> 1.13) 173 | rackup (>= 1.0.0) 174 | rake (>= 12.2) 175 | thor (~> 1.0, >= 1.2.2) 176 | zeitwerk (~> 2.6) 177 | rainbow (3.1.1) 178 | rake (13.2.1) 179 | rdoc (6.12.0) 180 | psych (>= 4.0.0) 181 | regexp_parser (2.10.0) 182 | reline (0.6.0) 183 | io-console (~> 0.5) 184 | rspec-core (3.13.3) 185 | rspec-support (~> 3.13.0) 186 | rspec-expectations (3.13.3) 187 | diff-lcs (>= 1.2.0, < 2.0) 188 | rspec-support (~> 3.13.0) 189 | rspec-mocks (3.13.2) 190 | diff-lcs (>= 1.2.0, < 2.0) 191 | rspec-support (~> 3.13.0) 192 | rspec-rails (7.1.1) 193 | actionpack (>= 7.0) 194 | activesupport (>= 7.0) 195 | railties (>= 7.0) 196 | rspec-core (~> 3.13) 197 | rspec-expectations (~> 3.13) 198 | rspec-mocks (~> 3.13) 199 | rspec-support (~> 3.13) 200 | rspec-support (3.13.2) 201 | rubocop (1.70.0) 202 | json (~> 2.3) 203 | language_server-protocol (>= 3.17.0) 204 | parallel (~> 1.10) 205 | parser (>= 3.3.0.2) 206 | rainbow (>= 2.2.2, < 4.0) 207 | regexp_parser (>= 2.9.3, < 3.0) 208 | rubocop-ast (>= 1.36.2, < 2.0) 209 | ruby-progressbar (~> 1.7) 210 | unicode-display_width (>= 2.4.0, < 4.0) 211 | rubocop-ast (1.38.0) 212 | parser (>= 3.3.1.0) 213 | rubocop-performance (1.23.1) 214 | rubocop (>= 1.48.1, < 2.0) 215 | rubocop-ast (>= 1.31.1, < 2.0) 216 | ruby-progressbar (1.13.0) 217 | securerandom (0.4.1) 218 | sqlite3 (2.5.0) 219 | mini_portile2 (~> 2.8.0) 220 | standard (1.44.0) 221 | language_server-protocol (~> 3.17.0.2) 222 | lint_roller (~> 1.0) 223 | rubocop (~> 1.70.0) 224 | standard-custom (~> 1.0.0) 225 | standard-performance (~> 1.6) 226 | standard-custom (1.0.2) 227 | lint_roller (~> 1.0) 228 | rubocop (~> 1.50) 229 | standard-performance (1.6.0) 230 | lint_roller (~> 1.1) 231 | rubocop-performance (~> 1.23.0) 232 | stringio (3.1.2) 233 | sys-uname (1.3.1) 234 | ffi (~> 1.1) 235 | thor (1.3.2) 236 | timeout (0.4.3) 237 | tzinfo (2.0.6) 238 | concurrent-ruby (~> 1.0) 239 | unicode-display_width (3.1.4) 240 | unicode-emoji (~> 4.0, >= 4.0.4) 241 | unicode-emoji (4.0.4) 242 | uri (1.0.2) 243 | useragent (0.16.11) 244 | zeitwerk (2.7.1) 245 | 246 | PLATFORMS 247 | java 248 | ruby 249 | 250 | DEPENDENCIES 251 | activerecord (>= 6.1.0) 252 | activestorage (>= 6.1.0) 253 | appraisal 254 | aruba 255 | cucumber 256 | factory_bot_rails! 257 | mutex_m 258 | rake 259 | rspec-rails 260 | sqlite3 261 | standard 262 | 263 | BUNDLED WITH 264 | 2.5.23 265 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008-2020 Joe Ferris and thoughtbot, inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | factory\_bot\_rails versioning is synced with factory\_bot releases. For this reason 2 | there might not be any notable changes in new versions of this project. 3 | 4 | # NEWS 5 | 6 | * Add: First-party support for [`file_fixture`](https://api.rubyonrails.org/classes/ActiveSupport/Testing/FileFixtures.html#method-i-file_fixture) within factory blocks 7 | * Internal: Add Rails 8.0 to the test matrix 8 | 9 | ## 6.4.4 (October 25, 2024) 10 | * Changed: Bump Factory Bot 6.5.0 11 | 12 | ## 6.4.3 (December 29, 2023) 13 | 14 | * Changed: allow sequence definitions for ActiveRecord primary keys (Mike 15 | Burns). 16 | * Changed: Support Ruby 3.0+, Rails 6.1+ (Mike Burns) 17 | * Documentation improvements (obregonia1). 18 | * Internal: GitHub Actions improvements (Lorenzo Zabot, ydah). 19 | * Internal: RubyGems points to changelog (Tilo Sloboda). 20 | * Internal: Bump standard, rake, activerecord, appraisal, rspec-rails (Mike 21 | Burns). 22 | 23 | ## 6.4.2 (November 23, 2023) 24 | * Fixed: Fix Rails 7.1.2 + monkey-patched ActiveRecord compatibility (Adif 25 | Sgaid, Benoit Tigeot) 26 | * Internal: Test against Rails 7.1 (y-yagi) 27 | * Internal: Fix links to old files after renaming the main branch to `main` 28 | (y-yagi) 29 | 30 | ## 6.4.0 (November 17, 2023) 31 | 32 | * Releasing this for consistency with the factory\_bot dependency. 33 | 34 | ## 6.3.0 (November 17, 2023) 35 | 36 | * Changed: reject sequence definitions for ActiveRecord primary keys (Sean 37 | Doyle). 38 | * Changed: factory\_bot dependency to ~> 6.4 (Mike Burns). 39 | * Changed: upgrade dependencies (Daniel Colson). 40 | * Add: `projections.json` for Rails.vim (Caleb Hearth). 41 | * Docs: fix broken link (Edu Depetris). 42 | * Docs: mention Rails generator in docs (Edu Depetris). 43 | * Docs: fix typo (Yudai Takada). 44 | * Internal: skip Spring version 2.1.1 due to a bug in that release (Christina 45 | Entcheva, Daniel Colson). 46 | * Internal: test against Rails 6.1 (Antonis Berkakis). 47 | * Internal: test against Ruby 3 (Daniel Colson). 48 | * Internal: fewer warnings in Cucumber tests (Daniel Colson). 49 | * Internal: use GitHub Actions for CI (Mathieu Jobin). 50 | * Internal: a whole bunch of cleanup (Daniel Colson). 51 | * Internal: fix CI due to a Bundler output change (Mike Burns). 52 | 53 | ## 6.2.0 (May 7, 2021) 54 | 55 | * Changed: factory\_bot dependency to ~> 6.2.0 56 | 57 | ## 6.1.0 (July 8, 2020) 58 | 59 | * Changed: factory\_bot dependency to ~> 6.1.0 60 | 61 | ## 6.0.0 (June 18, 2020) 62 | 63 | * Fixed: generate a plural factory name when the --force-plural flag is provided 64 | * Changed: factory\_bot dependency to ~> 6.0.0 65 | * Removed: `"factory_bot.register_reloader"` initializer, now registering the 66 | reloader after application initialization 67 | * Removed: support for EOL versions of Ruby (2.3, 2.4) and Rails (4.2) 68 | 69 | ## 5.2.0 (April 26, 2020) 70 | 71 | * Changed: factory\_bot dependency to ~> 5.2.0 72 | 73 | ## 5.1.1 (September 24, 2019) 74 | 75 | * Fixed: Ensure definitions do not load before I18n is initialized 76 | 77 | ## 5.1.0 (September 24, 2019) 78 | 79 | * Changed: factory\_bot dependency to ~> 5.1.0 80 | 81 | ## 5.0.2 (April 14, 2019) 82 | 83 | * Bugfix: Reload factory\_bot whenever the application changes to avoid holding 84 | onto stale object references 85 | * Bugfix: Avoid watching project root when no factory definitions exist 86 | 87 | ## 5.0.1 (February 9, 2019) 88 | 89 | * Bugfix: Avoid watching files and directories that don't exist (to avoid a 90 | file watching bug in Rails https://github.com/rails/rails/issues/32700) 91 | 92 | ## 5.0.0 (February 1, 2019) 93 | 94 | * Added: calling reload! in the Rails console will reload any factory definition files that have changed 95 | * Added: support for custom generator templates 96 | * Added: `definition_file_paths` configuration option, making it easier to place factories in custom locations 97 | * Changed: namespaced models are now generated inside a directory matching the namespace 98 | * Changed: added newline between factories generated into the same file 99 | * Removed: support for EOL version of Ruby and Rails 100 | 101 | ## 4.11.1 (September 7, 2018) 102 | 103 | * Update generator to use dynamic attributes instead of deprecated static attributes 104 | 105 | ## 4.11.0 (August 16, 2018) 106 | 107 | * No notable changes 108 | 109 | ## 4.10.0 (May 25, 2018) 110 | 111 | * No notable changes 112 | 113 | ## 4.8.2 (October 20, 2017) 114 | 115 | * Rename factory\_girl\_rails to factory\_bot\_rails 116 | 117 | ## 4.7.0 (April 1, 2016) 118 | 119 | * No notable changes 120 | 121 | ## 4.6.0 (February 1, 2016) 122 | 123 | * No notable changes 124 | 125 | ## 4.5.0 (October 17, 2014) 126 | 127 | * Improved README 128 | 129 | ## 4.4.1 (February 26, 2014) 130 | 131 | * Support Spring 132 | 133 | ## 4.2.1 (February 8, 2013) 134 | 135 | * Fix bug when configuring FG and RSpec fixture directory 136 | * Remove debugging 137 | * Require factory\_girl\_rails explicitly in generator 138 | 139 | ## 4.2.0 (January 25, 2013) 140 | 141 | * Add appraisal and get test suite working reliably with turn gem 142 | * Support MiniTest 143 | * Allow a custom directory for factories to be specified 144 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # factory_bot_rails [![Code Climate][grade-image]][grade] [![Gem Version][version-image]][version] 2 | 3 | [factory_bot][fb] is a fixtures replacement with a straightforward definition 4 | syntax, support for multiple build strategies (saved instances, unsaved 5 | instances, attribute hashes, and stubbed objects), and support for multiple 6 | factories for the same class (`user`, `admin_user`, and so on), including factory 7 | inheritance. 8 | 9 | ### Transitioning from factory\_girl\_rails? 10 | 11 | Check out the [guide](https://github.com/thoughtbot/factory_bot/blob/4-9-0-stable/UPGRADE_FROM_FACTORY_GIRL.md). 12 | 13 | ## Rails 14 | 15 | factory\_bot\_rails provides Rails integration for [factory_bot][fb]. 16 | 17 | Supported Rails versions are listed in [`Appraisals`](Appraisals). Supported 18 | Ruby versions are listed in [`.github/workflows/build.yml`](.github/workflows/build.yml). 19 | 20 | ## Download 21 | 22 | Github: http://github.com/thoughtbot/factory_bot_rails 23 | 24 | Gem: 25 | 26 | $ gem install factory_bot_rails 27 | 28 | ## Configuration 29 | 30 | Add `factory_bot_rails` to your Gemfile in both the test and development groups: 31 | 32 | ```ruby 33 | group :development, :test do 34 | gem 'factory_bot_rails' 35 | end 36 | ``` 37 | 38 | You may want to configure your test suite to include factory\_bot methods; see 39 | [configuration](https://github.com/thoughtbot/factory_bot/blob/main/GETTING_STARTED.md#configure-your-test-suite). 40 | 41 | ### Automatic Factory Definition Loading 42 | 43 | By default, factory\_bot\_rails will automatically load factories 44 | defined in the following locations, 45 | relative to the root of the Rails project: 46 | 47 | ``` 48 | factories.rb 49 | test/factories.rb 50 | spec/factories.rb 51 | factories/*.rb 52 | test/factories/*.rb 53 | spec/factories/*.rb 54 | ``` 55 | 56 | You can configure by adding the following to `config/application.rb` or the 57 | appropriate environment configuration in `config/environments`: 58 | 59 | ```ruby 60 | config.factory_bot.definition_file_paths = ["custom/factories"] 61 | ``` 62 | 63 | This will cause factory\_bot\_rails to automatically load factories in 64 | `custom/factories.rb` and `custom/factories/*.rb`. 65 | 66 | It is possible to use this setting to share factories from a gem: 67 | 68 | ```rb 69 | begin 70 | require 'factory_bot_rails' 71 | rescue LoadError 72 | end 73 | 74 | class MyEngine < ::Rails::Engine 75 | config.factory_bot.definition_file_paths += 76 | [File.expand_path('../factories', __FILE__)] if defined?(FactoryBotRails) 77 | end 78 | ``` 79 | 80 | You can also disable automatic factory definition loading entirely by 81 | using an empty array: 82 | 83 | ```rb 84 | config.factory_bot.definition_file_paths = [] 85 | ``` 86 | 87 | ### File Fixture Support 88 | 89 | Factories have access to [ActiveSupport::Testing::FileFixtures#file_fixture][] 90 | helper to read files from tests. 91 | 92 | To disable file fixture support, set `file_fixture_support = false`: 93 | 94 | ```rb 95 | config.factory_bot.file_fixture_support = false 96 | ``` 97 | 98 | [ActiveSupport::Testing::FileFixtures#file_fixture]: https://api.rubyonrails.org/classes/ActiveSupport/Testing/FileFixtures.html#method-i-file_fixture 99 | 100 | ### Generators 101 | 102 | Including factory\_bot\_rails in the development group of your Gemfile 103 | will cause Rails to generate factories instead of fixtures. 104 | If you want to disable this feature, you can either move factory\_bot\_rails out 105 | of the development group of your Gemfile, or add the following configuration: 106 | 107 | ```ruby 108 | config.generators do |g| 109 | g.factory_bot false 110 | end 111 | ``` 112 | 113 | If fixture replacement is enabled and you already have a `test/factories.rb` 114 | file (or `spec/factories.rb` if using rspec_rails), generated factories will be 115 | inserted at the top of the existing file. 116 | Otherwise, factories will be generated in the 117 | `test/factories` directory (`spec/factories` if using rspec_rails), 118 | in a file matching the name of the table (e.g. `test/factories/users.rb`). 119 | 120 | To generate factories in a different directory, you can use the following 121 | configuration: 122 | 123 | ```ruby 124 | config.generators do |g| 125 | g.factory_bot dir: 'custom/dir/for/factories' 126 | end 127 | ``` 128 | 129 | Note that factory\_bot\_rails will not automatically load files in custom 130 | locations unless you add them to `config.factory_bot.definition_file_paths` as 131 | well. 132 | 133 | The suffix option allows you to customize the name of the generated file with a 134 | suffix: 135 | 136 | ```ruby 137 | config.generators do |g| 138 | g.factory_bot suffix: "factory" 139 | end 140 | ``` 141 | 142 | This will generate `test/factories/users_factory.rb` instead of 143 | `test/factories/users.rb`. 144 | 145 | For even more customization, use the `filename_proc` option: 146 | 147 | ```ruby 148 | config.generators do |g| 149 | g.factory_bot filename_proc: ->(table_name) { "prefix_#{table_name}_suffix" } 150 | end 151 | ``` 152 | 153 | To override the [default factory template][], define your own template in 154 | `lib/templates/factory_bot/model/factories.erb`. This template will have 155 | access to any methods available in `FactoryBot::Generators::ModelGenerator`. 156 | Note that factory\_bot\_rails will only use this custom template if you are 157 | generating each factory in a separate file; it will have no effect if you are 158 | generating all of your factories in `test/factories.rb` or `spec/factories.rb`. 159 | 160 | Factory\_bot\_rails will add a custom generator: 161 | 162 | ```shell 163 | rails generate factory_bot:model NAME [field:type field:type] [options] 164 | ``` 165 | 166 | [default factory template]: https://github.com/thoughtbot/factory_bot_rails/tree/main/lib/generators/factory_bot/model/templates/factories.erb 167 | 168 | ## Contributing 169 | 170 | Please see [CONTRIBUTING.md](CONTRIBUTING.md). 171 | 172 | factory_bot_rails was originally written by Joe Ferris and is maintained by thoughtbot. Many improvements and bugfixes were contributed by the [open source 173 | community](https://github.com/thoughtbot/factory_bot_rails/graphs/contributors). 174 | 175 | ## License 176 | 177 | factory_bot_rails is Copyright © 2008 Joe Ferris and thoughtbot. It is free 178 | software, and may be redistributed under the terms specified in the 179 | [LICENSE](LICENSE) file. 180 | 181 | 182 | ## About thoughtbot 183 | 184 | ![thoughtbot](https://thoughtbot.com/thoughtbot-logo-for-readmes.svg) 185 | 186 | This repo is maintained and funded by thoughtbot, inc. 187 | The names and logos for thoughtbot are trademarks of thoughtbot, inc. 188 | 189 | We love open source software! 190 | See [our other projects][community]. 191 | We are [available for hire][hire]. 192 | 193 | [community]: https://thoughtbot.com/community?utm_source=github 194 | [hire]: https://thoughtbot.com/hire-us?utm_source=github 195 | 196 | 197 | 198 | [fb]: https://github.com/thoughtbot/factory_bot 199 | [grade]: https://codeclimate.com/github/thoughtbot/factory_bot_rails 200 | [grade-image]: https://codeclimate.com/github/thoughtbot/factory_bot_rails.svg 201 | [community]: https://thoughtbot.com/community?utm_source=github 202 | [hire]: https://thoughtbot.com/hire-us?utm_source=github 203 | [version-image]: https://badge.fury.io/rb/factory_bot_rails.svg 204 | [version]: https://badge.fury.io/rb/factory_bot_rails 205 | [hound-image]: https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg 206 | [hound]: https://houndci.com 207 | -------------------------------------------------------------------------------- /RELEASING.md: -------------------------------------------------------------------------------- 1 | # Releasing 2 | 3 | 1. Update the version in the gemspec (and the factory\_bot version, if necessary) 4 | and run `bundle install` 5 | 2. Update `NEWS.md` to reflect the changes since last release. 6 | 3. Commit changes. 7 | There shouldn't be code changes, 8 | and thus CI doesn't need to run, 9 | so you can add "[ci skip]" to the commit message. 10 | 4. Tag the release: `git tag -s vVERSION` 11 | - We recommend the [_quick guide on how to sign a release_] from git ready. 12 | 5. Push changes: `git push && git push --tags` 13 | 6. Build and publish: 14 | ```bash 15 | gem build factory_bot_rails.gemspec 16 | gem push factory_bot_rails-VERSION.gem 17 | ``` 18 | 7. Add a new GitHub release using the recent `NEWS.md` as the content. Sample 19 | URL: https://github.com/thoughtbot/factory_bot_rails/releases/new?tag=vVERSION 20 | 8. Announce the new release, 21 | making sure to say "thank you" to the contributors 22 | who helped shape this version! 23 | 24 | [_quick guide on how to sign a release_]: http://gitready.com/advanced/2014/11/02/gpg-sign-releases.html 25 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/setup" 2 | require "cucumber/rake/task" 3 | require "rspec/core/rake_task" 4 | require "minitest/test_task" 5 | require "standard/rake" 6 | 7 | Bundler::GemHelper.install_tasks name: "factory_bot_rails" 8 | 9 | Cucumber::Rake::Task.new(:cucumber) do |t| 10 | t.fork = true 11 | t.cucumber_opts = ["--format", ENV.fetch("CUCUMBER_FORMAT", "progress")] 12 | end 13 | 14 | RSpec::Core::RakeTask.new(:spec) 15 | 16 | Minitest::TestTask.create 17 | 18 | desc "Run the test suite and standard" 19 | task default: %w[spec cucumber standard] 20 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Run this script immediately after cloning the codebase. 4 | 5 | # Exit if any subcommand fails 6 | set -e 7 | 8 | # Set up Ruby dependencies via Bundler 9 | bundle install 10 | 11 | # Add binstubs to PATH in ~/.zshenv like this: 12 | # export PATH=".git/safe/../../bin:$PATH" 13 | mkdir -p .git/safe 14 | 15 | # Set up Appraisal to help us test against multiple Rails versions 16 | bundle exec appraisal install 17 | -------------------------------------------------------------------------------- /cucumber.yml: -------------------------------------------------------------------------------- 1 | default: --publish-quiet 2 | -------------------------------------------------------------------------------- /factory_bot_rails.gemspec: -------------------------------------------------------------------------------- 1 | $LOAD_PATH << File.expand_path("lib", __dir__) 2 | require "factory_bot_rails/version" 3 | 4 | Gem::Specification.new do |s| 5 | s.name = "factory_bot_rails" 6 | s.version = FactoryBotRails::VERSION 7 | s.authors = ["Joe Ferris"] 8 | s.email = "jferris@thoughtbot.com" 9 | s.homepage = "https://github.com/thoughtbot/factory_bot_rails" 10 | s.summary = "factory_bot_rails provides integration between " \ 11 | "factory_bot and Rails 6.1 or newer" 12 | s.description = "factory_bot_rails provides integration between " \ 13 | "factory_bot and Rails 6.1 or newer" 14 | 15 | s.files = Dir["lib/**/*"] + %w[CONTRIBUTING.md LICENSE NEWS.md README.md] 16 | s.metadata["changelog_uri"] = "https://github.com/thoughtbot/factory_bot_rails/blob/main/NEWS.md" 17 | s.require_paths = ["lib"] 18 | s.required_ruby_version = Gem::Requirement.new(">= 3.0.0") 19 | s.executables = [] 20 | s.license = "MIT" 21 | 22 | s.add_runtime_dependency("factory_bot", "~> 6.5") 23 | s.add_runtime_dependency("railties", ">= 6.1.0") 24 | 25 | s.add_development_dependency("activerecord", ">= 6.1.0") 26 | s.add_development_dependency("activestorage", ">= 6.1.0") 27 | s.add_development_dependency("mutex_m") 28 | s.add_development_dependency("sqlite3") 29 | end 30 | -------------------------------------------------------------------------------- /features/fixture_replacement_config.feature: -------------------------------------------------------------------------------- 1 | Feature: 2 | In order to not have to manually configure Factory Bot as the Rails testing fixture replacement by using the --fixture-replacement=factory_bot option 3 | I would like the Factory Bot Rails gem to configure Factory Bot as the fixture replacement. 4 | 5 | Background: 6 | Given I create a new rails application 7 | And I add "factory_bot_rails" from this project as a dependency 8 | 9 | Scenario: Using Factory Bot and Factory Bot Rails with Test Unit generates a factory file and does not generate a fixture file 10 | And I run `bundle install --verbose` with a clean environment 11 | And I run `bundle exec rails generate model User name:string` with a clean environment 12 | Then the following files should exist: 13 | | test/factories/users.rb | 14 | And the following files should not exist: 15 | | test/fixtures/users.yml | 16 | 17 | Scenario: Using Factory Bot and Factory Bot Rails with RSpec should generate a factory file 18 | When I add "rspec-rails" as a dependency 19 | And I configure the factories as: 20 | """ 21 | config.generators do |g| 22 | g.test_framework :rspec, fixture: true 23 | g.fixture_replacement :factory_bot 24 | end 25 | """ 26 | And I run `bundle install --verbose` with a clean environment 27 | Then the output should contain "rspec-rails" 28 | And I run `bundle exec rails generate model User name:string` with a clean environment 29 | Then the following files should exist: 30 | | spec/factories/users.rb | 31 | And the following files should not exist: 32 | | spec/fixtures/users.yml | 33 | 34 | Scenario: Using Factory Bot and Factory Bot Rails with RSpec and suffix configuration should generate a factory file with suffix 35 | When I add "rspec-rails" as a dependency 36 | And I configure the factories as: 37 | """ 38 | config.generators do |g| 39 | g.test_framework :rspec, fixture: true 40 | g.fixture_replacement :factory_bot, suffix: 'factory' 41 | end 42 | """ 43 | And I run `bundle install --verbose` with a clean environment 44 | Then the output should contain "rspec-rails" 45 | And I run `bundle exec rails generate model User name:string` with a clean environment 46 | Then the following files should exist: 47 | | spec/factories/users_factory.rb | 48 | And the following files should not exist: 49 | | spec/fixtures/users.yml | 50 | 51 | Scenario: Using Factory Bot and Factory Bot Rails does not override a manually-configured factories directory using RSpec 52 | When I add "rspec-rails" as a dependency 53 | And I configure the factories directory as "custom/dir" 54 | And I run `bundle install --verbose` with a clean environment 55 | Then the output should contain "rspec-rails" 56 | And I run `bundle exec rails generate model User name:string` with a clean environment 57 | Then the following files should not exist: 58 | | test/factories/users.rb | 59 | | spec/factories/users.rb | 60 | But the following files should exist: 61 | | custom/dir/users.rb | 62 | 63 | Scenario: Using Factory Bot and Factory Bot Rails does not override a manually-configured factories directory using Test::Unit 64 | When I configure the factories directory as "custom/dir" 65 | And I run `bundle install --verbose` with a clean environment 66 | And I run `bundle exec rails generate model User name:string` with a clean environment 67 | Then the following files should not exist: 68 | | test/factories/users.rb | 69 | | spec/factories/users.rb | 70 | But the following files should exist: 71 | | custom/dir/users.rb | 72 | 73 | Scenario: Using Factory Bot Rails with MiniTest should generate a factory file 74 | When I run `bundle install --verbose` with a clean environment 75 | And I run `bundle exec rails generate model User name:string` with a clean environment 76 | Then the following files should exist: 77 | | test/factories/users.rb | 78 | But the following files should not exist: 79 | | spec/fixtures/users.yml | 80 | 81 | Scenario: Using Factory Bot Rails with MiniTest and a custom directory should generate a factory file 82 | When I configure the factories directory as "custom/dir" 83 | And I run `bundle install --verbose` with a clean environment 84 | And I run `bundle exec rails generate model User name:string` with a clean environment 85 | Then the following files should exist: 86 | | custom/dir/users.rb | 87 | But the following files should not exist: 88 | | spec/fixtures/users.yml | 89 | 90 | Scenario: Disable Factory Bot generator 91 | When I configure the factories as: 92 | """ 93 | config.generators do |g| 94 | g.factory_bot false 95 | end 96 | """ 97 | And I run `bundle install --verbose` with a clean environment 98 | And I run `bundle exec rails generate model User name:string` with a clean environment 99 | Then the following files should not exist: 100 | | test/factories/users.rb | 101 | | spec/factories/users.rb | 102 | 103 | Scenario: Use a suffix with the Factory Bot generator 104 | When I add "rspec-rails" as a dependency 105 | When I configure the factories as: 106 | """ 107 | config.generators do |g| 108 | g.factory_bot suffix: 'suffix' 109 | end 110 | """ 111 | And I run `bundle install --verbose` with a clean environment 112 | And I run `bundle exec rails generate model User name:string` with a clean environment 113 | Then the following files should exist: 114 | | spec/factories/users_suffix.rb | 115 | Then the following files should not exist: 116 | | spec/factories/users.rb | 117 | 118 | Scenario: Use a filename_proc with the Factory Bot generator 119 | When I add "rspec-rails" as a dependency 120 | When I configure the factories as: 121 | """ 122 | config.generators do |g| 123 | g.factory_bot filename_proc: Proc.new { |tb| "prefix_#{tb.singularize}_suffix" } 124 | end 125 | """ 126 | And I run `bundle install --verbose` with a clean environment 127 | And I run `bundle exec rails generate model User name:string` with a clean environment 128 | Then the following files should exist: 129 | | spec/factories/prefix_user_suffix.rb | 130 | Then the following files should not exist: 131 | | spec/factories/users.rb | 132 | -------------------------------------------------------------------------------- /features/generators.feature: -------------------------------------------------------------------------------- 1 | Feature: 2 | In order to easily generate factory files instead of fixture files when generating models 3 | As a user of Rails and Factory Bot 4 | I would like to use factory_bot_rails generators. 5 | 6 | Background: 7 | Given I create a new rails application 8 | And I add "factory_bot_rails" from this project as a dependency 9 | And I run `bundle install` with a clean environment 10 | 11 | Scenario: The factory_bot_rails generators create a factory file for each model if there is not a factories.rb file 12 | When I run `bundle exec rails generate model User name:string age:integer` with a clean environment 13 | And I run `bundle exec rails generate model Namespaced::User name:string` with a clean environment 14 | Then the output should contain "test/factories/users.rb" 15 | And the output should contain "test/factories/namespaced/users.rb" 16 | And the file "test/factories/users.rb" should contain exactly: 17 | """ 18 | FactoryBot.define do 19 | factory :user do 20 | name { "MyString" } 21 | age { 1 } 22 | end 23 | end 24 | """ 25 | And the file "test/factories/namespaced/users.rb" should contain "factory :namespaced_user, class: 'Namespaced::User' do" 26 | 27 | Scenario: The factory_bot_rails generators create a factory file with correct naming when I use --force-plural 28 | When I run `bundle exec rails generate model UserMedia filename:string --force-plural` with a clean environment 29 | Then the output should contain "test/factories/user_media.rb" 30 | And the file "test/factories/user_media.rb" should contain exactly: 31 | """ 32 | FactoryBot.define do 33 | factory :user_media do 34 | filename { "MyString" } 35 | end 36 | end 37 | """ 38 | 39 | Scenario: The factory_bot_rails generators add a factory in the correct spot 40 | When I write to "test/factories.rb" with: 41 | """ 42 | FactoryBot.define do 43 | end 44 | """ 45 | And I run `bundle exec rails generate model User name:string` with a clean environment 46 | And I run `bundle exec rails generate model Robot name:string` with a clean environment 47 | Then the file "test/factories.rb" should contain exactly: 48 | """ 49 | FactoryBot.define do 50 | factory :robot do 51 | name { "MyString" } 52 | end 53 | 54 | factory :user do 55 | name { "MyString" } 56 | end 57 | 58 | end 59 | """ 60 | 61 | Scenario: The factory_bot_rails generators does not create a factory file for each model if there is a factories.rb file in the test directory 62 | When I write to "test/factories.rb" with: 63 | """ 64 | FactoryBot.define do 65 | end 66 | """ 67 | And I run `bundle exec rails generate model User name:string` with a clean environment 68 | Then the file "test/factories/users.rb" should not contain "factory :user do" 69 | 70 | Scenario: The factory_bot_rails generators use a custom template 71 | When I write to "lib/templates/factory_bot/model/factories.erb" with: 72 | """ 73 | <%= "Custom factory definition" %> 74 | """ 75 | And I run `bundle exec rails generate model User` with a clean environment 76 | Then the file "test/factories/users.rb" should contain exactly: 77 | """ 78 | Custom factory definition 79 | """ 80 | 81 | Scenario: The factory_bot_rails generator can be disabled 82 | When I append to "config/application.rb" with: 83 | """ 84 | Rails.application.configure do 85 | config.generators do |g| 86 | g.factory_bot false 87 | end 88 | end 89 | """ 90 | And I run `bundle exec rails generate model User name:string age:integer` with a clean environment 91 | Then the output should not contain "test/factories/users.rb" 92 | And the output should contain "test/fixtures/users.yml" 93 | -------------------------------------------------------------------------------- /features/initializers.feature: -------------------------------------------------------------------------------- 1 | Feature: properly integrate with Rails and other gems 2 | 3 | Background: 4 | When I create a new rails application 5 | And I add "factory_bot_rails" from this project as a dependency 6 | And I run `bundle install` with a clean environment 7 | 8 | Scenario: handle already loaded ActiveRecord::Base by another gems earlier 9 | When I run the following commands: 10 | """bash 11 | cat config/application.rb 12 | sed -i -e '/require "rails\/test_unit\/railtie"/a\'$'\n''require "active_record/base"' config/application.rb 13 | """ 14 | When I run `bundle exec rake test` with a clean environment 15 | Then the output should contain "0 runs" 16 | -------------------------------------------------------------------------------- /features/load_definitions.feature: -------------------------------------------------------------------------------- 1 | Feature: automatically load factory definitions 2 | 3 | Background: 4 | When I create a new rails application 5 | And I add "factory_bot_rails" from this project as a dependency 6 | And I run `bundle install` with a clean environment 7 | And I write to "db/migrate/1_create_users.rb" with: 8 | """ 9 | migration_class = 10 | if ActiveRecord::Migration.respond_to?(:[]) 11 | ActiveRecord::Migration[4.2] 12 | else 13 | ActiveRecord::Migration 14 | end 15 | 16 | class CreateUsers < migration_class 17 | def self.up 18 | create_table :users do |t| 19 | t.string :name 20 | end 21 | end 22 | end 23 | """ 24 | When I run `bundle exec rake db:migrate` with a clean environment 25 | And I write to "app/models/user.rb" with: 26 | """ 27 | class User < ActiveRecord::Base 28 | end 29 | """ 30 | 31 | Scenario: generate a Rails application and use factory definitions 32 | When I write to "test/factories.rb" with: 33 | """ 34 | FactoryBot.define do 35 | factory :user do 36 | name { "Frank" } 37 | end 38 | end 39 | """ 40 | When I write to "test/unit/user_test.rb" with: 41 | """ 42 | require 'test_helper' 43 | 44 | class UserTest < ActiveSupport::TestCase 45 | test "use factory" do 46 | user = FactoryBot.create(:user) 47 | assert_equal 'Frank', user.name 48 | end 49 | end 50 | """ 51 | When I run `bundle exec rake test` with a clean environment 52 | Then the output should contain "1 assertions, 0 failures, 0 errors" 53 | 54 | Scenario: use custom definition file paths 55 | When I configure the factories as: 56 | """ 57 | config.factory_bot.definition_file_paths = ["custom_factories_path"] 58 | """ 59 | When I write to "custom_factories_path.rb" with: 60 | """ 61 | FactoryBot.define do 62 | factory :user do 63 | name { "Frank" } 64 | end 65 | end 66 | """ 67 | When I write to "test/unit/user_test.rb" with: 68 | """ 69 | require 'test_helper' 70 | 71 | class UserTest < ActiveSupport::TestCase 72 | test "use factory" do 73 | user = FactoryBot.create(:user) 74 | assert_equal 'Frank', user.name 75 | end 76 | end 77 | """ 78 | When I run `bundle exec rake test` with a clean environment 79 | Then the output should contain "1 assertions, 0 failures, 0 errors" 80 | 81 | Scenario: use 3rd-party factories with configured definition file paths 82 | When I append to "config/application.rb" with: 83 | """ 84 | require File.expand_path('../../lib/some_railtie/railties.rb', __FILE__) 85 | """ 86 | When I write to "lib/some_railtie/railties.rb" with: 87 | """ 88 | module SomeRailtie 89 | class Railtie < ::Rails::Engine 90 | config.factory_bot.definition_file_paths << File.expand_path('../factories', __FILE__) 91 | end 92 | end 93 | """ 94 | When I write to "lib/some_railtie/factories.rb" with: 95 | """ 96 | FactoryBot.define do 97 | factory :factory_from_some_railtie, class: 'User' do 98 | name { 'Artem' } 99 | end 100 | end 101 | """ 102 | When I write to "test/unit/user_test.rb" with: 103 | """ 104 | require 'test_helper' 105 | 106 | class UserTest < ActiveSupport::TestCase 107 | test "use factory of some_railtie" do 108 | user = FactoryBot.create(:factory_from_some_railtie) 109 | assert_equal 'Artem', user.name 110 | end 111 | end 112 | """ 113 | When I run `bundle exec rake test` with a clean environment 114 | Then the output should contain "1 assertions, 0 failures, 0 errors" 115 | 116 | Scenario: use 3rd-party factories with an initializer and without any user-defined factories 117 | When I append to "config/application.rb" with: 118 | """ 119 | require File.expand_path('../../lib/some_railtie/railties.rb', __FILE__) 120 | """ 121 | When I write to "lib/some_railtie/railties.rb" with: 122 | """ 123 | module SomeRailtie 124 | class Railtie < ::Rails::Engine 125 | initializer "some_railtie.factories", :after => "factory_bot.set_factory_paths" do 126 | FactoryBot.definition_file_paths << File.expand_path('../factories', __FILE__) 127 | end 128 | end 129 | end 130 | """ 131 | When I write to "lib/some_railtie/factories.rb" with: 132 | """ 133 | FactoryBot.define do 134 | factory :factory_from_some_railtie, class: 'User' do 135 | name { 'Artem' } 136 | end 137 | end 138 | """ 139 | When I write to "test/unit/user_test.rb" with: 140 | """ 141 | require 'test_helper' 142 | 143 | class UserTest < ActiveSupport::TestCase 144 | test "use factory of some_railtie" do 145 | railtie_user = FactoryBot.create(:factory_from_some_railtie) 146 | assert_equal 'Artem', railtie_user.name 147 | end 148 | end 149 | """ 150 | When I run `bundle exec rake test` with a clean environment 151 | Then the output should contain "1 assertions, 0 failures, 0 errors" 152 | 153 | Scenario: use 3rd-party factories with an initializer together with a user-defined factory 154 | When I append to "config/application.rb" with: 155 | """ 156 | require File.expand_path('../../lib/some_railtie/railties.rb', __FILE__) 157 | """ 158 | When I write to "lib/some_railtie/railties.rb" with: 159 | """ 160 | module SomeRailtie 161 | class Railtie < ::Rails::Engine 162 | initializer "some_railtie.factories", :after => "factory_bot.set_factory_paths" do 163 | FactoryBot.definition_file_paths << File.expand_path('../factories', __FILE__) 164 | end 165 | end 166 | end 167 | """ 168 | When I write to "lib/some_railtie/factories.rb" with: 169 | """ 170 | FactoryBot.define do 171 | factory :factory_from_some_railtie, class: 'User' do 172 | name { 'Artem' } 173 | end 174 | end 175 | """ 176 | When I write to "test/factories.rb" with: 177 | """ 178 | FactoryBot.define do 179 | factory :user do 180 | name { "Frank" } 181 | end 182 | end 183 | """ 184 | When I write to "test/unit/user_test.rb" with: 185 | """ 186 | require 'test_helper' 187 | 188 | class UserTest < ActiveSupport::TestCase 189 | test "use factory of some_railtie" do 190 | railtie_user = FactoryBot.create(:factory_from_some_railtie) 191 | assert_equal 'Artem', railtie_user.name 192 | 193 | user = FactoryBot.create(:user) 194 | assert_equal 'Frank', user.name 195 | end 196 | end 197 | """ 198 | When I run `bundle exec rake test` with a clean environment 199 | Then the output should contain "2 assertions, 0 failures, 0 errors" 200 | -------------------------------------------------------------------------------- /features/reloading.feature: -------------------------------------------------------------------------------- 1 | Feature: automatically reloading factory_bot definitions 2 | Background: 3 | When I create a new rails application 4 | And I add "factory_bot_rails" from this project as a dependency 5 | And I run `bundle install` with a clean environment 6 | And I write to "db/migrate/1_create_users.rb" with: 7 | """ 8 | class CreateUsers < ActiveRecord::Migration[5.0] 9 | def self.up 10 | create_table :users do |t| 11 | t.string :name 12 | end 13 | end 14 | end 15 | """ 16 | And I run `bin/rails db:migrate` with a clean environment 17 | 18 | Scenario: When using factory_bot_rails together with Spring 19 | I want changes to my application to trigger the factory_bot_rails reloader 20 | So that factory_bot_rails doesn't hold onto stale class references 21 | 22 | When I write to "app/models/user.rb" with: 23 | """ 24 | class User < ActiveRecord::Base 25 | end 26 | """ 27 | And I write to "test/factories.rb" with: 28 | """ 29 | FactoryBot.define do 30 | factory :author, class: User do 31 | name { "Frank" } 32 | end 33 | end 34 | """ 35 | And I write to "test/unit/user_test.rb" with: 36 | """ 37 | require 'test_helper' 38 | 39 | class UserTest < ActiveSupport::TestCase 40 | test "user factory" do 41 | author = FactoryBot.create(:author) 42 | 43 | assert_equal author.class.object_id, User.object_id 44 | end 45 | end 46 | """ 47 | And I run `bundle binstubs bundler spring --force` with a clean environment 48 | And I run `bin/spring binstub --all` with a clean environment 49 | And I run `bin/rails test` with Spring enabled 50 | And I append to "app/models/user.rb" with: 51 | """ 52 | # User model edited 53 | """ 54 | And I run `bin/rails test` with Spring enabled 55 | And I run `bin/spring stop` with a clean environment 56 | #Then the output should contain "1 runs, 1 assertions" 57 | And the output should not contain "Failure:" 58 | 59 | Scenario: When using factory_bot_rails together with Spring 60 | I want changes to my factory_bot definitions to trigger a reload 61 | So that I can use my updated definitions without stopping spring 62 | 63 | When I write to "app/models/user.rb" with: 64 | """ 65 | class User < ActiveRecord::Base 66 | end 67 | """ 68 | And I write to "test/factories.rb" with: 69 | """ 70 | # Empty definition file to be picked up by the file watcher 71 | 72 | """ 73 | And I run `bundle binstubs bundler spring --force` with a clean environment 74 | And I run `bin/spring binstub --all` with a clean environment 75 | And I run `bin/rails test` with Spring enabled 76 | And I append to "test/factories.rb" with: 77 | """ 78 | FactoryBot.define do 79 | factory :author, class: User do 80 | name { "Frank" } 81 | end 82 | end 83 | """ 84 | And I write to "test/unit/user_test.rb" with: 85 | """ 86 | require 'test_helper' 87 | 88 | class UserTest < ActiveSupport::TestCase 89 | test "user factory" do 90 | author = FactoryBot.create(:author) 91 | 92 | assert_equal author.class.object_id, User.object_id 93 | end 94 | end 95 | """ 96 | And I run `bin/rails test` with Spring enabled 97 | And I run `bin/spring stop` with a clean environment 98 | #Then the output should contain "1 runs, 1 assertions" 99 | And the output should not contain "Failure:" 100 | 101 | Scenario: Initializing the reloader with I18n support 102 | When I write to "app/models/user.rb" with: 103 | """ 104 | class User 105 | TRANSLATION = I18n.translate("translation_key") 106 | end 107 | """ 108 | And I write to "config/locales/en.yml" with: 109 | """ 110 | en: 111 | translation_key: "translation_value" 112 | """ 113 | And I write to "test/factories.rb" with: 114 | """ 115 | FactoryBot.define do 116 | factory :user do 117 | User::TRANSLATION 118 | end 119 | end 120 | """ 121 | And I write to "test/unit/user_test.rb" with: 122 | """ 123 | require 'test_helper' 124 | 125 | class UserTest < ActiveSupport::TestCase 126 | test "user factory" do 127 | user = FactoryBot.build(:user) 128 | 129 | assert_equal "translation_value", User::TRANSLATION 130 | end 131 | end 132 | """ 133 | And I run `bin/rails test` with a clean environment 134 | Then the output should contain "1 runs, 1 assertions" 135 | And the output should not contain "Failure:" 136 | -------------------------------------------------------------------------------- /features/step_definitions/appraisal.rb: -------------------------------------------------------------------------------- 1 | When(/^I run `([^"]+)` with a clean environment$/) do |command| 2 | step <<~STEP 3 | I successfully run `ruby -e 'system({"BUNDLE_GEMFILE" => nil, "DISABLE_SPRING" => "true"}, "#{command}")'` 4 | STEP 5 | end 6 | 7 | When(/^I run `([^"]+)` with Spring enabled$/) do |command| 8 | step <<~STEP 9 | I successfully run `ruby -e 'system({"BUNDLE_GEMFILE" => nil}, "#{command}")'` 10 | STEP 11 | end 12 | -------------------------------------------------------------------------------- /features/step_definitions/rails_steps.rb: -------------------------------------------------------------------------------- 1 | When(/^I create a new rails application$/) do 2 | options = 3 | %w[ 4 | --api 5 | --skip-bootsnap 6 | --skip-javascript 7 | --skip-action-mailer 8 | --skip-active-storage 9 | --skip-action-cable 10 | --skip-sprockets 11 | --skip-bundle 12 | ].join(" ") 13 | 14 | template = "-m ../../features/support/rails_template" 15 | result = run_command("bundle exec rails new test_app #{options} #{template}") 16 | 17 | expect(result).to have_output(/README/) 18 | expect(last_command_started).to be_successfully_executed 19 | 20 | cd("test_app") 21 | end 22 | 23 | When(/^I add "([^"]+)" from this project as a dependency$/) do |gem_name| 24 | append_to_file("Gemfile", %(gem "#{gem_name}", :path => "#{PROJECT_ROOT}"\n)) 25 | end 26 | 27 | When(/^I add "([^"]+)" as a dependency$/) do |gem_name| 28 | append_to_file("Gemfile", %(gem "#{gem_name}"\n)) 29 | end 30 | 31 | When(/^I print out "([^"]*)"$/) do |path| 32 | in_current_dir do 33 | File.open(path, "r") do |f| 34 | puts f.inspect 35 | end 36 | end 37 | end 38 | 39 | When(/^I configure the factories as:$/) do |string| 40 | append_to_file File.join("config", "application.rb"), <<~RUBY 41 | class TestApp::Application 42 | #{string} 43 | end 44 | RUBY 45 | end 46 | 47 | When(/^I configure the factories directory as "([^"]+)"$/) do |factory_dir| 48 | append_to_file File.join("config", "application.rb"), <<~RUBY 49 | class TestApp::Application 50 | config.generators do |g| 51 | g.fixture_replacement :factory_bot, :dir => "#{factory_dir}" 52 | end 53 | end 54 | RUBY 55 | end 56 | 57 | When(/^I comment out gem "([^"]*)" from my Gemfile$/) do |gem_name| 58 | in_current_dir do 59 | content = File.read("Gemfile") 60 | File.write("Gemfile", content.sub(/gem ['"]#{gem_name}/, '#\1')) 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /features/support/env.rb: -------------------------------------------------------------------------------- 1 | require "aruba/cucumber" 2 | 3 | PROJECT_ROOT = 4 | File.expand_path(File.join(File.dirname(__FILE__), "..", "..")).freeze 5 | 6 | Aruba.configure do |config| 7 | config.exit_timeout = Integer ENV.fetch("ARUBA_TIMEOUT", 120) 8 | end 9 | 10 | if RUBY_PLATFORM == "java" 11 | Aruba.configure do |config| 12 | config.before_cmd do 13 | # disable JIT since these processes are so short lived 14 | set_env("JRUBY_OPTS", "-X-C #{ENV["JRUBY_OPTS"]}") 15 | 16 | java_options = ENV["JAVA_OPTS"] 17 | 18 | if 1.size == 4 # 4 for 32 bit java, 8 for 64 bit java. 19 | set_env("JAVA_OPTS", "-d32 #{java_options}") 20 | else 21 | set_env( 22 | "JAVA_OPTS", 23 | "-XX:+TieredCompilation -XX:TieredStopAtLevel=1 #{java_options}" 24 | ) 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /features/support/rails_template: -------------------------------------------------------------------------------- 1 | if Rails.gem_version < Gem::Version.new('7.1') 2 | append_to_file("Gemfile", %(gem "bigdecimal"\n)) 3 | append_to_file("Gemfile", %(gem "logger"\n)) 4 | append_to_file("Gemfile", %(gem "mutex_m"\n)) 5 | append_to_file("Gemfile", %(gem "drb"\n)) 6 | append_to_file("Gemfile", %(gem "concurrent-ruby", "< 1.3.5"\n)) 7 | end 8 | 9 | gsub_file "Gemfile", /^ gem 'spring'$/, ' gem "spring", "!= 2.1.1"' 10 | gsub_file "Gemfile", /^ gem "debug".*/, '' 11 | 12 | if Rails.gem_version >= Gem::Version.new('7.1') 13 | append_to_file File.join("config", "application.rb"), <<~RUBY 14 | class TestApp::Application 15 | config.autoload_lib(ignore: %w(some_railtie)) 16 | end 17 | RUBY 18 | 19 | gsub_file "config/routes.rb", /^ get/, ' # get' 20 | end 21 | -------------------------------------------------------------------------------- /gemfiles/rails5.0.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "appraisal" 6 | gem "aruba" 7 | gem "cucumber" 8 | gem "rake" 9 | gem "rspec-rails" 10 | gem "standard" 11 | gem "byebug" 12 | gem "listen", "~> 3.0.5" 13 | gem "puma", "~> 3.0" 14 | gem "rails", "~> 5.0.7", ">= 5.0.7.2" 15 | gem "spring", "!= 2.1.1" 16 | gem "spring-watcher-listen", "~> 2.0.0" 17 | gem "sqlite3", "~> 1.3.6" 18 | 19 | gemspec name: "factory_bot_rails", path: "../" 20 | -------------------------------------------------------------------------------- /gemfiles/rails5.1.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "appraisal" 6 | gem "aruba" 7 | gem "cucumber" 8 | gem "rake" 9 | gem "rspec-rails" 10 | gem "standard" 11 | gem "byebug" 12 | gem "listen", ">= 3.0.5", "< 3.2" 13 | gem "puma", "~> 3.7" 14 | gem "rails", "~> 5.1.7" 15 | gem "spring", "!= 2.1.1" 16 | gem "spring-watcher-listen", "~> 2.0.0" 17 | gem "sqlite3", "~> 1.3.6" 18 | 19 | gemspec name: "factory_bot_rails", path: "../" 20 | -------------------------------------------------------------------------------- /gemfiles/rails5.2.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "appraisal" 6 | gem "aruba" 7 | gem "cucumber" 8 | gem "rake" 9 | gem "rspec-rails" 10 | gem "standard" 11 | gem "byebug" 12 | gem "listen", ">= 3.0.5", "< 3.2" 13 | gem "puma", "~> 3.11" 14 | gem "rails", "~> 5.2.4", ">= 5.2.4.2" 15 | gem "spring", "!= 2.1.1" 16 | gem "spring-watcher-listen", "~> 2.0.0" 17 | gem "sqlite3", "~> 1.3.6" 18 | 19 | gemspec name: "factory_bot_rails", path: "../" 20 | -------------------------------------------------------------------------------- /gemfiles/rails6.0.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "appraisal" 6 | gem "aruba" 7 | gem "cucumber" 8 | gem "rake" 9 | gem "rspec-rails" 10 | gem "standard" 11 | gem "byebug" 12 | gem "listen", "~> 3.2" 13 | gem "puma", "~> 4.1" 14 | gem "rails", "~> 6.0.2", ">= 6.0.2.2" 15 | gem "spring", "!= 2.1.1" 16 | gem "spring-watcher-listen", "~> 2.0.0" 17 | gem "sqlite3", "~> 1.4" 18 | 19 | gemspec name: "factory_bot_rails", path: "../" 20 | -------------------------------------------------------------------------------- /gemfiles/rails6.1.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "appraisal" 6 | gem "aruba" 7 | gem "cucumber" 8 | gem "rake" 9 | gem "rspec-rails" 10 | gem "standard" 11 | gem "bigdecimal" 12 | gem "byebug" 13 | gem "concurrent-ruby", "< 1.3.5" 14 | gem "drb" 15 | gem "listen", "~> 3.2" 16 | gem "puma", "~> 5.0" 17 | gem "rails", "~> 6.1.0", ">= 6.1.0.0" 18 | gem "spring", "!= 2.1.1" 19 | gem "spring-watcher-listen", "~> 2.0.0" 20 | gem "sqlite3", "~> 1.4" 21 | 22 | gemspec name: "factory_bot_rails", path: "../" 23 | -------------------------------------------------------------------------------- /gemfiles/rails7.0.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "appraisal" 6 | gem "aruba" 7 | gem "cucumber" 8 | gem "rake" 9 | gem "rspec-rails" 10 | gem "standard" 11 | gem "bigdecimal" 12 | gem "byebug" 13 | gem "concurrent-ruby", "< 1.3.5" 14 | gem "drb" 15 | gem "listen", "~> 3.2" 16 | gem "puma", "~> 5.0" 17 | gem "rails", "~> 7.0.1", ">= 7.0.1" 18 | gem "spring", "!= 2.1.1" 19 | gem "spring-watcher-listen", "~> 2.0.0" 20 | gem "sqlite3", "~> 1.4" 21 | 22 | gemspec name: "factory_bot_rails", path: "../" 23 | -------------------------------------------------------------------------------- /gemfiles/rails7.1.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "appraisal" 6 | gem "aruba" 7 | gem "byebug" 8 | gem "cucumber" 9 | gem "error_highlight" 10 | gem "listen", "~> 3.2" 11 | gem "puma", "~> 6.0" 12 | gem "rails", "~> 7.1.0" 13 | gem "rake" 14 | gem "rspec-rails" 15 | gem "spring", "!= 2.1.1" 16 | gem "spring-watcher-listen", "~> 2.0.0" 17 | gem "sqlite3", "~> 1.4" 18 | gem "standard" 19 | 20 | gemspec name: "factory_bot_rails", path: "../" 21 | -------------------------------------------------------------------------------- /gemfiles/rails7.2.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "appraisal" 6 | gem "aruba" 7 | gem "brakeman" 8 | gem "byebug" 9 | gem "cucumber" 10 | gem "listen", "~> 3.2" 11 | gem "puma", "~> 6.0" 12 | gem "rails", "~> 7.2.0" 13 | gem "rake" 14 | gem "rspec-rails" 15 | gem "rubocop-rails-omakase" 16 | gem "spring", "!= 2.1.1" 17 | gem "spring-watcher-listen", "~> 2.0.0" 18 | gem "sqlite3", "~> 1.4" 19 | gem "standard" 20 | 21 | gemspec name: "factory_bot_rails", path: "../" 22 | -------------------------------------------------------------------------------- /gemfiles/rails8.0.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "appraisal" 6 | gem "aruba" 7 | gem "brakeman" 8 | gem "byebug" 9 | gem "cucumber" 10 | gem "kamal" 11 | gem "listen", "~> 3.2" 12 | gem "puma", "~> 6.0" 13 | gem "rails", "~> 8.0.0" 14 | gem "rake" 15 | gem "rspec-rails" 16 | gem "rubocop-rails-omakase" 17 | gem "solid_cache" 18 | gem "solid_queue" 19 | gem "spring", "!= 2.1.1" 20 | gem "spring-watcher-listen", "~> 2.0.0" 21 | gem "sqlite3", ">= 2.1" 22 | gem "standard" 23 | gem "thruster" 24 | 25 | gemspec name: "factory_bot_rails", path: "../" 26 | -------------------------------------------------------------------------------- /lib/factory_bot_rails.rb: -------------------------------------------------------------------------------- 1 | require "factory_bot_rails/railtie" 2 | 3 | module FactoryBotRails 4 | end 5 | -------------------------------------------------------------------------------- /lib/factory_bot_rails/definition_file_paths.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module FactoryBotRails 4 | class DefinitionFilePaths 5 | def initialize(definition_file_paths) 6 | @files = [] 7 | @directories = {} 8 | 9 | definition_file_paths.each do |path| 10 | @files << "#{path}.rb" 11 | @directories[path.to_s] = [:rb] 12 | end 13 | end 14 | 15 | def directories 16 | @directories.select { |path| Dir.exist?(path) } 17 | end 18 | 19 | def files 20 | @files.select { |file| File.exist?(file) } 21 | end 22 | 23 | def any? 24 | directories.any? || files.any? 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /lib/factory_bot_rails/factory_validator.rb: -------------------------------------------------------------------------------- 1 | module FactoryBotRails 2 | class FactoryValidator 3 | def initialize(validators = []) 4 | @validators = Array(validators) 5 | end 6 | 7 | def add_validator(validator) 8 | @validators << validator 9 | end 10 | 11 | def run 12 | ActiveSupport::Notifications.subscribe("factory_bot.compile_factory", &validate_compiled_factory) 13 | end 14 | 15 | private 16 | 17 | def validate_compiled_factory 18 | proc do |event| 19 | @validators.each { |validator| validator.validate!(event.payload) } 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/factory_bot_rails/file_fixture_support.rb: -------------------------------------------------------------------------------- 1 | module FactoryBotRails 2 | module FileFixtureSupport 3 | def self.included(klass) 4 | klass.cattr_accessor :file_fixture_support 5 | 6 | klass.delegate :file_fixture, to: "self.class.file_fixture_support" 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/factory_bot_rails/generator.rb: -------------------------------------------------------------------------------- 1 | require "factory_bot_rails/generators/rspec_generator" 2 | require "factory_bot_rails/generators/non_rspec_generator" 3 | require "factory_bot_rails/generators/null_generator" 4 | 5 | module FactoryBotRails 6 | class Generator 7 | def initialize(config) 8 | @generators = config.app_generators 9 | end 10 | 11 | def run 12 | generator.new(@generators).run 13 | end 14 | 15 | def generator 16 | return Generators::NullGenerator if factory_bot_disabled? 17 | 18 | if test_framework == :rspec 19 | Generators::RSpecGenerator 20 | else 21 | Generators::NonRSpecGenerator 22 | end 23 | end 24 | 25 | def test_framework 26 | rails_options[:test_framework] 27 | end 28 | 29 | def factory_bot_disabled? 30 | rails_options[:factory_bot] == false 31 | end 32 | 33 | def rails_options 34 | @generators.options[:rails] 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /lib/factory_bot_rails/generators/non_rspec_generator.rb: -------------------------------------------------------------------------------- 1 | module FactoryBotRails 2 | module Generators 3 | class NonRSpecGenerator 4 | def initialize(generators) 5 | @generators = generators 6 | end 7 | 8 | def run 9 | @generators.test_framework( 10 | test_framework, 11 | fixture: false, 12 | fixture_replacement: :factory_bot 13 | ) 14 | end 15 | 16 | private 17 | 18 | def test_framework 19 | @generators.options[:rails][:test_framework] 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/factory_bot_rails/generators/null_generator.rb: -------------------------------------------------------------------------------- 1 | module FactoryBotRails 2 | module Generators 3 | class NullGenerator 4 | def initialize(*) 5 | end 6 | 7 | def run 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/factory_bot_rails/generators/rspec_generator.rb: -------------------------------------------------------------------------------- 1 | module FactoryBotRails 2 | module Generators 3 | class RSpecGenerator 4 | def initialize(generators) 5 | @generators = generators 6 | end 7 | 8 | def run 9 | @generators.fixture_replacement( 10 | fixture_replacement_setting, 11 | dir: factory_bot_directory 12 | ) 13 | end 14 | 15 | private 16 | 17 | def fixture_replacement_setting 18 | @generators.options[:rails][:fixture_replacement] || :factory_bot 19 | end 20 | 21 | def factory_bot_directory 22 | factory_bot_options.fetch(:dir, "spec/factories") 23 | end 24 | 25 | def factory_bot_options 26 | @generators.options.fetch(:factory_bot, {}) 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/factory_bot_rails/railtie.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "factory_bot" 4 | require "factory_bot_rails/generator" 5 | require "factory_bot_rails/reloader" 6 | require "factory_bot_rails/factory_validator" 7 | require "factory_bot_rails/file_fixture_support" 8 | require "rails" 9 | 10 | module FactoryBotRails 11 | class Railtie < Rails::Railtie 12 | config.factory_bot = ActiveSupport::OrderedOptions.new 13 | config.factory_bot.definition_file_paths = FactoryBot.definition_file_paths 14 | config.factory_bot.validator = FactoryBotRails::FactoryValidator.new 15 | config.factory_bot.file_fixture_support = true 16 | 17 | initializer "factory_bot.set_fixture_replacement" do 18 | Generator.new(config).run 19 | end 20 | 21 | initializer "factory_bot.set_factory_paths" do 22 | FactoryBot.definition_file_paths = definition_file_paths 23 | end 24 | 25 | config.after_initialize do 26 | if config.factory_bot.file_fixture_support 27 | FactoryBot::SyntaxRunner.include FactoryBotRails::FileFixtureSupport 28 | 29 | ActiveSupport.on_load :active_support_test_case do 30 | setup { FactoryBot::SyntaxRunner.file_fixture_support = self } 31 | end 32 | 33 | if defined?(RSpec) && RSpec.respond_to?(:configure) 34 | RSpec.configure do |config| 35 | config.before { FactoryBot::SyntaxRunner.file_fixture_support = self } 36 | end 37 | end 38 | end 39 | end 40 | 41 | config.after_initialize do |app| 42 | FactoryBot.find_definitions 43 | Reloader.new(app).run 44 | app.config.factory_bot.validator.run 45 | end 46 | 47 | private 48 | 49 | def definition_file_paths 50 | config.factory_bot.definition_file_paths.map do |path| 51 | Rails.root.join(path) 52 | end 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /lib/factory_bot_rails/reloader.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "factory_bot_rails/definition_file_paths" 4 | 5 | module FactoryBotRails 6 | class Reloader 7 | def initialize(app) 8 | @app = app 9 | @paths = DefinitionFilePaths.new(FactoryBot.definition_file_paths) 10 | end 11 | 12 | def run 13 | return unless @paths.any? 14 | 15 | register_reloader(build_reloader) 16 | end 17 | 18 | private 19 | 20 | attr_reader :app 21 | 22 | def build_reloader 23 | reloader_class.new(@paths.files, @paths.directories) do 24 | FactoryBot.reload 25 | end 26 | end 27 | 28 | def reloader_class 29 | app.config.file_watcher 30 | end 31 | 32 | def register_reloader(reloader) 33 | app.reloader.to_prepare do 34 | reloader.execute 35 | end 36 | 37 | app.reloaders << reloader 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /lib/factory_bot_rails/version.rb: -------------------------------------------------------------------------------- 1 | module FactoryBotRails 2 | VERSION = "6.4.4".freeze 3 | end 4 | -------------------------------------------------------------------------------- /lib/generators/factory_bot.rb: -------------------------------------------------------------------------------- 1 | require "rails/generators/named_base" 2 | 3 | module FactoryBot 4 | module Generators 5 | class Base < Rails::Generators::NamedBase # :nodoc: 6 | def self.source_root 7 | path = File.join( 8 | File.dirname(__FILE__), 9 | "factory_bot", 10 | generator_name, 11 | "templates" 12 | ) 13 | 14 | File.expand_path(path) 15 | end 16 | 17 | def factory_name 18 | class_name.gsub("::", "").underscore 19 | end 20 | 21 | def explicit_class_option 22 | return if class_name.underscore == factory_name 23 | 24 | ", class: '#{class_name}'" 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/generators/factory_bot/model/model_generator.rb: -------------------------------------------------------------------------------- 1 | require "generators/factory_bot" 2 | require "factory_bot_rails" 3 | 4 | module FactoryBot 5 | module Generators 6 | class ModelGenerator < Base 7 | argument( 8 | :attributes, 9 | type: :array, 10 | default: [], 11 | banner: "field:type field:type" 12 | ) 13 | 14 | class_option( 15 | :dir, 16 | type: :string, 17 | default: "test/factories", 18 | desc: "The directory or file root where factories belong" 19 | ) 20 | 21 | class_option( 22 | :suffix, 23 | type: :string, 24 | default: nil, 25 | desc: "Suffix to add factory file" 26 | ) 27 | 28 | def create_fixture_file 29 | if File.exist?(factories_file) 30 | insert_factory_into_existing_file 31 | else 32 | create_factory_file 33 | end 34 | end 35 | 36 | private 37 | 38 | def factories_file 39 | options[:dir] + ".rb" 40 | end 41 | 42 | def insert_factory_into_existing_file 43 | insert_into_file( 44 | factories_file, 45 | factory_definition, 46 | after: "FactoryBot.define do\n" 47 | ) 48 | end 49 | 50 | def create_factory_file 51 | file = File.join(options[:dir], "#{filename}.rb") 52 | template "factories.erb", file 53 | end 54 | 55 | def factory_definition 56 | <<~RUBY 57 | factory :#{factory_name}#{explicit_class_option} do 58 | #{factory_attributes.gsub(/^/, " ")} 59 | end 60 | 61 | RUBY 62 | end 63 | 64 | def factory_attributes 65 | attributes.map { |attribute| 66 | "#{attribute.name} { #{attribute.default.inspect} }" 67 | }.join("\n") 68 | end 69 | 70 | def filename 71 | if factory_bot_options[:filename_proc].present? 72 | factory_bot_options[:filename_proc].call(table_name) 73 | else 74 | name = File.join(class_path, plural_name) 75 | [name, filename_suffix].compact.join("_") 76 | end 77 | end 78 | 79 | def filename_suffix 80 | factory_bot_options[:suffix] || options[:suffix] 81 | end 82 | 83 | def factory_bot_options 84 | generators.options[:factory_bot] || {} 85 | end 86 | 87 | def generators 88 | FactoryBotRails::Railtie.config.app_generators 89 | end 90 | end 91 | end 92 | end 93 | -------------------------------------------------------------------------------- /lib/generators/factory_bot/model/templates/factories.erb: -------------------------------------------------------------------------------- 1 | FactoryBot.define do 2 | <%= factory_definition.rstrip %> 3 | end 4 | -------------------------------------------------------------------------------- /lib/rails/projections.json: -------------------------------------------------------------------------------- 1 | { 2 | "spec/factories/*.rb": { 3 | "alternate": "app/models/{singular}.rb", 4 | "collection": "model", 5 | "command": "factory", 6 | "template": [ 7 | "FactoryBot.define do", 8 | " factory :{singular} do", 9 | " end", 10 | "end" 11 | ], 12 | "test": "spec/models/{singular}_spec.rb" 13 | }, 14 | "test/factories/*.rb": { 15 | "alternate": "app/models/{singular}.rb", 16 | "collection": "model", 17 | "command": "factory", 18 | "template": [ 19 | "FactoryBot.define do", 20 | " factory :{singular} do", 21 | " end", 22 | "end" 23 | ], 24 | "test": "test/models/{singular}_test.rb" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /spec/factory_bot_rails/definition_file_paths_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe FactoryBotRails::DefinitionFilePaths do 4 | describe "#files" do 5 | it "returns a list of definition files that only exist" do 6 | definition_file_paths = ["spec/fixtures/factories", "not_exist_directory"] 7 | 8 | files = described_class.new(definition_file_paths).files 9 | 10 | expect(files).to eq ["spec/fixtures/factories.rb"] 11 | end 12 | end 13 | 14 | describe "#directories" do 15 | it "returns a hash of definition directories that only exist" do 16 | definition_file_paths = ["spec/fixtures/factories", "not_exist_directory"] 17 | 18 | directories = described_class.new(definition_file_paths).directories 19 | 20 | expect(directories).to eq( 21 | "spec/fixtures/factories" => [:rb] 22 | ) 23 | end 24 | 25 | it "converts Pathname objects to strings" do 26 | definition_file_paths = [Pathname.new("spec/fixtures/factories")] 27 | 28 | directories = described_class.new(definition_file_paths).directories 29 | 30 | expect(directories).to eq("spec/fixtures/factories" => [:rb]) 31 | end 32 | end 33 | 34 | describe "#any?" do 35 | it "returns true only if definition file paths exist" do 36 | definition_file_paths = ["spec/fixtures/factories", "not_exist_directory"] 37 | expect(described_class.new(definition_file_paths).any?).to eq true 38 | 39 | definition_file_paths = ["not_exist_directory"] 40 | expect(described_class.new(definition_file_paths).any?).to eq false 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /spec/factory_bot_rails/factory_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "spec_helper" 4 | 5 | describe "factory extensions" do 6 | describe "#file_fixture" do 7 | it "delegates to the test harness" do 8 | FactoryBot.define do 9 | factory :upload, class: Struct.new(:filename) do 10 | filename { file_fixture("file.txt") } 11 | end 12 | end 13 | 14 | upload = FactoryBot.build(:upload) 15 | 16 | expect(Pathname(upload.filename)).to eq(file_fixture("file.txt")) 17 | end 18 | 19 | it "uploads an ActiveStorage::Blob" do 20 | FactoryBot.define do 21 | factory :active_storage_blob, class: ActiveStorage::Blob do 22 | filename { pathname.basename } 23 | 24 | transient do 25 | pathname { file_fixture("file.txt") } 26 | end 27 | 28 | after :build do |model, factory| 29 | model.upload factory.pathname.open 30 | end 31 | end 32 | end 33 | 34 | blob = FactoryBot.create(:active_storage_blob) 35 | 36 | expect(blob.filename.to_s).to eq("file.txt") 37 | expect(blob.download).to eq(file_fixture("file.txt").read) 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /spec/factory_bot_rails/railtie_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe FactoryBotRails::Railtie do 4 | describe "application reloading" do 5 | context "when a definition file has been updated" do 6 | it "reloads the factory definitions" do 7 | allow(FactoryBot).to receive(:reload) 8 | 9 | touch("factories.rb") 10 | reload_rails! 11 | 12 | expect(FactoryBot).to have_received(:reload).at_least(1).times 13 | end 14 | end 15 | 16 | context "when a file in a definition directory has been updated" do 17 | it "reloads the factory definitions" do 18 | allow(FactoryBot).to receive(:reload) 19 | 20 | touch("factories/definitions.rb") 21 | reload_rails! 22 | 23 | expect(FactoryBot).to have_received(:reload).at_least(1).times 24 | end 25 | end 26 | 27 | context "when the factory definitions have NOT been updated" do 28 | it "reloads the factory definitions" do 29 | allow(FactoryBot).to receive(:reload) 30 | 31 | reload_rails! 32 | 33 | expect(FactoryBot).to have_received(:reload).at_least(1).times 34 | end 35 | end 36 | 37 | def touch(file) 38 | FileUtils.touch(Rails.root.join(file)) 39 | end 40 | 41 | def reload_rails! 42 | Rails.application.reloader.reload! 43 | wait_for_rails_to_reload 44 | end 45 | 46 | def wait_for_rails_to_reload 47 | sleep 0.01 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /spec/factory_bot_rails/reloader_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe FactoryBotRails::Reloader do 4 | describe "#run" do 5 | before do 6 | @original_definition_file_paths = FactoryBot.definition_file_paths 7 | end 8 | 9 | after do 10 | FactoryBot.definition_file_paths = @original_definition_file_paths 11 | end 12 | 13 | context "when a definition file paths exist" do 14 | it "registers a reloader" do 15 | file_watcher = file_watcher_double 16 | 17 | run_reloader( 18 | ["spec/fixtures/factories", "not_exist_directory"], 19 | file_watcher 20 | ) 21 | 22 | expect(file_watcher).to have_received(:new) 23 | end 24 | end 25 | 26 | context "when a file exists but not a directory" do 27 | it "registers a reloader" do 28 | file_watcher = file_watcher_double 29 | 30 | run_reloader( 31 | ["spec/fake_app", "not_exist_directory"], 32 | file_watcher 33 | ) 34 | 35 | expect(file_watcher).to have_received(:new) 36 | end 37 | end 38 | 39 | context "when a definition file paths NOT exist" do 40 | it "does NOT register a reloader" do 41 | file_watcher = file_watcher_double 42 | 43 | run_reloader(["not_exist_directory"], file_watcher) 44 | 45 | expect(file_watcher).not_to have_received(:new) 46 | end 47 | end 48 | 49 | def run_reloader(definition_file_paths, file_watcher) 50 | FactoryBot.definition_file_paths = definition_file_paths 51 | app = app_double(file_watcher) 52 | FactoryBotRails::Reloader.new(app).run 53 | end 54 | 55 | def file_watcher_double 56 | class_double( 57 | Rails.application.config.file_watcher, 58 | new: double(:reloader, execute: nil) 59 | ) 60 | end 61 | 62 | def app_double(file_watcher) 63 | instance_double( 64 | Rails.application.class, 65 | config: app_config_double(file_watcher), 66 | reloader: reloader_double, 67 | reloaders: [] 68 | ) 69 | end 70 | 71 | def app_config_double(file_watcher) 72 | instance_double( 73 | Rails.application.config.class, 74 | file_watcher: file_watcher 75 | ) 76 | end 77 | 78 | def reloader_double 79 | class_double( 80 | Rails.application.reloader, 81 | to_prepare: nil 82 | ) 83 | end 84 | end 85 | end 86 | -------------------------------------------------------------------------------- /spec/fake_app.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | ENV["DATABASE_URL"] = "sqlite3::memory:" 4 | 5 | require "active_record/railtie" 6 | require "active_storage/engine" 7 | 8 | module Dummy 9 | class Application < Rails::Application 10 | config.eager_load = false 11 | config.root = "spec/fixtures" 12 | 13 | if Rails.gem_version >= Gem::Version.new("7.1") 14 | config.active_support.cache_format_version = 7 15 | end 16 | 17 | config.active_storage.service = :local 18 | config.active_storage.service_configurations = { 19 | local: { 20 | root: root.join("tmp/storage"), 21 | service: "Disk" 22 | } 23 | } 24 | end 25 | end 26 | 27 | Rails.logger = Logger.new(File::NULL) 28 | 29 | Rails.application.initialize! 30 | -------------------------------------------------------------------------------- /spec/fixtures/factories.rb: -------------------------------------------------------------------------------- 1 | # Rails.root.join('factories.rb') 2 | -------------------------------------------------------------------------------- /spec/fixtures/factories/definitions.rb: -------------------------------------------------------------------------------- 1 | # Rails.root.join('factories', 'definitions.rb') 2 | -------------------------------------------------------------------------------- /spec/fixtures/files/file.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/factory_bot_rails/83109a5ff2a0601df21547a56797635616e0d8eb/spec/fixtures/files/file.txt -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | ENV["RAILS_ENV"] = "test" 4 | 5 | require "factory_bot_rails" 6 | require "fake_app" 7 | require "rspec/rails" 8 | 9 | Dir["spec/support/**/*.rb"].each { |f| require File.expand_path(f) } 10 | 11 | RSpec.configure do |config| 12 | config.run_all_when_everything_filtered = true 13 | config.filter_run :focus 14 | config.order = "random" 15 | end 16 | -------------------------------------------------------------------------------- /spec/support/active_record/migrations.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | ActiveStorage::Engine.root.glob("db/migrate/*.rb").each { |file| require file } 4 | 5 | ActiveSupport.on_load :active_support_test_case do 6 | setup do 7 | CreateActiveStorageTables.migrate :up 8 | end 9 | 10 | teardown do 11 | CreateActiveStorageTables.migrate :down 12 | rescue ActiveRecord::StatementInvalid 13 | # no-op 14 | end 15 | end 16 | 17 | defined?(RSpec) && RSpec.configure do |config| 18 | config.before do 19 | CreateActiveStorageTables.migrate :up 20 | end 21 | 22 | config.after do 23 | CreateActiveStorageTables.migrate :down 24 | rescue ActiveRecord::StatementInvalid 25 | # no-op 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /test/factory_bot_rails/factory_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "test_helper" 4 | 5 | class FactoryBotRails::FactoryTest < ActiveSupport::TestCase 6 | self.file_fixture_path = "test/fixtures/files" 7 | 8 | test "delegates #file_fixture to the test harness" do 9 | FactoryBot.define do 10 | factory :upload, class: Struct.new(:filename) do 11 | filename { file_fixture("file.txt") } 12 | end 13 | end 14 | 15 | upload = FactoryBot.build(:upload) 16 | 17 | assert_equal file_fixture("file.txt"), upload.filename 18 | end 19 | 20 | test "uploads an ActiveStorage::Blob" do 21 | FactoryBot.define do 22 | factory :active_storage_blob, class: ActiveStorage::Blob do 23 | filename { pathname.basename } 24 | 25 | transient do 26 | pathname { file_fixture("file.txt") } 27 | end 28 | 29 | after :build do |model, factory| 30 | model.upload factory.pathname.open 31 | end 32 | end 33 | end 34 | 35 | blob = FactoryBot.create(:active_storage_blob) 36 | 37 | assert_equal "file.txt", blob.filename.to_s 38 | assert_equal file_fixture("file.txt").read, blob.download 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /test/fixtures/files/file.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtbot/factory_bot_rails/83109a5ff2a0601df21547a56797635616e0d8eb/test/fixtures/files/file.txt -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Configure Rails Environment 4 | ENV["RAILS_ENV"] = "test" 5 | 6 | require_relative "../spec/fake_app" 7 | 8 | require "rails/test_help" 9 | require "factory_bot_rails" 10 | 11 | Dir["spec/support/**/*.rb"].each { |f| require File.expand_path(f) } 12 | --------------------------------------------------------------------------------