Search code examples
ruby-on-railsrubyruby-on-rails-4rspecrspec-rails

Can an RSpec scenario example only have one assertion?


Update>

I was confusing the syntax here and 'scenario' is actually the example equivalent to 'it', containing multiple assertions. The original question assumes that the 'expect' statements are running as individual examples, whereas they are are actually multiple assertions for the 'scenario' example. See answer for full explanation.

====================================================================

I'm trying to configure a basic prototype with some simple feature specs for a home page. Rspec won't seem to run more than one of the three examples. Using rails 4.1.1 and rspec 3. Have tried changing many configurations in spec_helper.rb, including getting rid of the Spork config and setting it back to rails defaults. Following the syntax guideline from the rspec 3 docs https://www.relishapp.com/rspec/rspec-rails/v/3-0/docs/feature-specs/feature-spec

Any ideas? Can there only be one assertion per scenario with scenario specs?

===========================================

/spec/features/static_pages_spec.rb

require 'rails_helper'

feature "StaticPages" do

    scenario "Visit Home" do
        visit root_path

        expect(page).to have_text("Menu Mapper")
        expect(page).to have_title("Menu Mapper")
        expect(page).to have_content("Menu Mapper")
    end
end

========================================

/spec/helpers/spec_helper.rb

require 'rubygems'
require 'spork'

Spork.prefork do
  ENV["RAILS_ENV"] ||= 'test'
  require File.expand_path("../../config/environment", __FILE__)
  require 'rspec/rails'
  #require 'rspec/autorun'    

  Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
  ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)    

  RSpec.configure do |config|

    config.use_transactional_fixtures = true
    config.include FactoryGirl::Syntax::Methods
    config.fail_fast=false      

    config.run_all_when_everything_filtered = true

    if config.files_to_run.one?
      # Use the documentation formatter for detailed output,
      # unless a formatter has already been configured
      # (e.g. via a command-line flag).
      config.default_formatter = 'doc'
    end  

    # config.order = :random

    # Seed global randomization in this process using the `--seed` CLI option.
    # Setting this allows you to use `--seed` to deterministically reproduce
    # test failures related to randomization by passing the same `--seed` value
    # as the one that triggered the failure.
    Kernel.srand config.seed

    # rspec-expectations config goes here. You can use an alternate
    # assertion/expectation library such as wrong or the stdlib/minitest
    # assertions if you prefer.

    config.expect_with :rspec do |expectations|
      # Enable only the newer, non-monkey-patching expect syntax.
      # For more details, see:
      #   - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
      expectations.syntax = :expect
    end

    # rspec-mocks config goes here. You can use an alternate test double
    # library (such as bogus or mocha) by changing the `mock_with` option here.

    config.mock_with :rspec do |mocks|
    # Enable only the newer, non-monkey-patching expect syntax.
    # For more details, see:
    #   - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/

    mocks.syntax = :expect

      # Prevents you from mocking or stubbing a method that does not exist on
      # a real object. This is generally recommended.

      mocks.verify_partial_doubles = true
    end
  end
end

========================================

Houdini:menu-mapper Mike$ rspec spec/features

StaticPages
  Visit Home (FAILED - 1)

Failures:

  1) StaticPages Visit Home
     Failure/Error: expect(page).to have_title("Menu Mapper")
       expected "MenuMapper" to include "Menu Mapper"
     # ./spec/features/static_pages_spec.rb:9:in `block (2 levels) in <top (required)>'

Finished in 0.04204 seconds (files took 1.82 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/features/static_pages_spec.rb:5 # StaticPages Visit Home

Solution

  • Your spec (= feature) only has one example (= scenario). That example has three expectations (= assertions). (You may want to edit your title and question to clarify the terminology.) When an expectation in an example fails, it raises an exception, and subsequent expectations never get a chance to run. That's just the way RSpec works. (It has nothing to do with whether you're using Capybara.) It's not a big deal if this behavior hides that one of the subsequent expectations would have failed; you'll find out as soon as you fix the first one and run the example again.

    I recommend writing specs in the way that you have. Writing a separate spec for every expectation results in harder-to-read specs, because rspec's DSL was not designed to write specs efficiently or clearly with only one expectation per spec, and it results in more examples which makes your test suite slower.

    Side note: Capybara's have_content and have_text are the same, so you only need one of those expectations.