i'm a beginner in ruby on rails(and english :)), and i'm trying to use functional test but i had an error at fist
1)Error:
test_should_get_new(MicropostControllerTest)
NoMethodError: undefined method 'microposts' for nil:NilClass
My micropost_controller_test.rb
require 'test_helper'
class MicropostControllerTest < ActionController::TestCase
test "should get new" do
get :new
assert_response :success
end
end
My micropost_controller.rb
class MicropostController < ApplicationController
def new
#post = Micropost.new
#posts = current_user.microposts.all
end
def create
#post = current_user.microposts.create(:content => params[:content])
logger.debug "New post: #{#post.attributes.inspect}"
logger.debug "Post should be valid: #{#post.valid?}"
if #post
redirect_to micropost_new_path
else
end
end
end
I tried to put something in microposts.yml but it didn't work.
So, where i can find microposts method for functional test and how do i fix that?? Please help me?
p/s: My app still work in localhost
If you are using Devise for user authentication then you need to authenticate and set current_user in your MicropostController, by for instance having a before_action as follows:
class MicropostController < ApplicationController
before_action :authenticate_user!
def new
#post = Micropost.new
#posts = current_user.microposts.all
end
# rest of the code
end
In your test you need to import devise test helpers as follows, if you haven't done it in your test_helper
class MicropostControllerTest < ActionController::TestCase
include Devise::TestHelpers
end
You can then use the sign_in method to sign in a user using Fixtures in your test. search for some tutorials on that or check the response here to get some clue: Functional testing with Rails and Devise. What to put in my fixtures?
Related
Using Rails 6, I'm redirecting from native ids (/users/id) to friendly_ids (/users/username) (following the answer brought here) which handles the redirect as such:
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
def redirect_resource_if_not_latest_friendly_id(resource)
if resource.friendly_id != params[:id]
redirect_to resource, status: 301
end
end
end
In my controller, I call the method as such:
# app/controllers/users_controller.rb
class UsersController < ApplicationController
before_action :set_user, only: [:show]
def show
redirect_resource_if_not_latest_friendly_id(set_user)
end
protected
def set_user
#user = User.friendly.find(params[:id])
end
end
It's working fine and I want to include the redirection in my test suite. I found answer and topics about how to do that with Rspec but I'm using Minitest and couldn't figure it out.
I tried a bunch of different ways (with params[:id], etc.) but to keep it simple let's say it's the following fixture, test and result.
Here is the fixture:
# test/fixtures/users.yml
one:
username: username
email: email#example.com
slug: username
Here is the test:
# test/controllers/users_controller_test.rb
class UsersControllerTest < ActionDispatch::IntegrationTest
test "should 301 redirect to the friendly_id" do
#user = users(:one)
get user_path(#user)
assert_redirected_to "/users/#{#user.slug}"
end
end
Here is the result of the test:
FAIL["test_should_301_redirect_to_the_friendly_id", #<Minitest::Reporters::Suite:0x00007fe716c66600 #name="UsersControllerTest">, 0.7785789999979897]
test_should_301_redirect_to_the_friendly_id#UsersControllerTest (0.78s)
Expected response to be a <3XX: redirect>, but was a <200: OK>
test/controllers/users_controller_test.rb:8:in `block in <class:UsersControllerTest>'
What am I doing wrong?
The problem is you're using the "whole" user record to make the request, so when you do
user_path(#user)
The route extracts the friendly_id from the resource and then your condition is evaluated to false, because the resource.friendly_id is always going to be the same as the id coming from the params.
Try instead:
get user_path(id: #user.id)
That way you can explicitly pass the #user.id through the params.
possible the problem resource.friendly_id != params[:id] as I understood they are the same
My RSpec test failed but I couldn't figure out how I could fix that. Calling .all method on the Class pass but it fails with associations.
Error Message
0) CustomerDetail #index when logged in should render customer details index page
Failure/Error: #customer_details = current_shop.customer_details.load
NoMethodError:
undefined method `customer_details' for nil:NilClass
# ./app/controllers/customer_details_controller.rb:9:in `index'
ApplicationController
class ApplicationController < ActionController::Base
layout 'embedded_app'
def current_shop
#current_shop ||= Shop.find_by(shopify_domain: cookies[:shopify_domain])
end
end
Here is the Controller
class CustomerDetailsController < ApplicationController
before_action :authenticate_user!
def index
# This failed the test below and complains that NoMethodError: undefined method 'customer_details' for nil:NilClass
#customer_details = current_shop.customer_details.load
#This pass the test below
#customer_details = CustomerDetail.all.load
end
end
Models
class Shop < ActiveRecord::Base
include ShopifyApp::SessionStorage
has_many :customer_details
def api_version
ShopifyApp.configuration.api_version
end
end
class CustomerDetail < ApplicationRecord
belongs_to :shop
end
RSpec
context 'when logged in' do
before do
#shop = create(:shop)
#user = create(:user)
sign_in #user
end
it 'should return a 200 response' do
get customer_details_index_path
expect(response).to have_http_status '200'
end
it 'should render customer details index page' do
get customer_details_index_path
expect(response).to render_template(:index)
end
end
Any help will be appreciated.
current_shop is nil in your controller. It's not enough that you set shop in your spec code. Instance variables from specs are not shared with a controller under test.
Ensure that the shop you're creating in
#shop = create(:shop)
has field shopify_domain set to whatever value has cookies[:shopify_domain] in your test request.
Simple example that by all accounts should work:
require 'test_helper'
class FoosController < ApplicationController
def index
render plain: 'something'
end
end
class UsersControllerTest < ActionDispatch::IntegrationTest
def test_some_routing
with_routing do |set|
set.draw do
get '/foos' => 'foos#index'
end
get '/foos'
assert_equal 200, response.status
end
end
end
Instead I'm getting: ActionController::RoutingError: No route matches [GET] "/foos"
What am I doing wrong? This is latest Rails 4.1 btw.
For those who come here seeking a solution to test their controller concerns in isolation (like I did), it may pay to use setup and teardown blocks instead of littering your code with with_routing blocks:
require 'test_helper'
class ConcernedController < ApplicationController
include Concern
def action
render plain: "response", status: :ok
end
end
class ConcernTest < ActionDispatch::IntegrationTest
setup do
#controller = ConcernedController.new
Rails.application.routes.draw do
get "/action" => "concerned#action"
post "/action" => "concerned#action"
end
end
teardown do
Rails.application.reload_routes!
end
test "concern method" do
post "/action"
# Test what the concern does
assert_response :ok
assert_equal "Response", response.body
end
end
Tested against Rails 5.0.2.
Ok, so I'm answering my own questions again. Problem is that with_routing doesn't work at all inside integration tests. Oversight or something, not sure. It only works for controller tests. So here's the work around:
class ActionDispatch::IntegrationTest
def with_routing(&block)
yield ComfortableMexicanSofa::Application.routes
ensure
ComfortableMexicanSofa::Application.routes_reloader.reload!
end
end
Basically you will redefine your application routes within that block and then reload them back from the routes.rb file.
-- edited --
We can have a block with new routes by defining a new method like:
def with_foo_route
Rails.application.routes.draw do
get 'foo' => 'foo#index'
end
yield
Rails.application.routes_reloader.reload!
end
And then execute a get requests to this new route by:
with_foo_route do
get '/foo'
assert_equal 200, status
end
I'm doing an authentication application. I have this code
class UsersController < ApplicationController
def new
#user = User.new
#title = "User Sign Up"
end
def create
#user = User.new(params[:user])
sign_in_check #user
if #user.save
#flash[:status] = true
#flash[:alert] = "You have successfully signed up!!"
#sign_in_check #user
redirect_to root_path, :flash => { :success => "Welcome to the Bakeshop"}
else
#title = "User Sign Up"
render 'new'
end
end
end
This is a simple sign-up code, and whenever I try and sign up, rails returns an error:
undefined method `sign_in_check' for #<UsersController:0x68c0a90>
but I defined a method sign_in_check in my Users_helper.rb:
module UsersHelper
def sign_in_check(user)
#some stuff to enable session
end
end
Does anyone have an idea why this is happening, and how to fix it?
The reason is your method is a helper. Helpers will be available in views with matching name by default, but not open to controllers without setting.
Two ways to fix:
Allow this helper in UsersController
class UsersController < ApplicationController
helper :user #This will expose UsersHelper module to UsersController
Instead, put this method into ApplicationController. I would prefer this due to the method's nature.
Include your UserHelper in your UserController as follows and you should be able to use any methods defined within the helper.
class UsersController < ApplicationController
include UsersHelper
...
end
This is usually put in the application controller
class ApplicationController < ActionController::Base
def sign_in_check(user)
#some stuff to enable session
end
end
Helpers are used for views. If you want to use it in both - you can do that, but that doesn't sound like what you're looking for here.
just include your helper module in your controller
class UsersController < ApplicationController
helper :user
...
end
Thanks
View spec failing because the ApplicationController method, logged_in?, wants a user to be returned.
Not sure how to spec this. Currently in before(:each) I have:
controller.stub!(:logged_in?).and_return(FactoryGirl.create(:active_user))
#ballots = FactoryGirl.create_list(:full_ballot, 2)
which isn't working:
Failure/Error: render
ActionView::Template::Error:
undefined method 'logged_in?' for #<#<Class:0x007f9c908e4b10>:0x007f9c90873b68>
FWIW: :active_user is the user factory for the user that is attached to the :full_ballot
Update: As requested:
class ApplicationController < ActionController::Base
...
def current_user
#current_user ||= User.find(cookies[:id_token]) if cookies[:id_token]
end
def logged_in?
current_user
end
...
end
See how devise test helpers do it. It looks like you can define this method before tests and it should work:
def logged_in?
FactoryGirl.create :active_user
end