Suganya Selvarajan
Suganya Selvarajan

Reputation: 1082

Rails - Minitest + Capybara + Selenium - Test destroy action

I am new to Minitest / Capybara / Selenium. But I want to test my destroy Controller action. I an trying the following and it is failing

test "destroy" do
  companies_count = Company.count
  visit company_path(@company)
  click_on "Delete"
  page.driver.browser.switch_to.alert.accept
  assert_equal (companies_count - 1), Company.count
end

OUTPUT:

    test_destroy                                                    FAIL (2.17s)
    Expected: 6
      Actual: 7

Tried this way also.

test "destroy" do
    assert_difference('Company.count', -1) do
      delete company_url(@company)
    end
end

OUTPUT:

Minitest::UnexpectedError:         NoMethodError: undefined method `delete' for #<CompaniesControllerTest:0x000056171e550038>

Can someone help me in testing my destroy action?

Upvotes: 0

Views: 431

Answers (2)

Thomas Walpole
Thomas Walpole

Reputation: 49870

Assuming you're using a modern version of Rails (5.2/6) and a standard system test configuration (not running parallel tests in threads) then the concerns in the answer of Gregório Kusowski are irrelevant because the DB connection is shared between your tests and your application, preventing the issue of the tests not being able to see your apps changes.

Also assuming you're using Selenium in these system tests, the main problem you're dealing with is that actions in the browser occur asynchronously from your tests, so just because you've told your test to accept the dialog box doesn't mean the action to delete the company has completed when it returns. The way to verify that is to just sleep for a little bit before checking for the change in count. While that will work it's not a good final solution because it ends up wasting time. Instead, you should be checking for a visual change that indicates the action has completed before verifying the new count

test "destroy" do
  companies_count = Company.count
  visit company_path(@company)
  accept_confirm do      
    click_on "Delete"
  end

  assert_text "Company Deleted!" # Check for whatever text is shown to indicate the action has successfully completed

  assert_equal (companies_count - 1), Company.count
end

This works because Capybara provided assertions have a waiting/retrying behavior that allows the application up to a specific amount of time to catch up with what the test is expecting.

Note: I've replaced the page.driver... with the correct usage of Capybaras system modal API - If you're using page.driver... it generally indicates you're doing something wrong.

Upvotes: 1

Greg&#243;rio Kusowski
Greg&#243;rio Kusowski

Reputation: 188

This is very likely to happen because what you execute directly in your test happens in a transaction, and your web-driver is triggering actions that happen on another one. You can read more about how it happens here: https://edgeguides.rubyonrails.org/testing.html#testing-parallel-transactions

Here is a similar issue: Rails integration test with selenium as webdriver - can't sign_in

And as it is stated in the Rails Guides and the similar question, you will probably have to use a solution like http://rubygems.org/gems/database_cleaner

If you don't want to do this, the other option you have is to validate that your action was successful via the web-driver, like for example asserting that there are 6 rows in the table you list all companies.

Upvotes: 1

Related Questions