2
votes

I'm a Ruby on Rails developer and I was testing a fairly simple Rails application using RSpec. I was writing some Routing specs and then I faced this problem:

My routes are like this:

Rails.application.routes.draw do
  root 'trip_plans#index'
  resources :trip_plans
end

So I have a route like post /trip_plans for creating new plans and triggering the trip_plans#create action.

My Routing spec file spec/routing/trip_plans_spec.rb looks like this:

require 'rails_helper'

RSpec.describe 'trip_plans routes', type: :routing do
  describe 'creating a new plan' do
    it 'creates a new plan on post in /trip_plans' do
      expect(post: '/trip_plans').to route_to(controller: 'trip_plans', action: 'create', title: 'New Plan', day: '3')
    end
  end
end

Now I need to somehow pass the params title: 'New Plan', day: '3' to my expect(post: '/trip_plans') so it seems like a real user is filling in the forms and hitting submit.

How do I pass params for POST requests to my RSpec Routing spec?

Thanks in advance!

1
I would recommend writing feature specs for these types of tests. IMO a feature spec is a perfect way to validate routing, controller actions and screen flow.steve klein

1 Answers

0
votes

Routing specs don't often add much value. In a routing spec you simply test that a certain route matches the correct controller. The controller is never actually called.

Instead what you can use are controller specs which are used to test how your application responds to user input:

# spec/controllers/trip_plans_controller_spec.rb
RSpec.describe TripPlansController, type: :controller do

  let(:valid_params) do
    {
        title: 'New Plan',
        day: '3'
    }
  end

  let(:invalid_params) do
    {
        day: 'xxx'
    }
  end

  describe 'POST #create' do

    let(:action) { post :create, valid_params }
    context 'with valid attributes' do
      it 'creates a new post' do
        expect { action }.to change(Post, :count).by(+1)
      end
      it 'has the correct attrributes' do
        action
        expect(assigns(:trip_plan).title).to eq 'New Plan'
        expect(assigns(:trip_plan).day).to eq 3
      end
    end

    context 'with invalid attributes' do
      let(:action) { post :create, invalid_params }

      it 'does not create a new post' do
        expect { action }.to_not change(Post, :count)
      end

      it 'renders the new template' do
        action
        expect(response).to render_template :new
      end
    end
  end
end

and feature specs which are end to end specs which test the actual user experience:

RSpec.feature 'Trip Plans' do
  context 'as a User' do
    scenario 'I should be able to create a trip plan' do
      visit root_path
      click_link 'Create a new trip plan'
      fill_in 'Title', with: 'Go west'
      fill_in 'Day', with: 5
      click_button 'Create trip plan'
      expect(page).to have_content 'Trip plan created.'
      expect(page).to have_content 'Go west'
    end
  end
end

Controller specs are very useful for testing exactly how your controller responds to params and where you write actual expectations on the database state.

Feature specs are nice since they cover your views as well and well written specs also guarantee that your user paths are accessible. However they often do not catch errors which are not readily apparent from the front end and are slower, since you often need to render several pages to get to the actual meat of the test.

The stack trace or error message from feature specs is often less useful than lower level specs.

A good test suite is usually made of a combination of model specs, controller specs and feature specs which cover the most important paths through the application.