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

Capybara/RSpec系统测试中数据库数据不显示的问题解决

Rails Capybara/RSpec系统测试:测试数据未在页面显示的问题

我在运行Rails项目的Capybara/RSpec系统测试时,遇到创建的测试数据库数据无法在页面显示的问题。以下是我的spec/system/group_index_spec.rb测试文件:

require_relative '../rails_helper'

RSpec.describe 'Group Index', type: :system do
  let(:user) { User.create(name: 'First User', email: 'test@user.com', password: 'password') }
  before do
    # driven_by(:rack_test)
    puts 'Creating test data...'

    5.times do |i|
      group = Group.create(name: "Group #{i}", author: user)
      group.icon.attach(io: File.open(Rails.root.join('spec', 'models', 'files', 'test.jpg')), filename: 'test.jpg',
                        content_type: 'image/jpeg')

      5.times do |j|
        Entity.create(name: "Entity #{j}", amount: 100, author: user)
      end
    end

    Group.all.each do |group|
      group.entities << Entity.all.sample(rand(1..3))
    end

    Entity.all.each do |entity|
      entity.groups << Group.all.sample(rand(1..3))
    end

    puts 'Logging in...'
    visit new_user_session_path
    fill_in 'user_email', with: 'test@user.com'
    fill_in 'user_password', with: 'password'
    click_button 'Log in'
  end

  it 'displays all groups', js: true do
    visit groups_path
    expect(page).to have_content('Group 0')
    expect(page).to have_content('Group 1')
    expect(page).to have_content('Group 2')
    expect(page).to have_content('Group 3')
    expect(page).to have_content('Group 4')
  end
end

运行测试后出现如下错误:

Creating test data...
Logging in...
F

Failures:

  1) Group Index displays all groups
     Failure/Error: expect(page).to have_content('Group 0')
       expected to find text "Group 0" in "CATEGORIES\nNew"
     
     [Screenshot Image]: /home/shasherazi/programming/microverse/budget-app/tmp/capybara/failures_r_spec_example_groups_g
roup_index_displays_all_groups_713.png

     
     # ./spec/system/group_index_spec.rb:36:in `block (2 levels) in <top (required)>'

Finished in 8.22 seconds (files took 1.64 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/system/group_index_spec.rb:34 # Group Index displays all groups

以下是我参考网上建议修改后的rails_helper.rb文件:

# This file is copied to spec/ when you run 'rails generate rspec:install'
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
# Prevent database truncation if the environment is production
abort('The Rails environment is running in production mode!') if Rails.env.production?
require 'rspec/rails'
require 'capybara/rspec'
require 'database_cleaner'
# Add additional requires below this line. Rails is not loaded until this point!

# Requires supporting ruby files with custom matchers and macros, etc, in
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
# run as spec files by default. This means that files in spec/support that end
# in _spec.rb will both be required and run as specs, causing the specs to be
# run twice. It is recommended that you do not name files matching this glob to
# end with _spec.rb. You can configure this pattern with the --pattern
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
#
# The following line is provided for convenience purposes. It has the downside
# of increasing the boot-up time by auto-requiring all files in the support
# directory. Alternatively, in the individual `*_spec.rb` files, manually
# require only the support files necessary.
#
# Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }

# Checks for pending migrations and applies them before tests are run.
# If you are not using ActiveRecord, you can remove these lines.
begin
  ActiveRecord::Migration.maintain_test_schema!
rescue ActiveRecord::PendingMigrationError => e
  abort e.to_s.strip
end
RSpec.configure do |config|
  # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
  config.fixture_path = "#{Rails.root}/spec/fixtures"

  # If you're not using ActiveRecord, or you'd prefer not to run each of your
  # examples within a transaction, remove the following line or assign false
  # instead of true.
  config.use_transactional_fixtures = false

  config.before(:suite) do
    DatabaseCleaner.strategy = :truncation
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end
  # You can uncomment this line to turn off ActiveRecord support entirely.
  # config.use_active_record = false

  # RSpec Rails can automatically mix in different behaviours to your tests
  # based on their file location, for example enabling you to call `get` and
  # `post` in specs under `spec/controllers`.
  #
  # You can disable this behaviour by removing the line below, and instead
  # explicitly tag your specs with their type, e.g.:
  #
  #     RSpec.describe UsersController, type: :controller do
  #       # ...
  #     end
  #
  # The different available types are documented in the features, such as in
  # https://rspec.info/features/6-0/rspec-rails
  config.infer_spec_type_from_file_location!

  # Filter lines from Rails gems in backtraces.
  config.filter_rails_from_backtrace!
  # arbitrary gems may also be filtered via:
  # config.filter_gems_from_backtrace("gem name")
  Capybara.run_server = true
  Capybara.server_port = 7000
  Capybara.app_host = "http://localhost:#{Capybara.server_port}"
end

开发环境中用faker以类似方式生成示例数据一切正常,但测试环境始终无法显示数据,折腾了一整天没找到解决方案,希望能得到帮助。


解决方案

问题根源是:创建模型实例并添加附件(如group.icon.attach)后,需要手动调用.save方法才能将变更持久化到数据库。以下是修正后的测试文件:

require_relative '../rails_helper'

RSpec.describe 'Groups', type: :system do
  let(:user) { User.create(name: 'First User', email: 'test@user.com', password: 'password') }
  before do
    # 注释下面一行可在浏览器中运行测试
    driven_by(:rack_test)

    puts "\nCreating test data..."

    5.times do |i|
      group = Group.create(name: "Group #{i}", author: user)
      group.icon.attach(io: File.open(Rails.root.join('spec', 'models', 'files', 'test.jpg')), filename: 'test.jpg',
                        content_type: 'image/jpeg')
      group.save

      5.times do |j|
        entity = Entity.create(name: "Entity #{j}", amount: 100, author: user)
        entity.save
      end
    end

    Group.all.each do |group|
      group.entities << Entity.all.sample(rand(1..3))
    end

    Entity.all.each do |entity|
      entity.groups << Group.all.sample(rand(1..3))
    end

    puts 'Logging in...'
    visit new_user_session_path
    fill_in 'user_email', with: 'test@user.com'
    fill_in 'user_password', with: 'password'
    click_button 'Log in'
  end

  after(:all) do
    puts "\nCleaning up..."
    Group.destroy_all
    Entity.destroy_all
    User.destroy_all
  end

  it 'displays all groups, their names, and icons', js: true do
    visit groups_path
    user.groups.each do |group|
      expect(page).to have_content(group.name)
      expect(page).to have_css("img[src*='#{group.icon.blob.filename}']")
    end
  end
end

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 09:55:09