That Cuking Paperclip!#$!

August 4th, 2009

Nick Rutherford

No, nothing to do with MS Office, promise.

This is a rehash of a conversation I had on the Cucumber mailing list / Google Group

If you are using the Paperclip plugin to handle user image submissions you may run into some head-scratching trouble when testing this with Cucumber. The following approach, while perhaps not ideal, tests the full stack, short of a browser.

The following example uses Machinist for random file selection and could be simplified to a single test image if desired.

Sample Images

Put some images into spec/fixtures directory with a common name, e.g. example1.jpg example2.gif example3.jpg and so on

Steps

My paperclip binding is called picture and it's on my service object. This is in my service steps file:

  def new_picture 
    @new_picture ||= Sham.image 
  end 

  When /^I provide an image file for "picture"$/ do 
    attach_file "service_picture", new_picture.path 
  end

And in my Sham.define block (in spec/blueprints.rb)

image do 
  images = [] 
  dirpath = File.join Rails.root, 'spec', 'fixtures' 
  Dir.new(dirpath).each { |file| images << File.new(File.join (dirpath, file)) if file =~ /^example\d/ } 
  images[rand(images.length)] 
end

Assertions?

Then /^I should see my photo$/ do 
  response.should have_selector("img[src*=''#{File.basename new_picture.path}]) 
end

or

response.body.should =~ /#{File.basename new_picture.path}/

and so on.

Note that paperclip will give you addresses resembling this:

  http://localhost:3000/system/pictures/2/index/example5.jpg?1258339851

so watch out for the secret token after the ? and don't just use == on the file path.

File Hangover

The gotcha is cleaning up the files afterwards, since we're not using the database for a file store. I took this approach (which is hacky but works, on unix) to put the paperclip test files into a different directory and delete the directory afterwards.

features/support.env

#remove paperclip files 
require 'paperclip' #make sure it's loaded, else cue intermittent weirdness 
module Paperclip::Interpolations 
  alias_method :org_attachment, :attachment 
  def attachment(att, style) 
    "CUKE/" + org_attachment(att, style) 
  end 
end 
After do 
  `rm -rf #{"#{RAILS_ROOT}/public/system/CUKE"}` 
end 
#end remove paperclip files

This wants to be an after block so that your database and file system stay in synch through your tests. Using an after all block (or equivalent) would mean the database having no pictures in it, but the directory having image files in it. While that may seem to work ok it's unnecessarily inconsistent.

Sorry, comments are closed for this article.