0
votes

I'm using Capybara to test a basic form - when the user fills it out and submits it should create a new User record

it "creates a new user" do
  visit some_random_path

  # Fill In Form
  fill_in("name", with: "foo bar")
  fill_in("email", with: "[email protected]")

  expect do
    click_button("Submit")
  end.to change { User.count }.by(1)
end

The expect blocks throws an error because it doesn't see the User.count increase by 1. However I noticed that if I do something like

click_button("Submit") && sleep(0.1)

it works just fine!

So it looks like RSpec is trying to check too quickly - i.e. before the browser that Capybara runs has a chance to actually submit the form and commit the results against the DB.

I'm not using any JavaScript, just a plain old :webkit spec.

Any thoughts on why this might be happening?

Below is my Capybara configuration. I have a multi-tenant app (I'm using the apartment gem for whatever it matters) so I use localhost and lvh.me as the app hosts as noted below, but I can't imagine that would interfere with the above.

Capybara.configure do |config|
  config.ignore_hidden_elements = true
  Capybara.default_driver = :webkit
  config.javascript_driver = :webkit
end

Capybara::Webkit.configure do |config|
  config.block_unknown_urls
  config.allow_url("lvh.me")
end

RSpec.configure do |config|
  config.before(:suite) do
    Capybara.always_include_port = true
    # The default is to treat each spec as single tennat, in which case
    # we want to hit localhost. Hitting the Capbyara default of www.example.com
    # causes the apartment setup to try and parse the `www` as a subdomain
    Capybara.app_host = "http://localhost"
  end

  config.before(:each, multi_tenant: true) do
    # For multi-tenant specs, use "lvh.me"
    Capybara.app_host = "http://lvh.me"
  end
end

Thanks!

1

1 Answers

1
votes

When using one of the "real browser" drivers with Capybara (pretty much any of them except for rack_test) no action triggered by clicking a button is guaranteed to have completed when the click method returns. This means you need to check for visible changes on the page that indicate the action has completed before moving on. In your case that would mean something like

expect do
  click_button("Submit")
  expect(page).to have_text("New User Created") # whatever appears on screen to indicate successful creation of the user
end.to change { User.count }.by(1)

Note that doing direct DB checks of things is generally considered a bad code smell when writing feature tests, and you really should just be checking the new user shows on the users index page, confirm a success message appears, or something similar rather than checking User.count.