How to test file uploads with Cucumber
In a previous article (in portuguese, but you can always use Google Translate to take a look at it) I showed how to use Cucumber to create functional tests for your web applications. Today I’ll show how to use Cucumber to test file uploads. I’ll use a Rails application as our example, but in general the concepts presented here could be applied to test file uploads in any web application.
Let’s consider a ProductsController controller with an get_csv_file action, which purpose is to receive a csv text file with and record the data in each line as a new instance of the Product class. What could be the expected behaviour of such action? Let’s describe it with a Cucumber feature:
Feature: CSV file upload In order to create new products in the database As a user I want to be able to upload a CSV file with the products' data Scenario: Uploading a valid file with data for 3 new products Given I visit the file upload page When I upload a file with valid data for 3 new products Then the number of products should change to 3 And I should be sent to the products index page Scenario: Uploading a malformed file Given I visit the file upload page When I upload a malformed file Then the number of products should not change And I should see the file upload page again
We have two basic scenarios, one for a correct file and another for a bad one. We don’t have any code yet for the steps Cucumber will execute when running the tests, so let’s do it. I’ll show just the steps for the file uploads.
When /^I upload a file with valid data for 3 new products$/ do attach_file(:csv_file, File.join(RAILS_ROOT, 'features', 'upload-files', 'products_csv_ok.csv')) click_button "Send file" end When /^I upload a malformed file$/ do attach_file(:csv_file, File.join(RAILS_ROOT, 'features', 'upload-files', 'products_csv_bad.csv')) click_button "Send file" end
The idea here is to create two files, one good and one invalid, and put them somewhere inside your application. I put them inside features/upload-files, you can place them wherever you like. The attach_file method received a symbol with the name of the field used for the upload and the path for a file in your disc. After associating the field with the path for the file, all we’ll have to do is “to click” at the submit button.
Here’s the code of the action I wrote
def create_from_csv_file csv_data = params[:csv_file] if Product.create_from_csv(csv_data) flash[:notice] = "Products succesfully created" redirect_to products_url else flash[:error] = "Invalid file contents" render :action => "new_csv_file" end end
With this solution you can test any kind of file uploads. A good example would be to create restrictions about the type of the files that can be uploaded, restrictions about the dimensions of uploaded images and so on.