Keep your tests clean

29 Sep 2014

Consider the following example. This test adds a product to our shopping cart and expects a confirmation message after checkout.

let(:mug) { Mug.create(name: 'Simple Mug') }

scenario 'user checkout with credit card' do
  visit root_path
  click_link mug.name
  click_button 'Add to cart'
  click_button 'Checkout'

  fill_in 'order_email', with: 'bob@example.com'
  click_button 'Continue'

  fill_in 'address_firstname', :with => 'Javier'
  fill_in 'address_lastname', :with => 'Saldana'
  fill_in 'address_address1', :with => '204 Some St'
  fill_in 'address_city', :with => 'Los Angeles'
  select country.name, :from => 'address_country_id'
  select state.name, :from => 'address_state_id'
  fill_in 'address_zipcode', :with => '90001'
  fill_in 'address_phone', :with => '(555) 555-5555'
  click_button 'Save and Continue'

  choose 'UPS Ground'
  click_button 'Save and Continue'

  choose 'Credit Card'
  fill_in 'Name On Card', :with => 'Javier Saldana'
  fill_in 'Card Number', :with => '4242424242424242'
  select '4', :from => 'card_month'
  select (Date.today.year + 1), from: 'card_year'
  fill_in 'Card Code', :with => '123'
  click_button 'Save and Continue'

  expect(page).to have_text('Your order has been processed successfully')
end

Not that bad but too many details are obscuring the intent of the test. We can extract this noise to separate methods in order to keep our tests clean and readable.

Take a look at the improved test.

scenario 'user checkout with credit card' do
  add_mug_to_cart
  click_button 'Checkout'

  fill_in 'order_email', with: 'bob@example.com'
  click_button 'Continue'

  fill_in_address
  fill_in_delivery
  fill_in_payment

  expect(page).to have_text('Your order has been processed successfully')
end

You can easily see what’s going on.

Credits to Spree for the test.