Reference

https://thoughtbot.com/upcase/test-driven-rails-resources/rspec_acceptance.pdf

#Basic Structure

Feature

feature accepts a string and is used to give an overview of the overall behavior.

RSpec.feature 'Signing in' do

end

Scenario

scenario accepts a string and outlines a particular scenario of the feature.

RSpec.feature 'Signing in' do
  scenario 'signs the user in successfully with a valid email and password' do
  end
  scenario 'notifies the user if his email or password is invalid' do
  end
end

Example Scenarios

RSpec.feature 'Signing in' do
  scenario 'signs the user in successfully with a valid email and password' do
    create :user, email: 'person@example.com', password: 'password' visit sign_in_path
    fill_in 'Email', with: 'person@example.com'
    fill_in 'Password', with: 'password'
    click_button 'Sign In'
    expect(page).to have_css 'nav .greeting', text: 'Welcome, person@example.com'
  end

  scenario 'notifies the user if his email or password is invalid' do
    create :user, email: 'person@example.com', password: 'password'
    visit sign_in_path
    fill_in 'Email', with: 'person@example.com'
    fill_in 'Password', with: 'wrong password'
    click_button 'Sign In'
    expect(page).to have_css '.flash.notice', text: 'Invalid email or password'
  end
end

Refactoring Scenarios

Identify common code and extract to methods (or use background). By moving as much Capybara interaction to well-named methods, intention becomes clear and the test becomes more about behavior than syntax.

RSpec.feature 'Signing in' do
  background do
    create :user, email: 'person@example.com', password: 'password'
  end
  scenario 'signs the user in successfully with a valid email and password' do
    sign_in_with 'person@example.com', 'password'
    user_sees_welcome_message 'Welcome, person@example.com'
  end
  scenario 'notifies the user if his email or password is invalid' do
    sign_in_with user.email, 'wrong password'
    user_sees_notice 'Invalid email or password'
  end
  def sign_in_with(email, password)
    visit sign_in_path
    fill_in 'Email', with: email
    fill_in 'Password', with: password
    click_button 'Sign In'
  end
  def user_sees_notice(text)
    expect(page).to have_css '.flash.notice', text: text
  end
  def user_sees_welcome_message(text)
    expect(page).to have_css 'nav .greeting', text: text
  end
end

Refactoring to Modules

Because RSpec acceptance tests are Ruby, modules can be included within RSpec to add methods. Extract methods which will be helpful in more than one feature.

# spec/features/sign_in_spec.rb
feature 'Sign in' do
  scenario 'signs the user in successfully with a valid email and password' do
    create :user, email: 'person@example.com', password: 'password'
    sign_in_with 'person@example.com', 'password'
    user_sees_welcome_message 'Welcome, person@example.com'
  end
  scenario 'notifies the user if his email or password is invalid' do
    create :user, email: 'person@example.com', password: 'password'
    sign_in_with 'person@example.com', 'wrong password'
    user_sees_notice 'Invalid email or password'
  end
  def user_sees_welcome_message(text)
    expect(page).to have_css 'nav .greeting', text: text
  end
end
# spec/support/features/sign_in_helpers.rb
module Features
  def sign_in_with(email, password)
    visit sign_in_path
    fill_in 'Email', with: email
    fill_in 'Password', with: password
    click_button 'Sign In'
  end
end
# spec/support/features/notice_helpers.rb
module Features
  def user_sees_notice(text)
    expect(page).to have_css '.flash.notice', text: text
  end
end
# spec/spec_helper.rb
RSpec.configure do |config|
  config.include Features, type: :feature
end

JavaScript-Enabled Tests

JavaScript can be enabled at the feature or scenario level.

```ruby feature ‘Viewing comments’, js: true do end

or

feature ‘Viewing comments’ do scenario ‘displays pertinent information’, js: true do end end