docs/oss/building-features/testing-configuration.md
This guide explains how to configure React on Rails for optimal testing with RSpec, Minitest, or other test frameworks.
For most applications, the recommended approach is React on Rails TestHelper with build_test_command:
# config/initializers/react_on_rails.rb
ReactOnRails.configure do |config|
config.build_test_command = "RAILS_ENV=test bin/shakapacker"
end
Then wire TestHelper into your test framework. If your app uses both RSpec and Minitest, wire both files.
RSpec — add to spec/rails_helper.rb:
require "react_on_rails/test_helper"
RSpec.configure do |config|
ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
end
Minitest — add to test/test_helper.rb:
require "react_on_rails/test_helper"
class ActiveSupport::TestCase
setup do
ReactOnRails::TestHelper.ensure_assets_compiled
end
end
React on Rails supports two mutually exclusive approaches for compiling webpack assets during tests:
Best for: Most applications, especially SSR, large suites, and explicit build control
Configuration:
# config/initializers/react_on_rails.rb
ReactOnRails.configure do |config|
config.build_test_command = "NODE_ENV=test RAILS_ENV=test bin/shakapacker"
# Or use your project's package manager with a custom script:
# config.build_test_command = "pnpm run build:test" # or: npm run build:test, yarn run build:test
end
In config/shakapacker.yml, keep test compilation off to avoid mixing approaches:
test:
<<: *default
compile: false
public_output_path: webpack/test
Then configure your test framework:
RSpec:
# spec/rails_helper.rb
require "react_on_rails/test_helper"
RSpec.configure do |config|
# Ensures webpack assets are compiled before the test suite runs
ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
end
See lib/react_on_rails/test_helper.rb for more details and customization options.
By default, the helper triggers compilation for examples tagged with :js, :server_rendering, or :controller. You can pass custom metatags as an optional second parameter if you need compilation for other specs — for example, if you use Webpack to build CSS assets for request and feature specs:
# spec/rails_helper.rb
RSpec.configure do |config|
ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config, :requires_webpack_assets)
config.define_derived_metadata(file_path: %r{spec/(features|requests)}) do |metadata|
metadata[:requires_webpack_assets] = true
end
end
Minitest:
# test/test_helper.rb
require "react_on_rails/test_helper"
class ActiveSupport::TestCase
setup do
ReactOnRails::TestHelper.ensure_assets_compiled
end
end
Alternatively, you can use a Minitest plugin to run the check in before_setup:
module MyMinitestPlugin
def before_setup
super
ReactOnRails::TestHelper.ensure_assets_compiled
end
end
class Minitest::Test
include MyMinitestPlugin
end
Asset detection settings:
The following settings in config/initializers/react_on_rails.rb control how the test helper detects stale assets:
ReactOnRails.configure do |config|
# Define the files to check for Webpack compilation when running tests.
config.webpack_generated_files = %w( manifest.json )
# If you're not hashing the server bundle, include it in the list:
# config.webpack_generated_files = %w( server-bundle.js manifest.json )
end
Important: The
build_test_commandmust not include the--watchoption. If you have separate server and client bundles, the command must build all of them.
How it works:
public_root_path and public_output_path in config/shakapacker.yml). If the folder is missing, empty, or contains files listed in webpack_generated_files with mtimes older than any source files, assets are recompiled.build_test_command configurationPros:
Cons:
build_test_command to be setWhen to use:
Best for: Simpler non-SSR test setups or teams that prefer minimal configuration
Configuration:
# config/shakapacker.yml
test:
<<: *default
compile: true
public_output_path: webpack/test
And remove React on Rails TestHelper wiring:
config.build_test_commandReactOnRails::TestHelper calls in spec/rails_helper.rb or test/test_helper.rbHow it works:
Pros:
Cons:
Do not use both approaches together. They are mutually exclusive:
# config/shakapacker.yml
test:
compile: true # ← Don't do this...
# config/initializers/react_on_rails.rb
config.build_test_command = "RAILS_ENV=test bin/shakapacker" # ← ...with this
# spec/rails_helper.rb
ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config) # ← ...and this
This will cause assets to be compiled multiple times unnecessarily.
Set compile: true in config/shakapacker.yml test section:
test:
compile: true
public_output_path: webpack/test
Remove test helper configuration from spec/test helpers:
# spec/rails_helper.rb - REMOVE these lines:
require "react_on_rails/test_helper"
ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
Remove or comment out build_test_command in React on Rails config:
# config/initializers/react_on_rails.rb
# config.build_test_command = "RAILS_ENV=test bin/shakapacker" # ← Comment out
Set compile: false in config/shakapacker.yml test section:
test:
compile: false
public_output_path: webpack/test
Add build_test_command to React on Rails config:
# config/initializers/react_on_rails.rb
config.build_test_command = "RAILS_ENV=test bin/shakapacker"
Add test helper configuration:
# spec/rails_helper.rb (for RSpec)
require "react_on_rails/test_helper"
RSpec.configure do |config|
ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
end
Use the React on Rails doctor command to verify your test configuration:
bundle exec rake react_on_rails:doctor
To auto-apply supported test-setup fixes (recommended path), run:
FIX=true bundle exec rake react_on_rails:doctor
The doctor will check:
compile: true is set in shakapacker.ymlbuild_test_command is configuredProblem: Tests fail because JavaScript/CSS assets are not compiled.
Solution: Check which approach you're using:
If using Shakapacker auto-compilation:
# config/shakapacker.yml
test:
compile: true # ← Make sure this is true
If using React on Rails test helper:
build_test_command is setbundle exec rake react_on_rails:doctorProblem: Tests are slow because assets compile repeatedly.
Solutions:
If using Shakapacker auto-compilation:
cache_manifest: true in shakapacker.ymlIf using React on Rails test helper:
compile: true in shakapacker.ymlProblem: You added a source file but the test helper doesn't trigger recompilation.
Cause: The test helper compares mtimes of source files against generated output files. If you add a source file that has an older timestamp than the existing output (e.g., copied from another directory or restored from version control), it won't be detected as a change.
Solution: Clear out your Webpack-generated files directory to force recompilation:
rm -rf public/webpack/test
Problem: build_test_command fails with errors.
Check:
Does bin/shakapacker exist and is it executable?
ls -la bin/shakapacker
chmod +x bin/shakapacker # If needed
Can you run the command manually?
RAILS_ENV=test bin/shakapacker
Are your webpack configs valid for test environment?
Problem: LoadError: cannot load such file -- react_on_rails/test_helper
Solution: Make sure react_on_rails gem is available in test environment:
# Gemfile
gem "react_on_rails" # Not in a specific group
# Or explicitly in test group:
group :test do
gem "react_on_rails"
end
Shakapacker auto-compilation:
React on Rails test helper:
If you're using the React on Rails test helper and want to avoid waiting for compilation on each test run, run your build command with the --watch flag in a separate terminal:
RAILS_ENV=test bin/shakapacker --watch
# Or with your package manager:
# pnpm run build:test --watch
# npm run build:test -- --watch
# yarn run build:test --watch
This keeps webpack running and recompiling automatically when files change, so your tests start faster.
Note: The
--watchflag should only be used in a separate terminal process — never include it inbuild_test_command, which must exit after compilation.
When you run bin/dev static, React on Rails automatically detects the fresh development assets and reuses them for tests — no extra commands or environment variables needed.
# Terminal 1: Start static development
bin/dev static
# Terminal 2: Just run tests — they automatically use dev assets
bundle exec rspec
How it works: When bundle exec rspec (or Minitest) runs and test assets are stale or missing, the TestHelper checks if development assets in public/packs/ are:
http:// URLs in manifest entries)If all checks pass, React on Rails temporarily overrides Shakapacker's test config to point at the development output. You'll see:
====> React on Rails: Reusing development assets from packs
(detected fresh static-mode webpack output, skipping test compilation)
No shakapacker.yml changes are needed. The override only lasts for the test process.
bin/dev (HMR) and Tests TogetherHMR assets are served from webpack-dev-server memory and contain http:// URLs in the manifest, so they cannot be reused by tests. When using HMR mode, you have two options:
Option A: Let TestHelper compile on demand (simplest)
# Terminal 1
bin/dev
# Terminal 2 — TestHelper runs build_test_command automatically if assets are stale
bundle exec rspec
This works but adds compilation time to the first test run.
Option B: Use a test watcher for fast iteration
# Terminal 1
bin/dev
# Terminal 2 — keeps test assets fresh in the background
bin/dev test-watch
# Terminal 3
bundle exec rspec
bin/dev test-watch auto-selects watch mode:
auto (default): picks client-only if another shakapacker watcher is already running; otherwise fullfull: always builds test client + server bundles (--test-watch-mode=full)client-only: only builds test client bundles (--test-watch-mode=client-only)| Scenario | Recommendation |
|---|---|
| General development | bin/dev static — simpler, no FOUC, tests just work |
| Need Hot Module Replacement | bin/dev + bin/dev test-watch for fast test iteration |
| CI / no dev server running | Just bundle exec rspec — TestHelper compiles automatically |
| Only running a few tests | bin/dev static + bundle exec rspec spec/path/to_spec.rb |
bin/dev test-watchIf you previously ran manual test watcher commands, migrate to the new wrapper:
Old: RAILS_ENV=test bin/shakapacker --watch
New: bin/dev test-watch
Old: RAILS_ENV=test CLIENT_BUNDLE_ONLY=yes bin/shakapacker --watch
New: bin/dev test-watch --test-watch-mode=client-only
If you prefer to manually share output paths instead of using automatic detection:
Set the test output path equal to development in config/shakapacker.yml:
development:
public_output_path: packs
test:
public_output_path: packs
Run static development mode and tests:
bin/dev static # Terminal 1
bundle exec rspec # Terminal 2
Warning: Do not share output paths with
bin/dev(HMR mode) — HMR manifests will cause test failures.
Improve compilation speed with caching:
# config/shakapacker.yml
test:
cache_manifest: true # Cache manifest between runs
When running tests in parallel (with parallel_tests gem):
Shakapacker auto-compilation:
RAILS_ENV=test bin/shakapacker
bundle exec rake parallel:spec
React on Rails test helper:
Option 1: Precompile before tests
- name: Compile test assets
run: RAILS_ENV=test bundle exec rake react_on_rails:assets:compile_environment
- name: Run tests
run: bundle exec rspec
Option 2: Use Shakapacker auto-compilation
# config/shakapacker.yml
test:
compile: true
# CI workflow
- name: Run tests (assets auto-compile)
run: bundle exec rspec
When running tests in Docker, consider:
node_modules between buildsrake react_on_rails:doctor to verify configuration| Scenario | Recommendation |
|---|---|
| Default setup | React on Rails test helper |
| SSR test coverage | React on Rails test helper |
| Large test suite | React on Rails test helper |
| Parallel testing | React on Rails test helper or precompile |
| CI/CD pipeline | Precompile before tests |
| Quick local tests | Shakapacker compile: true |
| Custom build command | React on Rails test helper |
bin/dev (HMR vs static) interacts with Capybara, Playwright, Minitest system tests, and SSR request specs