Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stubbing S3 uploads in Node.js

How would I go about stubbing S3 uploads in Node.js?

For insight, I'm using Mocha for tests and Sinon for stubbing, but I'm open to changing anything. I have a file that exports a function that performs the upload. It looks like this:

var AWS = require('aws-sdk');
var s3 = new AWS.S3({ params: { Bucket: process.env.S3_BUCKET }});
var params = { Key: key, Body: body };
s3.upload(params, function (error, data) {
  // Handle upload or error
});

If I try to stub AWS.S3 or AWS.S3.prototype, nothing changes. I assume this is because my tests have required aws-sdk themselves and have their own copy of each function.

My test looks like this:

describe('POST /files', function () {
  var url = baseURL + '/files';
  it('uploads the file to s3', function (done) {
    var fs = require('fs');
    var formData = {
      video: fs.createReadStream(process.cwd() + '/test/support/video.mp4')
    };
    var params = {url: url, formData: formData};
    request.post(params, function (error, response, body) {
      expect(response.statusCode).to.eq(200);
      expect(response.body).to.eq('Uploaded');
      done();
    });
  });
});

This test works fine, but it does not stub the upload to S3, so the upload actually goes through :X.

like image 531
Baub Avatar asked Oct 20 '22 01:10

Baub


2 Answers

There are several options to mock S3 in Node.

Some modules specific to S3:

  • https://www.npmjs.com/package/mock-s3
  • https://www.npmjs.com/package/mock-aws-s3

Some modules for general AWS mocking:

  • https://www.npmjs.com/package/aws-sdk-mock
  • https://www.npmjs.com/package/mock-aws-sinon
  • https://www.npmjs.com/package/mock-aws

And you can even start a simple server that responds to some of the S3 API calls:

  • https://www.npmjs.com/package/s3rver

The last one can easily be used in other languages and runtimes, not only in Node.

like image 163
rsp Avatar answered Oct 22 '22 00:10

rsp


You can stub with Sinon.js as follows if you'd like:

  1. Expose the AWS.S3 instance:

    var AWS = require('aws-sdk');
    var s3 = new AWS.S3({ params: { Bucket: process.env.S3_BUCKET }});
    var params = { Key: key, Body: body };
    exports.s3.upload(params, function (error, data) {
    
    });
    //Expose S3 instance
    exports.s3 = s3;
    
  2. Stub the same instance like so:

    var sinon = require('sinon');
    //Import module you are going to test
    var UploadService = require('./uploadService');
    
    describe('POST /files', function () {
    
      before(function() {
        //Stub before, and specify what data you'd like in the callback.
        this.uploadS3Stub = sinon.stub(uploadService.s3, 'upload').callsArgWith(1, null, { data: 'Desired response' });
      });
    
      after(function() {
        //Restore after
        this.uploadS3Stub.restore();
      });
    
      var url = baseURL + '/files';
      it('uploads the file to s3', function (done) {
        var fs = require('fs');
        var formData = {
          video: fs.createReadStream(process.cwd() + '/test/support/video.mp4')
        };
        var params = {url: url, formData: formData};
        var self = this;
    
        request.post(params, function (error, response, body) {
          expect(response.statusCode).to.eq(200);
          expect(response.body).to.eq('Uploaded');
          //You can also check whether the stub was called :)
          expect(self.uploadS3Stub.calledOnce).to.eql(true);
          done();
        });
      });
    });
    
like image 38
gyamana Avatar answered Oct 22 '22 00:10

gyamana