tirdadc

Web Development | Ruby on Rails | React.js

Nested feature tests with Capybara and RSpec

I recently wrote some automated user acceptance tests with Capybara for a multi-step wizard, and the initial approach didn’t seem very DRY. I was rehashing the steps involved in previous scenarios to reach whatever step was currently being tested, and I was combining multiple expectations at various steps:

feature 'User creates a thing' do
  Capybara.javascript_driver = :poltergeist
  WebMock.disable_net_connect!(:allow_localhost => true)

  background do
    user_login
  end

  scenario 'Step 0: User signs in' do
    expect(page).to have_content('Signed in successfully.')
  end

    scenario 'Step 1: selects A, continues, reaches Step 2', :js => true do
    visit('/wizard/type')
    expect(page).to have_content('Step 1')
    find('.type-a').click
    find('.continue').click
    expect(page).to have_content('Step 2')
    end

    scenario 'Step 2: picks name, continues, reaches Step 3', :js => true do
    visit('/wizard/type')
    find('.type-a').click
    find('.continue').click
    expect(page).to have_content('Step 2')

    fill_in 'name', with: 'Funeralopolis'
    find('.continue').click
    expect(page).to have_content('Step 3')
    end
end

Thankfully you can nest features since the 2.2.1 version, which allows you to better separate the tests and setups while sequentially continuing from whatever state the previous test left you in:

feature 'User creates a thing' do
  Capybara.javascript_driver = :poltergeist
  WebMock.disable_net_connect!(:allow_localhost => true)

  background do
    user_login
  end

  scenario 'Step 0: User signs in' do
    expect(page).to have_content('Signed in successfully.')
  end

  feature 'Step 1: Type', :js => true do
    background do
      visit('/wizard/type')
    end

    scenario 'it is on Step 1' do
      expect(page).to have_content('Step 1')
    end

    feature 'it selects A, continues, reaches Step 2' do
      background do
        find('.type-a').click
        find('.continue').click
      end

      scenario 'it reaches Step 2' do
        expect(page).to have_content('Step 2')
      end

      feature 'Step 2: Name', :js => true do
        background do
          fill_in 'name', with: 'Funeralopolis'
          find('.continue').click
        end

        scenario 'it reaches Step 3' do
          expect(page).to have_content('Step 3')
        end
      end
    end
  end
end