4

I am testing a controller method for creating new orders (e-commerce-like app). If user is present in the system, he should be redirected to new_user_session_path, else to new_order_path. Simple as that.

This is my orders_controller.rb

def new
        if !User.where(phone: params[:phone]).blank? && !user_signed_in?

            redirect_to new_user_session_path()
            flash[:info] = "Already present"
        else
            @order = Order.new
            @menu = Menu.find(params[:menu_id])
            @menu_price = @menu.calculate_price(@menu, params)
        end
    end

In my app, I need the calculate_price method to be called, because it calculates the overall price given the params. But in my test, I just want to ensure, that the redirect is correct.

Right now I'm getting errors like (they are sourced inside the Menu.rb file, since calculate_price is called) :

Front::OrdersController#new redirects user to new order page if user is not present in the system
     Failure/Error: menu_price_change = menu_amount.split(",")[1].gsub(" ","").gsub("]",'')

     NoMethodError:
       undefined method `split' for nil:NilClass

This is my spec file:

require 'rails_helper'


describe Front::OrdersController, type: :controller do
    describe '#new' do
        # Set up dummy menu
        let (:menu) { Menu.create() }

        it "redirects user to sign up page if user is present in the system" do
            user = User.create(name: "Bob", password: "bobspassword", phone: "+7 (903) 227-8874")

            get :new, params: { phone: user.phone }
            expect(response).to redirect_to(new_user_session_path(phone: user.phone))
        end

        it "redirects user to new order page if user is not present in the system" do
            non_present_phone = "+7 (903) 227-8874"    
            get :new, params: { phone: non_present_phone, menu_id: menu.id}
            expect(response).to redirect_to(new_order_path)
        end

    end
end

Of course I could provide all the params, but there is a pretty big amount of them and besides, I just want to test the correct redirect. As far as I know, mocks and subs are useful in this case, when you want to explicitly test the methods. But in my case, I want to - somehow - omit them. How can I ensure that behaviour?

mohnstrudel
  • 639
  • 8
  • 22

1 Answers1

5

So you want just to test redirects and the errors occured when calculate_price method executes bother you. Why don't you just stub that method? Your spec file might be like this:

require 'rails_helper'


describe Front::OrdersController, type: :controller do
    describe '#new' do
        # Set up dummy menu
        let (:menu) { Menu.create() }

        # Check this out
        before do
          allow_any_instance_of(Menu).to receive(:calculate_price)
          # or if you need certain value
          allow_any_instance_of(Menu).to receive(:calculate_price).and_return(your_value)
        end

        it "redirects user to sign up page if user is present in the system" do
            user = User.create(name: "Bob", password: "bobspassword", phone: "+7 (903) 227-8874")

            get :new, params: { phone: user.phone }
            expect(response).to redirect_to(new_user_session_path(phone: user.phone))
        end

        it "redirects user to new order page if user is not present in the system" do
            non_present_phone = "+7 (903) 227-8874"    
            get :new, params: { phone: non_present_phone, menu_id: menu.id}
            expect(response).to redirect_to(new_order_path)
        end

    end
end
VAD
  • 2,351
  • 4
  • 20
  • 32
  • Thanks! I was trying some different syntaxes, e.g. `Menu.any_instance.stub(:date).and_return("")`, but yours works like a charm! – mohnstrudel Jan 22 '17 at 15:54
  • For the great justice `allow_any_instance_of` is not the best solution. It's just lighweight option. To make things more classy create `Menu` instance, make the request using it's ID as `params['menu_id']` (you have it already). And then stub `calculate_price` method calling not on any instance of `Menu`, but on your `Menu` instance exactly. It can make little more trouble for you but it would be better option anyway. – VAD Jan 22 '17 at 16:09