'Capybara and Factorybot - created data does not appear
I am facing a wired issue, factoryBot is creating a record in Db, but when capybara try to access it, there is no record in HTML.
I tried debugging with "byebug", on prompt, when I say @topics => It gives me Nil data. (@topic is instance variable in topics_controller.rb -> index method )
If I do "Topic.all.first" it will show me correct record of Topic with an expected random name that is -> "Toys & Garden" If I do "random_topic.name" -> "Toys & Garden"
I have somewhat similar setup in other feature i.e "account creation feature", it is working fine in there. Any pointer or help would be highly appreciated.
My factory file is
FactoryBot.define do
factory :topic do
name { Faker::Commerce.department(2, true) }
archived false
end
end
My Feature spec file looks like below
require 'rails_helper'
describe "topics" do
let(:user) {create(:user)}
before do
sign_user_in(user) #support fuction to sign user in
end
it "allows topics to be edited" do
random_topic = create(:topic)
visit topics_path # /topics/
expect(page).to have_text random_topic.name # Error1
click_edit_topic_button random_topic.name # Another support fuction
random_topic_name_2 = Faker::Commerce.department(2, true)
fill_in "Name", with: random_topic_name_2
check "Archived"
click_button "Update Topic"
expect(page).to have_text "Topic updated!"
expect(page).to have_text random_topic_name_2
end
end
I get the error on line marked as "Error 1" , please note that "Toys & Garden" is sample name generated by Faker Gem.
Failure/Error: expect(page).to have_text random_topic.name
expected #has_text?("Toys & Garden") to return true, got false
my Rails helper(rails_helper.rb) file setup is as below.
# This file is copied to spec/ when you run 'rails generate rspec:install'
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'rspec/rails'
require 'database_cleaner'
require 'capybara/rspec'
require 'shoulda/matchers'
require 'email_spec'
require "email_spec/rspec"
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
ActiveRecord::Migration.maintain_test_schema!
Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :rails
end
end
# This is for setting up Capybara right host.
# https://stackoverflow.com/questions/6536503/capybara-with-subdomains-default-host
def set_host (host)
default_url_options[:host] = host
Capybara.app_host = "http://" + host
end
RSpec.configure do |config|
config.include Capybara::DSL
config.include Rails.application.routes.url_helpers
config.include FactoryBot::Syntax::Methods
config.include EmailSpec::Helpers
config.include EmailSpec::Matchers
config.order = "random"
config.use_transactional_fixtures = false
config.before(:each) do
set_host "lvh.me:3000"
end
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, :js => true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
My Topics Controller file is something like below
class TopicsController < ApplicationController
layout 'dashboard'
before_action :authenticate_user!
def index
@topics = Topic.all
end
end
Updated with @smallbutton.com comments, but issue continues.
SOLVED
I am using apartment gem and hence topic was getting created in public schema while test was looking into a respective tenant.
As per @thomas suggestion, I modified the code:
before do
set_subdomain(account.subdomain)
sign_user_in(user) #support fuction to sign user in
Apartment::Tenant.switch!(account.subdomain)
end
Solution 1:[1]
When this happens it's generally caused by one of a few things
The record isn't actually being created
From your code it doesn't appear to be that
The record is being created in one transaction while the app is running in a different transaction.
You appear to have database_cleaner configured correctly, and this shouldn't be an issue in your case, however you should be using - https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example - rather than the configuration you have (which depends on the :js metadata rather than checking which driver is actually being used)
The user has configured Capybara to hit a different server than the one the test is actually running on.
Here we appear to have an issue, since you're configuring
Capybara.app_host
to be 'lvh.me:3000'. Port 3000 is what your dev app is generally run on, while Capybara (by default) starts your app on a random port for tests. This probably means your tests are actually running against your dev app/db instance which has nothing to do with the test app/db instance, and therefore the tests won't see anything you create in your tests. Remove the setting ofCapybara.app_host
unless you have an actual need for its setting (in which case remove the port from your app_host setting and enableCapybara.always_include_server_port
)
This all being said, since you're using Rails 5.1+ database_cleaner should not be needed anymore. You should be able to remove all of database_cleaner, reenable use_transactional_fixtures
, and set Capybara.server = :puma
and have things work fine (still would need to fix the app_host setting)
Solution 2:[2]
Your record isn't persisted when you visit the page, so it's normal that it return false.
Try the following :
require 'rails_helper'
describe "topics" do
let(:user) {create(:user)}
let!(:random_topic) {create(:topic)}
before do
sign_user_in(user) #support fuction to sign user in
visit topics_path # /topics/
end
it "allows topics to be edited" do
expect(page).to have_text random_topic.name # Error1
click_edit_topic_button random_topic.name # Another support fuction
random_topic_name_2 = Faker::Commerce.department(2, true)
fill_in "Name", with: random_topic_name_2
check "Archived"
click_button "Update Topic"
expect(page).to have_text "Topic updated!"
expect(page).to have_text random_topic_name_2
end
end
Note that random_topic is extracted in a let! (more info about the difference between let and let! : https://relishapp.com/rspec/rspec-core/v/2-5/docs/helper-methods/let-and-let !
Solution 3:[3]
You should create the record before you visit the page. Currently you do it the other way around so your record cannot appear.
Solution 4:[4]
People having this kind of issue should definitly try this:
instance.reload
after clicking and before using "expect".
This solved my issue I've been stuck on for a whole day ...
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Thomas Walpole |
Solution 2 | Philippe B. |
Solution 3 | smallbutton |
Solution 4 | Sunamin34 |