0

For RSpec Capybara Test Case [ Selenium ], I have near about 7 to 8 spec files. Few of the test cases are dependent on each other. For example, before deleting an product, I have to create the product.

But when test cases excution starts, delete product based rspec runs before the create product rspec.

File Name:-

product_delete.rspec

product_listing.rspec

product_newly_added.rspec

Command : rspec

.rspec file in root folder

--require spec_helper
--format html
--out ./log/rspec_results.html
--color

Test case failed while execution for delete product.

Is there any way to define the sequence of file execution while running RSpec.

Community
  • 1
  • 1
Rubyist
  • 6,486
  • 10
  • 51
  • 86
  • 3
    Test cases should really be independent. Order-dependent tests are a code smell. – Roman Kiselenko Sep 29 '17 at 05:01
  • @Зелёный - Agree but here if I tried to execute the single delete test case then I have to write creation of product in same test case. DRY will be violated in that case. – Rubyist Sep 29 '17 at 05:04
  • Tests must be DAMP the code must be DRY. To maintain code, you first need to understand the code. [To understand it, you have to read it. Consider for a moment how much time you spend reading code. It's a lot. DAMP increases maintainability by reducing the time necessary to read and understand the code.](https://stackoverflow.com/questions/6453235/what-does-damp-not-dry-mean-when-talking-about-unit-tests.) – Roman Kiselenko Sep 29 '17 at 05:06
  • @Зелёный - Excellent one. Valid point. Still if any one can suggest to rearrange the sequence then I believe it would be great. Everyone faced such type of problem. May be any warrior have the suggestion. – Rubyist Sep 29 '17 at 05:08

3 Answers3

1

Test cases should be independent. For your delete test case you can use factory and create a record then delete it in a single test case as shown in example. just define factory once and use it to create records, in this way DRY wont be violated.

describe 'POST destroy' do
 before(:each) do
  @obj = build(:factory_name)
  @obj.save
 end

 it 'it has status 200' do
  post :destroy, {"id" => @obj.id}
  expect(ClassOfObj.count).to eq(0)
 end
end
  • Buddy It's a selenium test case. Forgot to mention in Question. Thanks for reminding. – Rubyist Sep 29 '17 at 08:06
  • @Rubyist It doesn't matter what kind of tests you have. This example just describes the approach, and does that properly – chumakoff Sep 29 '17 at 09:12
  • @chumakoff: he probably meant that, in this case, server is running in a separate process and is not seeing factory-built objects from this process (because of transaction isolation). So yes, "kind of tests" can matter. – Sergio Tulentsev Sep 29 '17 at 09:14
  • @sergio-tulentsev RSpec + Capybara are used. There should be no problem with seeing factory-built objects – chumakoff Sep 29 '17 at 09:20
  • @chumakoff: why do you think so? Because selenium _does_ run a standalone firefox for the tests (and also runs the server as a separate process). I personally have had this problem. – Sergio Tulentsev Sep 29 '17 at 09:34
  • @chumakoff yeah, but for these kind of tests the set up time + test time can be significant, and usually you don't need them independent but test the whole flow. For unit tests that's another story, and the described approach would be appropriate. – Greg Sep 29 '17 at 14:21
  • 1
    @SergioTulentsev While selenium does run firefox/chrome/etc in a separate process, Capybara (by default) runs the app server in a separate thread (not process). In Rails < 5.1 that would require running something like database_cleaner and not running in transactional testing mode for factory created objects to be seen by the app, however Rails 5.1+ handles sharing of the DB connection between threads and can run transactional testing without issue in most cases. – Thomas Walpole Sep 29 '17 at 15:26
  • @ThomasWalpole: ah, didn't know that (connection sharing). Still, it's selenium here, so yes, something like database cleaner must be used. – Sergio Tulentsev Sep 29 '17 at 16:01
  • 1
    @SergioTulentsev database_cleaner is not needed if running rails 5.1+ (It's Capybara using selenium as the driver, where the browser is running doesn't matter as long as the app and tests are running in the same process and sharing the DB connection between threads) – Thomas Walpole Sep 29 '17 at 16:04
  • @ThomasWalpole: Ah, indeed. It's friday night, you must excuse me. :) – Sergio Tulentsev Sep 29 '17 at 16:05
1

One possible approach is to not separate these actions into their own test cases. With feature specs you test whole features, not single buttons. So, your test might look like this:

  1. Navigate to new item page. Make sure form is displayed
  2. Fill out the form. Click submit. Verify that success message is displayed on screen.
  3. Verify that you have been redirected to item index page. Verify that newly created item is indeed present on the page.
  4. Click "delete" button.
  5. Confirm that you're on index page and that item is no longer displayed.
Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
  • SergioTulentsev : Thanks for the reply. Already done with in the file. Tried to separate the code to make it more manageable, only struggling with sequence. – Rubyist Sep 29 '17 at 09:04
  • @Rubyist: yes, that's a dead end. Listen to the other guys. Your only two options are: make each test self-sufficient or... there's no option 2, really. – Sergio Tulentsev Sep 29 '17 at 09:13
  • SergioTulentsev - May be you are right. I have to find some other alternative with in the system by making some function calls. Thanks – Rubyist Sep 29 '17 at 10:18
0

As mentioned by most/all the other answers, your tests should be independent, and RSpec supports running tests in random order to guarantee that. One of the easiest ways to implement testing in these conditions is to use factories for the creation of your test data (FactorGirl, etc). In this case you would end up with a test along the lines of

feature "deleting of products" do
  scenario "removes last product" do
     create(:product) # Use factory to create one product
     visit products_path 
     expect(page).to have_css('div.product', count: 1) # verify there is only one product shown on the page
     click_link('delete') # click the delete button
     expect(page).to have_text("Product deleted!") # check for a visible change that indicates deletion has completed        
     visit products_path
     expect(page).not_to have_css('div.product') # No products shown any more - you may need to expect for something else first if the products are dynamically loaded to the page to ensure that has completed
  end
end

You could check the DB contents rather than revisiting the products_path, but direct DB querying in feature tests is generally a bad smell since it's coupling user experience with implementation details.

If using this in Rails < 5.1 with a JS capable driver, you'll probably need to install database_cleaner and turn off transaction mode for JS tests - https://github.com/teamcapybara/capybara#transactions-and-database-setup and https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example. In Rails 5.1+ the DB connection is shared between the app and tests so you can generally leave transactional testing enabled and database_cleaner is unneeded.

Thomas Walpole
  • 48,548
  • 5
  • 64
  • 78