Three silent-failure cases in pro_generator.rb from #2822. The generator reports success while user tests, type checks, or Gemfiles are broken.
1. jest.mock('react-on-rails', ...) is never rewritten
The dynamic-call regex at pro_generator.rb:353-361 only matches import( and require(. jest.mock(, vi.mock(, etc. don't match any branch.
Repro:
import ReactOnRails from 'react-on-rails';
jest.mock('react-on-rails', () => ({ authenticityHeaders: jest.fn() }));
After update_imports_to_pro_package:
import ReactOnRails from 'react-on-rails-pro'; // rewritten
jest.mock('react-on-rails', () => ({ ... })); // NOT rewritten
jest.mock is the standard Jest API for stubbing modules. Any test file that mocks react-on-rails ends up in a broken state: the import points at Pro but the mock still targets the old package, so Jest loads the real module — crashing with "Cannot find module" if Pro isn't installed yet at generator time, or running assertions against real functions instead of stubs.
Fix:
mock_call_pattern = %r{
(?<!["'`])\b\w+\.(?:mock|unmock|doMock|dontMock|requireActual|requireMock)\s*\(\s*
(?<quote>["'])react-on-rails(?!-pro)(?=(?:["']|/))
}x
2. declare module 'react-on-rails' is never rewritten
None of the three regexes in rewrite_react_on_rails_module_specifiers handle TypeScript/Flow module declarations — all branches require import|export|require(|import(.
Repro (.d.ts):
declare module 'react-on-rails' {
export function register(c: Record<string, any>): void;
}
declare module 'react-on-rails/client' {
export * from 'react-on-rails';
}
The declare module headers stay at 'react-on-rails', but the inner export * from 'react-on-rails' gets rewritten to 'react-on-rails-pro'. The file ends up mixing old and new names inside one declaration.
This pattern shows up in any project that ran flow-typed install react-on-rails or hand-wrote a .d.ts stub — shakacode/hichee has one at client/flow-typed/npm/react-on-rails_vx.x.x.js (130 lines, 31 declare module statements). Running the parser directly on that file: 48 react-on-rails occurrences in, 48 out, 0 rewrites. Flow and/or tsc break across the client tree after migration.
Fix:
declare_module_pattern = %r{
\A\s*declare\s+module\s+
(?<quote>["'])react-on-rails(?!-pro)(?=(?:["']|/))
}x
Also catches TypeScript module augmentation inside regular .ts files.
3. Gemfile swap silently overwrites the user's version pin
build_pro_gem_replacement_line at pro_generator.rb:894-916 constructs the new line using pro_gem_version_requirement (pro_setup.rb:489-495), which always returns the currently-running ReactOnRails::VERSION. The user's original version argument is dropped.
Repro:
# input
gem 'react_on_rails', '~> 16.4', require: false
# output
gem 'react_on_rails_pro', '~> 16.6.0', require: false
require: false preserved, '~> 16.4' silently replaced with the generator's current version.
Every Gemfile with an explicit pin is affected, which is the normal case. The user's intentional version constraint is lost — no warning, no prompt, visible only by diffing the Gemfile. If they were on an older version deliberately, the generator forces them onto whatever ROR version they happen to have installed locally.
Fix: when the matched declaration has an explicit version argument, preserve it. consume_non_parenthesized_base_gem_declaration already captures the full declaration for multi-line handling, so the version string is available there.
Introduced in #2822 (commit 691ae701b).
Three silent-failure cases in
pro_generator.rbfrom #2822. The generator reports success while user tests, type checks, or Gemfiles are broken.1.
jest.mock('react-on-rails', ...)is never rewrittenThe dynamic-call regex at
pro_generator.rb:353-361only matchesimport(andrequire(.jest.mock(,vi.mock(, etc. don't match any branch.Repro:
After
update_imports_to_pro_package:jest.mockis the standard Jest API for stubbing modules. Any test file that mocksreact-on-railsends up in a broken state: the import points at Pro but the mock still targets the old package, so Jest loads the real module — crashing with "Cannot find module" if Pro isn't installed yet at generator time, or running assertions against real functions instead of stubs.Fix:
2.
declare module 'react-on-rails'is never rewrittenNone of the three regexes in
rewrite_react_on_rails_module_specifiershandle TypeScript/Flow module declarations — all branches requireimport|export|require(|import(.Repro (
.d.ts):The
declare moduleheaders stay at'react-on-rails', but the innerexport * from 'react-on-rails'gets rewritten to'react-on-rails-pro'. The file ends up mixing old and new names inside one declaration.This pattern shows up in any project that ran
flow-typed install react-on-railsor hand-wrote a.d.tsstub —shakacode/hicheehas one atclient/flow-typed/npm/react-on-rails_vx.x.x.js(130 lines, 31declare modulestatements). Running the parser directly on that file: 48react-on-railsoccurrences in, 48 out, 0 rewrites. Flow and/ortscbreak across the client tree after migration.Fix:
Also catches TypeScript module augmentation inside regular
.tsfiles.3. Gemfile swap silently overwrites the user's version pin
build_pro_gem_replacement_lineatpro_generator.rb:894-916constructs the new line usingpro_gem_version_requirement(pro_setup.rb:489-495), which always returns the currently-runningReactOnRails::VERSION. The user's original version argument is dropped.Repro:
require: falsepreserved,'~> 16.4'silently replaced with the generator's current version.Every Gemfile with an explicit pin is affected, which is the normal case. The user's intentional version constraint is lost — no warning, no prompt, visible only by diffing the Gemfile. If they were on an older version deliberately, the generator forces them onto whatever ROR version they happen to have installed locally.
Fix: when the matched declaration has an explicit version argument, preserve it.
consume_non_parenthesized_base_gem_declarationalready captures the full declaration for multi-line handling, so the version string is available there.Introduced in #2822 (commit
691ae701b).