旧Rails项目中如何用Rspec/Capybara/Chromedriver实现模态框系统测试
背景信息
这是一个2017年的Rails旧项目,相关Gem配置:
group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platform: :mri gem 'rspec-rails', '~> 3.5.0' gem 'puma', '~> 3.0' end group :test do gem 'capybara', '~> 3.6.0' gem 'factory_girl_rails', '~> 4.7' gem 'faker' gem 'selenium-webdriver', '~> 3.0.0' gem "database_cleaner", "~> 1.5" gem 'shoulda-matchers', '~> 3.1' gem 'launchy' end
Capybara配置:
Capybara.register_driver :selenium_chrome do |app| Capybara::Selenium::Driver.new(app, browser: :chrome) end Capybara.javascript_driver = :selenium_chrome
测试需求:用户登录后点击模态框链接,验证模态框存在并交互。当前遇到两个问题:
- 不加
:js => true时,点击模态框链接触发AJAX请求,控制器报错ActionController::UnknownFormat - 加
:js => true后,出现NameError: uninitialized constant Selenium::WebDriver::Error::ElementNotInteractableError
问题1:ActionController::UnknownFormat 解决
这个错误的核心原因是:Capybara默认使用的rack_test驱动不支持JavaScript/AJAX请求。点击模态框链接的操作是触发AJAX(JS格式请求),但rack_test只会发送HTML格式的请求,导致控制器找不到对应格式的响应,抛出未知格式错误。
解决办法:必须给需要JS交互的测试场景加上:js => true(Rspec 3.x也可以用js: true),这样Capybara会切换到你配置的selenium_chrome驱动运行测试,支持JS和AJAX。
问题2:NameError: uninitialized constant Selenium::WebDriver::Error::ElementNotInteractableError 解决
这个错误是因为你使用的selenium-webdriver (~> 3.0.0)版本太老,而capybara (~> 3.6.0)依赖了Selenium 3.x后期版本才引入的ElementNotInteractableError常量,旧版Selenium没有这个类,导致报错。
修复方案:
升级selenium-webdriver到3.x系列的稳定兼容版本,比如3.141.0(这是Selenium 3的最后一个稳定版,完全支持Capybara 3.6.0的需求)。修改Gemfile中的对应行:
gem 'selenium-webdriver', '~> 3.141.0'
然后执行bundle update selenium-webdriver更新依赖。
额外测试优化建议
测试代码中的细节修正:
- 你写的
within('#actionModal') do page.should have_content('#fan1') end存在问题:have_content是检查页面文本内容,如果你要验证#fan1元素存在,应该用have_css('#fan1'),正确写法:within('#actionModal') do expect(page).to have_css '#fan1' end - 尽量使用Capybara的断言式方法(比如
expect(page).to have_link)而非直接find,因为断言式方法会自动等待元素出现,避免异步加载导致的失败。
- 你写的
无需拆分测试场景:
加了js: true后,整个测试场景都会在Chrome浏览器中运行,登录流程和模态框交互可以连贯执行,不需要拆分到单独的JS测试中。只要确保你的create_fan_in_canada方法能正确在测试数据库中创建用户(注意JS驱动运行时,测试线程和Rails服务器线程是分开的,需要确保数据库清理策略正确,database_cleaner配置要适配JS测试)。
内容的提问来源于stack exchange,提问作者daveasdf

