Skip to content

Commit 8b28de4

Browse files
justin808claude
andcommitted
Move React/Shakapacker version compatibility to generator smoke tests
This moves React and Shakapacker version compatibility testing from spec/dummy to the generator smoke tests, as suggested in PR #2114 review. Changes: - Update spec/dummy to always use latest React 19 and Shakapacker 9.4.0 - Add minimum version example apps (basic-minimum, basic-server-rendering-minimum) that use React 18.0.0 and Shakapacker 8.2.0 - Add ExampleType.minimum_versions flag to support version-specific examples - Add rake tasks for filtered testing: - run_rspec:shakapacker_examples_latest (for latest versions only) - run_rspec:shakapacker_examples_minimum (for minimum versions only) - Simplify script/convert to only handle Node.js tooling compatibility (removed React/Shakapacker version modifications) - Update CI workflows to run appropriate examples per dependency level Benefits: - Clearer separation: spec/dummy tests latest, generators test compatibility - Simpler CI configuration for integration tests - Better reflects real-world usage patterns Closes #2123 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent b50a74d commit 8b28de4

File tree

9 files changed

+87
-45
lines changed

9 files changed

+87
-45
lines changed

.github/workflows/examples.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ jobs:
130130
echo "Node version: "; node -v
131131
echo "Yarn version: "; yarn --version
132132
echo "Bundler version: "; bundle --version
133-
- name: run conversion script to support shakapacker v6
133+
- name: Run conversion script for older Node compatibility
134134
if: matrix.dependency-level == 'minimum'
135135
run: script/convert
136136
- name: Save root ruby gems to cache
@@ -172,8 +172,12 @@ jobs:
172172
- name: Set packer version environment variable
173173
run: |
174174
echo "CI_DEPENDENCY_LEVEL=${{ matrix.dependency-level }}" >> $GITHUB_ENV
175-
- name: Main CI
176-
run: cd react_on_rails && bundle exec rake run_rspec:shakapacker_examples
175+
- name: Main CI - Latest version examples
176+
if: matrix.dependency-level == 'latest'
177+
run: cd react_on_rails && bundle exec rake run_rspec:shakapacker_examples_latest
178+
- name: Main CI - Minimum version examples
179+
if: matrix.dependency-level == 'minimum'
180+
run: cd react_on_rails && bundle exec rake run_rspec:shakapacker_examples_minimum
177181
- name: Store test results
178182
uses: actions/upload-artifact@v4
179183
with:

.github/workflows/integration-tests.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ jobs:
132132
echo "Node version: "; node -v
133133
echo "Yarn version: "; yarn --version
134134
echo "Bundler version: "; bundle --version
135-
- name: run conversion script to support shakapacker v6
135+
- name: Run conversion script for older Node compatibility
136136
if: matrix.dependency-level == 'minimum'
137137
run: script/convert
138138
- name: Install Node modules with Yarn for renderer package
@@ -211,7 +211,7 @@ jobs:
211211
echo "Node version: "; node -v
212212
echo "Yarn version: "; yarn --version
213213
echo "Bundler version: "; bundle --version
214-
- name: run conversion script to support shakapacker v6
214+
- name: Run conversion script for older Node compatibility
215215
if: matrix.dependency-level == 'minimum'
216216
run: script/convert
217217
- name: Save root ruby gems to cache

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@
5555
"prettier": "^3.5.2",
5656
"prop-types": "^15.8.1",
5757
"publint": "^0.3.4",
58-
"react": "18.0.0",
59-
"react-dom": "18.0.0",
58+
"react": "^19.0.0",
59+
"react-dom": "^19.0.0",
6060
"react-on-rails-rsc": "19.0.2",
6161
"redux": "^4.2.1",
6262
"stylelint": "^16.14.0",

react_on_rails/rakelib/example_type.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,17 @@ def self.all
1313
@all ||= { shakapacker_examples: [] }
1414
end
1515

16-
attr_reader :packer_type, :name, :generator_options
16+
# Minimum supported versions for compatibility testing
17+
MINIMUM_REACT_VERSION = "18.0.0"
18+
MINIMUM_SHAKAPACKER_VERSION = "8.2.0"
1719

18-
def initialize(packer_type: nil, name: nil, generator_options: nil)
20+
attr_reader :packer_type, :name, :generator_options, :minimum_versions
21+
22+
def initialize(packer_type: nil, name: nil, generator_options: nil, minimum_versions: false)
1923
@packer_type = packer_type
2024
@name = name
2125
@generator_options = generator_options
26+
@minimum_versions = minimum_versions
2227
self.class.all[packer_type.to_sym] << self
2328
end
2429

react_on_rails/rakelib/examples_config.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,10 @@ example_type_data:
77
generator_options: --redux
88
- name: redux-server-rendering
99
generator_options: --redux --example-server-rendering
10+
# Minimum version compatibility tests - tests React 18 and Shakapacker 8.2.0
11+
- name: basic-minimum
12+
generator_options: ''
13+
minimum_versions: true
14+
- name: basic-server-rendering-minimum
15+
generator_options: --example-server-rendering
16+
minimum_versions: true

react_on_rails/rakelib/run_rspec.rake

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,25 @@ namespace :run_rspec do
9090
ExampleType.all[:shakapacker_examples].each { |example_type| Rake::Task[example_type.rspec_task_name].invoke }
9191
end
9292

93+
# Helper methods for filtering examples
94+
def latest_examples
95+
ExampleType.all[:shakapacker_examples].reject(&:minimum_versions)
96+
end
97+
98+
def minimum_examples
99+
ExampleType.all[:shakapacker_examples].select(&:minimum_versions)
100+
end
101+
102+
desc "Runs Rspec for latest version example apps only (excludes minimum version tests)"
103+
task shakapacker_examples_latest: latest_examples.map(&:gen_task_name) do
104+
latest_examples.each { |example_type| Rake::Task[example_type.rspec_task_name].invoke }
105+
end
106+
107+
desc "Runs Rspec for minimum version example apps only (React 18, Shakapacker 8.2.0)"
108+
task shakapacker_examples_minimum: minimum_examples.map(&:gen_task_name) do
109+
minimum_examples.each { |example_type| Rake::Task[example_type.rspec_task_name].invoke }
110+
end
111+
93112
Coveralls::RakeTask.new if ENV["USE_COVERALLS"] == "TRUE"
94113

95114
desc "run all tests no examples"

react_on_rails/rakelib/shakapacker_examples.rake

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,40 @@
88
require "yaml"
99
require "rails/version"
1010
require "pathname"
11+
require "json"
1112

1213
require_relative "example_type"
1314
require_relative "task_helpers"
1415

1516
namespace :shakapacker_examples do # rubocop:disable Metrics/BlockLength
1617
include ReactOnRails::TaskHelpers
1718

19+
# Updates package.json to use minimum supported versions for compatibility testing
20+
def apply_minimum_versions(dir)
21+
package_json_path = File.join(dir, "package.json")
22+
return unless File.exist?(package_json_path)
23+
24+
package_json = JSON.parse(File.read(package_json_path))
25+
26+
# Update React versions to minimum supported
27+
if package_json["dependencies"]
28+
package_json["dependencies"]["react"] = ExampleType::MINIMUM_REACT_VERSION
29+
package_json["dependencies"]["react-dom"] = ExampleType::MINIMUM_REACT_VERSION
30+
end
31+
32+
# Update Shakapacker to minimum supported version
33+
if package_json["devDependencies"]&.key?("shakapacker")
34+
package_json["devDependencies"]["shakapacker"] = ExampleType::MINIMUM_SHAKAPACKER_VERSION
35+
elsif package_json["dependencies"]&.key?("shakapacker")
36+
package_json["dependencies"]["shakapacker"] = ExampleType::MINIMUM_SHAKAPACKER_VERSION
37+
end
38+
39+
File.write(package_json_path, "#{JSON.pretty_generate(package_json)}\n")
40+
puts " Updated package.json with minimum versions:"
41+
puts " React: #{ExampleType::MINIMUM_REACT_VERSION}"
42+
puts " Shakapacker: #{ExampleType::MINIMUM_SHAKAPACKER_VERSION}"
43+
end
44+
1845
# Define tasks for each example type
1946
ExampleType.all[:shakapacker_examples].each do |example_type|
2047
relative_gem_root = Pathname(gem_root).relative_path_from(Pathname(example_type.dir))
@@ -46,6 +73,10 @@ namespace :shakapacker_examples do # rubocop:disable Metrics/BlockLength
4673
"REACT_ON_RAILS_SKIP_VALIDATION=true #{cmd}"
4774
end
4875
sh_in_dir(example_type.dir, generator_commands)
76+
77+
# Apply minimum versions for compatibility testing examples
78+
apply_minimum_versions(example_type.dir) if example_type.minimum_versions
79+
4980
sh_in_dir(example_type.dir, "npm install")
5081
# Generate the component packs after running the generator to ensure all
5182
# auto-bundled components have corresponding pack files created

react_on_rails/spec/dummy/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
"node-libs-browser": "^2.2.1",
1919
"null-loader": "^4.0.0",
2020
"prop-types": "^15.7.2",
21-
"react": "18.0.0",
22-
"react-dom": "18.0.0",
21+
"react": "^19.0.0",
22+
"react-dom": "^19.0.0",
2323
"react-helmet": "^6.1.0",
2424
"react-on-rails": "link:.yalc/react-on-rails",
2525
"react-redux": "^8.0.2",

script/convert

Lines changed: 10 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
#!/usr/bin/env ruby
22
# frozen_string_literal: true
33

4+
# This script converts the codebase to use minimum supported dependency versions.
5+
# It's run during CI when testing the "minimum" dependency matrix to ensure
6+
# backward compatibility.
7+
#
8+
# React/Shakapacker version compatibility is now tested through generator smoke tests
9+
# (see examples_config.yml for minimum version examples like basic-minimum).
10+
# This script only handles Node.js/tooling compatibility and Pro package test adjustments.
11+
412
def gsub_file_content(path, old_content, new_content)
513
path = File.expand_path(path, __dir__)
614

@@ -17,19 +25,6 @@ def gsub_file_content(path, old_content, new_content)
1725
File.binwrite(path, content)
1826
end
1927

20-
def move(old_path, new_path)
21-
old_path = File.expand_path(old_path, __dir__)
22-
new_path = File.expand_path(new_path, __dir__)
23-
File.rename(old_path, new_path)
24-
end
25-
26-
# Keep shakapacker.yml since we're using Shakapacker 8+
27-
# move("../react_on_rails/spec/dummy/config/shakapacker.yml", "../react_on_rails/spec/dummy/config/webpacker.yml")
28-
29-
# Shakapacker - use version with async script loading support (8.2.0+)
30-
gsub_file_content("../react_on_rails/Gemfile.development_dependencies", /gem "shakapacker", "[^"]*"/, 'gem "shakapacker", "8.2.0"')
31-
gsub_file_content("../react_on_rails/spec/dummy/package.json", /"shakapacker": "[^"]*",/, '"shakapacker": "8.2.0",')
32-
3328
# The below packages don't work on the oldest supported Node version and aren't needed there anyway
3429
# Note: All dev dependencies remain in root package.json even after workspace migration
3530
gsub_file_content("../package.json", /"[^"]*eslint[^"]*": "[^"]*",?/, "")
@@ -42,35 +37,16 @@ gsub_file_content("../package.json", %r{"@testing-library/[^"]*": "[^"]*",}, "")
4237
# Clean up any trailing commas before closing braces
4338
gsub_file_content("../package.json", /,(\s*})/, "\\1")
4439

45-
# Switch to minimum supported React version (React 18 since we removed PropTypes)
46-
gsub_file_content("../package.json", /"react": "[^"]*",/, '"react": "18.0.0",')
47-
gsub_file_content("../package.json", /"react-dom": "[^"]*",/, '"react-dom": "18.0.0",')
48-
gsub_file_content("../react_on_rails/spec/dummy/package.json", /"react": "[^"]*",/, '"react": "18.0.0",')
49-
gsub_file_content("../react_on_rails/spec/dummy/package.json", /"react-dom": "[^"]*",/, '"react-dom": "18.0.0",')
40+
# Pro package: Skip RSC tests on React 18 since RSC requires React 19
5041
gsub_file_content(
5142
"../packages/react-on-rails-pro/package.json",
5243
/"test:non-rsc": "(?:\\"|[^"])*",/,
5344
'"test:non-rsc": "jest tests --testPathIgnorePatterns=\".*(RSC|stream|' \
5445
'registerServerComponent|serverRenderReactComponent|SuspenseHydration).*\"",'
5546
)
56-
# Make test:rsc script do nothing
47+
# Make test:rsc script do nothing on React 18
5748
gsub_file_content(
5849
"../packages/react-on-rails-pro/package.json",
5950
/"test:rsc": "(?:\\"|[^"])*",/,
6051
'"test:rsc": "exit 0",'
6152
)
62-
# Keep modern JSX transform for React 18+
63-
# gsub_file_content("../tsconfig.json", "react-jsx", "react")
64-
# gsub_file_content("../spec/dummy/babel.config.js", "runtime: 'automatic'", "runtime: 'classic'")
65-
# Keep modern ReScript configuration for React 18+
66-
# gsub_file_content("../spec/dummy/rescript.json", '"version": 4', '"version": 4, "mode": "classic"')
67-
# Skip React 16 file replacements since we're using React 18+
68-
# Dir.glob(File.expand_path("../spec/dummy/**/app-react16/**/*.*", __dir__)).each do |file|
69-
# move(file, file.gsub("-react16", ""))
70-
# end
71-
72-
# These replacements were incorrect - generateWebpackConfig() is the correct function from shakapacker
73-
# gsub_file_content("../spec/dummy/config/webpack/commonWebpackConfig.js", /generateWebpackConfig(\(\))?/,
74-
# "webpackConfig")
75-
#
76-
# gsub_file_content("../spec/dummy/config/webpack/webpack.config.js", /generateWebpackConfig(\(\))?/, "webpackConfig")

0 commit comments

Comments
 (0)