I am having difficulties with testing image download.
def download_img
#image = Photo.find params[:id] unless params[:id].nil?
#c = Cat.find params[:cat_id] unless params[:cat_id].nil?
#foo = #image.foo unless #image.nil?
send_file(Paperclip.io_adapters.for(#image.file).path, type: "jpeg", :disposition => "attachment", :filename => #image.name)
end
My RSpec test (controller):
describe 'download_img' do
before do
get :download_img, { id: image.id }
end
it 'retrieves image by id' do
img = Photo.find image.id
expect(img).not_to be_nil
end
it 'downloads image' do
page.response_headers["Content-Type"].should == "application/jpg"
page.response_headers["Content-Disposition"].should == "attachment; filename=\"image.name.jpg\""
end
end
When I run rspec test for both tests I get an error: "No such file or directory # rb_sysopen - /home/public/system/photos/files/000/000/001/foo/IMG123.JPG"
Thank you.
Is that image you are referring to in Photo.find image.id coming from fixtures? Will you please check if there's a corresponding file referenced from fixtures. I suppose you'll have to change the path in fixtures and create that file as well, a good place for it is spec/fixtures.
Related
I am using paperclip-dropbox gem to store my assets. I want to create a test to ensure assets are properly destroyed if the destroy checkbox is checked.
I can see on dropbox the image is uploaded and deleted but just after it's created again. Don't understand why.
Here is my test file:
require 'test_helper'
#
# == Admin namespace
#
module Admin
#
# == SettingsController test
#
class SettingsControllerTest < ActionController::TestCase
include Devise::TestHelpers
setup :initialize_test
#
# == Avatar
#
test 'should be able to upload logo' do
upload_dropbox_paperclip_attachment
setting = assigns(:setting)
assert setting.logo?
assert_equal 'bart.png', setting.logo_file_name
assert_equal 'image/png', setting.logo_content_type
end
test 'should be able to destroy logo' do
upload_dropbox_paperclip_attachment
remove_dropbox_paperclip_attachment
end
private
def initialize_test
#setting = settings(:one)
#administrator = users(:bob)
sign_in #administrator
end
def upload_dropbox_paperclip_attachment
puts '=== Uploading logo to Dropbox'
attachment = fixture_file_upload 'images/bart.png', 'image/png'
patch :update, id: #setting, setting: { logo: attachment }
end
def remove_dropbox_paperclip_attachment
puts '=== Removing logo from Dropbox'
patch :update, id: #setting, setting: { logo: nil, delete_logo: '1' }
assert_not assigns(:setting).logo?
end
end
end
Do someone know what is wrong with this test ?
Am I in the right way trying to test for dropbox or should I test only in local ? the documentation for paperclip-dropbox doesn't give any information about testing.
Thanks
My project:
Rails 4.2.3
Ruby 2.2.2
I'm trying to figure out the how to test file attachments w/ the Fabrication and Rspec gems. The file upload works fine when testing the site manually, there's just no Rspec coverage. The problem seems to be that I don't know how to include an attachment in a PUT request.
How do I add a file attachment, preferably using a fabricator, to this test
Fabricator:
Fabricator(:application) do
email Faker::Internet.email
name Faker::Name.name
resume_url { File.open(
File.join(
Rails.root,
"spec",
"support",
"files",
"hey_look_a_pdf_pdf_lolz.pdf"
)
)
}
end
Controller:
class ApplicationsController < ApplicationController
def update
#application = Application.find_or_initialize_by(id: params[:id])
if #application.update(application_params)
flash[:success] = "Application has been saved :)"
redirect_to application_path(#application)
else
render :edit
end
end
private
def application_params
params[:application].permit(:email, :job_id, :name, :resume_url)
end
end
Controller test
require "spec_helper"
# this is a sample application attributes being passed into controller
# it should have a file attachment, but haven't figured out how to do that
#
# {
# "id"=>"fa446fdf-b82d-48c0-8979-cbbb2de4fb47",
# "email"=>"old#example.com",
# "name"=>"Dr. Rebeca Dach",
# "resume_url"=>nil,
# "job_id"=>"cf66dbcf-d110-42cc-889b-0b5ceeeed239",
# "created_at"=>nil,
# "updated_at"=>nil
# }
describe ApplicationsController do
context "PUT /applications/:id" do
it "creates an application" do
expect { put(
:update,
application: application.attributes,
id: application.id
)}.to change{Application.count}.from(0).to(1)
end
end
end
Update #1
The following Fabricator seems to work okay. I'm still not able to get file attachments to work in controller tests.
Fabricator(:application) do
email Faker::Internet.email
name Faker::Name.name
resume_url { ActionDispatch::Http::UploadedFile.new(
tempfile: File.new(Rails.root.join(
"./spec/support/files/hey_look_a_pdf_pdf_lolz.pdf"
)),
filename: File.basename(File.new(Rails.root.join(
"./spec/support/files/hey_look_a_pdf_pdf_lolz.pdf"
)))
)}
end
OK, I got it figured out. There were two pieces.
1) I had to fix the Fabricator, which I mentioned in "Update #1" to my question. Here's a simpler format for the Fabricator using Rack::Test::Upload.new
Fabricator(:application) do
email Faker::Internet.email
name Faker::Name.name
resume_url {
Rack::Test::UploadedFile.new(
"./spec/support/files/hey_look_a_pdf_pdf_lolz.pdf",
"application/pdf"
)
}
end
2) I was using Fabricator.build(:application).attributes, which wasn't compatible with a file attachment. Instead, I started using Fabricator.attributes_for(:application), and everything started working great. Here's the passing.
describe ApplicationsController do
context "PUT /applications/:id" do
let(:job) { Fabricate(:job) }
let(:application) do
Fabricate.attributes_for(
:application,
email: "old#example.com",
id: SecureRandom.uuid,
job_id: job.id
)
end
it "creates an application" do
expect { put(
:update,
application: application,
id: application["id"]
)}.to change{Application.count}.from(0).to(1)
end
end
end
Is there a good way to check on existence of images and favicons using rspec and capybara?
I can check on the DOM of favicons and images, but I want to be able to check that those images load as well. Is this possible with rspec and capybara?
describe "check images and favicon" do
before { visit "url/to/check")
it "should have the images" do
page.should have_css('img', text: "image1.jpg")
it "should have the favicon" do
page.should have_xpath("/html/head/link[#href='favicon.ico']"
end
end
# frozen_string_literal: true
module Capybara
module CustomMatchers
include Capybara::DSL
class Asset
def asset_exists?(actual, src)
js_script = <<JSS
xhr = new XMLHttpRequest();
xhr.open('GET', '#{src}', true);
xhr.send();
JSS
actual.execute_script(js_script)
status = actual.evaluate_script('xhr.status') # get js variable value
status == 200 || status == 302
end
end
class LoadImage < Asset
def initialize(*args)
#args = args
#src = args.first
end
def matches?(actual)
is_present = actual.has_selector?("img[src='#{#src}']")
is_present && asset_exists?(actual, #src)
end
def does_not_match?(actual)
actual.has_no_selector?("img[src='#{#src}']")
end
def failure_message
"No image loaded with source: '#{#src}'"
end
def failure_message_when_negated
"Image loaded with source: '#{#src}'"
end
def description
"Verify if image with source: '#{#src}' is loaded"
end
end
class LoadFavicon < Asset
def initialize(*args)
#args = args
#rel = args.first
#href = args.second
end
def matches?(actual)
is_present = actual.has_selector?("link[rel='#{#rel}'][href='#{#href}']", visible: false)
is_present && asset_exists?(actual, #href)
end
def does_not_match?(actual)
actual.has_no_selector?("link[rel='#{#rel}'][href='#{#href}']", visible: false)
end
def failure_message
"No favicon loaded with rel: '#{#rel}' and href: '#{#href}'"
end
def failure_message_when_negated
"Favicon loaded with rel: '#{#rel}' and href: '#{#href}'"
end
def description
"Verify if favicon with rel: '#{#rel}' and href: '#{#href}' is loaded"
end
end
def load_image(*args)
LoadImage.new(*args)
end
def load_favicon(*args)
LoadFavicon.new(*args)
end
end
end
RSpec.configure do |config|
config.include Capybara::CustomMatchers
end
Check https://gist.github.com/yovasx2/1c767114f2e003474a546c89ab4f90db to star and download
The question is to find out if the actual img and favicon are present. Here is the code to check that all images for the slider are present.
page.all('#carousel img').each do |img|
visit img[:src]
page.status_code.should be 200
end
For individual image with id myimage use
visit page.find('img#myimage')[:src]
page.status_code.should be 200
And for favicon simplest is to run the following
page.all('link[rel~="icon"]', visible: :any).each do |fav|
visit fav[:href]
page.status_code.should be 200
end
To test for all broken images on a page versus,
a specific image,
the presence of a selector, or
the image availability in the pipeline
I gather all the images and check a "get" response using the following:
describe "Check for Images" do
before { visit page_path }
it "should not have broken images" do
all_images = page.all('img')
all_images.each do |img|
get img[:src]
expect(response).to be_successful
end
end
end
Hope that helps.
I'm working the a Documents class, trying to test it. I've defined the following factory:
require 'factory_girl'
FactoryGirl.define do
factory :document do
user_id '6315'
name 'Test doc'
description 'W9'
filename 'test_doc.pdf'
filetype 'file'
filesize 500
end
factory :invalid_doc, parent: :document do
filesize 5242900
end
end
with the following helper method to access the right attributes in the test:
def build_attributes(*args)
attrs = FactoryGirl.build(*args).attributes
attrs.delete_if do |k, v|
["id", "created_at", "updated_at"].member?(k)
end
paramify_values(attrs)
end
Before each test I run:
before(:each) do
login_as_admin
#doc = #user.documents.create(FactoryGirl.attributes_for(:document))
end
where #user is set in the login_as_admin macro. Within my test, I'm running this:
describe 'POST #create' do
it "should create a new document" do
expect{
post :create, document: build_attributes(:document, user_id: #doc.user_id)
}.to change(Document,:count).by(1)
end
it "should find the right user" do
post :create, document: build_attributes(:document, user_id: #doc.user_id)
assigns(:user).should eq(#user)
end
# some other tests...
end
The former test was suggested on this article, the latter is just what I think should be happening. The controller action is assigning the instance with the following:
#user = User.find(document[:user_id])
so, pretty standard. However, both of these tests throw the same error,
Failure/Error: post :create, document: build_attributes(:document, user_id: #doc.user_id)
NoMethodError:
undefined method `original_filename' for nil:NilClass
but I never call that method explicitly, so is it something FactoryGirl is calling? The model is described as follows:
attr_accessible :description, :filename, :filesize, :filetype, :name, :user_id
where :filename is just a string. What could be going wrong here? I'm not using paperclip to upload the files, just a file_field in the view. I grab the path and save the file to the production server in the controller, but never call this method.
Edit:
I suppose an actual controller description might help haha
def create
uploaded_file = params[:document][:file]
document = params[:document]
document.delete(:file)
#user = User.find(document[:user_id])
filepath = Rails.root.join('documents', #user.company_id.to_s, #user.id.to_s, uploaded_file.original_filename)
%x[ mkdir #{Rails.root.join('documents', #user.company_id.to_s)} ]
%x[ mkdir #{Rails.root.join('documents', #user.company_id.to_s, #user.id.to_s)} ]
File.open(filepath, 'wb') do |file|
file.write(uploaded_file.read)
end
document[:filesize]= File.size(filepath)
document[:filetype]= File.ftype(filepath)
document[:filename] = uploaded_file.original_filename
d =Document.new(document)
d.save
redirect_to :action => 'show', :id => user.id
end
Please keep in mind I'm sure there are many things wrong with this method. I'm trying to refactor it and test as I go. For the moment, all I'm trying to do is get past this first hiccough, the original_filename method is being called somewhere, and I don't define it myself. Can anyone see why/where?
original_filename is a method on an uploaded file, see the rack documentation.
filepath = Rails.root.join('documents', #user.company_id.to_s, #user.id.to_s, uploaded_file.original_filename)
and
document[:filename] = uploaded_file.original_filename
In the controller are getting the original filename, since when a file gets uploaded it gets an ugly temp filename for storage you want to use the original filename to make it readable and accurate.
Consider using the fixture_file_upload helper in rspec. Here is an example spec:
expect {
post :create, document: attributes_for(:document, user_id: #doc.user_id, file: fixture_file_upload('spec/assets/documents/test_doc.pdf', 'appliation/pdf'))
}.to change(Document, :count).by(1)
And place a test pdf in spec/assets/documents/test_doc.pdf
You can use
Rack::Multipart::UploadedFile.new(path)
for your test.
I want to test a file upload in rails, but am not sure how to do this.
Here is the controller code:
def uploadLicense
#Create the license object
#license = License.create(params[:license])
#Get Session ID
sessid = session[:session_id]
puts "\n\nSession_id:\n#{sessid}\n"
#Generate a random string
chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
newpass = ""
1.upto(5) { |i| newpass << chars[rand(chars.size-1)] }
#Get the original file name
upload=params[:upload]
name = upload['datafile'].original_filename
#license.format = File.extname(name)
#calculate license ID and location
#license.location = './public/licenses/' + sessid + newpass + name
#Save the license file
#Fileupload.save(params[:upload], #license.location)
File.open(#license.location, "wb") { |f| f.write(upload['datafile'].read) }
#Set license ID
#license.license_id = sessid + newpass
#Save the license
#license.save
redirect_to :action => 'show', :id => #license.id
end
I have tried this spec, but it doesnt work:
it "can upload a license and download a license" do
file = File.new(Rails.root + 'app/controllers/lic.xml')
license = HashWithIndifferentAccess.new
license[:datafile] = file
info = {:id => 4}
post :uploadLicense, {:license => info, :upload => license}
end
How can I simulate the file upload, using rspec?
You can use fixture_file_upload method to test file uploading:
Put your test file in "{Rails.root}/spec/fixtures/files" directory
before :each do
#file = fixture_file_upload('files/test_lic.xml', 'text/xml')
end
it "can upload a license" do
post :uploadLicense, :upload => #file
response.should be_success
end
In case you were expecting the file in the form of params['upload']['datafile']
it "can upload a license" do
file = Hash.new
file['datafile'] = #file
post :uploadLicense, :upload => file
response.should be_success
end
I am not sure if you can test file uploads using RSpec alone. Have you tried Capybara?
It's easy to test file uploads using capybara's attach_file method from a request spec.
For example (this code is a demo only):
it "can upload a license" do
visit upload_license_path
attach_file "uploadLicense", /path/to/file/to/upload
click_button "Upload License"
end
it "can download an uploaded license" do
visit license_path
click_link "Download Uploaded License"
page.should have_content("Uploaded License")
end
if you include Rack::Test*, simply include the test methods
describe "my test set" do
include Rack::Test::Methods
then you can use the UploadedFile method:
post "/upload/", "file" => Rack::Test::UploadedFile.new("path/to/file.ext", "mime/type")
*NOTE: My example is based on Sinatra, which extends Rack, but should work with Rails, which also uses Rack, TTBOMK
I haven't done this using RSpec, but I do have a Test::Unit test that does something similar for uploading a photo. I set up the uploaded file as an instance of ActionDispatch::Http::UploadedFile, as follows:
test "should create photo" do
setup_file_upload
assert_difference('Photo.count') do
post :create, :photo => #photo.attributes
end
assert_redirected_to photo_path(assigns(:photo))
end
def setup_file_upload
test_photo = ActionDispatch::Http::UploadedFile.new({
:filename => 'test_photo_1.jpg',
:type => 'image/jpeg',
:tempfile => File.new("#{Rails.root}/test/fixtures/files/test_photo_1.jpg")
})
#photo = Photo.new(
:title => 'Uploaded photo',
:description => 'Uploaded photo description',
:filename => test_photo,
:public => true)
end
Something similar might work for you also.
This is how I did it with Rails 6, RSpec and Rack::Test::UploadedFile
describe 'POST /create' do
it 'responds with success' do
post :create, params: {
license: {
picture: Rack::Test::UploadedFile.new("#{Rails.root}/spec/fixtures/test-pic.png"),
name: 'test'
}
}
expect(response).to be_successful
end
end
DO NOT include ActionDispatch::TestProcess or any other code unless you're sure about what you're including.
I had to add both of these includes to get it working:
describe "my test set" do
include Rack::Test::Methods
include ActionDispatch::TestProcess