You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从jquery_ujs迁移到rails-ujs后JS测试中jQuery对象仅首次初始化

解决Rails 5.1替换rails-ujs后系统测试中jQuery/Select2仅首次测试生效的问题

我之前也碰到过一模一样的问题!把jquery_ujs换成rails-ujs之后,Capybara的JS测试就出现了这种“单个测试跑都没问题,连起来跑就只有第一个能找到Select2元素”的诡异情况。折腾了一阵后发现,核心原因是rails-ujs和jquery_ujs在页面加载、Turbolinks处理以及测试环境重置上的差异,导致后续测试的jQuery/Select2没有正确初始化。

下面是几个我亲测有效的解决思路,按优先级推荐:


1. 修正Select2的初始化时机(最常见原因)

如果你的Select2是用$(document).ready()初始化的,换成rails-ujs后就踩坑了——因为rails-ujs配合Turbolinks时,页面切换是通过Turbolinks完成的,不会触发传统的ready事件,只有首次加载页面才会触发。后续测试里访问页面时,Select2根本没初始化,自然找不到.select2-container。

把初始化代码改成绑定到turbolinks:load事件:

// 替换原来的$(document).ready()
$(document).on('turbolinks:load', function() {
  $('.my-select').select2();
});

另外,别忘了加个页面缓存前的销毁逻辑,避免残留的Select2实例影响下一个测试:

$(document).on('turbolinks:before-cache', function() {
  $('.select2-container').select2('destroy');
});

2. 强制测试之间重置Capybara会话

有时候rails-ujs的页面清理逻辑没完全跟上,导致前一个测试的JS环境残留到了下一个测试里。可以在RSpec配置里给所有JS测试前后强制重置会话:

RSpec.configure do |config|
  config.before(:each, :js) do
    Capybara.reset_sessions!
  end

  config.after(:each, :js) do
    Capybara.reset_sessions!
    # 跳转到空白页彻底清理上下文
    page.execute_script('window.location.href = "about:blank"')
  end
end

这样每个测试都能拿到全新的浏览器会话,不会被之前的测试污染。


3. 检查Capybara驱动的复用设置

如果你用的是Chrome/Selenium驱动,有时候驱动会复用浏览器进程,导致JS环境没重置。可以在配置里明确让驱动每次启动新进程:

Capybara.register_driver :selenium_chrome do |app|
  options = Selenium::WebDriver::Chrome::Options.new(args: ['--no-sandbox'])
  Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
end

Capybara.javascript_driver = :selenium_chrome

这个设置能避免驱动复用会话带来的各种奇怪问题。


4. 极端情况:手动注入jQuery(不推荐但有效)

如果上面的方法都没用,可能是测试环境里jQuery没被正确加载。可以在测试的before块里手动注入:

before(:each, :js) do
  visit new_my_object_path
  # 如果页面没有jQuery就加载
  page.execute_script(<<-JS
    if (typeof jQuery === 'undefined') {
      const script = document.createElement('script');
      script.src = 'https://code.jquery.com/jquery-3.6.4.min.js';
      document.head.appendChild(script);
    }
  JS
  )
  # 等待jQuery加载完成
  page.wait_for do
    page.evaluate_script('typeof jQuery !== "undefined"')
  end
end

不过这属于hack手段,尽量先排查前面的常规问题。


我当时是用第一种方法解决的,改完Select2的初始化事件后,所有测试连起来跑都正常了。你可以先试试这个方案!

内容的提问来源于stack exchange,提问作者Andy Harvey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:47:54