diff --git a/.github/workflows/rubocop.yml b/.github/workflows/rubocop.yml new file mode 100644 index 000000000..efdebfd27 --- /dev/null +++ b/.github/workflows/rubocop.yml @@ -0,0 +1,23 @@ +name: Rubocop + +on: [push] + +jobs: + rubocop: + name: Rubocop + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + ruby: ['2.7', '3.0'] + + steps: + - uses: actions/checkout@v2 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + - name: Install linting gems + run: gem install rubocop rubocop-performance rubocop-minitest + - name: Run rubocop + run: rubocop diff --git a/.rubocop.yml b/.rubocop.yml index 20275c8cc..7dd7e917e 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,10 +1,89 @@ +inherit_from: .rubocop_todo.yml + +require: + - rubocop-performance + - rubocop-minitest + AllCops: - TargetRubyVersion: 2.3 + NewCops: enable + TargetRubyVersion: 2.5 DisplayCopNames: true + + Include: + - '**/Rakefile' + - '**/config.ru' + - 'Gemfile' + - '**/*.rb' + - '**/*.rake' + Exclude: - - test/dummy_sprockets/**/* - - test/dummy_webpacker1/**/* - - test/dummy_webpacker2/**/* - - test/dummy_webpacker3/**/* - - node_modules/**/* - - react_ujs/**/* + <% `git status --ignored --porcelain`.lines.grep(/^!! /).each do |path| %> + - <%= path.sub(/^!! /, '') %> + <% end %> + - '**/*.js' + - '**/node_modules/**/*' + - '**/public/**/*' + - '**/tmp/**/*' + - 'vendor/**/*' + - 'test/dummy_sprockets/**/*' + - 'test/dummy_webpacker1/**/*' + - 'test/dummy_webpacker2/**/*' + - 'test/dummy_webpacker3/**/*' + - 'react_ujs/**/*' + +Naming/FileName: + Exclude: + - '**/Gemfile' + - '**/Rakefile' + - 'lib/react-rails.rb' + +Layout/LineLength: + Max: 120 + +Style/StringLiterals: + EnforcedStyle: double_quotes + +Style/Documentation: + Enabled: false + +Style/HashEachMethods: + Enabled: true + +Style/HashTransformKeys: + Enabled: true + +Style/HashTransformValues: + Enabled: true + +Metrics/AbcSize: + Max: 28 + +Metrics/CyclomaticComplexity: + Max: 7 + +Metrics/PerceivedComplexity: + Max: 10 + +Metrics/ClassLength: + Max: 150 + +Metrics/ParameterLists: + Max: 5 + CountKeywordArgs: false + +Metrics/MethodLength: + Max: 41 + +Metrics/ModuleLength: + Max: 180 + +Naming/RescuedExceptionsVariableName: + Enabled: false + +# Style/GlobalVars: + # Exclude: + # - 'spec/dummy/config/environments/development.rb' + +Metrics/BlockLength: + Exclude: + - 'test/**/*_test.rb' \ No newline at end of file diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml new file mode 100644 index 000000000..52d1e7311 --- /dev/null +++ b/.rubocop_todo.yml @@ -0,0 +1,18 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2023-06-30 00:26:13 UTC using RuboCop version 1.53.1. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 2 +Lint/IneffectiveAccessModifier: + Exclude: + - 'lib/generators/react/component_generator.rb' + +# Offense count: 1 +# Configuration parameters: CountComments, CountAsOne. +Metrics/ClassLength: + Exclude: + - 'lib/generators/react/component_generator.rb' diff --git a/Gemfile b/Gemfile index 19fb41265..8926579c4 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,6 @@ -source 'http://rubygems.org' +# frozen_string_literal: true + +source "http://rubygems.org" gemspec # This is an optional dev-dependency, required whenever sprockets is required diff --git a/Gemfile.lock b/Gemfile.lock index 310654374..2468b94fd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -103,11 +103,9 @@ GEM matrix (0.4.2) method_source (1.0.0) mini_mime (1.0.2) - mini_portile2 (2.8.1) minitest (5.17.0) nenv (0.3.0) - nokogiri (1.14.3) - mini_portile2 (~> 2.8.0) + nokogiri (1.14.3-x86_64-darwin) racc (~> 1.4) nokogiri (1.14.3-x86_64-linux) racc (~> 1.4) @@ -168,7 +166,7 @@ GEM zeitwerk (2.6.6) PLATFORMS - ruby + x86_64-darwin-20 x86_64-linux DEPENDENCIES diff --git a/Rakefile b/Rakefile index 541ad6b2f..d1af1ced5 100644 --- a/Rakefile +++ b/Rakefile @@ -1,7 +1,9 @@ +# frozen_string_literal: true + begin - require 'bundler/setup' + require "bundler/setup" rescue LoadError - puts 'You must `gem install bundler` and `bundle install` to run rake tasks' + puts "You must `gem install bundler` and `bundle install` to run rake tasks" end Bundler::GemHelper.install_tasks @@ -20,22 +22,22 @@ def yarn_run_in(dirname, cmd) end namespace :react do - desc 'Run the JS build process to put files in the gem source' - task update: [:install, :build, :copy] + desc "Run the JS build process to put files in the gem source" + task update: %i[install build copy] - desc 'Install the JavaScript dependencies' + desc "Install the JavaScript dependencies" task :install do - yarn_run_in('react-builds', 'install') + yarn_run_in("react-builds", "install") end - desc 'Build the JS bundles with Webpack' + desc "Build the JS bundles with Webpack" task :build do - yarn_run_in('react-builds', 'build') + yarn_run_in("react-builds", "build") end desc "Copy browser-ready JS files to the gem's asset paths" task :copy do - environments = ['development', 'production'] + environments = %w[development production] environments.each do |environment| copy_react_asset("#{environment}/react-browser.js", "#{environment}/react.js") copy_react_asset("#{environment}/react-server.js", "#{environment}/react-server.js") @@ -44,48 +46,48 @@ namespace :react do end namespace :ujs do - desc 'Run the JS build process to put files in the gem source' - task update: [:install, :build, :copy] + desc "Run the JS build process to put files in the gem source" + task update: %i[install build copy] - desc 'Install the JavaScript dependencies' + desc "Install the JavaScript dependencies" task :install do `yarn install` end - desc 'Build the JS bundles with Webpack' + desc "Build the JS bundles with Webpack" task :build do `yarn build` end desc "Copy browser-ready JS files to the gem's asset paths" task :copy do - full_webpack_path = File.expand_path('../react_ujs/dist/react_ujs.js', __FILE__) - full_destination_path = File.expand_path('../lib/assets/javascripts/react_ujs.js', __FILE__) + full_webpack_path = File.expand_path("react_ujs/dist/react_ujs.js", __dir__) + full_destination_path = File.expand_path("lib/assets/javascripts/react_ujs.js", __dir__) FileUtils.cp(full_webpack_path, full_destination_path) end - desc 'Publish the package in ./react_ujs/ to npm as `react_ujs`' + desc "Publish the package in ./react_ujs/ to npm as `react_ujs`" task publish: :update do `npm publish` end end -require 'appraisal' -require 'minitest/test_task' +require "appraisal" +require "minitest/test_task" Minitest::TestTask.create(:test) do |t| - t.libs << 'lib' - t.libs << 'test' - t.test_globs = ENV['TEST_PATTERN'] || 'test/**/*_test.rb' - t.verbose = ENV['TEST_VERBOSE'] == '1' + t.libs << "lib" + t.libs << "test" + t.test_globs = ENV["TEST_PATTERN"] || "test/**/*_test.rb" + t.verbose = ENV["TEST_VERBOSE"] == "1" t.warning = false end task default: :test task :test_setup do - load 'webdrivers/Rakefile' - Dir.chdir('./test/dummy') do + load "webdrivers/Rakefile" + Dir.chdir("./test/dummy") do `yarn install` end end diff --git a/lib/generators/react/component_generator.rb b/lib/generators/react/component_generator.rb index bc98fe360..90b6ab18d 100644 --- a/lib/generators/react/component_generator.rb +++ b/lib/generators/react/component_generator.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + module React module Generators class ComponentGenerator < ::Rails::Generators::NamedBase - source_root File.expand_path '../../templates', __FILE__ + source_root File.expand_path "../templates", __dir__ desc <<-DESC.strip_heredoc Description: Scaffold a React component into `components/` of your Webpacker source or asset pipeline. @@ -46,110 +48,101 @@ class ComponentGenerator < ::Rails::Generators::NamedBase DESC argument :attributes, - :type => :array, - :default => [], - :banner => 'field[:type] field[:type] ...' + type: :array, + default: [], + banner: "field[:type] field[:type] ..." class_option :es6, type: :boolean, default: false, - desc: 'Output es6 class based component' + desc: "Output es6 class based component" class_option :ts, type: :boolean, default: false, - desc: 'Output tsx class based component' + desc: "Output tsx class based component" class_option :coffee, type: :boolean, default: false, - desc: 'Output coffeescript based component' + desc: "Output coffeescript based component" REACT_PROP_TYPES = { - 'node' => 'PropTypes.node', - 'bool' => 'PropTypes.bool', - 'boolean' => 'PropTypes.bool', - 'string' => 'PropTypes.string', - 'number' => 'PropTypes.number', - 'object' => 'PropTypes.object', - 'array' => 'PropTypes.array', - 'shape' => 'PropTypes.shape({})', - 'element' => 'PropTypes.element', - 'func' => 'PropTypes.func', - 'function' => 'PropTypes.func', - 'any' => 'PropTypes.any', - - 'instanceOf' => ->(type) { - 'PropTypes.instanceOf(%s)' % type.to_s.camelize + "node" => "PropTypes.node", + "bool" => "PropTypes.bool", + "boolean" => "PropTypes.bool", + "string" => "PropTypes.string", + "number" => "PropTypes.number", + "object" => "PropTypes.object", + "array" => "PropTypes.array", + "shape" => "PropTypes.shape({})", + "element" => "PropTypes.element", + "func" => "PropTypes.func", + "function" => "PropTypes.func", + "any" => "PropTypes.any", + + "instanceOf" => lambda { |type| + "PropTypes.instanceOf(#{type.to_s.camelize})" }, - 'oneOf' => ->(*options) { - enums = options.map{ |k| "'#{k.to_s}'" }.join(',') - 'PropTypes.oneOf([%s])' % enums + "oneOf" => lambda { |*options| + enums = options.map { |k| "'#{k}'" }.join(",") + "PropTypes.oneOf([#{enums}])" }, - 'oneOfType' => ->(*options) { - types = options.map{ |k| "#{lookup(k.to_s, k.to_s)}" }.join(',') - 'PropTypes.oneOfType([%s])' % types + "oneOfType" => lambda { |*options| + types = options.map { |k| lookup(k.to_s, k.to_s).to_s }.join(",") + "PropTypes.oneOfType([#{types}])" } - } + }.freeze TYPESCRIPT_TYPES = { - 'node' => 'React.ReactNode', - 'bool' => 'boolean', - 'boolean' => 'boolean', - 'string' => 'string', - 'number' => 'number', - 'object' => 'object', - 'array' => 'Array', - 'shape' => 'object', - 'element' => 'object', - 'func' => 'object', - 'function' => 'object', - 'any' => 'any', - - 'instanceOf' => ->(type) { + "node" => "React.ReactNode", + "bool" => "boolean", + "boolean" => "boolean", + "string" => "string", + "number" => "number", + "object" => "object", + "array" => "Array", + "shape" => "object", + "element" => "object", + "func" => "object", + "function" => "object", + "any" => "any", + + "instanceOf" => lambda { |type| type.to_s.camelize }, - 'oneOf' => ->(*opts) { - opts.map{ |k| "'#{k.to_s}'" }.join(" | ") + "oneOf" => lambda { |*opts| + opts.map { |k| "'#{k}'" }.join(" | ") }, - 'oneOfType' => ->(*opts) { - opts.map{ |k| "#{ts_lookup(k.to_s, k.to_s)}" }.join(" | ") + "oneOfType" => lambda { |*opts| + opts.map { |k| ts_lookup(k.to_s, k.to_s).to_s }.join(" | ") } - } + }.freeze def create_component_file - template_extension = if options[:coffee] - 'js.jsx.coffee' - elsif options[:ts] - 'js.jsx.tsx' - elsif options[:es6] || webpacker? - 'es6.jsx' - else - 'js.jsx' - end - + template_extension = detect_template_extension # Prefer webpacker to sprockets: if webpacker? new_file_name = file_name.camelize extension = if options[:coffee] - 'coffee' - elsif options[:ts] - 'tsx' - else - 'js' - end + "coffee" + elsif options[:ts] + "tsx" + else + "js" + end target_dir = webpack_configuration.source_path - .join('components') - .relative_path_from(::Rails.root) - .to_s + .join("components") + .relative_path_from(::Rails.root) + .to_s else new_file_name = file_name extension = template_extension - target_dir = 'app/assets/javascripts/components' + target_dir = "app/assets/javascripts/components" end file_path = File.join(target_dir, class_path, "#{new_file_name}.#{extension}") @@ -168,18 +161,19 @@ def component_name def file_header if webpacker? - return %|import * as React from "react"\n| if options[:ts] - %|import React from "react"\nimport PropTypes from "prop-types"\n| + return %(import * as React from "react"\n) if options[:ts] + + %(import React from "react"\nimport PropTypes from "prop-types"\n) else - '' + "" end end def file_footer if webpacker? - %|export default #{component_name}| + %(export default #{component_name}) else - '' + "" end end @@ -189,46 +183,42 @@ def webpacker? def parse_attributes! self.attributes = (attributes || []).map do |attr| - name = '' - type = '' - args = '' + args = "" args_regex = /(?{.*})/ - name, type = attr.split(':') + name, type = attr.split(":") - if matchdata = args_regex.match(type) + if (matchdata = args_regex.match(type)) args = matchdata[:args] - type = type.gsub(args_regex, '') + type = type.gsub(args_regex, "") end if options[:ts] - { :name => name, :type => ts_lookup(name, type, args), :union => union?(args) } + { name: name, type: ts_lookup(name, type, args), union: union?(args) } else - { :name => name, :type => lookup(type, args) } + { name: name, type: lookup(type, args) } end end end - def union?(args = '') - return args.to_s.gsub(/[{}]/, '').split(',').count > 1 + def union?(args = "") + args.to_s.gsub(/[{}]/, "").split(",").count > 1 end - def self.ts_lookup(name, type = 'node', args = '') + def self.ts_lookup(_name, type = "node", args = "") ts_type = TYPESCRIPT_TYPES[type] if ts_type.blank? - if type =~ /^[[:upper:]]/ - ts_type = TYPESCRIPT_TYPES['instanceOf'] - else - ts_type = TYPESCRIPT_TYPES['node'] - end + ts_type = if /^[[:upper:]]/.match?(type) + TYPESCRIPT_TYPES["instanceOf"] + else + TYPESCRIPT_TYPES["node"] + end end - args = args.to_s.gsub(/[{}]/, '').split(',') + args = args.to_s.gsub(/[{}]/, "").split(",") if ts_type.respond_to? :call - if args.blank? - return ts_type.call(type) - end + return ts_type.call(type) if args.blank? ts_type = ts_type.call(*args) end @@ -236,29 +226,41 @@ def self.ts_lookup(name, type = 'node', args = '') ts_type end - def ts_lookup(name, type = 'node', args = '') + def ts_lookup(name, type = "node", args = "") self.class.ts_lookup(name, type, args) end - def self.lookup(type = 'node', options = '') - react_prop_type = REACT_PROP_TYPES[type] - if react_prop_type.blank? - if type =~ /^[[:upper:]]/ - react_prop_type = REACT_PROP_TYPES['instanceOf'] - else - react_prop_type = REACT_PROP_TYPES['node'] - end - end - - options = options.to_s.gsub(/[{}]/, '').split(',') - - react_prop_type = react_prop_type.call(*options) if react_prop_type.respond_to? :call - react_prop_type - end - - def lookup(type = 'node', options = '') - self.class.lookup(type, options) - end + def self.lookup(type = "node", options = "") + react_prop_type = REACT_PROP_TYPES[type] + if react_prop_type.blank? + react_prop_type = if /^[[:upper:]]/.match?(type) + REACT_PROP_TYPES["instanceOf"] + else + REACT_PROP_TYPES["node"] + end + end + + options = options.to_s.gsub(/[{}]/, "").split(",") + + react_prop_type = react_prop_type.call(*options) if react_prop_type.respond_to? :call + react_prop_type + end + + def lookup(type = "node", options = "") + self.class.lookup(type, options) + end + + def detect_template_extension + if options[:coffee] + "js.jsx.coffee" + elsif options[:ts] + "js.jsx.tsx" + elsif options[:es6] || webpacker? + "es6.jsx" + else + "js.jsx" + end + end end end end diff --git a/lib/generators/react/install_generator.rb b/lib/generators/react/install_generator.rb index 7164cfbfc..cf5978837 100644 --- a/lib/generators/react/install_generator.rb +++ b/lib/generators/react/install_generator.rb @@ -1,45 +1,47 @@ +# frozen_string_literal: true + module React module Generators class InstallGenerator < ::Rails::Generators::Base - source_root File.expand_path '../../templates', __FILE__ + source_root File.expand_path "../templates", __dir__ - desc 'Create default react.js folder layout and prep application.js' + desc "Create default react.js folder layout and prep application.js" class_option :skip_git, - type: :boolean, - aliases: '-g', - default: false, - desc: 'Skip Git keeps' + type: :boolean, + aliases: "-g", + default: false, + desc: "Skip Git keeps" class_option :skip_server_rendering, - type: :boolean, - default: false, - desc: "Don't generate server_rendering.js or config/initializers/react_server_rendering.rb" + type: :boolean, + default: false, + desc: "Don't generate server_rendering.js or config/initializers/react_server_rendering.rb" # For Shakapacker below version 7, we need to set relative path for source_entry_path def modify_webpacker_yml - webpacker_yml_path = 'config/webpacker.yml' - if webpacker? && Pathname.new(webpacker_yml_path).exist? - gsub_file( - webpacker_yml_path, - "source_entry_path: /\n", - "source_entry_path: packs\n" - ) - reloaded_webpacker_config - end + webpacker_yml_path = "config/webpacker.yml" + return unless webpacker? && Pathname.new(webpacker_yml_path).exist? + + gsub_file( + webpacker_yml_path, + "source_entry_path: /\n", + "source_entry_path: packs\n" + ) + reloaded_webpacker_config end # Make an empty `components/` directory in the right place: def create_directory components_dir = if webpacker? - Pathname.new(javascript_dir).parent.to_s - else - javascript_dir - end - empty_directory File.join(components_dir, 'components') - unless options[:skip_git] - create_file File.join(components_dir, 'components/.keep') - end + Pathname.new(javascript_dir).parent.to_s + else + javascript_dir + end + empty_directory File.join(components_dir, "components") + return if options[:skip_git] + + create_file File.join(components_dir, "components/.keep") end # Add requires, setup UJS @@ -53,15 +55,15 @@ def setup_react def create_server_rendering if options[:skip_server_rendering] - return + nil elsif webpacker? - ssr_manifest_path = File.join(javascript_dir, 'server_rendering.js') - template('server_rendering_pack.js', ssr_manifest_path) + ssr_manifest_path = File.join(javascript_dir, "server_rendering.js") + template("server_rendering_pack.js", ssr_manifest_path) else - ssr_manifest_path = File.join(javascript_dir, 'server_rendering.js') - template('server_rendering.js', ssr_manifest_path) - initializer_path = 'config/initializers/react_server_rendering.rb' - template('react_server_rendering.rb', initializer_path) + ssr_manifest_path = File.join(javascript_dir, "server_rendering.js") + template("server_rendering.js", ssr_manifest_path) + initializer_path = "config/initializers/react_server_rendering.rb" + template("react_server_rendering.rb", initializer_path) end end @@ -77,12 +79,12 @@ def javascript_dir .relative_path_from(::Rails.root) .to_s else - 'app/assets/javascripts' + "app/assets/javascripts" end end def manifest - Pathname.new(destination_root).join(javascript_dir, 'application.js') + Pathname.new(destination_root).join(javascript_dir, "application.js") end def setup_react_sprockets @@ -91,9 +93,9 @@ def setup_react_sprockets if manifest.exist? manifest_contents = File.read(manifest) - if match = manifest_contents.match(/\/\/=\s+require\s+turbolinks\s+\n/) + if (match = manifest_contents.match(%r{//=\s+require\s+turbolinks\s+\n})) inject_into_file manifest, require_react, { after: match[0] } - elsif match = manifest_contents.match(/\/\/=\s+require_tree[^\n]*/) + elsif (match = manifest_contents.match(%r{//=\s+require_tree[^\n]*})) inject_into_file manifest, require_react, { before: match[0] } else append_file manifest, require_react @@ -103,16 +105,16 @@ def setup_react_sprockets end components_js = "//= require_tree ./components\n" - components_file = File.join(javascript_dir, 'components.js') + components_file = File.join(javascript_dir, "components.js") create_file components_file, components_js end - WEBPACKER_SETUP_UJS = <<-JS -// Support component names relative to this directory: -var componentRequireContext = require.context("components", true); -var ReactRailsUJS = require("react_ujs"); -ReactRailsUJS.useContext(componentRequireContext); -JS + WEBPACKER_SETUP_UJS = <<~JS + // Support component names relative to this directory: + var componentRequireContext = require.context("components", true); + var ReactRailsUJS = require("react_ujs"); + ReactRailsUJS.useContext(componentRequireContext); + JS def setup_react_webpacker `yarn add react_ujs` @@ -123,8 +125,6 @@ def setup_react_webpacker end end - private - def webpack_source_path if Webpacker.respond_to?(:config) Webpacker.config.source_entry_path # Webpacker >3 diff --git a/lib/generators/templates/react_server_rendering.rb b/lib/generators/templates/react_server_rendering.rb index fca0cb2bf..66901081c 100644 --- a/lib/generators/templates/react_server_rendering.rb +++ b/lib/generators/templates/react_server_rendering.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + # To render React components in production, precompile the server rendering manifest: -Rails.application.config.assets.precompile += ['server_rendering.js'] +Rails.application.config.assets.precompile += ["server_rendering.js"] diff --git a/lib/react-rails.rb b/lib/react-rails.rb index d140b0136..4cfc1d5cf 100644 --- a/lib/react-rails.rb +++ b/lib/react-rails.rb @@ -1,10 +1,12 @@ -require 'react' -require 'react/jsx' -require 'react/rails' -require 'react/server_rendering' +# frozen_string_literal: true + +require "react" +require "react/jsx" +require "react/rails" +require "react/server_rendering" module React module Rails - autoload :TestHelper, 'react/rails/test_helper' + autoload :TestHelper, "react/rails/test_helper" end -end \ No newline at end of file +end diff --git a/lib/react.rb b/lib/react.rb index ebfd611ef..1b7743a69 100644 --- a/lib/react.rb +++ b/lib/react.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module React # Recursively camelize `props`, returning a new Hash # @param props [Object] If it's a Hash or Array, it will be recursed. Otherwise it will be returned. diff --git a/lib/react/jsx.rb b/lib/react/jsx.rb index a559d8221..ee3844fb6 100644 --- a/lib/react/jsx.rb +++ b/lib/react/jsx.rb @@ -1,10 +1,12 @@ -require 'execjs' -require 'react/jsx/processor' -require 'react/jsx/template' -require 'react/jsx/jsx_transformer' -require 'react/jsx/babel_transformer' -require 'react/jsx/sprockets_strategy' -require 'rails' +# frozen_string_literal: true + +require "execjs" +require "react/jsx/processor" +require "react/jsx/template" +require "react/jsx/jsx_transformer" +require "react/jsx/babel_transformer" +require "react/jsx/sprockets_strategy" +require "rails" module React module JSX diff --git a/lib/react/jsx/babel_transformer.rb b/lib/react/jsx/babel_transformer.rb index 9303022f4..175cde16f 100644 --- a/lib/react/jsx/babel_transformer.rb +++ b/lib/react/jsx/babel_transformer.rb @@ -1,21 +1,27 @@ -require 'babel/transpiler' +# frozen_string_literal: true + +require "babel/transpiler" module React module JSX # A {React::JSX}-compliant transformer which uses `Babel::Transpiler` to transform JSX. class BabelTransformer - DEPRECATED_OPTIONS = [:harmony, :strip_types, :asset_path] - DEFAULT_TRANSFORM_OPTIONS = { blacklist: ['spec.functionName', 'validation.react', 'strict'] } + DEPRECATED_OPTIONS = %i[harmony strip_types asset_path].freeze + DEFAULT_TRANSFORM_OPTIONS = { blacklist: ["spec.functionName", "validation.react", "strict"] }.freeze def initialize(options) if (options.keys & DEPRECATED_OPTIONS).any? - ActiveSupport::Deprecation.warn('Setting config.react.jsx_transform_options for :harmony, :strip_types, and :asset_path keys is now deprecated and has no effect with the default Babel Transformer.'+ - 'Please use new Babel Transformer options :whitelist, :plugin instead.') + ActiveSupport::Deprecation.warn( + <<-MSG + Setting config.react.jsx_transform_options for :harmony, :strip_types, and :asset_path keys is now deprecated and has no effect with the default Babel Transformer. + Please use new Babel Transformer options :whitelist, :plugin instead. + MSG + ) end @transform_options = DEFAULT_TRANSFORM_OPTIONS.merge(options) end def transform(code) - Babel::Transpiler.transform(code, @transform_options)['code'] + Babel::Transpiler.transform(code, @transform_options)["code"] end end end diff --git a/lib/react/jsx/jsx_transformer.rb b/lib/react/jsx/jsx_transformer.rb index 859189432..ba85ed62b 100644 --- a/lib/react/jsx/jsx_transformer.rb +++ b/lib/react/jsx/jsx_transformer.rb @@ -1,26 +1,28 @@ +# frozen_string_literal: true + module React module JSX # A {React::JSX}-compliant transformer which uses the deprecated `JSXTransformer.js` to transform JSX. class JSXTransformer - DEFAULT_ASSET_PATH = 'JSXTransformer.js' + DEFAULT_ASSET_PATH = "JSXTransformer.js" def initialize(options) @transform_options = { stripTypes: options.fetch(:strip_types, false), - harmony: options.fetch(:harmony, false) + harmony: options.fetch(:harmony, false) } @asset_path = options.fetch(:asset_path, DEFAULT_ASSET_PATH) # If execjs uses therubyracer, there is no 'global'. Make sure # we have it so JSX script can work properly. - js_code = 'var global = global || this;' + jsx_transform_code + js_code = "var global = global || this;#{jsx_transform_code}" @context = ExecJS.compile(js_code) end def transform(code) - result = @context.call('JSXTransformer.transform', code, @transform_options) - result['code'] + result = @context.call("JSXTransformer.transform", code, @transform_options) + result["code"] end # search for transformer file using sprockets - allows user to override diff --git a/lib/react/jsx/processor.rb b/lib/react/jsx/processor.rb index b827d0c92..5db7f40c6 100644 --- a/lib/react/jsx/processor.rb +++ b/lib/react/jsx/processor.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + module React module JSX # A Sprockets 3+-compliant processor class Processor def self.call(input) - JSX::transform(input[:data]) + JSX.transform(input[:data]) end end end diff --git a/lib/react/jsx/sprockets_strategy.rb b/lib/react/jsx/sprockets_strategy.rb index 39c8e19b1..8c718c8d2 100644 --- a/lib/react/jsx/sprockets_strategy.rb +++ b/lib/react/jsx/sprockets_strategy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module React module JSX # Depending on the Sprockets version, @@ -17,15 +19,15 @@ module SprocketsStrategy # @param [Symbol, Nil] A strategy name, or `nil` to detect a strategy def attach_with_strategy(sprockets_env, strategy_or_nil) strategy = strategy_or_nil || detect_strategy - self.public_send(strategy, sprockets_env) + public_send(strategy, sprockets_env) end # @return [Symbol] based on the environment, return a method name to call with the sprockets environment def detect_strategy sprockets_version = Gem::Version.new(Sprockets::VERSION) - if sprockets_version >= Gem::Version.new('4.a') + if sprockets_version >= Gem::Version.new("4.a") :register_processors - elsif sprockets_version >= Gem::Version.new('3.0.0') + elsif sprockets_version >= Gem::Version.new("3.0.0") :register_engine_with_mime_type else :register_engine @@ -33,20 +35,24 @@ def detect_strategy end def register_engine(sprockets_env) - sprockets_env.register_engine('.jsx', React::JSX::Template) + sprockets_env.register_engine(".jsx", React::JSX::Template) end def register_engine_with_mime_type(sprockets_env) - sprockets_env.register_engine('.jsx', React::JSX::Processor, mime_type: 'application/javascript', silence_deprecation: true) + sprockets_env.register_engine(".jsx", React::JSX::Processor, mime_type: "application/javascript", + silence_deprecation: true) end def register_processors(sprockets_env) - sprockets_env.register_mime_type('application/jsx', extensions: ['.jsx', '.js.jsx', '.es.jsx', '.es6.jsx']) - sprockets_env.register_mime_type('application/jsx+coffee', extensions: ['.jsx.coffee', '.js.jsx.coffee']) - sprockets_env.register_transformer('application/jsx', 'application/javascript', React::JSX::Processor) - sprockets_env.register_transformer('application/jsx+coffee', 'application/jsx', Sprockets::CoffeeScriptProcessor) - sprockets_env.register_preprocessor('application/jsx', Sprockets::DirectiveProcessor.new(comments: ['//', ['/*', '*/']])) - sprockets_env.register_preprocessor('application/jsx+coffee', Sprockets::DirectiveProcessor.new(comments: ['#', ['###', '###']])) + sprockets_env.register_mime_type("application/jsx", extensions: [".jsx", ".js.jsx", ".es.jsx", ".es6.jsx"]) + sprockets_env.register_mime_type("application/jsx+coffee", extensions: [".jsx.coffee", ".js.jsx.coffee"]) + sprockets_env.register_transformer("application/jsx", "application/javascript", React::JSX::Processor) + sprockets_env.register_transformer("application/jsx+coffee", "application/jsx", + Sprockets::CoffeeScriptProcessor) + sprockets_env.register_preprocessor("application/jsx", + Sprockets::DirectiveProcessor.new(comments: ["//", ["/*", "*/"]])) + sprockets_env.register_preprocessor("application/jsx+coffee", + Sprockets::DirectiveProcessor.new(comments: ["#", ["###", "###"]])) end end end diff --git a/lib/react/jsx/template.rb b/lib/react/jsx/template.rb index dbe1f5d08..1f3252214 100644 --- a/lib/react/jsx/template.rb +++ b/lib/react/jsx/template.rb @@ -1,16 +1,17 @@ -require 'tilt' +# frozen_string_literal: true + +require "tilt" module React module JSX # Sprockets 2-compliant processor class Template < Tilt::Template - self.default_mime_type = 'application/javascript' + self.default_mime_type = "application/javascript" - def prepare - end + def prepare; end - def evaluate(scope, locals, &block) - @output ||= JSX::transform(data) + def evaluate(_scope, _locals) + @evaluate ||= JSX.transform(data) end end end diff --git a/lib/react/rails.rb b/lib/react/rails.rb index f39342fe9..10934004c 100644 --- a/lib/react/rails.rb +++ b/lib/react/rails.rb @@ -1,7 +1,9 @@ -require 'react/rails/asset_variant' -require 'react/rails/railtie' -require 'react/rails/controller_lifecycle' -require 'react/rails/version' -require 'react/rails/component_mount' -require 'react/rails/view_helper' -require 'react/rails/controller_renderer' +# frozen_string_literal: true + +require "react/rails/asset_variant" +require "react/rails/railtie" +require "react/rails/controller_lifecycle" +require "react/rails/version" +require "react/rails/component_mount" +require "react/rails/view_helper" +require "react/rails/controller_renderer" diff --git a/lib/react/rails/asset_variant.rb b/lib/react/rails/asset_variant.rb index 42f8db0c9..70bc343e4 100644 --- a/lib/react/rails/asset_variant.rb +++ b/lib/react/rails/asset_variant.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + module React module Rails # This class accepts some options for which build you want, then exposes where you can find # them. In general, these paths should be added to the sprockets environment. class AssetVariant - GEM_ROOT = Pathname.new('../../../../').expand_path(__FILE__) + GEM_ROOT = Pathname.new("../../../../").expand_path(__FILE__) # @return [String] "production" or "development" attr_reader :react_build @@ -15,12 +17,11 @@ class AssetVariant # @param [Hash] Options for the asset variant # @option variant [Symbol] if `:production`, use the minified React.js build - def initialize(options={}) - - @react_build = options[:variant] == :production ? 'production' : 'development' + def initialize(options = {}) + @react_build = options[:variant] == :production ? "production" : "development" - @react_directory = GEM_ROOT.join('lib/assets/react-source/').join(@react_build).to_s - @jsx_directory = GEM_ROOT.join('lib/assets/javascripts/').to_s + @react_directory = GEM_ROOT.join("lib/assets/react-source/").join(@react_build).to_s + @jsx_directory = GEM_ROOT.join("lib/assets/javascripts/").to_s end end end diff --git a/lib/react/rails/component_mount.rb b/lib/react/rails/component_mount.rb index 83bb80e89..6aef2c72f 100644 --- a/lib/react/rails/component_mount.rb +++ b/lib/react/rails/component_mount.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module React module Rails # This is the default view helper implementation. @@ -9,6 +11,7 @@ class ComponentMount include ActionView::Helpers::TagHelper include ActionView::Helpers::TextHelper attr_accessor :output_buffer + mattr_accessor :camelize_props_switch def initialize @@ -21,57 +24,62 @@ def setup(controller) @controller = controller end - def teardown(controller) - end + def teardown(controller); end # Render a UJS-type HTML tag annotated with data attributes, which # are used by react_ujs to actually instantiate the React component # on the client. def react_component(name, props = {}, options = {}, &block) - options = { :tag => options } if options.is_a?(Symbol) - if options.fetch(:camelize_props, camelize_props_switch) - props = React.camelize_props(props) - end + options = { tag: options } if options.is_a?(Symbol) + props = React.camelize_props(props) if options.fetch(:camelize_props, camelize_props_switch) prerender_options = options[:prerender] - if prerender_options - block = Proc.new{ concat(prerender_component(name, props, prerender_options)) } - end + block = proc { concat(prerender_component(name, props, prerender_options)) } if prerender_options + + html_options = generate_html_options(name, options, props, prerender_options) + + rendered_tag(html_options, &block) + end + + private + + # If this controller has checked out a renderer, use that one. + # Otherwise, use {React::ServerRendering} directly (which will check one out for this rendering). + def prerender_component(component_name, props, prerender_options) + renderer = @controller.try(:react_rails_prerenderer) || React::ServerRendering + renderer.render(component_name, props, prerender_options) + end + + def generate_html_options(name, options, props, prerender_options) + html_options = options.reverse_merge(data: {}) - html_options = options.reverse_merge(:data => {}) unless prerender_options == :static html_options[:data].tap do |data| data[:react_class] = name data[:react_props] = (props.is_a?(String) ? props : props.to_json) - data[:hydrate] = 't' if prerender_options + data[:hydrate] = "t" if prerender_options num_components = @cache_ids.count { |c| c.start_with? name } data[:react_cache_id] = "#{name}-#{num_components}" end end + + html_options + end + + def rendered_tag(html_options, &block) html_tag = html_options[:tag] || :div # remove internally used properties so they aren't rendered to DOM - html_options.except!(:tag, :prerender, :camelize_props) - - rendered_tag = content_tag(html_tag, '', html_options, &block) - if React::ServerRendering.renderer_options[:replay_console] - # Grab the server-rendered console replay script - # and move it _outside_ the container div - rendered_tag.sub!(/\n()$}m, '\1') + tag.html_safe end end end diff --git a/lib/react/rails/controller_lifecycle.rb b/lib/react/rails/controller_lifecycle.rb index bb71137d8..0f5a7e950 100644 --- a/lib/react/rails/controller_lifecycle.rb +++ b/lib/react/rails/controller_lifecycle.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module React module Rails # This module is included into ActionController so that diff --git a/lib/react/rails/controller_renderer.rb b/lib/react/rails/controller_renderer.rb index 462aa05bd..f03252f14 100644 --- a/lib/react/rails/controller_renderer.rb +++ b/lib/react/rails/controller_renderer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module React module Rails # A renderer class suitable for `ActionController::Renderers`. @@ -20,7 +22,7 @@ class ControllerRenderer attr_accessor :output_buffer - def initialize(options={}) + def initialize(options = {}) controller = options[:controller] @__react_component_helper = controller.__react_component_helper end diff --git a/lib/react/rails/railtie.rb b/lib/react/rails/railtie.rb index 0ea5be9d5..43a549896 100644 --- a/lib/react/rails/railtie.rb +++ b/lib/react/rails/railtie.rb @@ -1,4 +1,6 @@ -require 'rails' +# frozen_string_literal: true + +require "rails" module React module Rails @@ -17,18 +19,17 @@ class Railtie < ::Rails::Railtie config.react.server_renderer = nil # defaults to BundleRenderer config.react.server_renderer_options = {} # BundleRenderer provides defaults # Changing files with these extensions in these directories will cause the server renderer to reload: - config.react.server_renderer_directories = ['/app/assets/javascripts/', 'app/javascript'] - config.react.server_renderer_extensions = ['jsx', 'js'] + config.react.server_renderer_directories = ["/app/assets/javascripts/", "app/javascript"] + config.react.server_renderer_extensions = %w[jsx js] # View helper implementation: config.react.view_helper_implementation = nil # Defaults to ComponentMount # Watch .jsx files for changes in dev, so we can reload the JS VMs with the new JS code. - initializer 'react_rails.add_watchable_files', after: :load_config_initializers, group: :all do |app| + initializer "react_rails.add_watchable_files", after: :load_config_initializers, group: :all do |app| # Watch files ending in `server_renderer_extensions` in each of `server_renderer_directories` - reload_paths = config.react.server_renderer_directories.reduce({}) do |memo, dir| + reload_paths = config.react.server_renderer_directories.each_with_object({}) do |dir, memo| app_dir = File.join(app.root, dir) memo[app_dir] = config.react.server_renderer_extensions - memo end # Rails checks these objects for changes: @@ -42,8 +43,7 @@ class Railtie < ::Rails::Railtie end # Include the react-rails view helper lazily - initializer 'react_rails.setup_view_helpers', after: :load_config_initializers, group: :all do |app| - + initializer "react_rails.setup_view_helpers", after: :load_config_initializers, group: :all do |app| app.config.react.jsx_transformer_class ||= React::JSX::DEFAULT_TRANSFORMER React::JSX.transformer_class = app.config.react.jsx_transformer_class React::JSX.transform_options = app.config.react.jsx_transform_options @@ -58,11 +58,11 @@ class Railtie < ::Rails::Railtie ActiveSupport.on_load(:action_view) do include ::React::Rails::ViewHelper - ActionDispatch::IntegrationTest.send(:include, React::Rails::TestHelper) if ::Rails.env.test? + ActionDispatch::IntegrationTest.include React::Rails::TestHelper if ::Rails.env.test? end end - initializer 'react_rails.add_component_renderer', group: :all do |app| + initializer "react_rails.add_component_renderer", group: :all do |_app| ActionController::Renderers.add :component do |component_name, options| renderer = ::React::Rails::ControllerRenderer.new(controller: self) html = renderer.call(component_name, options) @@ -71,22 +71,21 @@ class Railtie < ::Rails::Railtie end end - initializer 'react_rails.bust_cache', after: :load_config_initializers, group: :all do |app| + initializer "react_rails.bust_cache", after: :load_config_initializers, group: :all do |app| asset_variant = React::Rails::AssetVariant.new({ - variant: app.config.react.variant, - }) + variant: app.config.react.variant + }) sprockets_env = app.assets || app.config.try(:assets) # sprockets-rails 3.x attaches this at a different config unless sprockets_env.nil? - sprockets_env.version = [sprockets_env.version, "react-#{asset_variant.react_build}"].compact.join('-') + sprockets_env.version = [sprockets_env.version, "react-#{asset_variant.react_build}"].compact.join("-") end - end - initializer 'react_rails.set_variant', after: :engines_blank_point, group: :all do |app| + initializer "react_rails.set_variant", after: :engines_blank_point, group: :all do |app| asset_variant = React::Rails::AssetVariant.new({ - variant: app.config.react.variant, - }) + variant: app.config.react.variant + }) if app.config.respond_to?(:assets) app.config.assets.paths << asset_variant.react_directory @@ -105,16 +104,14 @@ class Railtie < ::Rails::Railtie React::ServerRendering.reset_pool end - initializer 'react_rails.setup_engine', :group => :all do |app| + initializer "react_rails.setup_engine", group: :all do |app| # Sprockets 3.x expects this in a different place - sprockets_env = app.assets || defined?(Sprockets) && Sprockets + sprockets_env = app.assets || (defined?(Sprockets) && Sprockets) if app.config.react.sprockets_strategy == false # pass, Sprockets opt-out elsif sprockets_env.present? React::JSX::SprocketsStrategy.attach_with_strategy(sprockets_env, app.config.react.sprockets_strategy) - else - # pass, Sprockets is not preset end end end diff --git a/lib/react/rails/test_helper.rb b/lib/react/rails/test_helper.rb index d79b358b3..6d7d38dc9 100644 --- a/lib/react/rails/test_helper.rb +++ b/lib/react/rails/test_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module React module Rails module TestHelper @@ -20,4 +22,4 @@ def assert_react_component(name) end end end -end \ No newline at end of file +end diff --git a/lib/react/rails/version.rb b/lib/react/rails/version.rb index c14da7794..ecf2bb6fe 100644 --- a/lib/react/rails/version.rb +++ b/lib/react/rails/version.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + module React module Rails # If you change this, make sure to update VERSIONS.md # and republish the UJS by updating package.json and `bundle exec rake ujs:publish` - VERSION = '2.7.1' + VERSION = "2.7.1" end end diff --git a/lib/react/rails/view_helper.rb b/lib/react/rails/view_helper.rb index 89bd6f238..5e09a33f0 100644 --- a/lib/react/rails/view_helper.rb +++ b/lib/react/rails/view_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module React module Rails module ViewHelper @@ -18,7 +20,7 @@ module ViewHelper # Otherwise, make a new instance. def react_component(*args, &block) helper_obj = @__react_component_helper ||= helper_implementation_class.new - helper_obj.react_component(*args) { capture &block if block_given? } + helper_obj.react_component(*args) { capture(&block) if block } end end end diff --git a/lib/react/server_rendering.rb b/lib/react/server_rendering.rb index 682c1ce41..3abe72cfe 100644 --- a/lib/react/server_rendering.rb +++ b/lib/react/server_rendering.rb @@ -1,11 +1,13 @@ -require 'connection_pool' -require 'react/server_rendering/exec_js_renderer' -require 'react/server_rendering/bundle_renderer' +# frozen_string_literal: true + +require "connection_pool" +require "react/server_rendering/exec_js_renderer" +require "react/server_rendering/bundle_renderer" module React module ServerRendering mattr_accessor :renderer, :renderer_options, - :pool_size, :pool_timeout + :pool_size, :pool_timeout self.renderer_options = {} @@ -14,7 +16,7 @@ module ServerRendering # @return [void] def self.reset_pool options = { size: pool_size, timeout: pool_timeout } - @@pool = ConnectionPool.new(options) { self.renderer.new(self.renderer_options) } + @pool = ConnectionPool.new(options) { renderer.new(renderer_options) } end # Check a renderer out of the pool and use it to render the component. @@ -23,21 +25,21 @@ def self.reset_pool # @param prerender_options [Hash] Renderer-specific options # @return [String] Prerendered HTML from `component_name` def self.render(component_name, props, prerender_options) - @@pool.with do |renderer| + @pool.with do |renderer| renderer.render(component_name, props, prerender_options) end end # Yield a renderer for an arbitrary block - def self.with_renderer - @@pool.with { |renderer| yield(renderer) } + def self.with_renderer(&block) + @pool.with(&block) end # Raised when something went wrong during server rendering. class PrerenderError < RuntimeError def initialize(component_name, props, js_message) message = ["Encountered error \"#{js_message.inspect}\" when prerendering #{component_name} with #{props}", - js_message.backtrace.join("\n")].join("\n") + js_message.backtrace.join("\n")].join("\n") super(message) end end diff --git a/lib/react/server_rendering/bundle_renderer.rb b/lib/react/server_rendering/bundle_renderer.rb index 390b5a00a..cb7621919 100644 --- a/lib/react/server_rendering/bundle_renderer.rb +++ b/lib/react/server_rendering/bundle_renderer.rb @@ -1,7 +1,9 @@ -require 'react/server_rendering/environment_container' -require 'react/server_rendering/manifest_container' -require 'react/server_rendering/yaml_manifest_container' -require 'react/server_rendering/separate_server_bundle_container' +# frozen_string_literal: true + +require "react/server_rendering/environment_container" +require "react/server_rendering/manifest_container" +require "react/server_rendering/yaml_manifest_container" +require "react/server_rendering/separate_server_bundle_container" module React module ServerRendering @@ -11,17 +13,17 @@ module ServerRendering # - implements console replay class BundleRenderer < ExecJSRenderer # Reimplement console methods for replaying on the client - CONSOLE_POLYFILL = File.read(File.join(File.dirname(__FILE__), 'bundle_renderer/console_polyfill.js')) - CONSOLE_REPLAY = File.read(File.join(File.dirname(__FILE__), 'bundle_renderer/console_replay.js')) - CONSOLE_RESET = File.read(File.join(File.dirname(__FILE__), 'bundle_renderer/console_reset.js')) - TIMEOUT_POLYFILL = File.read(File.join(File.dirname(__FILE__), 'bundle_renderer/timeout_polyfill.js')) + CONSOLE_POLYFILL = File.read(File.join(File.dirname(__FILE__), "bundle_renderer/console_polyfill.js")) + CONSOLE_REPLAY = File.read(File.join(File.dirname(__FILE__), "bundle_renderer/console_replay.js")) + CONSOLE_RESET = File.read(File.join(File.dirname(__FILE__), "bundle_renderer/console_reset.js")) + TIMEOUT_POLYFILL = File.read(File.join(File.dirname(__FILE__), "bundle_renderer/timeout_polyfill.js")) - def initialize(options={}) + def initialize(options = {}) @replay_console = options.fetch(:replay_console, true) - filenames = options.fetch(:files, ['server_rendering.js']) + filenames = options.fetch(:files, ["server_rendering.js"]) js_code = CONSOLE_POLYFILL.dup js_code << TIMEOUT_POLYFILL.dup - js_code << options.fetch(:code, '') + js_code << options.fetch(:code, "") filenames.each do |filename| js_code << asset_container.find_asset(filename) @@ -40,12 +42,12 @@ def render(component_name, props, prerender_options) super(component_name, t_props, t_options) end - def before_render(component_name, props, prerender_options) - @replay_console ? CONSOLE_RESET : '' + def before_render(_component_name, _props, _prerender_options) + @replay_console ? CONSOLE_RESET : "" end - def after_render(component_name, props, prerender_options) - @replay_console ? CONSOLE_REPLAY : '' + def after_render(_component_name, _props, _prerender_options) + @replay_console ? CONSOLE_REPLAY : "" end class << self @@ -72,7 +74,6 @@ def prepare_options(options) r_func = render_function(options) opts = case options when Hash then options - when TrueClass then {} else {} end @@ -82,9 +83,9 @@ def prepare_options(options) def render_function(opts) if opts == :static - 'renderToStaticMarkup'.freeze + "renderToStaticMarkup" else - 'renderToString'.freeze + "renderToString" end end diff --git a/lib/react/server_rendering/environment_container.rb b/lib/react/server_rendering/environment_container.rb index 141ab7972..96b4c63ed 100644 --- a/lib/react/server_rendering/environment_container.rb +++ b/lib/react/server_rendering/environment_container.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module React module ServerRendering # Return asset contents by getting them from a Sprockets::Environment instance. diff --git a/lib/react/server_rendering/exec_js_renderer.rb b/lib/react/server_rendering/exec_js_renderer.rb index d133ffda9..997034db9 100644 --- a/lib/react/server_rendering/exec_js_renderer.rb +++ b/lib/react/server_rendering/exec_js_renderer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module React module ServerRendering # A bare-bones renderer for React.js + Exec.js @@ -8,8 +10,8 @@ class ExecJSRenderer # @return [ExecJS::Runtime::Context] The JS context for this renderer attr_reader :context - def initialize(options={}) - js_code = options[:code] || raise('Pass `code:` option to instantiate a JS context!') + def initialize(options = {}) + js_code = options[:code] || raise("Pass `code:` option to instantiate a JS context!") full_code = GLOBAL_WRAPPER + js_code # File.write("./test/dummy/tmp/latest_js_context.js", full_code) @context = ExecJS.compile(full_code) @@ -25,8 +27,13 @@ def render(component_name, props, prerender_options) end # Hooks for inserting JS before/after rendering - def before_render(component_name, props, prerender_options); ''; end - def after_render(component_name, props, prerender_options); ''; end + def before_render(_component_name, _props, _prerender_options) + "" + end + + def after_render(_component_name, _props, _prerender_options) + "" + end # Handle Node.js & other ExecJS contexts GLOBAL_WRAPPER = <<-JS @@ -42,7 +49,7 @@ def render_from_parts(before, main, after) end def main_render(component_name, props, prerender_options) - render_function = prerender_options.fetch(:render_function, 'renderToString') + render_function = prerender_options.fetch(:render_function, "renderToString") "this.ReactRailsUJS.serverRender('#{render_function}', '#{component_name}', #{props})" end diff --git a/lib/react/server_rendering/manifest_container.rb b/lib/react/server_rendering/manifest_container.rb index 2dea10cb3..032330ebc 100644 --- a/lib/react/server_rendering/manifest_container.rb +++ b/lib/react/server_rendering/manifest_container.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module React module ServerRendering # Get asset content by reading the compiled file from disk using a Sprockets::Manifest. @@ -10,8 +12,10 @@ def initialize end def find_asset(logical_path) - asset_path = @manifest.assets[logical_path] || raise("No compiled asset for #{logical_path}, was it precompiled?") - asset_full_path = ::Rails.root.join('public', @manifest.dir, asset_path) + asset_path = @manifest.assets[logical_path] || raise( + "No compiled asset for #{logical_path}, was it precompiled?" + ) + asset_full_path = ::Rails.root.join("public", @manifest.dir, asset_path) File.read(asset_full_path) end diff --git a/lib/react/server_rendering/separate_server_bundle_container.rb b/lib/react/server_rendering/separate_server_bundle_container.rb index 891f55b28..daee42662 100644 --- a/lib/react/server_rendering/separate_server_bundle_container.rb +++ b/lib/react/server_rendering/separate_server_bundle_container.rb @@ -1,17 +1,18 @@ -require 'open-uri' +# frozen_string_literal: true + +require "open-uri" module React module ServerRendering # Get a compiled file from Webpacker's output path class SeparateServerBundleContainer - def self.compatible? !!defined?(Webpacker) end def find_asset(filename) - asset_path = Webpacker.config.public_output_path.join(filename).to_s - File.read(asset_path) + asset_path = Webpacker.config.public_output_path.join(filename).to_s + File.read(asset_path) end end end diff --git a/lib/react/server_rendering/yaml_manifest_container.rb b/lib/react/server_rendering/yaml_manifest_container.rb index b4cbf5624..3bb725846 100644 --- a/lib/react/server_rendering/yaml_manifest_container.rb +++ b/lib/react/server_rendering/yaml_manifest_container.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module React module ServerRendering # Get asset content by reading the compiled file from disk using the generated manifest.yml file @@ -6,7 +8,7 @@ module ServerRendering # but sometimes, they're compiled to other directories (or other servers) class YamlManifestContainer def initialize - @assets = YAML.load_file(public_asset_path('manifest.yml')) + @assets = YAML.load_file(public_asset_path("manifest.yml")) end def find_asset(logical_path) @@ -21,7 +23,7 @@ def self.compatible? private def public_asset_path(asset_name) - asset_path = File.join('public', ::Rails.application.config.assets.prefix, asset_name) + asset_path = File.join("public", ::Rails.application.config.assets.prefix, asset_name) ::Rails.root.join(asset_path) end end diff --git a/rakelib/create_release.rake b/rakelib/create_release.rake index 18698f9ce..e3c1159eb 100644 --- a/rakelib/create_release.rake +++ b/rakelib/create_release.rake @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'English' +require "English" desc("Releases both the gem and node package using the given version. IMPORTANT: the gem version must be in valid rubygem format (no dashes). @@ -23,8 +23,8 @@ task :create_release, %i[gem_version dry_run] do |_t, args| is_dry_run = Release.object_to_boolean(args_hash[:dry_run]) puts "is_dry_run: #{is_dry_run}" if is_dry_run - gem_version = args_hash.fetch(:gem_version, '').strip - npm_version = gem_version.empty? ? '' : Release.convert_rubygem_to_npm_version(gem_version) + gem_version = args_hash.fetch(:gem_version, "").strip + npm_version = gem_version.empty? ? "" : Release.convert_rubygem_to_npm_version(gem_version) Release.update_the_local_project Release.ensure_there_is_nothing_to_commit @@ -32,12 +32,12 @@ task :create_release, %i[gem_version dry_run] do |_t, args| # Preparing for release # Updating the pre-bundled react - puts 'Updating react' - Rake::Task['react:update'].invoke + puts "Updating react" + Rake::Task["react:update"].invoke # Updating ReactRailsUJS - puts 'Updating ujs:update' - Rake::Task['ujs:update'].invoke + puts "Updating ujs:update" + Rake::Task["ujs:update"].invoke Release.make_sure_react_and_ujs_are_updated_and_commited @@ -53,7 +53,7 @@ module Release extend FileUtils class << self def gem_root - File.expand_path('..', __dir__) + File.expand_path("..", __dir__) end # Executes a string or an array of strings in a shell in the given directory in an unbundled environment @@ -71,18 +71,18 @@ module Release def nothing_to_commit? status = `git status --porcelain` - $CHILD_STATUS.success? && status == '' + $CHILD_STATUS.success? && status == "" end def ensure_there_is_nothing_to_commit status = `git status --porcelain` - return if $CHILD_STATUS.success? && status == '' + return if $CHILD_STATUS.success? && status == "" error = if $CHILD_STATUS.success? - 'You have uncommitted code. Please commit or stash your changes before continuing' + "You have uncommitted code. Please commit or stash your changes before continuing" else - 'You do not have Git installed. Please install Git, and commit your changes before continuing' + "You do not have Git installed. Please install Git, and commit your changes before continuing" end raise(error) end @@ -90,18 +90,21 @@ module Release def make_sure_react_and_ujs_are_updated_and_commited status = `git status --porcelain` - return if $CHILD_STATUS.success? && status == '' + return if $CHILD_STATUS.success? && status == "" error = if $CHILD_STATUS.success? - 'Running react:update and ujs:update resulted in uncommitted changes. Please commit those changes & confirm that CI passes before continuing.' + <<-MSG + Running react:update and ujs:update resulted in uncommitted changes. + Please commit those changes & confirm that CI passes before continuing. + MSG else - 'You do not have Git installed. Please install Git, and commit your changes before continuing' + "You do not have Git installed. Please install Git, and commit your changes before continuing" end raise(error) end def object_to_boolean(value) - [true, 'true', 'yes', 1, '1', 't'].include?(value.instance_of?(String) ? value.downcase : value) + [true, "true", "yes", 1, "1", "t"].include?(value.instance_of?(String) ? value.downcase : value) end def convert_rubygem_to_npm_version(gem_version) @@ -112,51 +115,51 @@ module Release end def update_the_local_project - puts 'Pulling latest commits from remote repository' + puts "Pulling latest commits from remote repository" - sh_in_dir(gem_root, 'git pull --rebase') - sh_in_dir(gem_root, 'bundle') - sh_in_dir(gem_root, 'yarn') - sh_in_dir(File.join(gem_root, 'react-builds'), 'yarn') + sh_in_dir(gem_root, "git pull --rebase") + sh_in_dir(gem_root, "bundle") + sh_in_dir(gem_root, "yarn") + sh_in_dir(File.join(gem_root, "react-builds"), "yarn") - raise 'Failed in pulling latest changes from default remore repository.' unless $CHILD_STATUS.success? + raise "Failed in pulling latest changes from default remore repository." unless $CHILD_STATUS.success? rescue Errno::ENOENT - raise 'Ensure you have Git and Bundler installed before continuing.' + raise "Ensure you have Git and Bundler installed before continuing." end def bump_gem_version(gem_version, is_dry_run) - puts 'Bumping gem version' + puts "Bumping gem version" Release.sh_in_dir( gem_root, "gem bump --no-commit #{gem_version == '' ? '' : %(--version #{gem_version})}", - 'bundle install', - (is_dry_run ? nil: commit_the_changes("Bump version to #{gem_version}")) + "bundle install", + (is_dry_run ? nil : commit_the_changes("Bump version to #{gem_version}")) ) end def release_the_new_gem_version(is_dry_run) - puts 'ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ' - puts 'Use the OTP for RubyGems!' - puts 'ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ' + puts "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" + puts "Use the OTP for RubyGems!" + puts "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" - sh_in_dir(gem_root, 'gem release --push --tag') unless is_dry_run + sh_in_dir(gem_root, "gem release --push --tag") unless is_dry_run end def release_the_new_npm_version(npm_version, is_dry_run) puts "Making npm release, #{is_dry_run ? 'dry run' : 'real run'}" # Will bump the yarn version, commit, tag the commit, push to repo, and release on yarn - puts 'ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ' - puts 'Use the OTP for NPM!' - puts 'ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ' - release_it_command = +'release-it' - release_it_command << " #{npm_version}" unless npm_version == '' - release_it_command << ' --npm.publish --no-git.requireCleanWorkingDir' - release_it_command << ' --dry-run --verbose' if is_dry_run + puts "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" + puts "Use the OTP for NPM!" + puts "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" + release_it_command = +"release-it" + release_it_command << " #{npm_version}" unless npm_version == "" + release_it_command << " --npm.publish --no-git.requireCleanWorkingDir" + release_it_command << " --dry-run --verbose" if is_dry_run sh_in_dir(gem_root, release_it_command) end def push - sh_in_dir(gem_root, 'git push') + sh_in_dir(gem_root, "git push") end end end diff --git a/react-rails.gemspec b/react-rails.gemspec index aeb4092c8..4d3476a21 100644 --- a/react-rails.gemspec +++ b/react-rails.gemspec @@ -30,6 +30,7 @@ Gem::Specification.new do |s| s.add_development_dependency 'test-unit', '~> 2.5' s.add_development_dependency 'pry-byebug' + s.add_dependency 'connection_pool' s.add_dependency 'execjs' s.add_dependency 'railties', '>= 3.2' diff --git a/test/dummy/Rakefile b/test/dummy/Rakefile index 4135d7a46..a2918d43c 100644 --- a/test/dummy/Rakefile +++ b/test/dummy/Rakefile @@ -1,6 +1,8 @@ +# frozen_string_literal: true + # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. -require File.expand_path('../config/application', __FILE__) +require File.expand_path("config/application", __dir__) Dummy::Application.load_tasks diff --git a/test/dummy/app/controllers/application_controller.rb b/test/dummy/app/controllers/application_controller.rb index d83690e1b..1ff0944d0 100644 --- a/test/dummy/app/controllers/application_controller.rb +++ b/test/dummy/app/controllers/application_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. diff --git a/test/dummy/app/controllers/pack_components_controller.rb b/test/dummy/app/controllers/pack_components_controller.rb index 547f40c2c..e3d4aa908 100644 --- a/test/dummy/app/controllers/pack_components_controller.rb +++ b/test/dummy/app/controllers/pack_components_controller.rb @@ -1,6 +1,7 @@ +# frozen_string_literal: true + class PackComponentsController < ApplicationController # make sure Sprockets application.js isn't loaded: layout false - def show - end + def show; end end diff --git a/test/dummy/app/controllers/pages_controller.rb b/test/dummy/app/controllers/pages_controller.rb index f7cf90da3..6c99fb939 100644 --- a/test/dummy/app/controllers/pages_controller.rb +++ b/test/dummy/app/controllers/pages_controller.rb @@ -1,10 +1,10 @@ +# frozen_string_literal: true + class PagesController < ApplicationController - if WebpackerHelpers.available? || SprocketsHelpers.available? - per_request_react_rails_prerenderer - end + per_request_react_rails_prerenderer if WebpackerHelpers.available? || SprocketsHelpers.available? def show - @prerender = !!params[:prerender] + @prerender = !params[:prerender].nil? if @prerender js_context = react_rails_prerenderer.context # This isn't safe for production, we're just testing the render context: @@ -12,15 +12,15 @@ def show setup_code = "global.ctx = {}; global.ctx.greeting = '#{greeting_override}';" js_context.exec(setup_code) end - @name = %w(Alice Bob)[params[:id].to_i % 2] + @name = %w[Alice Bob][params[:id].to_i % 2] render :show - if @prerender - js_context.exec("global.ctx = undefined;") - end + return unless @prerender + + js_context.exec("global.ctx = undefined;") end def no_turbolinks @prerender = false - render :show, layout: 'app_no_turbolinks' + render :show, layout: "app_no_turbolinks" end end diff --git a/test/dummy/app/controllers/server_controller.rb b/test/dummy/app/controllers/server_controller.rb index b2df49093..a13658614 100644 --- a/test/dummy/app/controllers/server_controller.rb +++ b/test/dummy/app/controllers/server_controller.rb @@ -1,11 +1,13 @@ +# frozen_string_literal: true + class ServerController < ApplicationController def show @component_name = params[:component_name] || "TodoList" - @todos = %w{todo1 todo2 todo3} + @todos = %w[todo1 todo2 todo3] end def console_example - @todos = %w{todo1 todo2 todo3} + @todos = %w[todo1 todo2 todo3] end def inline_component_prerender_true @@ -17,22 +19,23 @@ def inline_component_prerender_false end def inline_component_with_camelize_props_prerender_true - render component: 'TodoList', props: { test_camelize_props: true, todos: ['dummy'] }, camelize_props: true + render component: "TodoList", props: { test_camelize_props: true, todos: ["dummy"] }, camelize_props: true end def inline_component_with_camelize_props_prerender_false - render component: 'TodoList', props: { test_camelize_props: true, todos: ['dummy'] }, camelize_props: true, prerender: false + render component: "TodoList", props: { test_camelize_props: true, todos: ["dummy"] }, camelize_props: true, + prerender: false end private def component_options { - component: 'TodoList', - props: { todos: ['Render this inline'] }, - tag: 'span', - class: 'custom-class', - id: 'custom-id', + component: "TodoList", + props: { todos: ["Render this inline"] }, + tag: "span", + class: "custom-class", + id: "custom-id", data: { remote: true } } end diff --git a/test/dummy/app/helpers/application_helper.rb b/test/dummy/app/helpers/application_helper.rb index de6be7945..15b06f0f6 100644 --- a/test/dummy/app/helpers/application_helper.rb +++ b/test/dummy/app/helpers/application_helper.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + module ApplicationHelper end diff --git a/test/dummy/bin/bundle b/test/dummy/bin/bundle index 66e9889e8..5015ba6f8 100755 --- a/test/dummy/bin/bundle +++ b/test/dummy/bin/bundle @@ -1,3 +1,5 @@ #!/usr/bin/env ruby -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) -load Gem.bin_path('bundler', 'bundle') +# frozen_string_literal: true + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) +load Gem.bin_path("bundler", "bundle") diff --git a/test/dummy/bin/rails b/test/dummy/bin/rails index 728cd85aa..22f2d8dee 100755 --- a/test/dummy/bin/rails +++ b/test/dummy/bin/rails @@ -1,4 +1,6 @@ #!/usr/bin/env ruby -APP_PATH = File.expand_path('../../config/application', __FILE__) -require_relative '../config/boot' -require 'rails/commands' +# frozen_string_literal: true + +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/test/dummy/bin/rake b/test/dummy/bin/rake index 17240489f..e436ea54a 100755 --- a/test/dummy/bin/rake +++ b/test/dummy/bin/rake @@ -1,4 +1,6 @@ #!/usr/bin/env ruby -require_relative '../config/boot' -require 'rake' +# frozen_string_literal: true + +require_relative "../config/boot" +require "rake" Rake.application.run diff --git a/test/dummy/bin/webpacker b/test/dummy/bin/webpacker index 47ef0c4ca..68748b9ad 100755 --- a/test/dummy/bin/webpacker +++ b/test/dummy/bin/webpacker @@ -1,4 +1,5 @@ #!/usr/bin/env ruby +# frozen_string_literal: true require "pathname" require "bundler/setup" @@ -6,7 +7,7 @@ require "webpacker" require "webpacker/webpack_runner" ENV["RAILS_ENV"] ||= "development" -ENV["NODE_ENV"] ||= ENV["RAILS_ENV"] +ENV["NODE_ENV"] ||= ENV.fetch("RAILS_ENV", nil) ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", Pathname.new(__FILE__).realpath) APP_ROOT = File.expand_path("..", __dir__) diff --git a/test/dummy/bin/webpacker-dev-server b/test/dummy/bin/webpacker-dev-server index fb4e90f35..8d46b25be 100755 --- a/test/dummy/bin/webpacker-dev-server +++ b/test/dummy/bin/webpacker-dev-server @@ -1,11 +1,12 @@ #!/usr/bin/env ruby +# frozen_string_literal: true ENV["RAILS_ENV"] ||= "development" -ENV["NODE_ENV"] ||= ENV["RAILS_ENV"] +ENV["NODE_ENV"] ||= ENV.fetch("RAILS_ENV", nil) require "pathname" ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) + Pathname.new(__FILE__).realpath) require "bundler/setup" @@ -15,4 +16,4 @@ require "webpacker/dev_server_runner" APP_ROOT = File.expand_path("..", __dir__) Dir.chdir(APP_ROOT) do Webpacker::DevServerRunner.run(ARGV) -end \ No newline at end of file +end diff --git a/test/dummy/bin/yarn b/test/dummy/bin/yarn index 3ccb9c411..1b8fbd2ff 100755 --- a/test/dummy/bin/yarn +++ b/test/dummy/bin/yarn @@ -1,10 +1,10 @@ #!/usr/bin/env ruby -VENDOR_PATH = File.expand_path('..', __dir__) +# frozen_string_literal: true + +VENDOR_PATH = File.expand_path("..", __dir__) Dir.chdir(VENDOR_PATH) do - begin - exec "yarnpkg #{ARGV.join(" ")}" - rescue Errno::ENOENT - puts "Yarn executable was not detected in the system." - puts "Download Yarn at https://yarnpkg.com/en/docs/install" - end + exec "yarnpkg #{ARGV.join(' ')}" +rescue Errno::ENOENT + puts "Yarn executable was not detected in the system." + puts "Download Yarn at https://yarnpkg.com/en/docs/install" end diff --git a/test/dummy/config.ru b/test/dummy/config.ru index 5bc2a619e..da8ca8b2b 100644 --- a/test/dummy/config.ru +++ b/test/dummy/config.ru @@ -1,4 +1,6 @@ +# frozen_string_literal: true + # This file is used by Rack-based servers to start the application. -require ::File.expand_path('../config/environment', __FILE__) +require File.expand_path("config/environment", __dir__) run Rails.application diff --git a/test/dummy/config/application.rb b/test/dummy/config/application.rb index 6df0ee9e5..187b6c119 100644 --- a/test/dummy/config/application.rb +++ b/test/dummy/config/application.rb @@ -1,4 +1,6 @@ -require File.expand_path('../boot', __FILE__) +# frozen_string_literal: true + +require File.expand_path("boot", __dir__) # Pick the frameworks you want: # require "active_record/railtie" @@ -6,16 +8,14 @@ require "action_mailer/railtie" # Test no-sprockets environment by testing the gemfile name -if SprocketsHelpers.available? - require "sprockets/railtie" -end +require "sprockets/railtie" if SprocketsHelpers.available? require "rails/test_unit/railtie" # Make sure gems in development group are required, for example, react-rails and turbolinks. # These gems are specified in .gemspec file by add_development_dependency. They are not runtime # dependencies for react-rails project but probably runtime dependencies for this dummy rails app. -Bundler.require(*(Rails.groups | ['development'])) +Bundler.require(*(Rails.groups | ["development"])) module Dummy class Application < Rails::Application @@ -32,11 +32,11 @@ class Application < Rails::Application # config.i18n.default_locale = :de config.react.variant = :production config.react.server_renderer_options = { - replay_console: true, + replay_console: true } if SprocketsHelpers.available? - config.assets.precompile += %w( app_no_turbolinks.js ) + config.assets.precompile += %w[app_no_turbolinks.js] config.assets.enabled = true end end diff --git a/test/dummy/config/boot.rb b/test/dummy/config/boot.rb index 6266cfc50..59459d4ae 100644 --- a/test/dummy/config/boot.rb +++ b/test/dummy/config/boot.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + # Set up gems listed in the Gemfile. -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__) +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile", __dir__) -require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) -$LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__) +require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"]) +$LOAD_PATH.unshift File.expand_path("../../../lib", __dir__) diff --git a/test/dummy/config/environment.rb b/test/dummy/config/environment.rb index 10e0cadcf..78973b15e 100644 --- a/test/dummy/config/environment.rb +++ b/test/dummy/config/environment.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + # Load the Rails application. -require File.expand_path('../application', __FILE__) +require File.expand_path("application", __dir__) # Initialize the Rails application. Dummy::Application.initialize! diff --git a/test/dummy/config/environments/development.rb b/test/dummy/config/environments/development.rb index ebcbc9792..fb1aadb46 100644 --- a/test/dummy/config/environments/development.rb +++ b/test/dummy/config/environments/development.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Dummy::Application.configure do # Settings specified here will take precedence over those in config/application.rb. diff --git a/test/dummy/config/environments/production.rb b/test/dummy/config/environments/production.rb index b690b1cf6..0035bf8ea 100644 --- a/test/dummy/config/environments/production.rb +++ b/test/dummy/config/environments/production.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Dummy::Application.configure do # Settings specified here will take precedence over those in config/application.rb. @@ -33,7 +35,7 @@ config.assets.digest = true # Version of your assets, change this if you want to expire all your assets. - config.assets.version = '1.0' + config.assets.version = "1.0" # Specifies the header that your server uses for sending files. # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache @@ -76,5 +78,5 @@ # config.autoflush_log = false # Use default logging formatter so that PID and timestamp are not suppressed. - config.log_formatter = ::Logger::Formatter.new + config.log_formatter = Logger::Formatter.new end diff --git a/test/dummy/config/environments/test.rb b/test/dummy/config/environments/test.rb index f90e42d62..6ff1487ce 100644 --- a/test/dummy/config/environments/test.rb +++ b/test/dummy/config/environments/test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Dummy::Application.configure do # Settings specified here will take precedence over those in config/application.rb. @@ -9,9 +11,7 @@ # we need this to reload the jsx transformer when different version is dropped in config.cache_classes = false config.reload_plugins = true - if SprocketsHelpers.available? - config.assets.cache_store = :null_store - end + config.assets.cache_store = :null_store if SprocketsHelpers.available? # Do not eager load code on boot. This avoids loading your whole application # just for the purpose of running a single test. If you are using a tool that diff --git a/test/dummy/config/initializers/backtrace_silencers.rb b/test/dummy/config/initializers/backtrace_silencers.rb index 59385cdf3..d0f0d3b5d 100644 --- a/test/dummy/config/initializers/backtrace_silencers.rb +++ b/test/dummy/config/initializers/backtrace_silencers.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # Be sure to restart your server when you modify this file. # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. diff --git a/test/dummy/config/initializers/filter_parameter_logging.rb b/test/dummy/config/initializers/filter_parameter_logging.rb index 4a994e1e7..7a4f47b4c 100644 --- a/test/dummy/config/initializers/filter_parameter_logging.rb +++ b/test/dummy/config/initializers/filter_parameter_logging.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # Configure sensitive parameters which will be filtered from the log file. diff --git a/test/dummy/config/initializers/inflections.rb b/test/dummy/config/initializers/inflections.rb index ac033bf9d..aa7435fbc 100644 --- a/test/dummy/config/initializers/inflections.rb +++ b/test/dummy/config/initializers/inflections.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # Be sure to restart your server when you modify this file. # Add new inflection rules using the following format. Inflections diff --git a/test/dummy/config/initializers/mime_types.rb b/test/dummy/config/initializers/mime_types.rb index 72aca7e44..f75864f9c 100644 --- a/test/dummy/config/initializers/mime_types.rb +++ b/test/dummy/config/initializers/mime_types.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # Be sure to restart your server when you modify this file. # Add new mime types for use in respond_to blocks: diff --git a/test/dummy/config/initializers/react.rb b/test/dummy/config/initializers/react.rb index 3b7ce0c96..3eee3c8f6 100644 --- a/test/dummy/config/initializers/react.rb +++ b/test/dummy/config/initializers/react.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Override setting set in application.rb class CustomComponentMount < React::Rails::ComponentMount end @@ -10,4 +12,3 @@ class CustomComponentMount < React::Rails::ComponentMount "app/javascript", "app/pants"] end - diff --git a/test/dummy/config/initializers/secret_token.rb b/test/dummy/config/initializers/secret_token.rb index 5dea6d691..91a10c463 100644 --- a/test/dummy/config/initializers/secret_token.rb +++ b/test/dummy/config/initializers/secret_token.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # Your secret key is used for verifying the integrity of signed cookies. @@ -9,7 +11,7 @@ # Make sure your secret_key_base is kept private # if you're sharing your code publicly. -Dummy::Application.config.secret_key_base = '43fa5672451bbd0a171668e625edc433eb00eeeb14c2606546e262e499ab853cfb532998d4809abe5019bf13888863e3a2c7d5cf7757de7a2b1fb50826d9874e' +Dummy::Application.config.secret_key_base = "43fa5672451bbd0a171668e625edc433eb00eeeb14c2606546e262e499ab853cfb532998d4809abe5019bf13888863e3a2c7d5cf7757de7a2b1fb50826d9874e" # rubocop:disable Layout/LineLength # For Rails 3.2. Dummy::Application.config.secret_token = Dummy::Application.config.secret_key_base diff --git a/test/dummy/config/initializers/session_store.rb b/test/dummy/config/initializers/session_store.rb index 155f7b028..fa158b8df 100644 --- a/test/dummy/config/initializers/session_store.rb +++ b/test/dummy/config/initializers/session_store.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. -Dummy::Application.config.session_store :cookie_store, key: '_dummy_session' +Dummy::Application.config.session_store :cookie_store, key: "_dummy_session" diff --git a/test/dummy/config/initializers/wrap_parameters.rb b/test/dummy/config/initializers/wrap_parameters.rb index 33725e95f..246168a42 100644 --- a/test/dummy/config/initializers/wrap_parameters.rb +++ b/test/dummy/config/initializers/wrap_parameters.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # This file contains settings for ActionController::ParamsWrapper which diff --git a/test/dummy/config/routes.rb b/test/dummy/config/routes.rb index 46cdd035d..ef57ce2ac 100644 --- a/test/dummy/config/routes.rb +++ b/test/dummy/config/routes.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + Dummy::Application.routes.draw do - get 'no-turbolinks', to: 'pages#no_turbolinks' + get "no-turbolinks", to: "pages#no_turbolinks" resources :pages, only: [:show] resources :server, only: [:show] do collection do diff --git a/test/generators/coffee_component_generator_test.rb b/test/generators/coffee_component_generator_test.rb index 63d9d6c0d..151c4166e 100644 --- a/test/generators/coffee_component_generator_test.rb +++ b/test/generators/coffee_component_generator_test.rb @@ -1,46 +1,49 @@ -require 'test_helper' -require 'generators/react/component_generator' +# frozen_string_literal: true + +require "test_helper" +require "generators/react/component_generator" class CoffeeComponentGeneratorTest < Rails::Generators::TestCase - destination File.join(Rails.root, 'tmp', 'component_generator_test_output') + destination File.join(Rails.root, "tmp", "component_generator_test_output") setup :prepare_destination tests React::Generators::ComponentGenerator if WebpackerHelpers.available? def filename - 'app/javascript/components/GeneratedComponent.coffee' + "app/javascript/components/GeneratedComponent.coffee" end - test 'that Webpacker defaults to ES6' do - run_generator %w(GeneratedComponent name) + test "that Webpacker defaults to ES6" do + run_generator %w[GeneratedComponent name] + + es6 = File.read(File.join(destination_root, "app/javascript/components/GeneratedComponent.js")) - es6 = File.read(File.join(destination_root, 'app/javascript/components/GeneratedComponent.js')) - assert_match(%r{extends React.Component}, es6) + assert_match(/extends React.Component/, es6) end else def filename - 'app/assets/javascripts/components/generated_component.js.jsx.coffee' + "app/assets/javascripts/components/generated_component.js.jsx.coffee" end end def class_name - 'GeneratedComponent' + "GeneratedComponent" end - test 'that it the uses CoffeeScript syntax' do - run_generator %w(GeneratedComponent name --coffee) + test "that it the uses CoffeeScript syntax" do + run_generator %w[GeneratedComponent name --coffee] assert_file filename, /^class #{class_name}\sextends\sReact\.Component/ end - test 'that propTypes get assigned' do - run_generator %w(GeneratedComponent name --coffee) + test "that propTypes get assigned" do + run_generator %w[GeneratedComponent name --coffee] assert_file filename, /@propTypes\s=/ assert_file filename, /PropTypes/ end - test 'that it generates working jsx' do - run_generator %w(GeneratedComponent name:string address:shape --coffee) + test "that it generates working jsx" do + run_generator %w[GeneratedComponent name:string address:shape --coffee] jsx = React::JSX.transform(CoffeeScript.compile(File.read(File.join(destination_root, filename)))) assert_match(Regexp.new(expected_working_jsx), jsx) diff --git a/test/generators/component_generator_test.rb b/test/generators/component_generator_test.rb index 743de5d07..9605fd072 100644 --- a/test/generators/component_generator_test.rb +++ b/test/generators/component_generator_test.rb @@ -1,81 +1,89 @@ -require 'test_helper' -require 'generators/react/component_generator' +# frozen_string_literal: true + +require "test_helper" +require "generators/react/component_generator" class ComponentGeneratorTest < Rails::Generators::TestCase - destination File.join(Rails.root, 'tmp', 'component_generator_test_output') + destination File.join(Rails.root, "tmp", "component_generator_test_output") setup :prepare_destination tests React::Generators::ComponentGenerator if WebpackerHelpers.available? def filename - 'app/javascript/components/GeneratedComponent.js' + "app/javascript/components/GeneratedComponent.js" end + def filename_with_subfolder - 'app/javascript/components/generated_folder/GeneratedComponent.js' + "app/javascript/components/generated_folder/GeneratedComponent.js" end else def filename - 'app/assets/javascripts/components/generated_component.js.jsx' + "app/assets/javascripts/components/generated_component.js.jsx" end + def filename_with_subfolder - 'app/assets/javascripts/components/generated_folder/generated_component.js.jsx' + "app/assets/javascripts/components/generated_folder/generated_component.js.jsx" end end - test 'creates the component file' do - run_generator %w(GeneratedComponent) + test "creates the component file" do + run_generator %w[GeneratedComponent] assert_file filename do |contents| if WebpackerHelpers.available? - assert_match /^import React from "react"/, contents - assert_match /export default GeneratedComponent\n$/m, contents + assert_match(/^import React from "react"/, contents) + assert_match(/export default GeneratedComponent\n$/m, contents) end end end - test 'creates the component file in a subdirectory' do + test "creates the component file in a subdirectory" do puts WebpackerHelpers.available? - run_generator %w(generated_folder/GeneratedComponent) + run_generator %w[generated_folder/GeneratedComponent] assert_file filename_with_subfolder do |contents| if WebpackerHelpers.available? - assert_match /^import React from "react"/, contents - assert_match /export default GeneratedComponent\n$/m, contents + assert_match(/^import React from "react"/, contents) + assert_match(/export default GeneratedComponent\n$/m, contents) end end end - test 'creates the component file with a node argument' do - run_generator %w(GeneratedComponent name) - assert_file filename, %r{name: PropTypes.node} + test "creates the component file with a node argument" do + run_generator %w[GeneratedComponent name] + + assert_file filename, /name: PropTypes.node/ end - test 'creates the component file with various standard proptypes' do - proptypes = %w(string bool number array func number object any) - run_generator %w(GeneratedComponent) + proptypes.map { |type| "my_#{type}:#{type}" } + test "creates the component file with various standard proptypes" do + proptypes = %w[string bool number array func number object any] + run_generator %w[GeneratedComponent] + proptypes.map { |type| "my_#{type}:#{type}" } + proptypes.each do |type| - assert_file filename, %r(my#{type.capitalize}: PropTypes.#{type}) + assert_file filename, /my#{type.capitalize}: PropTypes.#{type}/ end end - test 'creates a component file with an instanceOf property' do - run_generator %w(GeneratedComponent favorite_food:instanceOf{food}) + test "creates a component file with an instanceOf property" do + run_generator %w[GeneratedComponent favorite_food:instanceOf{food}] + assert_file filename, /favoriteFood: PropTypes.instanceOf\(Food\)/ end - test 'creates a component file with a oneOf property' do - run_generator %w(GeneratedComponent favorite_food:oneOf{pizza,hamburgers}) + test "creates a component file with a oneOf property" do + run_generator %w[GeneratedComponent favorite_food:oneOf{pizza,hamburgers}] + assert_file filename, /favoriteFood: PropTypes.oneOf\(\['pizza','hamburgers'\]\)/ end - test 'creates a component file with a oneOfType property' do - run_generator %w(GeneratedComponent favorite_food:oneOfType{string,Food}) - expected_property = 'favoriteFood: PropTypes.oneOfType([PropTypes.string,PropTypes.instanceOf(Food)])' + test "creates a component file with a oneOfType property" do + run_generator %w[GeneratedComponent favorite_food:oneOfType{string,Food}] + expected_property = "favoriteFood: PropTypes.oneOfType([PropTypes.string,PropTypes.instanceOf(Food)])" assert_file filename, Regexp.new(Regexp.quote(expected_property)) end - test 'generates working jsx' do - run_generator %w(GeneratedComponent name:string address:shape) + test "generates working jsx" do + run_generator %w[GeneratedComponent name:string address:shape] jsx = React::JSX.transform(File.read(File.join(destination_root, filename))) assert_match(Regexp.new(expected_working_jsx), jsx) diff --git a/test/generators/es6_component_generator_test.rb b/test/generators/es6_component_generator_test.rb index 2ab3e9fab..c82fa728c 100644 --- a/test/generators/es6_component_generator_test.rb +++ b/test/generators/es6_component_generator_test.rb @@ -1,40 +1,41 @@ +# frozen_string_literal: true -require 'test_helper' -require 'generators/react/component_generator' +require "test_helper" +require "generators/react/component_generator" class Es6ComponentGeneratorTest < Rails::Generators::TestCase - destination File.join(Rails.root, 'tmp', 'component_generator_test_output') + destination File.join(Rails.root, "tmp", "component_generator_test_output") setup :prepare_destination tests React::Generators::ComponentGenerator if WebpackerHelpers.available? def filename - 'app/javascript/components/GeneratedComponent.js' + "app/javascript/components/GeneratedComponent.js" end else def filename - 'app/assets/javascripts/components/generated_component.es6.jsx' + "app/assets/javascripts/components/generated_component.es6.jsx" end end def class_name - 'GeneratedComponent' + "GeneratedComponent" end - test 'uses es6 syntax' do - run_generator %w(GeneratedComponent name --es6) + test "uses es6 syntax" do + run_generator %w[GeneratedComponent name --es6] assert_file filename, /^class\s#{class_name}\sextends\sReact\.Component/ end - test 'assigns defaultProps after class definintion' do - run_generator %w(GeneratedComponent name --es6) + test "assigns defaultProps after class definintion" do + run_generator %w[GeneratedComponent name --es6] assert_file filename, /\s^#{class_name}\.propTypes/ end - test 'generates working jsx' do - run_generator %w(GeneratedComponent name:string address:shape --es6) + test "generates working jsx" do + run_generator %w[GeneratedComponent name:string address:shape --es6] jsx = React::JSX.transform(File.read(File.join(destination_root, filename))) assert_match(Regexp.new(expected_working_jsx), jsx) diff --git a/test/generators/install_generator_sprockets_test.rb b/test/generators/install_generator_sprockets_test.rb index 67a4aa79e..f4a8a57ec 100644 --- a/test/generators/install_generator_sprockets_test.rb +++ b/test/generators/install_generator_sprockets_test.rb @@ -1,10 +1,12 @@ -require 'test_helper' -require 'generators/react/install_generator' +# frozen_string_literal: true + +require "test_helper" +require "generators/react/install_generator" # If webpacker is available, its setup is preferred unless WebpackerHelpers.available? class InstallGeneratorSprocketsTest < Rails::Generators::TestCase - destination File.join(Rails.root, 'tmp', 'generator_test_output') + destination File.join(Rails.root, "tmp", "generator_test_output") tests React::Generators::InstallGenerator setup :prepare_destination @@ -16,87 +18,98 @@ def copy_directory(dir) FileUtils.cp_r source, dest end - test 'adds requires to `application.js`' do + test "adds requires to `application.js`" do run_generator + assert_application_file_created end test "it modifes an existing 'application.js'" do - copy_directory('app/assets/javascripts/application.js') + copy_directory("app/assets/javascripts/application.js") run_generator + assert_application_file_modified end test "creates `application.js` if it doesn't exist" do - copy_directory('app/assets/javascripts/application.js') - File.delete destination_root + '/app/assets/javascripts/application.js' + copy_directory("app/assets/javascripts/application.js") + File.delete "#{destination_root}/app/assets/javascripts/application.js" run_generator + assert_application_file_created end test "modifies `application.js` if it's empty" do - init_application_js '' + init_application_js "" run_generator + assert_application_file_created end - test 'updates `application.js` if require_tree is commented' do - init_application_js <<-END + test "updates `application.js` if require_tree is commented" do + init_application_js <<-DIRECTIVE // // require_tree . // - END + DIRECTIVE run_generator + assert_application_file_modified end - test 'updates `application.js` if require turbolinks has extra spaces' do - init_application_js <<-END + test "updates `application.js` if require turbolinks has extra spaces" do + init_application_js <<-DIRECTIVE // - //#{"= require turbolinks "} + //= require turbolinks#{' '} // - END + DIRECTIVE run_generator + assert_application_file_modified end - test 'creates server_rendering.js with default requires' do + test "creates server_rendering.js with default requires" do run_generator - server_rendering_file_path = 'app/assets/javascripts/server_rendering.js' + server_rendering_file_path = "app/assets/javascripts/server_rendering.js" + assert_file server_rendering_file_path, %r{//= require react-server\n} assert_file server_rendering_file_path, %r{//= require ./components\n} end - test 'creates server rendering initializer' do + test "creates server rendering initializer" do run_generator - initializer_path = 'config/initializers/react_server_rendering.rb' - assert_file(initializer_path, %r{Rails.application.config.assets.precompile \+= \['server_rendering.js'\]}) + initializer_path = "config/initializers/react_server_rendering.rb" + + assert_file(initializer_path, /Rails.application.config.assets.precompile \+= \["server_rendering.js"\]/) end - test 'skipping server rendering' do - run_generator %w(--skip-server-rendering) - assert_no_file 'config/initializers/react_server_rendering.rb' - assert_no_file 'app/assets/javascripts/server_rendering.js' + test "skipping server rendering" do + run_generator %w[--skip-server-rendering] + + assert_no_file "config/initializers/react_server_rendering.rb" + assert_no_file "app/assets/javascripts/server_rendering.js" end def init_application_js(content) - FileUtils.mkdir_p destination_root + '/app/assets/javascripts/' - File.write destination_root + '/app/assets/javascripts/application.js', content + FileUtils.mkdir_p "#{destination_root}/app/assets/javascripts/" + File.write "#{destination_root}/app/assets/javascripts/application.js", content end + private + def assert_application_file_created - assert_file 'app/assets/javascripts/application.js', + assert_file "app/assets/javascripts/application.js", %r{//= require react\n//= require react_ujs\n//= require components\n} end def assert_application_file_modified - assert_file 'app/assets/javascripts/application.js', %r{\n//= require react\n} - assert_file 'app/assets/javascripts/application.js', %r{\n//= require react_ujs\n} - assert_file 'app/assets/javascripts/application.js', %r{\n//= require components\n} + assert_file "app/assets/javascripts/application.js", %r{\n//= require react\n} + assert_file "app/assets/javascripts/application.js", %r{\n//= require react_ujs\n} + assert_file "app/assets/javascripts/application.js", %r{\n//= require components\n} end end end diff --git a/test/generators/install_generator_webpacker_test.rb b/test/generators/install_generator_webpacker_test.rb index cf1a825e3..f49e29211 100644 --- a/test/generators/install_generator_webpacker_test.rb +++ b/test/generators/install_generator_webpacker_test.rb @@ -1,19 +1,21 @@ -require 'test_helper' -require 'generators/react/install_generator' +# frozen_string_literal: true -WebpackerHelpers.when_webpacker_available do - class InstallGeneratorWebpackerTest < Rails::Generators::TestCase - destination File.join(Rails.root, 'tmp', 'generator_test_output') +require "test_helper" +require "generators/react/install_generator" + +class InstallGeneratorWebpackerTest < Rails::Generators::TestCase + WebpackerHelpers.when_webpacker_available do + destination File.join(Rails.root, "tmp", "generator_test_output") tests React::Generators::InstallGenerator setup :prepare_destination - EXPECTED_SETUP = %|// Support component names relative to this directory: + expected_setup = %|// Support component names relative to this directory: var componentRequireContext = require.context("components", true); var ReactRailsUJS = require("react_ujs"); ReactRailsUJS.useContext(componentRequireContext); | - DEFAULT_SERVER_RENDERING_PACK_PATH = 'app/javascript/packs/server_rendering.js' + default_server_rendering_pack_path = "app/javascript/packs/server_rendering.js" def copy_directory(dir) source = Rails.root.join(dir) @@ -23,24 +25,26 @@ def copy_directory(dir) FileUtils.cp_r source, dest end - test 'adds requires to `application.js`' do + test "adds requires to `application.js`" do run_generator - assert_file 'app/javascript/packs/application.js', EXPECTED_SETUP - assert_file 'app/javascript/components' + + assert_file "app/javascript/packs/application.js", expected_setup + assert_file "app/javascript/components" end - test 'creates server_rendering.js with default requires' do + test "creates server_rendering.js with default requires" do # rubocop:disable Minitest/MultipleAssertions run_generator - assert_file DEFAULT_SERVER_RENDERING_PACK_PATH do |contents| + assert_file default_server_rendering_pack_path do |contents| assert_includes contents, "var componentRequireContext = require.context(\"components\", true);\n" assert_includes contents, "var ReactRailsUJS = require(\"react_ujs\");\n" assert_includes contents, "ReactRailsUJS.useContext(componentRequireContext);\n" end end - test 'skipping server rendering' do - run_generator %w(--skip-server-rendering) - assert_no_file DEFAULT_SERVER_RENDERING_PACK_PATH + test "skipping server rendering" do + run_generator %w[--skip-server-rendering] + + assert_no_file default_server_rendering_pack_path end end end diff --git a/test/react/jsx/jsx_prepocessor_test.rb b/test/react/jsx/jsx_prepocessor_test.rb index 5ee7840a8..88783c553 100644 --- a/test/react/jsx/jsx_prepocessor_test.rb +++ b/test/react/jsx/jsx_prepocessor_test.rb @@ -1,18 +1,20 @@ -require 'test_helper' +# frozen_string_literal: true -SprocketsHelpers.when_available do - class JSXPreprocessorTest < ActiveSupport::TestCase - REQUIRED_JAVASCRIPT = 'var requirePlainJavascript = true;' - REQUIRED_COFFEESCRIPT = 'var requireCoffee; requireCoffee = true;' - REQUIRED_JSX = 'React.createElement("div", { className: "require-jsx" });' - OWN_JSX = 'React.createElement("div", { className: "le-javascript" });' - test 'executes //= require directives' do - require_parent = SprocketsHelpers.fetch_asset_body('require_test/jsx_preprocessor_test.js') +require "test_helper" - assert_compiled_javascript_includes(require_parent, REQUIRED_JAVASCRIPT) - assert_compiled_javascript_includes(require_parent, REQUIRED_COFFEESCRIPT) - assert_compiled_javascript_includes(require_parent, REQUIRED_JSX) - assert_compiled_javascript_includes(require_parent, OWN_JSX) +class JSXPreprocessorTest < ActiveSupport::TestCase + SprocketsHelpers.when_available do + required_javascript = "var requirePlainJavascript = true;" + required_coffeescript = "var requireCoffee; requireCoffee = true;" + required_jsx = 'React.createElement("div", { className: "require-jsx" });' + own_jsx = 'React.createElement("div", { className: "le-javascript" });' + test "executes //= require directives" do # rubocop:disable Minitest/MultipleAssertions + require_parent = SprocketsHelpers.fetch_asset_body("require_test/jsx_preprocessor_test.js") + + assert_compiled_javascript_includes(require_parent, required_javascript) + assert_compiled_javascript_includes(require_parent, required_coffeescript) + assert_compiled_javascript_includes(require_parent, required_jsx) + assert_compiled_javascript_includes(require_parent, own_jsx) end end end diff --git a/test/react/jsx/jsx_transformer_test.rb b/test/react/jsx/jsx_transformer_test.rb index 68bb6a1bc..5d1756c54 100644 --- a/test/react/jsx/jsx_transformer_test.rb +++ b/test/react/jsx/jsx_transformer_test.rb @@ -1,64 +1,69 @@ -require 'test_helper' +# frozen_string_literal: true -SprocketsHelpers.when_available do - class JSXTransformerTest < ActionDispatch::IntegrationTest +require "test_helper" + +class JSXTransformerTest < ActionDispatch::IntegrationTest + SprocketsHelpers.when_available do setup do reset_transformer React::JSX.transformer_class = React::JSX::JSXTransformer - SprocketsHelpers.manually_expire_asset('JSXTransformer.js') + SprocketsHelpers.manually_expire_asset("JSXTransformer.js") end teardown do reset_transformer - SprocketsHelpers.manually_expire_asset('JSXTransformer.js') + SprocketsHelpers.manually_expire_asset("JSXTransformer.js") end - test 'can use dropped-in version of JSX transformer' do - hidden_path = Rails.root.join('vendor/assets/react/JSXTransformer__.js') - replacing_path = Rails.root.join('vendor/assets/react/JSXTransformer.js') + test "can use dropped-in version of JSX transformer" do + hidden_path = Rails.root.join("vendor/assets/react/JSXTransformer__.js") + replacing_path = Rails.root.join("vendor/assets/react/JSXTransformer.js") FileUtils.cp hidden_path, replacing_path - SprocketsHelpers.manually_expire_asset('example3.js') + SprocketsHelpers.manually_expire_asset("example3.js") - get '/assets/example3.js' + get "/assets/example3.js" FileUtils.rm replacing_path assert_response :success - assert_equal 'test_confirmation_token_jsx_transformed;', @response.body.strip + assert_equal "test_confirmation_token_jsx_transformed;", @response.body.strip end - test 'accepts harmony: true option' do + test "accepts harmony: true option" do # rubocop:disable Minitest/MultipleAssertions React::JSX.transform_options = { harmony: true } - get '/assets/harmony_example.js' + get "/assets/harmony_example.js" + assert_response :success - assert_match(/generateGreeting:\s*function\(\)/, @response.body, 'object literal methods') - assert_match(/React.__spread/, @response.body, 'spreading props') - assert_match(/Your greeting is: '" \+ insertedGreeting \+ "'/, @response.body, 'string interpolation') - assert_match(/active=\$__0\.active/, @response.body, 'destructuring assignment') + assert_match(/generateGreeting:\s*function\(\)/, @response.body, "object literal methods") + assert_match(/React.__spread/, @response.body, "spreading props") + assert_match(/Your greeting is: '" \+ insertedGreeting \+ "'/, @response.body, "string interpolation") + assert_match(/active=\$__0\.active/, @response.body, "destructuring assignment") end - test 'accepts strip_types: true option' do + test "accepts strip_types: true option" do React::JSX.transform_options = { strip_types: true, harmony: true } - get '/assets/flow_types_example.js' + get "/assets/flow_types_example.js" + assert_response :success - assert_match(/\(i\s*,\s*name\s*\)\s*\{/, @response.body, 'type annotations are removed') + assert_match(/\(i\s*,\s*name\s*\)\s*\{/, @response.body, "type annotations are removed") end - test 'accepts asset_path: option' do - hidden_path = Rails.root.join('vendor/assets/react/JSXTransformer__.js') - custom_path = Rails.root.join('vendor/assets/react/custom') - replacing_path = custom_path.join('CustomTransformer.js') + test "accepts asset_path: option" do + hidden_path = Rails.root.join("vendor/assets/react/JSXTransformer__.js") + custom_path = Rails.root.join("vendor/assets/react/custom") + replacing_path = custom_path.join("CustomTransformer.js") - React::JSX.transform_options = { asset_path: 'custom/CustomTransformer.js' } + React::JSX.transform_options = { asset_path: "custom/CustomTransformer.js" } FileUtils.mkdir_p(custom_path) FileUtils.cp(hidden_path, replacing_path) - SprocketsHelpers.manually_expire_asset('example3.js') - get '/assets/example3.js' + SprocketsHelpers.manually_expire_asset("example3.js") + get "/assets/example3.js" FileUtils.rm_rf custom_path + assert_response :success - assert_equal 'test_confirmation_token_jsx_transformed;', @response.body.strip + assert_equal "test_confirmation_token_jsx_transformed;", @response.body.strip end end end diff --git a/test/react/jsx_test.rb b/test/react/jsx_test.rb index 3a56e4d47..c9ed8d43b 100644 --- a/test/react/jsx_test.rb +++ b/test/react/jsx_test.rb @@ -1,33 +1,36 @@ -require 'test_helper' +# frozen_string_literal: true + +require "test_helper" # Sprockets is inserting a newline after the docblock for some reason... -EXPECTED_JS = <render on the server'), 'it includes rendered HTML') - end + test "#react_component accepts string props with prerender: true" do + html = @helper.react_component("Todo", { todo: "render on the server" }.to_json, prerender: true) - test '#react_component passes :static to BundleRenderer' do - html = @helper.react_component('Todo', { todo: 'render on the server' }.to_json, prerender: :static) - assert(html.include?('>render on the server'), 'it includes rendered HTML') + assert_includes(html, 'data-react-class="Todo"', "it includes attrs for UJS") + assert_includes(html, ">render on the server", "it includes rendered HTML") end - test '#react_component does not include HTML properties with a static render' do - html = @helper.react_component('Todo', { todo: 'render on the server' }.to_json, prerender: :static) - assert_equal('
  • render on the server
  • ', html) + test "#react_component passes :static to BundleRenderer" do + html = @helper.react_component("Todo", { todo: "render on the server" }.to_json, prerender: :static) + + assert_includes(html, ">render on the server", "it includes rendered HTML") end - test '#react_component accepts HTML options and HTML tag' do - assert @helper.react_component('Foo', {}, :span).match(/<\/span>/) + test "#react_component does not include HTML properties with a static render" do + html = @helper.react_component("Todo", { todo: "render on the server" }.to_json, prerender: :static) - html = @helper.react_component('Foo', {}, { class: 'test', tag: :span, data: { foo: 1 } }) - assert html.match(/<\/span>/) - assert html.include?('class="test"') - assert html.include?('data-foo="1"') + assert_equal("
  • render on the server
  • ", html) end - module DummyRenderer - def self.render(component_name, props, prerender_options) - "rendered #{component_name} with #{props.to_json}" - end - end + test "#react_component accepts HTML options and HTML tag" do # rubocop:disable Minitest/MultipleAssertions + assert_match %r{}, @helper.react_component("Foo", {}, :span) - module DummyController - def self.react_rails_prerenderer - DummyRenderer - end + html = @helper.react_component("Foo", {}, { class: "test", tag: :span, data: { foo: 1 } }) + + assert_match %r{}, html + assert_includes html, 'class="test"' + assert_includes html, 'data-foo="1"' end test "it uses the controller's react_rails_prerenderer, if available" do @helper.setup(DummyController) - rendered_component = @helper.react_component('Foo', { 'ok' => true }, prerender: :static) - assert_equal %|
    rendered Foo with {"ok":true}
    |, rendered_component + rendered_component = @helper.react_component("Foo", { "ok" => true }, prerender: :static) + + assert_equal %(
    rendered Foo with {"ok":true}
    ), rendered_component end end end diff --git a/test/react/rails/controller_lifecycle_test.rb b/test/react/rails/controller_lifecycle_test.rb index 47baff0c8..88f3c1ec4 100644 --- a/test/react/rails/controller_lifecycle_test.rb +++ b/test/react/rails/controller_lifecycle_test.rb @@ -1,4 +1,6 @@ -require 'test_helper' +# frozen_string_literal: true + +require "test_helper" # This helper implementation just counts the number of # calls to `react_component` @@ -10,14 +12,14 @@ def initialize end def setup(controller) - @events << (controller.params['param_test'] || :setup) + @events << (controller.params["param_test"] || :setup) end - def teardown(env) + def teardown(_env) @events << :teardown end - def react_component(*args) + def react_component(*_args) @events << :react_component end end @@ -25,10 +27,7 @@ def react_component(*args) class ControllerLifecycleTest < ActionDispatch::IntegrationTest compiled = false setup do - unless compiled - compile = true - WebpackerHelpers.compile - end + WebpackerHelpers.compile unless compiled @previous_helper_implementation = React::Rails::ViewHelper.helper_implementation_class React::Rails::ViewHelper.helper_implementation_class = DummyHelperImplementation end @@ -37,24 +36,27 @@ def teardown React::Rails::ViewHelper.helper_implementation_class = @previous_helper_implementation end - test 'it creates a helper object and puts it in the request env' do - get '/pages/1' + test "it creates a helper object and puts it in the request env" do + get "/pages/1" helper_obj = controller.__react_component_helper - assert(helper_obj.is_a?(DummyHelperImplementation), 'It uses the view helper implementation class') + + assert(helper_obj.is_a?(DummyHelperImplementation), "It uses the view helper implementation class") end - test 'it calls setup and teardown methods' do - get '/pages/1?param_test=123' + test "it calls setup and teardown methods" do + get "/pages/1?param_test=123" helper_obj = controller.__react_component_helper - lifecycle_steps = ['123', :react_component, :react_component, :teardown] + lifecycle_steps = ["123", :react_component, :react_component, :teardown] + assert_equal(lifecycle_steps, helper_obj.events) end test "there's a new helper object for every request" do - get '/pages/1' + get "/pages/1" first_helper = controller.__react_component_helper - get '/pages/1' + get "/pages/1" second_helper = controller.__react_component_helper - assert(first_helper != second_helper, 'The helper for the second request is brand new') + + refute_equal(first_helper, second_helper, "The helper for the second request is brand new") end end diff --git a/test/react/rails/pages_controller_test.rb b/test/react/rails/pages_controller_test.rb index 22731b108..2f1c3713e 100644 --- a/test/react/rails/pages_controller_test.rb +++ b/test/react/rails/pages_controller_test.rb @@ -1,4 +1,6 @@ -require 'test_helper' +# frozen_string_literal: true + +require "test_helper" class PagesControllerTest < ActionController::TestCase include ParamsHelper @@ -6,24 +8,29 @@ class PagesControllerTest < ActionController::TestCase WebpackerHelpers.compile_if_missing end - test 'renders successfully' do - get :show, params: {id: 1} + test "renders successfully" do + get :show, params: { id: 1 } + assert_equal(200, response.status) end when_stateful_js_context_available do - test 'it sets up and tears down a react context' do - get :show, params: {id: 1, prerender: true} - assert_includes(response.body, 'Hello') + test "it sets up and tears down a react context" do + get :show, params: { id: 1, prerender: true } + + assert_includes(response.body, "Hello") + end + + test "it sets up and tears down a react context with the given greeting text" do + get :show, params: { id: 1, prerender: true, greeting: "Howdy" } - get :show, params: {id: 1, prerender: true, greeting: 'Howdy'} - assert_includes(response.body, 'Howdy') + assert_includes(response.body, "Howdy") + end - get :show, params: {id: 1, prerender: true, greeting: '👋'} - assert_includes(response.body, '👋') + test "it sets up and tears down a react context with the given greeting emoji" do + get :show, params: { id: 1, prerender: true, greeting: "👋" } - get :show, params: {id: 1, prerender: true} - assert_includes(response.body, 'Hello') + assert_includes(response.body, "👋") end end end diff --git a/test/react/rails/railtie_test.rb b/test/react/rails/railtie_test.rb index e49e5c9a8..7b1609c08 100644 --- a/test/react/rails/railtie_test.rb +++ b/test/react/rails/railtie_test.rb @@ -1,10 +1,13 @@ -require 'test_helper' +# frozen_string_literal: true + +require "test_helper" class RailtieTest < ActionDispatch::IntegrationTest - test 'reloaders are configured after initializers are loaded' do + test "reloaders are configured after initializers are loaded" do @test_file = File.expand_path("../../#{DUMMY_LOCATION}/app/pants/yfronts.js", File.dirname(__FILE__)) FileUtils.touch @test_file results = Dummy::Application.reloaders.map(&:updated?) + assert_includes(results, true) end end diff --git a/test/react/rails/react_rails_ujs_test.rb b/test/react/rails/react_rails_ujs_test.rb index 00bc99c3a..9e3b7c6ca 100644 --- a/test/react/rails/react_rails_ujs_test.rb +++ b/test/react/rails/react_rails_ujs_test.rb @@ -1,147 +1,187 @@ -require 'test_helper' +# frozen_string_literal: true -SprocketsHelpers.when_available do - class ReactRailsUJSTest < ActionDispatch::IntegrationTest +require "test_helper" + +class ReactRailsUJSTest < ActionDispatch::IntegrationTest + SprocketsHelpers.when_available do include Capybara::DSL # Normalize for webpacker check: def assert_greeting(page, greeting) - assert page.has_content?(greeting), [page.body, page.driver.browser.manage.logs.get(:browser).inspect] + assert page.has_content?(greeting), <<~MSG + #{page.body} + #{page.driver.browser.manage.logs.get(:browser).inspect} + MSG end def refute_greeting(page, greeting) - assert page.has_no_content?(greeting), [page.body, page.driver.browser.manage.logs.get(:browser).inspect] + assert page.has_no_content?(greeting), <<~MSG + #{page.body} + #{page.driver.browser.manage.logs.get(:browser).inspect} + MSG end - test 'ujs object present on the global React object and has our methods' do - visit '/pages/1' - assert_greeting(page, 'Hello Bob') + test "ujs object present on the global React object and has our methods" do # rubocop:disable Minitest/MultipleAssertions + visit "/pages/1" + + assert_greeting(page, "Hello Bob") # the exposed ujs object is present ujs_present = page.evaluate_script('typeof ReactRailsUJS === "object";') - assert_equal(ujs_present, true) + + assert(ujs_present) # it contains the constants class_name_present = page.evaluate_script('ReactRailsUJS.CLASS_NAME_ATTR === "data-react-class";') - assert_equal(class_name_present, true) + + assert(class_name_present) props_present = page.evaluate_script('ReactRailsUJS.PROPS_ATTR === "data-react-props";') - assert_equal(props_present, true) - #it contains the methods + assert(props_present) + + # it contains the methods find_dom_nodes_present = page.evaluate_script('typeof ReactRailsUJS.findDOMNodes === "function";') - assert_equal(find_dom_nodes_present, true) + + assert(find_dom_nodes_present) mount_components_present = page.evaluate_script('typeof ReactRailsUJS.mountComponents === "function";') - assert_equal(mount_components_present, true) + + assert(mount_components_present) unmount_components_present = page.evaluate_script('typeof ReactRailsUJS.unmountComponents === "function";') - assert_equal(unmount_components_present, true) + + assert(unmount_components_present) end - test 'react_ujs works with rendered HTML' do - visit '/pages/1' - assert_greeting(page, 'Hello Bob') + test "react_ujs works with rendered HTML" do + visit "/pages/1" + + assert_greeting(page, "Hello Bob") - page.click_button 'Goodbye' - refute_greeting(page, 'Hello Bob') - assert_greeting(page, 'Goodbye Bob') + page.click_button "Goodbye" + + refute_greeting(page, "Hello Bob") + assert_greeting(page, "Goodbye Bob") end - test 'react_ujs works with Turbolinks' do - visit '/pages/1' - assert_greeting(page, 'Hello Bob') - assert page.evaluate_script('Turbolinks.supported') + test "react_ujs works with Turbolinks" do # rubocop:disable Minitest/MultipleAssertions + visit "/pages/1" + + assert_greeting(page, "Hello Bob") + assert page.evaluate_script("Turbolinks.supported") # Try clicking links. - page.click_link('Alice') + page.click_link("Alice") wait_for_turbolinks_to_be_available - assert_greeting(page, 'Hello Alice') - page.click_link('Bob') + assert_greeting(page, "Hello Alice") + + page.click_link("Bob") wait_for_turbolinks_to_be_available - assert_greeting(page, 'Hello Bob') + + assert_greeting(page, "Hello Bob") # Try going back. - page.execute_script('history.back();') + page.execute_script("history.back();") wait_for_turbolinks_to_be_available - assert_greeting(page, 'Hello Alice') + + assert_greeting(page, "Hello Alice") # Try Turbolinks javascript API. page.execute_script('Turbolinks.visit("/pages/2");') wait_for_turbolinks_to_be_available - assert_greeting(page, 'Hello Alice') + + assert_greeting(page, "Hello Alice") page.execute_script('Turbolinks.visit("/pages/1");') wait_for_turbolinks_to_be_available - assert_greeting(page, 'Hello Bob') + + assert_greeting(page, "Hello Bob") # Component state is not persistent after clicking current page link. - page.click_button 'Goodbye' - assert_greeting(page, 'Goodbye Bob') + page.click_button "Goodbye" + + assert_greeting(page, "Goodbye Bob") - page.click_link('Bob') + page.click_link("Bob") wait_for_turbolinks_to_be_available - assert_greeting(page, 'Hello Bob') + + assert_greeting(page, "Hello Bob") end - test 'react_ujs works without Turbolinks' do # Fixes #743 - visit '/no-turbolinks' - assert_nil page.execute_script('ReactRailsUJS.detectEvents()') + test "react_ujs works without Turbolinks" do # Fixes #743 + visit "/no-turbolinks" + + assert_nil page.execute_script("ReactRailsUJS.detectEvents()") end - test 'react_ujs can unmount/mount using a selector reference for a component parent' do - visit '/pages/1' - assert_greeting(page, 'Hello Bob') + test "react_ujs can unmount/mount using a selector reference for a component parent" do + visit "/pages/1" + + assert_greeting(page, "Hello Bob") + + page.click_button "Unmount by parent selector" - page.click_button 'Unmount by parent selector' - refute_greeting(page, 'Hello Bob') + refute_greeting(page, "Hello Bob") - page.click_button 'Mount by parent selector' - assert_greeting(page, 'Hello Bob') + page.click_button "Mount by parent selector" + + assert_greeting(page, "Hello Bob") end - test 'react_ujs can unmount/mount using a selector reference for the component' do - visit '/pages/1' - assert_greeting(page, 'Hello Bob') + test "react_ujs can unmount/mount using a selector reference for the component" do + visit "/pages/1" + + assert_greeting(page, "Hello Bob") + + page.click_button "Unmount by own selector" + + refute_greeting(page, "Hello Bob") - page.click_button 'Unmount by own selector' - refute_greeting(page, 'Hello Bob') + page.click_button "Mount by own selector" - page.click_button 'Mount by own selector' - assert_greeting(page, 'Hello Bob') + assert_greeting(page, "Hello Bob") end - test 'react_ujs does not unmount components that do not match a selector reference for the component' do - visit '/pages/1' - assert_greeting page, 'Hello Bob' - assert page.has_content?('Another Component'), page.body + test "react_ujs does not unmount components that do not match a selector reference for the component" do # rubocop:disable Minitest/MultipleAssertions + visit "/pages/1" - page.click_button 'Unmount by own selector' - refute_greeting(page, 'Hello Bob') - assert page.has_content?('Another Component'), page.body + assert_greeting page, "Hello Bob" + assert page.has_content?("Another Component"), "Body of the page:\n#{page.body}" - page.click_button 'Mount by own selector' - assert_greeting(page, 'Hello Bob') - assert page.has_content?('Another Component'), page.body + page.click_button "Unmount by own selector" + + refute_greeting(page, "Hello Bob") + assert page.has_content?("Another Component"), "Body of the page:\n#{page.body}" + + page.click_button "Mount by own selector" + + assert_greeting(page, "Hello Bob") + assert page.has_content?("Another Component"), "Body of the page:\n#{page.body}" end - test 'react_ujs can unmount/mount using a dom node context' do - visit '/pages/1' - assert_greeting(page, 'Hello Bob') + test "react_ujs can unmount/mount using a dom node context" do + visit "/pages/1" + + assert_greeting(page, "Hello Bob") - page.click_button 'Unmount by parent node' - refute_greeting(page, 'Hello Bob') + page.click_button "Unmount by parent node" - page.click_button 'Mount by parent node' - assert_greeting(page, 'Hello Bob') + refute_greeting(page, "Hello Bob") + + page.click_button "Mount by parent node" + + assert_greeting(page, "Hello Bob") end - test 'react server rendering also gets mounted on client' do - visit '/server/1' - assert_match(/data-react-class=\"TodoList\"/, page.html) - assert_match(/yep/, page.find('#status').text) + test "react server rendering also gets mounted on client" do + visit "/server/1" + + assert_match(/data-react-class="TodoList"/, page.html) + assert_match(/yep/, page.find_by_id("status").text) end - test 'react server rendering does not include internal properties' do - visit '/server/1' + test "react server rendering does not include internal properties" do + visit "/server/1" + assert_no_match(/tag=/, page.html) assert_no_match(/prerender=/, page.html) end diff --git a/test/react/rails/test_helper_test.rb b/test/react/rails/test_helper_test.rb index e80dab106..1e4c3acfb 100644 --- a/test/react/rails/test_helper_test.rb +++ b/test/react/rails/test_helper_test.rb @@ -1,12 +1,15 @@ -require 'test_helper' +# frozen_string_literal: true + +require "test_helper" class TestHelperTest < ActionDispatch::IntegrationTest setup do WebpackerHelpers.compile_if_missing end - test 'assert_react_component' do + test "assert_react_component" do # rubocop:disable Minitest/MultipleAssertions get "/pages/1" + assert_equal 200, response.status assert_react_component "GreetingMessage" assert_react_component "GreetingMessage" do |props| diff --git a/test/react/rails/view_helper_test.rb b/test/react/rails/view_helper_test.rb index a8b13f017..d8fd47bc9 100644 --- a/test/react/rails/view_helper_test.rb +++ b/test/react/rails/view_helper_test.rb @@ -1,48 +1,49 @@ -require 'test_helper' +# frozen_string_literal: true + +require "test_helper" # Provide direct access to the view helper methods class ViewHelperHelper extend ActionView::Context extend ActionView::Helpers::CaptureHelper extend React::Rails::ViewHelper - end class ViewHelperTest < ActionView::TestCase - test 'view helper can be called directly' do - expected_html = %{
    } - rendered_html = ViewHelperHelper.react_component('Component', { a: 'b' }) + test "view helper can be called directly" do + expected_html = %(
    ) # rubocop:disable Layout/LineLength + rendered_html = ViewHelperHelper.react_component("Component", { a: "b" }) + assert_equal(expected_html, rendered_html) end - test 'view helper accepts block usage' do - expected_html = %{
    content
    } - rendered_html = ViewHelperHelper.react_component('Component', { a: 'b' }) do - 'content' + test "view helper accepts block usage" do + expected_html = %(
    content
    ) # rubocop:disable Layout/LineLength + rendered_html = ViewHelperHelper.react_component("Component", { a: "b" }) do + "content" end + assert_equal(expected_html, rendered_html) end - test 'view helper can be used in stand-alone views' do - @name = 'React-Rails' - render template: 'pages/show' - assert_includes(rendered, 'React-Rails') + test "view helper can be used in stand-alone views" do + @name = "React-Rails" + render template: "pages/show" + + assert_includes(rendered, "React-Rails") end - test 'view helper can accept block and render inner content only once' do - rendered_html = render partial: 'pages/component_with_inner_html' - expected_html = < -
    NestedContent
    - -HTML + test "view helper can accept block and render inner content only once" do + rendered_html = render partial: "pages/component_with_inner_html" + expected_html = <<~HTML +
    +
    NestedContent
    +
    + HTML assert_equal expected_html.strip, rendered_html end - test 'view helper uses the implementation class set in the initializer' do - assert_equal( - React::Rails::ViewHelper.helper_implementation_class.to_s, - 'CustomComponentMount' - ) + test "view helper uses the implementation class set in the initializer" do + assert_equal("CustomComponentMount", React::Rails::ViewHelper.helper_implementation_class.to_s) end end diff --git a/test/react/rails/webpacker_test.rb b/test/react/rails/webpacker_test.rb index 15e440777..218a67e5e 100644 --- a/test/react/rails/webpacker_test.rb +++ b/test/react/rails/webpacker_test.rb @@ -1,7 +1,9 @@ -require 'test_helper' +# frozen_string_literal: true -WebpackerHelpers.when_webpacker_available do - class ReactRailsWebpackerTest < ActionDispatch::IntegrationTest +require "test_helper" + +class ReactRailsWebpackerTest < ActionDispatch::IntegrationTest + WebpackerHelpers.when_webpacker_available do include Capybara::DSL setup do @@ -14,12 +16,13 @@ class ReactRailsWebpackerTest < ActionDispatch::IntegrationTest WebpackerHelpers.clear_webpacker_packs end - test 'it mounts components from the pack' do - visit '/pack_component' - assert page.has_content?('Export Default') - assert page.has_content?('Named Export') - assert page.has_content?('Exports') - assert page.has_content?('Global Component') + test "it mounts components from the pack" do # rubocop:disable Minitest/MultipleAssertions + visit "/pack_component" + + assert page.has_content?("Export Default") + assert page.has_content?("Named Export") + assert page.has_content?("Exports") + assert page.has_content?("Global Component") end end end diff --git a/test/react/server_rendering/bundle_renderer_test.rb b/test/react/server_rendering/bundle_renderer_test.rb index cddc00377..0e8d70551 100644 --- a/test/react/server_rendering/bundle_renderer_test.rb +++ b/test/react/server_rendering/bundle_renderer_test.rb @@ -1,8 +1,10 @@ -require 'test_helper' +# frozen_string_literal: true + +require "test_helper" if SprocketsHelpers.available? || WebpackerHelpers.available? class BundleRendererTest < ActiveSupport::TestCase - CALLBACKS = [:before_render, :after_render] + CALLBACKS = %i[before_render after_render].freeze webpacker_compiled = false setup do @@ -16,111 +18,121 @@ class BundleRendererTest < ActiveSupport::TestCase CALLBACKS.each do |callback_name| test "#render should pass prerender options to ##{callback_name}" do mocked_method = Minitest::Mock.new - mocked_method.expect :call, '', [ - 'Todo', + mocked_method.expect :call, "", [ + "Todo", '{"todo":"write tests"}', - { option: :value, render_function: 'renderToString' } + { option: :value, render_function: "renderToString" } ] @renderer.stub callback_name, mocked_method do - @renderer.render('Todo', { todo: 'write tests' }, { option: :value }) + @renderer.render("Todo", { todo: "write tests" }, { option: :value }) end mocked_method.verify end end - test '#render returns HTML' do - result = @renderer.render('Todo', { todo: 'write tests' }, nil) - assert_match(//, result) + test "#render returns HTML" do + result = @renderer.render("Todo", { todo: "write tests" }, nil) + + assert_match(%r{}, result) assert_match(/data-reactroot/, result) end - test '#render accepts strings' do - result = @renderer.render('Todo', { todo: 'write more tests' }.to_json, nil) - assert_match(//, result) + test "#render accepts strings" do + result = @renderer.render("Todo", { todo: "write more tests" }.to_json, nil) + + assert_match(%r{}, result) end - test '#render accepts :static pre-render option' do - result = @renderer.render('Todo', { todo: 'write more tests' }, :static) - assert_match(/
  • write more tests<\/li>/, result) + test "#render accepts :static pre-render option" do + result = @renderer.render("Todo", { todo: "write more tests" }, :static) + + assert_match(%r{
  • write more tests
  • }, result) assert_no_match(/data-reactroot/, result) end - test '#render replays console messages' do - result = @renderer.render('TodoListWithConsoleLog', { todos: ['log some messages'] }, nil) + test "#render replays console messages" do # rubocop:disable Minitest/MultipleAssertions + result = @renderer.render("TodoListWithConsoleLog", { todos: ["log some messages"] }, nil) + assert_match(/ + EXPECTED_REPLAY = <<~HTML + HTML - test 'it clears the state between each request' do + test "it clears the state between each request" do # Each request should only contain one log: - get '/server/1' + get "/server/1" + assert_includes(response.body, EXPECTED_REPLAY) - get '/server/1' + get "/server/1" + assert_includes(response.body, EXPECTED_REPLAY) end end diff --git a/test/react/server_rendering/exec_js_renderer_test.rb b/test/react/server_rendering/exec_js_renderer_test.rb index 86efca7bf..393791ac1 100644 --- a/test/react/server_rendering/exec_js_renderer_test.rb +++ b/test/react/server_rendering/exec_js_renderer_test.rb @@ -1,4 +1,6 @@ -require 'test_helper' +# frozen_string_literal: true + +require "test_helper" DUMMY_IMPLEMENTATION = " var Todo = null @@ -14,62 +16,70 @@ class ExecJSRendererTest < ActiveSupport::TestCase setup do - react_server_source = File.read(File.expand_path('../../../../lib/assets/react-source/production/react-server.js', __FILE__)) - react_ujs_source = File.read(File.expand_path('../../../../lib/assets/javascripts/react_ujs.js', __FILE__)) - todo_component_source = File.read(File.expand_path("../../../#{DUMMY_LOCATION}/app/assets/javascripts/components/PlainJSTodo.js", __FILE__)) + react_server_source = File.read(File.expand_path("../../../lib/assets/react-source/production/react-server.js", + __dir__)) + react_ujs_source = File.read(File.expand_path("../../../lib/assets/javascripts/react_ujs.js", __dir__)) + todo_component_source = File.read( + File.expand_path( + "../../../#{DUMMY_LOCATION}/app/assets/javascripts/components/PlainJSTodo.js", __FILE__ + ) + ) code = react_server_source + react_ujs_source + todo_component_source @renderer = React::ServerRendering::ExecJSRenderer.new(code: code) end - test '#render returns HTML' do - result = @renderer.render('Todo', { todo: 'write tests' }.to_json, {}) - assert_match(//, result) + test "#render returns HTML" do + result = @renderer.render("Todo", { todo: "write tests" }.to_json, {}) + + assert_match(%r{}, result) assert_match(/data-reactroot/, result) end - test '#render accepts render_function:' do - result = @renderer.render('Todo', { todo: 'write more tests' }.to_json, render_function: 'renderToStaticMarkup') - assert_match(/
  • write more tests<\/li>/, result) + test "#render accepts render_function:" do + result = @renderer.render("Todo", { todo: "write more tests" }.to_json, render_function: "renderToStaticMarkup") + + assert_match(%r{
  • write more tests
  • }, result) assert_no_match(/data-reactroot/, result) end - test '#before_render is called before #after_render' do - def @renderer.before_render(name, props, opts) + test "#before_render is called before #after_render" do + def @renderer.before_render(_name, _props, _opts) "throw 'before_render ' + afterRenderVar" end - def @renderer.after_render(name, props, opts) + def @renderer.after_render(_name, _props, _opts) "var afterRenderVar = 'assigned_after_render'" end error = assert_raises(React::ServerRendering::PrerenderError) do - @renderer.render('Todo', { todo: 'write tests' }.to_json, {}) + @renderer.render("Todo", { todo: "write tests" }.to_json, {}) end assert_match(/before_render/, error.message) assert_no_match(/assigned_after_render/, error.message) end - test '#after_render is called after #before_render' do - def @renderer.before_render(name, props, opts) + test "#after_render is called after #before_render" do + def @renderer.before_render(_name, _props, _opts) "var beforeRenderVar = 'assigned_before_render'" end - def @renderer.after_render(name, props, opts) + def @renderer.after_render(_name, _props, _opts) "throw 'after_render ' + beforeRenderVar" end error = assert_raises(React::ServerRendering::PrerenderError) do - @renderer.render('Todo', { todo: 'write tests' }.to_json, {}) + @renderer.render("Todo", { todo: "write tests" }.to_json, {}) end assert_match(/after_render/, error.message) assert_match(/assigned_before_render/, error.message) end - test '.new accepts code:' do + test ".new accepts code:" do dummy_renderer = React::ServerRendering::ExecJSRenderer.new(code: DUMMY_IMPLEMENTATION) - result = dummy_renderer.render('Todo', { todo: 'get a real job' }.to_json, {}) - assert_equal('serverRender was called', result) + result = dummy_renderer.render("Todo", { todo: "get a real job" }.to_json, {}) + + assert_equal("serverRender was called", result) end end diff --git a/test/react/server_rendering/manifest_container_test.rb b/test/react/server_rendering/manifest_container_test.rb index c2c1f0dba..740050ef1 100644 --- a/test/react/server_rendering/manifest_container_test.rb +++ b/test/react/server_rendering/manifest_container_test.rb @@ -1,11 +1,13 @@ -require 'test_helper' +# frozen_string_literal: true + +require "test_helper" # sprockets-rails < 2.2.2 does not support # `application.assets_manifest`. Since sprockets-rails < 2.1.2 does # not define `Sprockets::Rails::VERSION`, checking for # `Sprockets::Rails` is not enough. if defined?(Sprockets::Rails::VERSION) && - Gem::Version.new(Sprockets::Rails::VERSION) >= Gem::Version.new('2.2.2') + Gem::Version.new(Sprockets::Rails::VERSION) >= Gem::Version.new("2.2.2") class ManifestContainerTest < ActiveSupport::TestCase def setup @@ -19,8 +21,9 @@ def teardown end def test_find_asset_gets_asset_contents - application_js_content = @manifest_container.find_asset('application.js') - assert(application_js_content.length > 50000, "It's the compiled file") + application_js_content = @manifest_container.find_asset("application.js") + + assert(application_js_content.length > 50_000, "It's the compiled file") end end end diff --git a/test/react/server_rendering/webpacker_containers_test.rb b/test/react/server_rendering/webpacker_containers_test.rb index 5ccc1c187..37ea74e3d 100644 --- a/test/react/server_rendering/webpacker_containers_test.rb +++ b/test/react/server_rendering/webpacker_containers_test.rb @@ -1,16 +1,19 @@ -require 'test_helper' -require 'open-uri' +# frozen_string_literal: true -WebpackerHelpers.when_webpacker_available do - class WebpackerManifestContainerTest < ActiveSupport::TestCase +require "test_helper" +require "open-uri" + +class WebpackerManifestContainerTest < ActiveSupport::TestCase + WebpackerHelpers.when_webpacker_available do setup do WebpackerHelpers.clear_webpacker_packs end - def test_it_loads_JS_from_the_webpacker_container + def test_it_loads_js_from_the_webpacker_container WebpackerHelpers.compile container = React::ServerRendering::SeparateServerBundleContainer.new - assert_not_empty container.find_asset('server_rendering.js') + + assert_not_empty container.find_asset("server_rendering.js") end end end diff --git a/test/react/server_rendering/yaml_manifest_container_test.rb b/test/react/server_rendering/yaml_manifest_container_test.rb index a17fba4a1..56fdc9903 100644 --- a/test/react/server_rendering/yaml_manifest_container_test.rb +++ b/test/react/server_rendering/yaml_manifest_container_test.rb @@ -1,4 +1,6 @@ -require 'test_helper' +# frozen_string_literal: true + +require "test_helper" if Rails::VERSION::MAJOR == 3 class YamlManifestContainerTest < ActiveSupport::TestCase @@ -13,8 +15,9 @@ def teardown end def test_find_asset_gets_asset_contents - application_js_content = @manifest_container.find_asset('application.js') - assert(application_js_content.length > 50000, "It's the compiled file") + application_js_content = @manifest_container.find_asset("application.js") + + assert(application_js_content.length > 50_000, "It's the compiled file") end end end diff --git a/test/react/server_rendering_test.rb b/test/react/server_rendering_test.rb index eae44c400..4bd83f1a0 100644 --- a/test/react/server_rendering_test.rb +++ b/test/react/server_rendering_test.rb @@ -1,4 +1,6 @@ -require 'test_helper' +# frozen_string_literal: true + +require "test_helper" class NullRenderer def initialize(options) @@ -15,7 +17,7 @@ class ReactServerRenderingTest < ActiveSupport::TestCase setup do @previous_renderer = React::ServerRendering.renderer @previous_options = React::ServerRendering.renderer_options - React::ServerRendering.renderer_options = 'TEST' + React::ServerRendering.renderer_options = "TEST" React::ServerRendering.renderer = NullRenderer React::ServerRendering.reset_pool end @@ -26,19 +28,20 @@ class ReactServerRenderingTest < ActiveSupport::TestCase React::ServerRendering.reset_pool end - test '.render returns a rendered string' do - props = { 'props' => true } - result = React::ServerRendering.render('MyComponent', props, 'prerender-opts') + test ".render returns a rendered string" do + props = { "props" => true } + result = React::ServerRendering.render("MyComponent", props, "prerender-opts") + assert_equal("TEST rendered MyComponent with #{props} and prerender-opts", result) end - test '.reset_pool forgets old renderers' do + test ".reset_pool forgets old renderers" do # rubocop:disable Minitest/MultipleAssertions # At first, they use the first options: assert_match(/^TEST/, React::ServerRendering.render(nil, nil, nil)) assert_match(/^TEST/, React::ServerRendering.render(nil, nil, nil)) # Then change the init options and clear the pool: - React::ServerRendering.renderer_options = 'DIFFERENT' + React::ServerRendering.renderer_options = "DIFFERENT" React::ServerRendering.reset_pool # New renderers are created with the new init options: assert_match(/^DIFFERENT/, React::ServerRendering.render(nil, nil, nil)) diff --git a/test/react_asset_test.rb b/test/react_asset_test.rb index 9acab9eb9..c832b28a6 100644 --- a/test/react_asset_test.rb +++ b/test/react_asset_test.rb @@ -1,7 +1,9 @@ -require 'test_helper' +# frozen_string_literal: true -SprocketsHelpers.when_available do - class ReactAssetTest < ActionDispatch::IntegrationTest +require "test_helper" + +class ReactAssetTest < ActionDispatch::IntegrationTest + SprocketsHelpers.when_available do setup do SprocketsHelpers.clear_sprockets_cache end @@ -10,35 +12,34 @@ class ReactAssetTest < ActionDispatch::IntegrationTest SprocketsHelpers.clear_sprockets_cache end - test 'asset pipeline should deliver drop-in react file replacement' do - app_react_file_path = File.expand_path("../#{DUMMY_LOCATION}/vendor/assets/javascripts/react.js", __FILE__) + test "asset pipeline should deliver drop-in react file replacement" do + app_react_file_path = File.expand_path("../#{DUMMY_LOCATION}/vendor/assets/javascripts/react.js", __FILE__) react_file_token = "'test_confirmation_token_react_content_non_production';\n" File.write(app_react_file_path, react_file_token) - SprocketsHelpers.manually_expire_asset('react.js') - react_asset = Rails.application.assets['react.js'] + SprocketsHelpers.manually_expire_asset("react.js") + react_asset = Rails.application.assets["react.js"] - get '/assets/react.js' + get "/assets/react.js" File.unlink(app_react_file_path) assert_response :success - assert_equal react_file_token.length, react_asset.to_s.length, 'The asset pipeline serves the drop-in file' - assert_equal react_file_token.length, @response.body.length, 'The asset route serves the drop-in file' + assert_equal react_file_token.length, react_asset.to_s.length, "The asset pipeline serves the drop-in file" + assert_equal react_file_token.length, @response.body.length, "The asset route serves the drop-in file" end - test 'precompiling assets works' do - begin - SprocketsHelpers.precompile_assets - ensure - SprocketsHelpers.clear_precompiled_assets - end + test "precompiling assets works" do + SprocketsHelpers.precompile_assets + ensure + SprocketsHelpers.clear_precompiled_assets end - test 'the production build is optimized for production' do - production_path = File.expand_path('../../lib/assets/react-source/production/react.js', __FILE__) + test "the production build is optimized for production" do + production_path = File.expand_path("../lib/assets/react-source/production/react.js", __dir__) production_js = File.read(production_path) - env_checks = production_js.scan('NODE_ENV') - assert_equal(0, env_checks.length, 'Dead code is removed for production') + env_checks = production_js.scan("NODE_ENV") + + assert_equal(0, env_checks.length, "Dead code is removed for production") end end end diff --git a/test/react_test.rb b/test/react_test.rb index cff2b84f2..7f24c6f6e 100644 --- a/test/react_test.rb +++ b/test/react_test.rb @@ -1,4 +1,6 @@ -require 'test_helper' +# frozen_string_literal: true + +require "test_helper" class ReactTest < ActiveSupport::TestCase def test_it_camelizes_props @@ -7,23 +9,23 @@ def test_it_camelizes_props nested_key: [ { double_nested: true }, 1, - 'string item', + "string item", [{ nested_array: {} }] ] }, - 'alreadyCamelized' => :ok + "alreadyCamelized" => :ok } expected_props = { - 'multiWordSym' => { - 'nestedKey' => [ - { 'doubleNested' => true }, + "multiWordSym" => { + "nestedKey" => [ + { "doubleNested" => true }, 1, - 'string item', - [{ 'nestedArray' => {} }] + "string item", + [{ "nestedArray" => {} }] ] }, - 'alreadyCamelized' => 'ok' + "alreadyCamelized" => "ok" } assert_equal expected_props, React.camelize_props(raw_props) @@ -31,17 +33,17 @@ def test_it_camelizes_props def test_it_camelizes_params raw_params = ActionController::Parameters.new({ - foo_bar_baz: 'foo bar baz', - nested_keys: { - qux_etc: 'bish bash bosh' - } - }) + foo_bar_baz: "foo bar baz", + nested_keys: { + qux_etc: "bish bash bosh" + } + }) permitted_params = raw_params.permit(:foo_bar_baz, nested_keys: :qux_etc) expected_params = { - 'fooBarBaz' => 'foo bar baz', - 'nestedKeys' => { - 'quxEtc' => 'bish bash bosh' + "fooBarBaz" => "foo bar baz", + "nestedKeys" => { + "quxEtc" => "bish bash bosh" } } @@ -60,18 +62,18 @@ def as_json end raw_props = { - key_one: 'value1', + key_one: "value1", key_two: my_json_serializer.new( - nested_key_one: 'nested_value1', - nested_key_two: ['nested', 'value', 'two'] + nested_key_one: "nested_value1", + nested_key_two: %w[nested value two] ) } expected_params = { - 'keyOne' => 'value1', - 'keyTwo' => { - 'nestedKeyOne' => 'nested_value1', - 'nestedKeyTwo' => ['nested', 'value', 'two'] + "keyOne" => "value1", + "keyTwo" => { + "nestedKeyOne" => "nested_value1", + "nestedKeyTwo" => %w[nested value two] } } diff --git a/test/server_rendered_html_test.rb b/test/server_rendered_html_test.rb index 886209d52..b4b03d885 100644 --- a/test/server_rendered_html_test.rb +++ b/test/server_rendered_html_test.rb @@ -1,8 +1,10 @@ -require 'test_helper' -require 'fileutils' +# frozen_string_literal: true -SprocketsHelpers.when_available do - class ServerRenderedHtmlTest < ActionDispatch::IntegrationTest +require "test_helper" +require "fileutils" + +class ServerRenderedHtmlTest < ActionDispatch::IntegrationTest + SprocketsHelpers.when_available do # Rails' asset pipeline has trouble picking up changes to files if they happen too fast. # By sleeping for a little bit at certain points, we can make sure that rails notices the # change in the file mtime, and calls our renderer setup functions appropriately @@ -11,19 +13,17 @@ def wait_to_ensure_asset_pipeline_detects_changes end setup do - if WebpackerHelpers.available? - WebpackerHelpers.compile - end + WebpackerHelpers.compile if WebpackerHelpers.available? end - test 'react server rendering reloads jsx after changes to the jsx files' do + test "react server rendering reloads jsx after changes to the jsx files" do if WebpackerHelpers.available? - file_with_updates = File.expand_path('../helper_files/TodoListWithUpdates.js', __FILE__) - file_without_updates = File.expand_path('../helper_files/TodoListWithoutUpdates.js', __FILE__) + file_with_updates = File.expand_path("helper_files/TodoListWithUpdates.js", __dir__) + file_without_updates = File.expand_path("helper_files/TodoListWithoutUpdates.js", __dir__) app_file = File.expand_path("../#{DUMMY_LOCATION}/app/javascript/components/TodoList.js", __FILE__) else - file_with_updates = File.expand_path('../helper_files/TodoListWithUpdates.js.jsx', __FILE__) - file_without_updates = File.expand_path('../helper_files/TodoListWithoutUpdates.js.jsx', __FILE__) + file_with_updates = File.expand_path("helper_files/TodoListWithUpdates.js.jsx", __dir__) + file_without_updates = File.expand_path("helper_files/TodoListWithoutUpdates.js.jsx", __dir__) app_file = File.expand_path("../#{DUMMY_LOCATION}/app/assets/javascripts/components/TodoList.js.jsx", __FILE__) end @@ -32,7 +32,8 @@ def wait_to_ensure_asset_pipeline_detects_changes wait_to_ensure_asset_pipeline_detects_changes begin - get '/server/1' + get "/server/1" + refute_match(/Updated/, response.body) FileUtils.cp file_with_updates, app_file @@ -43,7 +44,8 @@ def wait_to_ensure_asset_pipeline_detects_changes wait_to_ensure_asset_pipeline_detects_changes end - get '/server/1' + get "/server/1" + assert_match(/Updated/, response.body) ensure # if we have a test failure, we want to make sure that we revert the dummy file @@ -53,48 +55,48 @@ def wait_to_ensure_asset_pipeline_detects_changes end end - test 'it reloads when new jsx files are added to the asset pipeline' do - begin - assert_raises(ActionView::Template::Error) { - get '/server/1?component_name=NewList' - } - - if WebpackerHelpers.available? - new_file_path = "../#{DUMMY_LOCATION}/app/javascript/components/NewList.js" - new_file_contents = <<-HEREDOC -var React = require("react") -module.exports = function() { return "New List" } -HEREDOC - else - new_file_path = "../#{DUMMY_LOCATION}/app/assets/javascripts/components/ZZ_NewComponent.js.jsx" - new_file_contents = <<-HEREDOC -var NewList = function() { return "New List" } -HEREDOC - end + test "it reloads when new jsx files are added to the asset pipeline" do + assert_raises(ActionView::Template::Error) do + get "/server/1?component_name=NewList" + end - new_file_path = File.expand_path(new_file_path, __FILE__) - File.write new_file_path, new_file_contents + if WebpackerHelpers.available? + new_file_path = "../#{DUMMY_LOCATION}/app/javascript/components/NewList.js" + new_file_contents = <<~HEREDOC + var React = require("react") + module.exports = function() { return "New List" } + HEREDOC + else + new_file_path = "../#{DUMMY_LOCATION}/app/assets/javascripts/components/ZZ_NewComponent.js.jsx" + new_file_contents = <<~HEREDOC + var NewList = function() { return "New List" } + HEREDOC + end - if WebpackerHelpers.available? - WebpackerHelpers.compile - else - wait_to_ensure_asset_pipeline_detects_changes - FileUtils.touch new_file_path - end + new_file_path = File.expand_path(new_file_path, __FILE__) + File.write new_file_path, new_file_contents - get '/server/1?component_name=NewList' - assert_match(/New List/, response.body) - ensure - FileUtils.rm_rf(new_file_path) + if WebpackerHelpers.available? + WebpackerHelpers.compile + else wait_to_ensure_asset_pipeline_detects_changes + FileUtils.touch new_file_path end + + get "/server/1?component_name=NewList" + + assert_match(/New List/, response.body) + ensure + FileUtils.rm_rf(new_file_path) + wait_to_ensure_asset_pipeline_detects_changes end - test 'react server rendering shows console output as html comment' do + test "react server rendering shows console output as html comment" do # rubocop:disable Minitest/MultipleAssertions # Make sure console messages are replayed when requested React::ServerRendering.renderer_options = { replay_console: true } React::ServerRendering.reset_pool - get '/server/console_example' + get "/server/console_example" + assert_match(/Console Logged/, response.body) assert_match(/console.log.apply\(console, \["got initial state"\]\)/, response.body) assert_match(/console.warn.apply\(console, \["mounted component"\]\)/, response.body) @@ -104,46 +106,50 @@ def wait_to_ensure_asset_pipeline_detects_changes React::ServerRendering.renderer_options = { replay_console: false } React::ServerRendering.reset_pool - get '/server/console_example' + get "/server/console_example" + assert_match(/Console Logged/, response.body) assert_no_match(/console.log/, response.body) assert_no_match(/console.warn/, response.body) assert_no_match(/console.error/, response.body) end - test 'react inline component rendering (pre-rendered)' do - get '/server/inline_component_prerender_true' + test "react inline component rendering (pre-rendered)" do # rubocop:disable Minitest/MultipleAssertions + get "/server/inline_component_prerender_true" rendered_html = response.body - assert_match(/<\/span>/, rendered_html, 'it accepts a tag override') + assert_match(%r{}, rendered_html, "it accepts a tag override") # make sure that prerendered items are marked - assert_match(/data-hydrate=\"t\"/, rendered_html) + assert_match(/data-hydrate="t"/, rendered_html) # make sure that the layout is rendered with the component - assert_match(/Dummy<\/title>/, rendered_html) + assert_match(%r{<title>Dummy}, rendered_html) # make sure that custom html attributes are rendered - assert_match(/class=\"custom-class\"/, rendered_html) - assert_match(/id=\"custom-id\"/, rendered_html) - assert_match(/data-remote=\"true\"/, rendered_html) + assert_match(/class="custom-class"/, rendered_html) + assert_match(/id="custom-id"/, rendered_html) + assert_match(/data-remote="true"/, rendered_html) end - test 'react inline component rendering (not pre-rendered)' do - get '/server/inline_component_prerender_false' + test "react inline component rendering (not pre-rendered)" do + get "/server/inline_component_prerender_false" rendered_html = response.body # make sure the tag closes immediately: - assert_match(/<\/span>/, rendered_html) + assert_match(%r{}, rendered_html) end - test 'react inline component rendering with camelize_props (pre-rendered)' do - get '/server/inline_component_with_camelize_props_prerender_true' + test "react inline component rendering with camelize_props (pre-rendered)" do + get "/server/inline_component_with_camelize_props_prerender_true" rendered_html = response.body + assert_match(/data-react-props.*testCamelizeProps.*true/, rendered_html) end - test 'react inline component rendering with camelize_props (not pre-rendered)' do - get '/server/inline_component_with_camelize_props_prerender_false' + test "react inline component rendering with camelize_props (not pre-rendered)" do + get "/server/inline_component_with_camelize_props_prerender_false" rendered_html = response.body + assert_match(/data-react-props.*testCamelizeProps.*true/, rendered_html) end end diff --git a/test/support/sprockets_helpers.rb b/test/support/sprockets_helpers.rb index 3a76a2a2d..e7c5dc22e 100644 --- a/test/support/sprockets_helpers.rb +++ b/test/support/sprockets_helpers.rb @@ -1,24 +1,27 @@ +# frozen_string_literal: true + module SprocketsHelpers module_function + def available? # We can't scan for sprockets in gemfile_lock because it's # a dependency of Rails even if not required. # We also can't scan for defined?(Sprockets) because this is used to # require Sprockets in the config/application.rb # !!Bundler.locked_gems.specs.find {|gem_spec| gem_spec.name == 'sprockets'} - ENV['BUNDLE_GEMFILE'] !~ /no_sprockets/ + !ENV.fetch("BUNDLE_GEMFILE", nil).include?("no_sprockets") end # The block depends on sprockets, don't run it if sprockets is missing def when_available - if available? - yield - end + return unless available? + + yield end def clear_sprockets_cache # Remove cached files - Rails.root.join('tmp/cache').tap do |tmp| + Rails.root.join("tmp/cache").tap do |tmp| tmp.rmtree if tmp.exist? tmp.mkpath end @@ -33,42 +36,51 @@ def fetch_asset_body(asset_logical_path) # so override `fresh?` to mark it as expired. def manually_expire_asset(asset_name) asset = Rails.application.assets[asset_name] - def asset.fresh?(env); false; end + def asset.fresh?(_env) + false + end end def precompile_assets - # Changing directories is required because: - # - assets:precompile runs webpacker:compile when availabled - # - webpacker:compile depends on `./bin/webpack`, so `.` must be the app root - Dir.chdir("./test/#{DUMMY_LOCATION}") do - - ENV['RAILS_GROUPS'] = 'assets' # required for Rails 3.2 - Rake::Task['assets:precompile'].reenable - - if Rails::VERSION::MAJOR == 3 - Rake::Task['assets:precompile:all'].reenable - Rake::Task['assets:precompile:primary'].reenable - Rake::Task['assets:precompile:nondigest'].reenable - end - - Rake::Task['assets:precompile'].invoke - end + invoke_assets_precompile_task if Rails.application.respond_to?(:assets_manifest) # Make a new manifest since assets weren't compiled before config = Rails.application.config - path = File.join(config.paths['public'].first, config.assets.prefix) + path = File.join(config.paths["public"].first, config.assets.prefix) new_manifest = Sprockets::Manifest.new(Rails.application.assets, path) Rails.application.assets_manifest = new_manifest end assets_directory = File.expand_path("../../#{DUMMY_LOCATION}/public/assets", __FILE__) - raise 'Asset precompilation failed' unless Dir.exists?(assets_directory) + raise "Asset precompilation failed" unless Dir.exist?(assets_directory) end def clear_precompiled_assets assets_directory = File.expand_path("../../#{DUMMY_LOCATION}/public/assets", __FILE__) FileUtils.rm_r(assets_directory) - ENV.delete('RAILS_GROUPS') + ENV.delete("RAILS_GROUPS") + end + + class << self + private + + def invoke_assets_precompile_task + # Changing directories is required because: + # - assets:precompile runs webpacker:compile when availabled + # - webpacker:compile depends on `./bin/webpack`, so `.` must be the app root + Dir.chdir("./test/#{DUMMY_LOCATION}") do + ENV["RAILS_GROUPS"] = "assets" # required for Rails 3.2 + Rake::Task["assets:precompile"].reenable + + if Rails::VERSION::MAJOR == 3 + Rake::Task["assets:precompile:all"].reenable + Rake::Task["assets:precompile:primary"].reenable + Rake::Task["assets:precompile:nondigest"].reenable + end + + Rake::Task["assets:precompile"].invoke + end + end end end diff --git a/test/support/webpacker_helpers.rb b/test/support/webpacker_helpers.rb index faa3d73ed..7c484a9eb 100644 --- a/test/support/webpacker_helpers.rb +++ b/test/support/webpacker_helpers.rb @@ -1,32 +1,36 @@ +# frozen_string_literal: true + module WebpackerHelpers - PACKS_DIRECTORY = File.expand_path("../../#{DUMMY_LOCATION}/public/packs", __FILE__) + PACKS_DIRECTORY = File.expand_path("../../#{DUMMY_LOCATION}/public/packs", __FILE__) module_function + def available? !!defined?(Webpacker) end def when_webpacker_available - if available? - yield - end + return unless available? + + yield end def compile return unless available? + clear_webpacker_packs Dir.chdir("./test/#{DUMMY_LOCATION}") do - Rake::Task['webpacker:compile'].reenable - Rake::Task['webpacker:compile'].invoke + Rake::Task["webpacker:compile"].reenable + Rake::Task["webpacker:compile"].invoke end # Reload cached JSON manifest: manifest_refresh end def compile_if_missing - unless File.exist?(PACKS_DIRECTORY) - compile - end + return if File.exist?(PACKS_DIRECTORY) + + compile end def clear_webpacker_packs @@ -37,13 +41,12 @@ def clear_webpacker_packs # Call the block # Make sure to clean up the server def with_dev_server - - old_env = ENV['NODE_ENV'] - ENV['NODE_ENV'] = 'development' + old_env = ENV.fetch("NODE_ENV", nil) + ENV["NODE_ENV"] = "development" # Start the server in a forked process: Dir.chdir("test/#{DUMMY_LOCATION}") do - spawn 'RAILS_ENV=development ./bin/webpacker-dev-server' + spawn "RAILS_ENV=development ./bin/webpacker-dev-server" end stop_time = Time.now + 30.seconds @@ -51,38 +54,37 @@ def with_dev_server loop do detected_dev_server = dev_server_running? break if detected_dev_server || Time.now > stop_time + sleep 0.5 end # If we didn't hook up with a dev server after waiting, fail loudly. - raise 'Failed to start dev server' unless detected_dev_server - puts 'Detected dev server - Continuing' + raise "Failed to start dev server" unless detected_dev_server + + puts "Detected dev server - Continuing" # Call the test block: yield - ensure - check_cmd = 'lsof -i :8080 -S' + check_cmd = "lsof -i :8080 -S" 10.times do # puts check_cmd status = `#{check_cmd}` # puts status remaining_pid_match = status.match(/\n[a-z]+\s+(\d+)/) - if remaining_pid_match - remaining_pid = remaining_pid_match[1] - # puts "Remaining #{remaining_pid}" - kill_cmd = "kill -9 #{remaining_pid}" - # puts kill_cmd - `#{kill_cmd}` - sleep 0.5 - else - break - end + break unless remaining_pid_match + + remaining_pid = remaining_pid_match[1] + # puts "Remaining #{remaining_pid}" + kill_cmd = "kill -9 #{remaining_pid}" + # puts kill_cmd + `#{kill_cmd}` + sleep 0.5 end # Remove the dev-server packs: WebpackerHelpers.clear_webpacker_packs - ENV['NODE_ENV'] = old_env + ENV["NODE_ENV"] = old_env puts "Killed." end @@ -93,12 +95,13 @@ def dev_server_running? ds = Webpacker.dev_server example_asset_path = manifest_data.values.first return false unless example_asset_path + begin - file = URI.open("#{ds.protocol}://#{ds.host}:#{ds.port}#{example_asset_path}") - rescue StandardError => e + file = URI.parse("#{ds.protocol}://#{ds.host}:#{ds.port}#{example_asset_path}").open + rescue StandardError file = nil end - if ! file + unless file puts "Dev server is not serving assets yet" return false end diff --git a/test/test_helper.rb b/test/test_helper.rb index 46e5c1312..f6d0df1d6 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,25 +1,27 @@ -if RUBY_PLATFORM != 'java' - require 'simplecov' +# frozen_string_literal: true + +if RUBY_PLATFORM != "java" + require "simplecov" SimpleCov.start end -DUMMY_LOCATION = 'dummy' +DUMMY_LOCATION = "dummy" -support_path = File.expand_path('../support/*.rb', __FILE__) -Dir.glob(support_path).each do |f| +support_path = File.expand_path("support/*.rb", __dir__) +Dir.glob(support_path).sort.each do |f| require(f) end # Configure Rails Environment -ENV['RAILS_ENV'] = 'test' +ENV["RAILS_ENV"] = "test" require File.expand_path("../#{DUMMY_LOCATION}/config/environment.rb", __FILE__) -require 'rails/test_help' -require 'rails/generators' -require 'pathname' -require 'minitest/mock' -require 'capybara/rails' -require 'selenium/webdriver' +require "rails/test_help" +require "rails/generators" +require "pathname" +require "minitest/mock" +require "capybara/rails" +require "selenium/webdriver" Dummy::Application.load_tasks WebpackerHelpers.clear_webpacker_packs @@ -48,16 +50,14 @@ def reset_transformer end # Load support files -Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } +Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].sort.each { |f| require f } # Load fixtures from the engine if ActiveSupport::TestCase.method_defined?(:fixture_path=) - ActiveSupport::TestCase.fixture_path = File.expand_path('../fixtures', __FILE__) + ActiveSupport::TestCase.fixture_path = File.expand_path("fixtures", __dir__) end -if ActiveSupport::TestCase.respond_to?(:test_order=) - ActiveSupport::TestCase.test_order = :random -end +ActiveSupport::TestCase.test_order = :random if ActiveSupport::TestCase.respond_to?(:test_order=) def wait_for_turbolinks_to_be_available sleep(1) @@ -68,21 +68,21 @@ def wait_for_turbolinks_to_be_available # Because appraisal is used, multiple versions of coffee-script are treated # together. Remove all spaces to make test pass. def assert_compiled_javascript_matches(javascript, expectation) - assert_equal expectation.gsub(/\s/, ''), javascript.gsub(/\s/, '') + assert_equal expectation.gsub(/\s/, ""), javascript.gsub(/\s/, "") end def assert_compiled_javascript_includes(javascript, expected_part) - assert_includes javascript.gsub(/\s/, ''), expected_part.gsub(/\s/, '') + assert_includes javascript.gsub(/\s/, ""), expected_part.gsub(/\s/, "") end def when_stateful_js_context_available - if defined?(V8) || defined?(MiniRacer) - yield - end + return unless defined?(V8) || defined?(MiniRacer) + + yield end def expected_working_jsx - /\.createElement\(\s*\S*\.Fragment,\s*null,\s*\"Name:\s*\",\s*this\.props\.name,\s*\"Address:\s*\",\s*this\.props\.address\s*\)/x + /\.createElement\(\s*\S*\.Fragment,\s*null,\s*"Name:\s*",\s*this\.props\.name,\s*"Address:\s*",\s*this\.props\.address\s*\)/x # rubocop:disable Layout/LineLength end module ParamsHelper