Use of Pagy rubygem in Rails tests with MiniTest - ruby-on-rails

I have a Rails app that I have upgraded from Rails 6 to 7 app. In previous version I was using will_paginate gem (v. 3.3.1) and Bootstrap 3. Now I have decided to switch to pagy (v. 5.10.1).
I have followed the migration guide and made necessary changes. I have run the local server and everything is working fine.
However I am having problems with testing of pagination in my integration tests. I have tried writing the code as shown in the API documentation but I keep getting errors. I would appreciate any advice or guidance on this as I am fairly new learner of Rails and am having hard time figuring out why it is not working in test environment while everything in development is fine.
Thanks to everyone in advance for the time and help, I really appreciate the community here.
Below are extracts from my tests and controllers, where I have omitted some parts for brevity.
user_following_test.rb
test 'feed on Home page' do
get root_path
#pagy, #user = pagy(#user.feed, page: 1).each do |micropost|
assert_match CGI.escapeHTML(micropost.content), response.body
end
end
# Previous code that worked with will_paginate
# test 'feed on Home page' do
# get root_path
# #user.feed.paginate(page: 1).each do |micropost|
# assert_match CGI.escapeHTML(micropost.content), response.body
# end
# end
end
users_controller.rb
class UsersController < ApplicationController
...
def index
#pagy, #users = pagy(User.where(activated: true))
end
def show
#user = User.find(params[:id])
#pagy, #microposts = pagy(#user.microposts)
redirect_to(root_url) unless #user.activated?
end
My intention to check that show method in users controller is working as intended.
Result of running the test is a very long stack trace that ends with:
Did you mean? pagy_t
test/integration/following_test.rb:60:in `block in <class:FollowingTest>'

The pagy method is in the default configuration only available on the controller level, but not globally. You need to include Pagy::Backend to have it available in other classes.
I reckon the following might work:
include Pagy::Backend
test 'feed on Home page' do
get root_path
_pagy, microposts = pagy(#user.feed, page: 1)
microposts.each do |micropost|
assert_match CGI.escapeHTML(micropost.content), response.body
end
end

Related

Ruby on rails - Template missing prob

I am having a hard time solving this problem because this is my first time to learn ruby on rail, i have a index.html.erb, new.html.erb, show.html.erb, edit.html.erb files. So when i go to localhost:3000/blogs/edit page the page that is showing is show.html.erb and when i delete the show.html.erb then access the edit.html.erb im having a template missing error. but when i access localhost:3000/blogs/new or just localhost:3000/blogs its working fine.So here's my code inside blogs_controller.rb
class BlogsController < ApplicationController
def index
#content_first = 'This 1' ;
#content_two = 'This 2' ;
end
def new
end
def create
end
def edit
end
def update
end
def show
end
def destroy
end
end
I think your problem is that you're trying to access /blogs/edit , and the route is probably /blogs/edit/:id. As in you need to provide the id of a blog object, so that you can edit it.
If you run
rake routes
You will be able to see your available routes.
Hope this helps =)

Simple controller tests with rspec rails4

I was looking into some rspec testing lately and I was wondering how to properly test controllers. My controller is fairly simple so it shouldn't be something too hard:
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
# GET /users
def index
#q = User.search(params[:q])
#users = #q.result(distinct: true)
#q.build_condition if #q.conditions.empty?
#q.build_sort if #q.sorts.empty?
end
# GET /users/1
def show
end
# GET /users/new
def new
#user = User.new
end
# GET /users/1/edit
def edit
end
def archive
#q = User.search(params[:q])
#users = #q.result(distinct: true)
#q.build_condition if #q.conditions.empty?
#q.build_sort if #q.sorts.empty?
end
# POST /users
def create
#user = User.new(user_params)
if #user.save
redirect_to users_path, notice: 'Student was successfully added.'
else
render action: 'new'
end
end
# PATCH/PUT /users/1
def update
if #user.update(user_params)
redirect_to #user, notice: 'Student information was successfully updated.'
else
render action: 'edit'
end
end
# DELETE /users/1
def destroy
#user.destroy
redirect_to users_url, notice: 'Student information was successfully deleted.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def user_params
params.require(:user).permit(:firstName, :lastName, :email, :dateOfBirth, :notes, :sex, :archive, :category => [])
end
end
So far I have written 2-3 tests but I am not sure if they even do anything:
describe 'GET #index' do
it "displays all users" do
get :index
response.should be_redirect
end
end
describe 'GET #new' do
it "creates a new user" do
get :new
response.should be_redirect
end
end
I tried doing the same for edit and show but they didn't work and I am not sure why (because as I said, I don't know what I am doing).
Could anyone give me a few test examples for these methods or could redirect me to an rspec guide for rails4?
Are you expecting the controller #index action to redirect? Because that wouldn't be typical.
I would
describe 'GET #index' do
get 'index'
it {expect(response).to be_success)}
end
This line...
it "displays all users" do
in a controller spec makes me wonder if your confusing controller and request specs. I did this when I first got running with testing. "Displaying all users" sounds like a request spec to me. Testing if a page redirects or response status codes is more akin to controller specs.
I found http://betterspecs.org/ to be a really helpful resource in understanding testing better.
RE: WHAT to test
This worked for me but results may vary.
Controller Specs - Don't test controllers
Controllers should be skinny so you're just testing whether Rails is working. e.g. an index action may contain #users = User.all or similar and very little else. What is there to test there? Nothing. If you have lots of code in your controller actions then it probably shouldn't be there. Move it out to the models. Remember: Fat models, skinny controllers. This is an example of how testing creates better code. I have very few controller specs and I think nearly all of them are double checking authorisation to pages. I only use them where there's code in the controller. Here's an example:
context "Non admin signed in" do
before(:each) do
sign_in user
controller.stub!(:current_user).and_return(user)
end
it {subject.current_user.should_not be_nil}
it "deny non admin access to index" do
sign_in user
get 'index'
expect(response).to render_template("pages/access_denied")
end
end
Request Specs Test what you would test in a browser (20% of tests)
Imagine that you weren't doing RSpec testing. If you're like me then this is not too hard to imagine. How would you test the thing you want to build? Chances are that the first thing you'd do is load up a browser and see if something is on the page that you were expecting. That IS a request spec. It's that simple. Request specs are the automated ways of loading up a browser, clicking on a few buttons and checking what happened. Whatever it is your checking in the browser... check that same thing using Capybara. If it has Javascript on the page then you'll need Webkit or Selenium on top of Capybara to push the buttons as you would. With selenium you actually see the browser window pop up on the desktop as if a mysterious gremlin had taken control of your keyboard. Don't test anything in a request spec that you wouldn't be testing manually in a browser. That means don't check the state of other models in the database. Request specs are what the user can see. If you can't see it, don't test it.
Model specs - Test what you would test in the console (80% of tests)
Before I became a good TDD/BDD boy I found I spent a lot of time loading up irb or console and making models and doing X to see if Y would happen. Automate that thing. That's a model spec. When your request spec fails (which it should at first if it's doing anything useful) then drop down into the model spec. A failing request spec might be:
it {expect(page.find('#login_box')).to have_content 'Logged in as Kevin Monk'}
from
no method full_name for instance of User
And if you weren't a TDD good boy you might load up the console and find what was happening with the full_name method.
> rails console
$> kevin = User.find(1)
$> kevin.full_name
And then visually check that you get the full name baack but this should be done as a model spec.
I hope that helps. A problem I've had with a lot of books on testing is that the authors tend to be such experts and therefore don't appreciate that us mortals really need to understand the basic premise of what it is your supposed to be testing.
you have a typo in your spec code , you have to change respone, for response
I think that´s the problem
you can find more information in about test controllers in
https://www.relishapp.com/rspec/rspec-rails/docs/controller-specs
regards

`flash.discard` in Rails 2.3 fails because flash is a Hash, not a FlashHash

Given a functional test such as:
def test_exciting_rails_upgrades
login(m=users(:manager))
post :import_users_map_fields, :csv_file => fixture_file_upload('/users.csv', 'text/csv')
assert flash.empty?
flash.discard
# other goodies omitted
end
In Rails 2.3.2 there are no errors, however in 2.3.15 the error is:
NoMethodError: undefined method `discard' for {}:Hash
/test/functional/broken_upgrades.rb:119:in `test_exciting_rails_upgrades'
Why is flash a Hash class instead of a FlashHash?
From the source it looks like both 2.3.2 and 2.3.15 ActionPack files lib/action_controller/flash.rb create the FlashHash class and inherit from Hash. However what is shown in this functional test in both 2.3.2 and 2.3.15 is a Hash class, not a HashFlash, so one cannot call discard on it.
Can anyone else reproduce this error with 2.3.15 and flash.discard?
Here are two test cases you can use to prove ActionController changes the type of 'flash' depending on whether or not it is already set.
In my app, you cannot see :index unless you're logged in, so in test_flash_is_now_a_flashhash you see that flash was set by the backend properly, while in test_flash_is_a_plain_hash it was not.
def test_flash_is_a_plain_hash
login(users(:permitted_user))
get :index
assert flash.instance_of?(Hash)
end
def test_flash_is_now_a_flashhash
get :index
assert_redirected_to :controller => "login"
assert flash.instance_of?(ActionController::Flash::FlashHash)
end
You can see this for yourself in the ActionController::TestRequest code:
def flash
session['flash'] || {}
end
Update: This has been fixed in Rails branch 2-3-stable.

Rails respond_with & Rspec controllers: Testing unsuccessful update

I'm trying to switch from using respond_to to respond_with in Rails controllers. Everything's going smoothly, except for testing invalid saves in controller specs. Here's an example:
describe MyController do
...
describe "PUT update" do
context "with invalid attributes" do
it "should re-render the edit page" do
style = stub_model(Style)
Style.stub(:find) { style }
Style.any_instance.stub(:save).and_return(false)
put :update
response.should render_template(:edit)
end
end
end
end
This works just fine with my old respond_to style update action, but with respond_with, I get
Failure/Error: response.should render_template("edit")
So, in short - how do I test this? ...Or should I just assume render_with knows what it's doing and not test at all? Any general suggestions?
Cheers in advance
PS: The update action:
def update
#style = Style.find(params[:id])
flash[:notice] = "Style updated" if #style.update_attributes(params[:style])
respond_with(#style)
end
I've been looking into this exact thing (how I found this topic) - so far I have the following:
Location.any_instance.stub(:valid?).and_return(false)
Location.any_instance.stub(:errors).and_return('anything')
(where Location is my model that uses respond_with)
however I believe there must be a nicer way to do it - if I find it, I'll be sure to post it!
Note: I'm also using the responders gem so one of these lines may not be necessary for you if you're not using it!

Integration testing with Authlogic?

For the life of me I don't understand why Authlogic isn't logging me in in this integration test. I haven't had any problems w/ Authlogic logging me in in functional tests using this code. According to the authlogic rdocs (http://tinyurl.com/mb2fp2), simulating a logged-in state is the same in functional & integration tests, so i'm pretty confused. any help is MUCH appreciated!
class TipsController < ApplicationController
before_filter :require_user, :only => [:destroy, :undelete]
def destroy
#tip = Tip.find(params[:id])
if can_delete?(#tip)
#tip.destroy
set_flash("good", "Tip deleted. Undo?")
respond_to do |format|
format.html { redirect_to city_path(#tip.city)}
end
else
set_flash("bad", "Seems like you can't delete this tip, sorry.")
respond_to do |format|
format.html { render :action => "show", :id => #tip}
end
end
end
end
class DeleteTipAndRender < ActionController::IntegrationTest
context "log user in" do
setup do
#user = create_user
#tip = create_tip
end
context "delete tip" do
setup do
activate_authlogic
UserSession.create(#user)
#us = UserSession.find
post "/tips/destroy", :id => #tip.id
end
should_redirect_to("city_path(#tip.city)"){city_path(#tip.city)}
end
end
end
I'm also using Authlogic with Shoulda (but with factory_girl on top).
My functionnal tests look like :
require 'test_helper'
class LoansControllerTest < ActionController::TestCase
[...]
context "as a signed-in user, with an active loan" do
setup do
#user = Factory(:user)
#user_session = UserSession.create(#user)
#loan = Factory(:loan, :ownership => Factory(:ownership, :user => #user))
end
context "on GET to :index" do
setup do
get :index
end
should_respond_with_success
end
end
end
Actually, you CAN pass a valid user to UserSession, it's in the rdoc also.
You should also avoid calling activate_authlogic in each controller test :
ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
require 'test_help'
class ActiveSupport::TestCase
[...]
# Add more helper methods to be used by all tests here...
include Authlogic::TestCase
def setup
activate_authlogic
end
end
Based on the code in the user_sessions_controller create method, which takes a hash of the login credentials, I was able to make it work like this in my integration test:
UserSession.create(:email => 'someone#example.com', :password => 'password')
but not with:
UserSession.create(#user)
I've found that for integration tests I need to login via a post:
setup do
post 'user_session', :user_session => {:email => 'someone#example.com', :password => 'password'}
end
This sets up the session correctly, while the method mentioned above only works for me in functional tests.
Yeah, I found this week that with rspec: in functional specs you simulate log in just fine w/ UserSession.create(#user). But if you try that in an integration spec it doesn't work. In order to log in from integration specs I found I had to drive the forms (with webrat) which clearly will be a problem for things like Facebook and OpenID log in.
I couldn't make it work with the accepted answer, but was close. I had to add the exclamation sign to the end of the function:
UserSession.create!(#user)
It's working with Ruby v3.2.18 and Authlogic v3.4.2. Thanks for pointing me in the right direction though.
For the people who find this post in Google and the Greater Justice - you have to set persitence_token attribute in User model. E.g. you can call #user.reset_persistence_token! and everything just start working. :)
I'm using Cucumber and James' solution along with the following fix worked for me:
https://webrat.lighthouseapp.com/projects/10503/tickets/383-reset_session-and-webrat-dont-play-nicely-with-one-another
I had the same problem and I could fix it by manually logging in (as others have already answered)
Additionally I had to fix my cookie domain:
Rails uses www.example.com for its tests and since I set the cookie domain to a different value in my application.rb (via config.cookie_domain) the session cookie created after the login was not accessible from subsequent requests.
After setting the correct cookie domain, everything worked again.
Have a look at the rdoc.

Resources