I'm following the Ruby on Rails 3 tutorial, chapter 6. Inside my directory spec/models/user_spec.rb, i have a 6 test cases (no need to rly read them):
require 'spec_helper'
describe User do
#pending "add some examples to (or delete) #{__FILE__}"
before(:each) do
#attr = { :name => "Example User", :email => "user#example.com"}
end
it "should creat a new instance given valid attributes" do
User.create!(#attr)
end
.
.
.
it "should reject invalid email addresses" do
addresses = %w[user#foo,com user_at_foo.org example.user#foo.]
addresses.each do |address|
invalid_email_user = User.new(#attr.merge(:email => address))
invalid_email_user.should_not be_valid
end
end
end
In the console, i type $ rspec spec/models/user_spec.rb and it spits out
No DRb server is running. Running in local process instead ...
*
Pending:
User add some examples to (or delete) /Users/matthew/Desktop/rails_projects/sample_app/spec/models/user_spec.rb
# Not Yet Implemented
# ./spec/models/user_spec.rb:4
Finished in 0.00023 seconds
1 example, 0 failures, 1 pending
The last line says i only have 1 example and 1 pending, but i've written 6 tests! This inconsistency boggles my mind! No syntax errors, i'm saving the file, i'm in the right directory, etc.
By far the strangest thing (i'm using Mac OS X and Textmate):
Despite correct code, directory, etc. CMD+S or File-> Save was not saving the files at all. I've been opening the files via command line. Solution is to just close the shell and open a new one.
Related
I have this problem with my code.This page inside my application is using http basic authentication. I'm testing my application with Rspec and Capybara, but I have problem with data confirmation when deleting comment, it just can't seem to pass.
Here is my test code:
before(:each) do
page.driver.browser.authorize ENV['ADMIN_LOGIN'], ENV['ADMIN_PASSWORD']
...
end
...
it "should redirect to create new inspiring post and create new post on click" do
visit admin_path
click_link("create_inspi")
fill_in("Title",:with => "Test title")
fill_in("Short",:with => "Test short desc")
fill_in("Body",:with => "Test body desc")
fill_in("Date",:with => "12.12.2012")
click_button("Create new post")
test(
have_content("Test title"),
have_content("12.12.2012")
)
end
example "when inside Link to all... you can delete particular comment",:js => true do
visit admin_path
click_link("Link to all comments in Web development and Motivation category")
click_link(#webdev_comment.id)
page.driver.browser.accept_js_confirms
end
Now for my test by default I use Capybara::RackTest::Driver, but now since I can't find a way to confirm data confirmation with RackTest I have to use Selenium driver to make this data confirmed. But now when using this Selenium driver for my last example test I found next problem:
1) testing admin webpage when inside Link to all... you can delete particular comment
Failure/Error: page.driver.browser.authorize ENV['ADMIN_LOGIN'], ENV['ADMIN_PASSWORD']
NoMethodError:
undefined method `authorize' for #<Selenium::WebDriver::Driver:0x00000003e6ad68>
# ./spec/features/admin.rb:13:in `block (2 levels) in <top (required)>'
MY QUESTION IS:
How to authenticate basic http with selenium?
-------------- EDITED ------------------
I found a way to log in into admin with selenium driver by using this code
example "when inside Link to all... you can delete particular comment",:js => true do
visit root_path
#url = current_url
#tablica = #url.split("http://")
#correct_url = #tablica[1]
admin_selenium_path = "http://#{ENV["ADMIN_LOGIN"]}:#{ENV["ADMIN_PASSWORD"]}##{#correct_url}admin"
page.visit admin_selenium_path
click_link("Link to all comments in Web development and Motivation category")
click_link(#webdev_comment.id)
page.driver.browser.accept_js_confirms
end
But now , even though it's logging in , there is literally no data inside test database, and it's throwing errors around saying that particular object couldn't be found.
before(:each) do
# page.driver.browser.authorize ENV['ADMIN_LOGIN'], ENV['ADMIN_PASSWORD']
#mystory = Mystory.create(name: "My story:",body: "My name is Matthew...")
end
This code above inside before block is not creating a required #mystory record inside database for capybara with selenium driver.
Any ideas how to populate database for capybara with selenium driver?
I'm not sure if it's exactly the same issue but I add this somewhere above/before to skip over confirm dialogs with Capybara
page.evaluate_script('window.confirm = function() { return true; }')
Many simmilar Q/A on this topic here and there, but I was unable to find exact solution for my problem. Using Rails 3.0.9 now, and trying to upgrade existing older application(not Rails).
The goal is to send simple email to new clients created by admins.
Have been following this oficial guide (and many others), but with no success.
The issue is, that method(s) defined in this controller, from class 'UserMailer', aren`t recognised from another controller, while class 'UserMailer' itself recognised is(how do I know this, will be explained below):
/app/mailers/user_mailer.rb
class UserMailer < ActionMailer::Base
default :from => "info#xxxxx.sk"
def kokotina # << this is just a dummy method for testing
caf = "ssss"
end
def regMailUsr(nazov, priezvisko, email, pass)
#nazov = nazov
#priezvisko = priezvisko
#email = email
#pass = pass
#url = "http://loyalty2.xxxx.sk"
mail(to: email, subject: 'Vaša registrácia bola dokončená.')
end
end
I have also created View for this mail controller but that is not important right now.
The fragments from clients controller are here:
/app/controllers/clients_controller.rb
# encoding: UTF-8
class ClientsController < ApplicationController
load_and_authorize_resource
.......
def new
#noveHeslo = genHeslo(10) # << I defined this in application_controller.rb and it works
UserMailer.kokotina # << just a dummy method from UserMailer
#client = Client.new(params[:client])
.......
end
.......
def create
.......
if #client.save
#send email to new client:
UserMailer.regMailUsr(params[:client][:fname], params[:client][:lname], params[:client][:email], params[:client][:password]).deliver
.....
end ......
Now how do I know that my class is loaded? If in client controller, I change 'UserMailer' to 'xUserMailer', I will get 'no class or method in ...' error, but without 'x', I get only:
'undefined method `kokotina' for UserMailer:Class'
I also tried to define my methods in UserMailer:Class like this:
def self.kokotina # << this is just a dummy method for testing
caf = "ssss"
end
#or even like this
def self <<
def kokotina # << this is just a dummy method for testing
caf = "ssss"
end
end
#and then tried to invoke this method(s) like this:
UserMailer.new.kokotina
#or simply
kokotina
Strange is, that when I put contents of file '/app/mailers/user_mailer.rb' at the end of 'application_helper.rb' file, just after the end of 'module ApplicationHelper', I get no errors but of course, it won`t work.
Please keep in mind that I have no problem coding in another languages, but this mystic/kryptic rules of Ruby on Rails are still a complete mistery to me and unfortunatelly, I don`t have time or even motivation to read time extensive quides or even books for RoR beginners. I have been coding much more difficult applications and implementations, but this heavily discriminating system is driving me nuts.
Thank you all!
Problem solved!
The trick was, that in '/app/mailers/user_mailer.rb', I had multibyte characters. In mail subject.
So I added:
# encoding: UTF-8
at the very first line of '/app/mailers/user_mailer.rb'
I found this by total accident: later my rails app could not start, and server was simply throwing HTTP 500 error. So no trace, error defining etc.
I found out that multibyte string in:
mail(to: email, subject: 'Vaša registrácia bola dokončená.')
Was responsible for crash. When I removed that string, I noticed one important side effect: my methods became magicaly available for another controller!!!!
So if someone could give me at least one reason to lowe Rails...
As i'm new to Rails, I made the mistake of using the default path ( /system/:attachment/:id/:style/:filename ) in 4 different models. Now, i would like to move each model to its own folder but without losing old data.
What is the proper way of handling this? Does Paperclip offer an option to automatically migrate data from old folders?
Thanks.
I had a similar dilemma. We were storing all our attachments in a certain path, and then business requirements changed and everything had to be moved and re-organized.
I'm surprised how little info there is on changing paperclip path and moving files. Maybe I'm missing the obvious?
Like Fernando I had to write a rake task. Here's what my code looks like (attachments model is Attachment, and the actual Paperclip::Attachment object is :file )
task :move_attachments_to_institution_folders => :environment do
attachments = Attachment.all
puts "== FOUND #{attachments.size} ATTACHMENTS =="
old_path_interpolation = APP_CONFIG[ 'paperclip_attachment_root' ] + "/:id_partition.:extension"
new_path_interpolation = APP_CONFIG[ 'paperclip_attachment_root' ] + "/:institution/reports/:id_:filename"
attachments.each do |attachment|
# the interpolate method of paperclip takes the symbol variables and evaluates them to proper path segments.
old_file_path = Paperclip::Interpolations.interpolate(old_path_interpolation, attachment.file, attachment.file.default_style) #see paperclip docs
puts "== Current file path: #{old_file_path}"
new_file_path = Paperclip::Interpolations.interpolate(new_path_interpolation, attachment.file, attachment.file.default_style)
if File.exists?(old_file_path)
if !File.exists?(new_file_path) #don't overwrite
FileUtils.mkdir_p(File.dirname(new_file_path)) #create folder if it doesn't exist
FileUtils.cp(old_file_path, new_file_path)
puts "==== File copied (^_^)"
else
puts "==== File already exists in new location."
end
else
puts "==== ! Real File Not Found ! "
end
end
The key thing for me was to have paperclip re-calculate the old path by using its default interpolations. From then it was just a matter of using standard FileUtils to copy the file over. The copy takes care of renaming.
P.S.
I'm on rails 2.3.8 branch, with paperclip -v 2.8.0
I ended up creating a small rake task to do this. Assuming that you have a model called User and your image file is called "image", place the following code in lib/tasks/change_users_folder.rb
desc "Change users folder"
task :change_users_folder => :environment do
#users = User.find :all
#users.each do |user|
unless user.image_file_name.blank?
filename = Rails.root.join('public', 'system', 'images', user.id.to_s, 'original', user.image_file_name)
if File.exists? filename
user.image = File.new filename
user.save
end
end
end
end
Them, run rake change_users_folder and wait.
Note that this won't delete old files. They will be kept at the original place and a copy will be created at the new folder. If everything went well, you can delete them later.
And for my future code, i will make sure i always set :path and :url when using paperclip :)
Can I execute a javascript in a link with capybara click_link('next_page') ?
The link looks like this:
<a onclick="$('#submit_direction').attr('value', '1');$('#quizForm').submit()" id="next_page" href="#">Next Question</a>
I read at capybara at github that I can submit a form by click at its submit button like this:
click_on('Submit Answer')
But, in my case, I need to submit the form using javascript in a link, so, how to test the link that has javascript inside ? isn't click_link('next_page') sufficient ?
EDIT
after setting :js=> true my test looks like this:
it "should pass when answering all correct", :js=>true do
login_as(student, :scope => :student)
visit ("/student_courses")
#page.execute_script("$('#submit_direction').attr('value', '1');$('#quizForm').submit()")
trace "HTML:------------", page.html
end
Before :js=> true, I could visit the page normally, But, I've noticed that the page cannot be visited after :js=> true, here is the error I got after visiting the page:
Started GET "/student_courses" for 127.0.0.1 at 2012-01-23 06:29:26
+0200 (5010.7ms) UPDATE "students" SET "last_sign_in_at" = '2012-01-23 04:29:26.274285', "current_sign_in_at" = '2012-01-23
04:29:26.274285', "last_sign_in_ip" = '127.0.0.1',
"current_sign_in_ip" = '127.0.0.1', "sign_in_count" = 1, "updated_at"
= '2012-01-23 04:29:26.276279' WHERE "students"."id" = 1 SQLite3::BusyException: database is locked: UPDATE "students" SET
"last_sign_in_at" = '2012-01-23 04:29:26.274285', "current_sign_in_at"
= '2012-01-23 04:29:26.274285', "last_sign_in_ip" = '127.0.0.1', "current_sign_in_ip" = '127.0.0.1', "sign_in_count" = 1, "updated_at"
= '2012-01-23 04:29:26.276279' WHERE "students"."id" = 1 HTML:------------__
Internal
Server Error
Internal Server Error
cannot rollback transaction - SQL statements in progress
WEBrick/1.3.1 (Ruby/1.9.3/2011-10-30) at
127.0.0.1:34718
so, why SQLite3::BusyException: database is locked now ?!
I just spent 8 hours resolving a similar issue, and I found the solution. The fix is so simple, I could cry.
First, diagnosis
The reason you're getting "SQLite3::BusyException: database is locked" is that you are launching an asynchronous thread, namely a form submission, that ends up losing the "database write" race to your test's main thread. In effect, as your test has already completed and is running your "after each" database cleanup routine (defined in your spec_helper), the form action has only just begun trying to run the business logic (which relies on the data that your test after:each hook is busy destroying).
This problem is a lot more likely to occur with tests that click on an AJAX POST button and then terminate without asserting something about the view change.
Second, the fix
As it turns out, Capybara is designed to "synchronize" all your requests. But only if you implicitly let it. Notice that after your form submission, you're not having Capybara look at your page. Therefore it thinks you're done and takes your data out of scope (while your form submission thread is hanging in the background.)
Simply add the following line of code to the end of your test, and it should suddenly work:
page.should_not have_content "dude, you forgot to assert anything about the view"
Third, make it pretty
Don't use execute_script. That's what Capybara is for. But also don't rely on "click_on" because it's not a great abstraction. You need to know too much about its internals. Instead, use CSS selectors like so:
page.find("#submit_button").click
And one more thing - your test shouldn't try to manipulate the DOM. A good Selenium test assumes to have to follow the same steps a normal user follows.
So in conclusion
it "should pass when answering all correct", :js => true do
login_as(student, :scope => :student)
visit ("/student_courses")
page.find(".my-js-enabled-button").click
page.find("#submit_button").click
# Synchronizes your view to your database state before exiting test,
# Therefore makes sure no threads remain unfinished before your teardown.
page.should_not have_content "dude, you forgot to expect / assert anything."
end
To expand on Alex's comment Capybara won't execute JS unless it's explicitly turned on for the given tests.
To do this, use :js => true on either your describe block or individual test eg.
describe "in such and such a context", :js => true do
# some stuff
end
It should work. with capybara, you are essentially test your application through the browser, and it will behave the same.
Using Sorcery 0.7.4 with Rails 3.1.1 for authentication.
Everything was going well until I tried to setup password resetting.
Activation works perfectly and emails are sent, but for some reason I get this error when trying to send the reset password email.
undefined method `reset_password_email' for nil:NilClass
I copied the tutorial exactly, and when I did a quick test in the console it shot off the email as expected. In console:
user = User.find(1)
user.deliver_reset_password_instructions!
In the actual controller, it finds the user by the email submitted from the form and in the log I can see it is retrieving the right user and setting the token, but errors out as above and rolls back.
I checked the gem's code for deliver_reset_password_instructions! and there seems to be no reason for it to fail.
PasswordResetsController:
#user = User.find_by_email(params[:email])
#user.deliver_reset_password_instructions! if #user
The following is copied from the gem code:
Instance Method in Gem:
def deliver_reset_password_instructions!
config = sorcery_config
# hammering protection
return false if config.reset_password_time_between_emails && self.send(config.reset_password_email_sent_at_attribute_name) && self.send(config.reset_password_email_sent_at_attribute_name) > config.reset_password_time_between_emails.ago.utc
self.send(:"#{config.reset_password_token_attribute_name}=", TemporaryToken.generate_random_token)
self.send(:"#{config.reset_password_token_expires_at_attribute_name}=", Time.now.in_time_zone + config.reset_password_expiration_period) if config.reset_password_expiration_period
self.send(:"#{config.reset_password_email_sent_at_attribute_name}=", Time.now.in_time_zone)
self.class.transaction do
self.save!(:validate => false)
generic_send_email(:reset_password_email_method_name, :reset_password_mailer)
end
end
The method called above for mailing:
def generic_send_email(method, mailer)
config = sorcery_config
mail = config.send(mailer).send(config.send(method),self)
if defined?(ActionMailer) and config.send(mailer).superclass == ActionMailer::Base
mail.deliver
end
end
Again all the required mailer bits and pieces are there and work from the console.
Uncomment this lines in the sorcery initializer
user.reset_password_mailer = UserMailer
user.reset_password_email_method_name = :reset_password_email
Check your app/mailers/user_mailer.rb file.
If you were following the tutorial you probably did something like copy and paste the method definition from the wiki (which takes one parameter) into the generated method definition (which doesn't take any parameter), hence the 1 for 0 ArgumentError.
In other words, you likely have something that looks like this:
def reset_password_email
def reset_password_email(user)
This is bad, but an easy fix :-)