Running unit tests on controllers fails before started - ruby-on-rails

Just started to learn Ruby and Rails and currently have I created a controller to authenticate a user and provide a token. It works perfect doing monkey testing (clicking around and postman), but when doing testing with this command:
rails test
will even this test fail:
require 'test_helper'
class UserControllerTest < ActionDispatch::IntegrationTest
test "should be true" do
assert true
end
end
It will output this in the terminal:
Error:
UserControllerTest#test_should_be_true:
ActiveRecord::StatementInvalid: SQLite3::ConstraintException: NOT
NULL constraint failed: users.email: INSERT INTO "users" ("created_at",
"updated_at", "id") VALUES ('2017-03-18 11:11:35.973444', '2017-03-18 11:11:35.973444', 980190962)
Can't see what the problem should be. Because if I try to create a unit test inside the a ActiveSupport:TestCase will it fail with same output.
Can anyone tell me why it does this?
Obs!
If you need more information about the user controller just post a comment. Thanks.
Edit
In my applicationcontroller have this code:
class ApplicationController < ActionController::Base
require 'json_web_token'
protect_from_forgery with: :exception
protected
def authenticate_request!
if !payload || !JsonWebToken.valid_payload(payload.first)
return invalid_authentication
end
load_current_user!
invalid_authentication unless #current_user
end
def invalid_authentication
render json: { error: 'Invalid Request'}, status: :unauthorized
end
private
def payload
auth_header = request.headers['Authorization']
token = auth_header.split(' ').last
JsonWebToken.decode(token)
rescue
nil
end
def load_current_user!
#current_user = User.find_by(id: payload[0]['user_id'])
end
end
My test settings under config/environments/test.rb
Rails.application.configure do
config.cache_classes = true
config.eager_load = false
config.public_file_server.enabled = true
config.public_file_server.headers = {
'Cache-Control' => 'public, max-age=3600'
}
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
config.action_dispatch.show_exceptions = false
config.action_controller.allow_forgery_protection = false
config.action_mailer.perform_caching = false
config.action_mailer.delivery_method = :test
config.active_support.deprecation = :stderr
config.action_controller.allow_forgery_protection = false
end

The problem is probably in your test/fixtures/users.yml. There are two users without attributes:
one: {}
# column: value
#
two: {}
# column: value
When minitest starts it attempts to create two users with empty fields and it violates not null constraint for email. Try to either remove these lines or populate them with correct values

Related

Session token not saving Rails 6 production build

I'm building a Rails 6.0.3.4 backend, React.js frontend app and for some reason my session token is not saving on the production build after working perfectly fine on the development build. I've loosened restrictions on the production build on Heroku (in session_store.rb I tweaked it from requiring a specific domain to all domains). When I log in I have it return the session token data and it is there but it's not saving anything (tried multiple browsers/computers). On my react front end I do have {withCredentials: true} in my login/sign up components.
session_store.rb
if Rails.env.production?
Rails.application.config.session_store :cookie_store, key: '_10-athletes', domain: :all
else
Rails.application.config.session_store :cookie_store, key: '_10-athletes'
end
In my sessions_controller.rb
def create
#user = User.find_by(email: session_params[:usernameOrEmail])
unless #user
#user = User.find_by(username: session_params[:usernameOrEmail])
end
if #user && #user.authenticate(session_params[:password])
login!
render json: {
logged_in: true,
user: #user,#returns gthe user
session: session, #returns appropriate session info: session_id: 32 digit hex value, user_id: 1
production: Rails.env.production? #returns true, was curious if it was not registering properly
}
else
# working fine
}
end
end
def is_logged_in?
if logged_in? && current_user
# logged_in? is returning false, jumping to else
else
render json: {
session: session[:user_id], #returns null
}
end
end
application_controller.rb
def login!
session[:user_id] = #user.id
end
def logged_in?
!!session[:user_id]
end
config/application.rb
class Application < Rails::Application
config.load_defaults 6.0
config.middleware.use ActionDispatch::Cookies
config.middleware.use ActionDispatch::Session::CookieStore
config.middleware.insert_after(ActionDispatch::Cookies, ActionDispatch::Session::CookieStore)
end
config/environments/production.rb
Rails.application.configure do
config.cache_classes = true
config.eager_load = true
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
config.assets.compile = false
config.active_storage.service = :local
config.force_ssl = true # tested both including this line and not
config.api_only = false #tested both including this line and not
config.log_level = :debug
config.log_tags = [ :request_id ]
config.action_mailer.perform_caching = false
config.i18n.fallbacks = true
config.active_support.deprecation = :notify
config.log_formatter = ::Logger::Formatter.new
if ENV["RAILS_LOG_TO_STDOUT"].present?
logger = ActiveSupport::Logger.new(STDOUT)
logger.formatter = config.log_formatter
config.logger = ActiveSupport::TaggedLogging.new(logger)
config.active_record.dump_schema_after_migration = false
end
Edit: Added in production.rb
Do you have secure cookies enabled as a option? With SSL?

Expected response to be a <2XX: success>, but was a <403: Forbidden> For Controller Test

I'm trying to run a simple test on a Ruby on Rails 6.0 application, but I am getting a 403 error.
Alberts-MacBook-Pro:rr albertski$ rails test test/controllers/categories_controller_test.rb
Running via Spring preloader in process 72301
Run options: --seed 53214
# Running:
F
Failure:
CategoriesControllerTest#test_should_get_categories_index [/Users/albertski/Sites/rr/test/controllers/categories_controller_test.rb:10]:
Expected response to be a <2XX: success>, but was a <403: Forbidden>
categories_controller.rb
class CategoriesController < ApplicationController
def index
end
def new
end
def show
end
end
categories_controller_test.rb
require 'test_helper'
class CategoriesControllerTest < ActionDispatch::IntegrationTest
def setup
#category = Category.create(name: "sports")
end
test "should get categories index" do
get categories_path
assert_response :success
end
end
application_controller.rb
class ApplicationController < ActionController::Base
helper_method :current_user, :logged_in?
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def logged_in?
!!current_user
end
def require_user
if !logged_in?
flash[:danger] = "You must be logged in to perform this action"
redirect_to root_path
end
end
end
config/environments/test.rb
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
Rails.application.routes.default_url_options[:host] = 'http://localhost:3000'
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
config.hosts << "localhost:3000"
config.cache_classes = false
# Do not eager load code on boot. This avoids loading your whole application
# just for the purpose of running a single test. If you are using a tool that
# preloads Rails for running tests, you may have to set it to true.
config.eager_load = false
# Configure public file server for tests with Cache-Control for performance.
config.public_file_server.enabled = true
config.public_file_server.headers = {
'Cache-Control' => "public, max-age=#{1.hour.to_i}"
}
# Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
config.cache_store = :null_store
# Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = false
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false
# Store uploaded files on the local file system in a temporary directory.
config.active_storage.service = :test
config.action_mailer.perform_caching = false
# Tell Action Mailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test
# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr
# Raises error for missing translations.
# config.action_view.raise_on_missing_translations = true
end
I did debug get categories_path and it returns /categories. Also, when viewing the /categories path in a browser I don't have any issues; it only happens in the test.
I was able to find the problem by adding byebug to my test, and printing out response which pointed me to the following message:
Blocked host: www.example.com
To allow requests to www.example.com, add the following to your environment configuration:
config.hosts << "www.example.com"
Updating to config.hosts << "www.example.com" fixed the problem.
Also, not sure why I had config.hosts << "localhost:3000" in there in the first place. Removing that line also fixes the issue.
Remove/Comment out any config.hosts << "your-hostname>" in your config/application.rb you may have.
In my case I had my ngrok there.
config.hosts << "2f0c5431228v.ngrok.io"
Make sure to run rspec using RAILS_ENV=test
RAILS_ENV=test rspec
Rspec will run with your development config if RAILS_ENV is not set, which can cause issues like this.

API test writes in dev db but reads in test db

I'm trying to test my api with airborne
The call to the api works and create a User, but in the dev DB : there is no log of the creation and i find it using rails c.
But when i do User.find in the test, it searches the test db : there are logs and it doesn't find the user.
Here's my test :
require 'rails_helper'
describe 'register#create' do
it 'should create a new user' do
post '/register',
{
email: 'mail#mail.fr',
password: '12345678',
password_confirmation: '12345678'
}
puts response.body
expect_status 200
expect(User.find_by_email('mail#mail.fr')).to exist
end
end
Here's the method i'm trying to test :
class RegistrationsController < Devise::RegistrationsController
respond_to :json
skip_before_filter :verify_authenticity_token
acts_as_token_authentication_handler_for User
skip_before_filter :authenticate_entity_from_token!, only: [:create]
skip_before_filter :authenticate_entity!, only: [:create]
skip_before_filter :authenticate_scope!
append_before_filter :authenticate_scope!, only: [:destroy]
def create
build_resource(sign_up_params)
if !resource.valid?
status = 422
message = "#{resource.errors.full_messages}"
elsif resource.save!
status = 200
message = "Successfully created new account for email #{sign_up_params[:email]}."
else
clean_up_passwords resource
status = 500
message = "Failed to create new account for email #{sign_up_params[:email]}."
end
respond_to do |format|
format.json { render json: { message: message }, status: status }
end
end
Here's rails_helper :
ENV['RAILS_ENV'] = 'test'
require File.expand_path('../../config/environment', __FILE__)
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'spec_helper'
require 'rspec/rails'
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_spec_type_from_file_location!
end
Here's spec_helper :
ENV['RAILS_ENV'] = 'test'
require 'airborne'
Airborne.configure do |config|
config.base_url = 'http://myapp.dev/api/v1'
end
RSpec.configure do |config|
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
end
And finally, here's the log :
$ rspec
WARN: Unresolved specs during Gem::Specification.reset:
minitest (~> 5.1)
WARN: Clearing out unresolved specs.
Please report a bug if this causes problems.
DEBUG -- : ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
DEBUG -- : (0.1ms) begin transaction
{"message":"Successfully created new account for email mail#mail.fr."}
DEBUG -- : User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."email" = ? LIMIT 1 [["email", "mail#mail.fr"]]
DEBUG -- : (0.1ms) rollback transaction
F
Failures:
1) register#create should create a new user
Failure/Error: expect(User.find_by_email('mail#mail.fr')).to exist
expected nil to exist but it does not respond to either `exist?` or `exists?`
# ./spec/registration_controller_spec.rb:19:in `block (2 levels) in <top (required)>'
I'm fairly new to rails and i don't know where the problem might come from.
Thanks for your help :)
In my test, i POST to http://myapp.dv/api/v1/register which is a Pow! url.
Pow! configuration was the default one, which points to the DEV env.
So my test was in the right env, not the call to the api.
I used powder to switch envs now and it works.
ps : i also replaced
expect(User.find_by_email('mail#mail.fr')).to exist
with
expect(User.find_by_email('mail#mail.fr')).not_to be_nil

NoMethodError in Rails::MailersController#preview undefined method `activation_token=' for nil:NilClass

Cannot seem to find a working answer for this. I'm on Chapter 10, section 10.1.2 of the Rails Tutorial and can't seem to get the mailer preview working. All the answers I've found dealing with the error are related to different sections of the tutorial, and I'm assuming the error I'm making is staring me in the face. I've gone through and copy/pasted the code from the tutorial into the relevant files and so far haven't been able to see a difference between what I typed and what was in the tutorial. So far, the suggestions have been to add or remove the argument user from the function definitions, but that hasn't solved the problem. The url triggering the error is http://localhost:3000/rails/mailers/user_mailer/account_activation. http://localhost:3000/rails/mailers/user_mailer/ is having no issues, and neither is http://localhost:3000/rails/mailers/user_mailer/password_reset (which I haven't done any customization of yet). What am I missing?
Here's the error:
NoMethodError in Rails::MailersController#preview
undefined method `activation_token=' for nil:NilClass
Extracted source:
def account_activation
user = User.first
user.activation_token = User.new_token # highlighted line
UserMailer.account_activation(user)
end
From what I can tell, the files involved here are:
user_mailer.rb:
class UserMailer < ApplicationMailer
# Subject can be set in your I18n file at config/locales/en.yml
# with the following lookup:
#
# en.user_mailer.account_activation.subject
#
def account_activation(user)
#user = user
mail to: user.email, subject: "Account activation"
end
def password_reset
#greeting = "Hi"
mail to: "to#example.org"
end
end
user_mailer_preview.rb:
# Preview all emails at http://localhost:3000/rails/mailers/user_mailer
class UserMailerPreview < ActionMailer::Preview
# Preview this email at http://localhost:3000/rails/mailers/user_mailer/account_activation
def account_activation
user = User.first
user.activation_token = User.new_token
UserMailer.account_activation(user)
end
# Preview this email at http://localhost:3000/rails/mailers/user_mailer/password_reset
def password_reset
UserMailer.password_reset
end
end
development.rb:
Rails.application.configure do
config.cache_classes = false
# Do not eager load code on boot.
config.eager_load = false
# Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :test
host = 'localhost:3000'
config.action_mailer.default_url_options = { host: host }
# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
# Raise an error on page load if there are pending migrations.
config.active_record.migration_error = :page_load
# Debug mode disables concatenation and preprocessing of assets.
# This option may cause significant delays in view rendering with a large
# number of complex assets.
config.assets.debug = true
# Asset digests allow you to set far-future HTTP expiration dates on all assets,
# yet still be able to expire them through the digest params.
config.assets.digest = true
# Adds additional error checking when serving assets at runtime.
# Checks for improperly declared sprockets dependencies.
# Raises helpful error messages.
config.assets.raise_runtime_errors = true
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
end
and for completeness, here are the views and my user model:
account_activation.html.erb:
<h1>Sample App</h1>
<p>Hi <%= #user.name %>,</p>
<p>
Welcome to the Sample App! Click on the link below to activate your account:
</p>
<%= link_to "Activate", edit_account_activation_url(#user.activation_token,
email: #user.email) %>
account_activation.text.erb:
Hi <%= #user.name %>,
Welcome to the Sample App. Click on the link below to activate your account:
<%= edit_account_activation_url(#user.activation_token, email: #user.email) %>
user.rb:
class User < ActiveRecord::Base
attr_accessor :remember_token, :activation_token
before_save :downcase_email
before_create :create_activation_digest
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, length: { minimum: 6 }, allow_blank: true
# Returns the hash digest of the given string.
def User.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
# Returns a random token
def User.new_token
SecureRandom.urlsafe_base64
end
# Remembers a user in the database for use in persistent sessions
def remember
self.remember_token = User.new_token
update_attribute(:remember_digest, User.digest(remember_token))
end
# Returns true if the given token matches the digest.
def authenticated?(remember_token)
return false if remember_digest.nil?
BCrypt::Password.new(remember_digest).is_password?(remember_token)
end
# Forgets a user.
def forget
update_attribute(:remember_digest, nil)
end
private
# Converts email to all lower-case.
def downcase_email
self.email = email.downcase
end
# Creates and assigns the activation token and digest.
def create_activation_digest
self.activation_token = User.new_token
self.activation_digest = User.digest(activation_token)
end
end
Wow, lot's of debugging and confusion to discover a really simple problem: I wasn't logged in, and hadn't defined any kind of error message for those trying to access that page if they weren't logged in (hence the user.activation_token method triggering a Nil:NilClass error). Seems like a good example of why TDD can help out a ton.
Not sure if your being logged in was the problem, but rather there were no users.
Did you run bundle exec rake db:seed to populate? Also in your console check to see if your database populated as expected... if it hasn't checkout your "seed.rb" file and in the section where users are created ensure that activated: true exists, like follows:
User.create!(name: "Example User",
email: "testing#akqa.com",
password: "foobar",
password_confirmation: "foobar",
admin: true,
** activated: true,
activated_at: Time.zone.now)
the error you mentioned above, 'activation_token=' for nil:NilClass appears to actually be because there were no users.
And while you mentioned you "logged in" you may have actually just re-registered, thus creating the user needed to get this feature to work. Hope this helps!
if its the same error as me , your data base dont have data and user.first retrieve NIL than the next line dont work .
check your seed file and you db.

Rails: Cucumber sending mail twice

This should be an easy one to track down...but it isn't proving that way for me:
I have the following cucumber scenario:
Scenario: Send mail
Given I am a guest
When I go to the new_contact page
And I fill in "contact_name" with "Test User"
And get mail count
And I fill in "contact_email" with "test#example.com"
And I fill in "contact_message" with "Test Message"
And I fill in "contact_phone_num" with "123456789"
And I press "Send Message"
And get mail count
All default steps except for "get mail count", which simply returns:
puts ActionMailer::Base.deliveries.count
The first step of "get mail count" returns zero, the second returns 2. Running ActionMailer::Base.deliveries confirms the email is identical (including object identifier). I cannot, for the life of me, figure out where that second send is coming from. When actually using the app, the mail only comes through once. Relevant code below:
Controller:
class ContactsController < ApplicationController
def new
#contact = Contact.new
#pagetitle = "Contact Us"
if (current_user) then
#contact.name = "#{current_user.first_name} #{current_user.last_name}"
#contact.email = current_user.email
end
end
def create
#contact = Contact.new(params[:contact])
if #contact.save
contactmailer = ContactMailer
puts 'here now'
contactmailer.contact_message(#contact).deliver
redirect_to contact_thanks_url, notice: 'Contact was successfully created.'
else
render action: "new"
end
end
def thanks
end
end
Mailer:
class ContactMailer < ActionMailer::Base
def contact_message(contact)
#contact = contact
mail(:to => ENV['MANAGER_EMAIL'], :from => #contact.email, :subject => t(:business_name), :content_type => 'text/plain')
end
end
Cucumber Config File:
BC::Application.configure do
require 'ruby-debug'
config.cache_classes = true
config.use_transactional_fixtures = true
config.serve_static_assets = true
config.static_cache_control = "public, max-age=3600"
config.whiny_nils = true
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
config.action_dispatch.show_exceptions = false
config.action_controller.allow_forgery_protection = false
config.action_mailer.delivery_method = :test
config.active_support.deprecation = :stderr
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
config.action_mailer.raise_delivery_errors = true
config.action_mailer.perform_deliveries = true
ENV['MANAGER_EMAIL'] = 'test#example.com'
end
Answer in case anyone has the same issue:
email_spec gem. The 'require' statement in support/features/env.rb was double-calling the mailer. Why I'm not sure, but I uninstalled the gem & everything worked fine.

Resources