lib/react_on_rails/test_helper.rb
# frozen_string_literal: true
module ReactOnRails
module TestHelper
# Because you will probably want to run RSpec tests that rely on compiled webpack assets
# (typically, your integration/feature specs where `js: true`), you will want to ensure you
# don't accidentally run tests on missing or stale webpack assets. If you did use stale
# Webpack assets, you will get invalid test results as your tests do not use the very latest
# JavaScript code.
#
# Call this method from inside of the `RSpec.configure` block in your `spec/rails_helper.rb`
# file, passing the config as an argument. You can customize this to your particular needs by
# replacing any of the default components.
#
# RSpec.configure do |config|
# ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
#
# You can pass an RSpec metatag as an list of parameter to this helper method
# if you want this helper to run on examples other than where `js: true` or
# `server_rendering: true` (default). The helper will compile webpack files at most
# once per test run.
#
# If you do not want to be slowed down by re-compiling webpack assets from scratch every test
# run, you can call `yarn run build:client` (and `yarn run build:server` if doing server
# rendering) to have webpack recompile these files in the background, which will be *much*
# faster. The helper looks for these processes and will abort recompiling if it finds them
# to be running.
#
# See docs/additional-reading/rspec-configuration.md for more info
#
# Params:
# config - config for rspec
# metatags - metatags to add the ensure_assets_compiled check.
# Default is :js, :server_rendering, :controller
def self.configure_rspec_to_compile_assets(config, *metatags)
metatags = %i[js server_rendering controller] if metatags.empty?
# Supported since RSpec 3.5.0
supports_first_matching_example = config.respond_to?(:when_first_matching_example_defined)
metatags.each do |metatag|
if supports_first_matching_example
config.when_first_matching_example_defined(metatag) do
ReactOnRails::TestHelper.ensure_assets_compiled
end
else
config.before(:example, metatag) { ReactOnRails::TestHelper.ensure_assets_compiled }
end
end
end
# Main entry point to ensuring assets are compiled. See `configure_rspec_to_compile_assets` for
# an example of usage.
#
# Typical usage passes all params as nil defaults.
# webpack_assets_status_checker: provide: `up_to_date?`, `whats_not_up_to_date`, `source_path`
# defaults to ReactOnRails::TestHelper::WebpackAssetsStatusChecker
# webpack_assets_compiler: provide one method: `def compile`
# defaults to ReactOnRails::TestHelper::WebpackAssetsCompiler
# source_path and generated_assets_full_path are passed into the default webpack_assets_status_checker if you
# don't provide one.
# webpack_generated_files List of files to check for up-to-date-status, defaulting to
# webpack_generated_files in your configuration
# rubocop:disable Metrics/CyclomaticComplexity
def self.ensure_assets_compiled(webpack_assets_status_checker: nil,
webpack_assets_compiler: nil,
source_path: nil,
generated_assets_full_path: nil,
webpack_generated_files: nil)
ReactOnRails::WebpackerUtils.check_manifest_not_cached
if webpack_assets_status_checker.nil?
source_path ||= ReactOnRails::Utils.source_path
generated_assets_full_path ||= ReactOnRails::Utils.generated_assets_full_path
webpack_generated_files ||= ReactOnRails.configuration.webpack_generated_files
webpack_assets_status_checker ||=
WebpackAssetsStatusChecker.new(source_path: source_path,
generated_assets_full_path: generated_assets_full_path,
webpack_generated_files: webpack_generated_files)
unless @printed_once
puts
puts "====> React On Rails: Checking files in " \
"#{webpack_assets_status_checker.generated_assets_full_path} for " \
"outdated/missing bundles based on source_path #{source_path}"
puts
@printed_once = true
if ReactOnRails::WebpackerUtils.using_webpacker? &&
ReactOnRails::Utils.using_webpacker_source_path_is_not_defined_and_custom_node_modules?
msg = <<-MSG.strip_heredoc
WARNING: Define config.webpacker.yml to include sourcePath to configure
the location of your JavaScript source for React on Rails.
Default location of #{source_path} is used.
MSG
puts ReactOnRails::Utils.wrap_message(msg, :orange)
end
end
end
webpack_assets_compiler ||= WebpackAssetsCompiler.new
ReactOnRails::TestHelper::EnsureAssetsCompiled.new(
webpack_assets_status_checker: webpack_assets_status_checker,
webpack_assets_compiler: webpack_assets_compiler
).call
end
end
# rubocop:enable Metrics/CyclomaticComplexity
end