Search code examples
ruby-on-railstestunit

Trouble with Rails controller (integration?) test


I'm making my first Rails app, so this is probably basic.

In my user profiles, I want to let users add a title and description. I made them attributes of the User model and added this to routes.rb:

  resources :users do
    member do
      post 'update_description'
    end
  end

The same method (not written yet) would handle both attributes. To practice TDD, I wanted to write a test that would simply show that, if the user submits a title, then the controller saves it to the database. I thought that would be an integration test, but I couldn't get the path right. (Should it be an integration test?) But then, with research, I managed to write a working post statement in a related controller test file. Here's the controller test:

  test "profile submits new title and description successfully" do
    log_in_as(@user)
    get :show, id: @user
    assert_nil @user.title
    post :update_description, id: @user, params: { title: "Lorem ipsum" }
    # Next:
    # @admin.reload.title
    # assert @admin.title == "Lorem ipsum"
    # assert_template 'users/show'
    # Etc.

  end

This raises the following error:

ERROR["test_profile_submits_new_title_and_description_successfully", UsersControllerTest, 2017-10-22 21:42:52 -0400]
 test_profile_submits_new_title_and_description_successfully#UsersControllerTest (1508722972.17s)
ActionView::MissingTemplate:         ActionView::MissingTemplate: Missing template users/update_description, application/update_description with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :jbuilder]}. Searched in:
          * "/var/lib/gems/2.3.0/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates"
          * "/home/globewalldesk/startthis/app/views"
          * "/var/lib/gems/2.3.0/gems/web-console-2.0.0.beta3/app/views"

            test/controllers/users_controller_test.rb:83:in `block in <class:UsersControllerTest>'
        test/controllers/users_controller_test.rb:83:in `block in <class:UsersControllerTest>'

I gather that this means Rails is looking for a view file and can't find one, but I don't see why post :update_description has it looking for a view...I thought it would be posting info without a view (I have a similar route that works the same way with no view). The update_description method is in the Users controller. I've done a lot of research but I cannot figure out what am I doing wrong. Help! TIA.


Solution

  • The way you write test it looks as a Integration test. But I personally would advice to write a System test. Because I see you create a update_descriptionmember route just to update User object? Thats not necessary - your Userresource has edit and update actions already, so you can remove that member route.

    Integration testing used to check workflows and how interacts different parts of the app. While System check is for user interactions - basically you check things that user would do and see in his browser. Also it appears to me much simpler to write test in this technique (at least at this level).

    So your system test would look like:

    setup do
      log_in_as(@user) // or what ever code to visit login page and login user
    end
    
    test "profile submits new title successfully" do
      visit edit_user_path
    
      fill_in "Title", with: "Lorem ipsum"
    
      click_on "Save"
    
      assert_response :redirect
      follow_redirect!
      assert_select "Title", text: "Lorem ipsum"
    end
    

    This assumes that after user submits his form, app redirects to user_path(@user) (show page).

    And Integration test would look something like:

    test "profile submits new title successfully" do
      log_in_as(@user) // or what ever code to login user
      get "/user/#{@user.id}/edit"
      assert_response :success
    
      updated_title = "Lorem ipsum"
    
      patch :update, user: { id: @user.id, title: updated_title }
    
      assert_response :redirect
      follow_redirect!
      assert_response :success
      assert_select "Title", text: "Lorem ipsum"
    end
    

    Note - I haven't tested this and I use Capybara and other tools, but not Minitest. But in this simple this should work I think.

    And check the docs if you havent done that yet..