ga-wdi-boston / capstone-project

Other
3 stars 28 forks source link

Handling ownership in RSpec tests #543

Open samordonez opened 7 years ago

samordonez commented 7 years ago

I am writing (read: editing the automatically generated) tests for my join table and am unsure how to handle user ownership in the tests. I have started to write some methods to first create the user and dataset, and I think I can manage for the request, but I'm unsure about the controller tests. Basically I am unsure how to get a token for the actions that need to be authenticated.

I imagine I can do something like what is being done in the request specs:

    def headers
      {
        'HTTP_AUTHORIZATION' => "Token token=#{@token}"
      }
    end

    before(:each) do
      post '/sign-up', params: { credentials: user_params }
      post '/sign-in', params: { credentials: user_params }

      @token = JSON.parse(response.body)['user']['token']
      @user_id = JSON.parse(response.body)['user']['id']
    end

But it is not clear to me that I can get to the sign up and in routes from the controller spec. I haven't tried this yet and it is time for me to stop for the night, but I wanted to ask this so that I might get some insight to start working on it in the morning.

raq929 commented 7 years ago

https://duckduckgo.com/?q=rails+mock+authenticated+user&atb=v38-4au&ia=qa

samordonez commented 7 years ago

All of the results I can find seem to be for older versions of ruby or rspec. I was aware that there would be errors because I hadn't added the relationships in the models yet. However, now that I have added those relationships, I think there is a problem with this

  before(:all) do
    Dataset.create!(dataset_params)
    @user = User.create!(user_params)
    @user.visualizations.build(visualization_params)
  end

because I am getting an empty response from get requests, even though it should have built a visualization.

I am probably going to move on and get my app to a point that meets requirements and try to finish these tests later if I can't solve this before 11.

samordonez commented 7 years ago

Another update: I can get the request tests to work with the authentication methods in the original post, I ha to use create! instead of build, I forgot that build doesn't save the record. I also had to add perhaps excessive deletions of users, datasets, and visualizations because I guess the tests don't all run in the order I thought they did, and the same user params are being used in several places.

Now I am wondering how to get the controller tests working, since it tries to go to the sign-up action on the VisualizationsController instead of the user Controller.

raq929 commented 7 years ago

Post the test that's doing that plz.

samordonez commented 7 years ago
RSpec.describe VisualizationsController, type: :controller do

  # This should return the minimal set of attributes required to create a valid
  # Visualization. As you add validations to Visualization, be sure to
  # adjust the attributes here as well.
  def valid_attributes
    {
      dataset_id: 1,
      color: '#000000',
    }
  end

  def invalid_attributes
    {
      dataset_id: 'hi',
      color: 704,
    }
  end

  def dataset_params
    {
      name: 'Property Assessment',
      year: 2017,
      resource: '9a4b1173-89ac-4a01-93e7-661eeb81ba16'
    }
  end

  def user_params
    {
      email: 'alice@example.com',
      password: 'foobarbaz',
      password_confirmation: 'foobarbaz'
    }
  end

  before(:all) do
    User.delete_all
    @user = User.create!(user_params)
    Dataset.create!(dataset_params)
  end

  after(:all) do
    User.delete_all
    Visualization.delete_all
    Dataset.delete_all
  end

  def headers
    {
      'HTTP_AUTHORIZATION' => "Token token=#{@token}"
    }
  end

  before(:each) do
    post '/sign-up', params: { credentials: user_params }
    post '/sign-in', params: { credentials: user_params }

    @token = JSON.parse(response.body)['user']['token']
    @user_id = JSON.parse(response.body)['user']['id']
  end

  describe 'GET #index' do
    it 'assigns all visualizations as @visualizations' do
      visualization = @user.visualizations.build(valid_attributes)
      get :index, params: {}, session: valid_session
      expect(assigns(:visualizations)).to eq([visualization])
    end
  end

  describe 'GET #show' do
    it 'assigns the requested visualization as @visualization' do
      visualization = @user.visualizations.build(valid_attributes)
      get :show, params: { id: visualization.to_param }, session: valid_session
      expect(assigns(:visualization)).to eq(visualization)
    end
  end
raq929 commented 7 years ago

http://stackoverflow.com/questions/3768718/rails-rspec-make-tests-pass-with-http-basic-authentication

samordonez commented 7 years ago

I created a new auth_helper.rb file with the following code and included the modules in the necessary specs:

auth_helper.rb:

# frozen_string_literal: true

# auth helper for controller tests
module AuthHelper
  def http_login
    user = 'username'
    pw = 'password'
    request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(user,pw)
  end
end

# auth helper for request specs
module AuthRequestHelper
  #
  # pass the @env along with your request, eg:
  #
  # GET '/labels', {}, @env
  #
  def http_login
    @env ||= {}
    user = 'username'
    pw = 'password'
    @env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(user,pw)
  end
end

When I try to run the tests I get this error

      Failure/Error: request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(user,pw)

      NoMethodError:
        undefined method `env' for nil:NilClass

Here is how I use the helper:

  before(:all) do
    http_login
    # User.delete_all
    # @user = User.create!(user_params)
    Dataset.create!(dataset_params)
  end
raq929 commented 7 years ago

I suspect you will need to modify this line of code to work with our auth controller: request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(user,pw)

gaand commented 7 years ago

Does this help ❓

https://github.com/ga-wdi-boston/rails-api-template/blob/master/spec/requests/users_spec.rb

samordonez commented 7 years ago

For the sake of transparency, I want to note here that I decided yesterday to leave fixing this test until after the presentation.

jrhorn424 commented 7 years ago

@Sofistication Would you like to leave this open? Is this still a goal for you over the next couple of weeks?

samordonez commented 7 years ago

I will leave this one open since I do plan to look at it in the next week and don't have a workaround yet.

gaand commented 7 years ago

@Sofistication Did you look at the file i referenced? Does that look like it will help?

samordonez commented 7 years ago

I had a look briefly and I think it could help. I'll update once I have made an attempt, which will likely happen tonight.

samordonez commented 7 years ago

I ot back to this later than I had planned, but I have made some changes and am now getting the following error:

     Failure/Error: post '/sign-up', params: { credentials: user_params }

     RuntimeError:
       @routes is nil: make sure you set it in your test's setup method.
     # ./spec/auth_helper.rb:6:in `http_login'
     # ./spec/controllers/visualizations_controller_spec.rb:59:in `block (2 levels) in <top (required)>'

The http_login method now looks like:

def http_login
    post '/sign-up', params: { credentials: user_params }
    post '/sign-in', params: { credentials: user_params }

    @token = JSON.parse(response.body)['user']['token']
    request.env['HTTP_AUTHORIZATION'] = "Token token=#{@token}"
  end

  def user_params
    {
      email: 'alice@example.com',
      password: 'foobarbaz',
      password_confirmation: 'foobarbaz'
    }
  end

The error seems to indicate that it doesn't know what routes exist when it call http_login but I am not sure why that would be.