fasantos
fasantos

Reputation: 189

How to mock AWS S3 getObject with sinon

I'm trying to unit test a restify route that returns an S3 object from a bucket

my route is:

module.exports = function(server) {
  server.get('/configs/:version', (req, res, next) => {
    const s3 = new AWS.S3();

    const params = {
      Bucket: 'testBucket',
      Key: 'testKey'
    };

    function send(data, next) {
      res.setHeader('Content-Type', 'text/plain');
      res.setHeader('Cache-Control', 'no-cache');
      res.status(200);
      res.send(data.Body);
      next();
    }

    s3.getObject(params, (err, data) => (err) ? next(err) : send(data, next));
  });
};

For my unit test I've been trying to mock the S3 constructor so I can stub getObject and failing miserably.

describe('#configs', () => {
  let req;
  let res;
  let next;
  let server;
  let config;
  let AWS;
  let S3;
  let route;

  beforeEach(() => {
    req = {
      params: {
        version: 'testVersion'
      }
    };

    res = {
      send: sinon.spy(),
    };

    next = sinon.spy();

    server = {
      get: sinon.stub(),
    };

    config = {
      get: sinon.stub(),
    }

    AWS = () => {
      return {
        S3: () => {
          return {
            getObject: sinon.stub()
          }
        }
      }
    }

    route = proxyquire(process.cwd() + '/lib/routes/configs/get', {
      'configs.js': config,
      'aws-sdk': AWS,
    });

    route(server);
  });

  describe('#GET', () => {
    it('Should register configs get route', () => {
      let s3 = sinon.createStubInstance(AWS.S3, {
        getObject: sinon.stub(),
      });

      server.get.callArgWith(1, req, res, next);
      expect(server.get).calledOnce.calledWith('/configs/:version');
      expect(s3.getObject).calledOnce.calledWith({
        Bucket: 'testBucket',
        Key: 'testKey'
      });
    });
  });
});

But I getting this error: TypeError: undefined is not a spy or a call to a spy! on the getObject method. After reading sinon docs over and over again I can't understand how to mock the constructor, how can I stub the getObject method so I can make sure it's being called correctly and it's returns so I know it's responses are being treated correctly Can someone help me with this?

Upvotes: 3

Views: 4836

Answers (2)

learner4567
learner4567

Reputation: 1

const getObjectStub = AWS.S3.prototype.getObject = Sinon.stub();
    getObjectStub.yields(null, {
    AcceptRanges: "bytes", 
    ContentLength: 3191, 
    ContentType: "image/jpeg", 
    Metadata: {
    }, 
    TagCount: 2, 
    VersionId: "null"
   }
);

Upvotes: 0

fasantos
fasantos

Reputation: 189

Finally made my mocks work, the issue was that I was mocking AWS as a function not has an object, it's S3 that needs to be mocked as a function, because it's S3 that needs to be instantiated. This is how the mock should look like:

function S3() { 
  return s3;
}

s3 = {
  getObject: sinon.stub(),
  putObject: sinon.stub()
};

AWS = {
  config: {
    update: sinon.stub()
  },
  S3: S3
};

Like this if one needs to mock putObject, he just needs for example do this: s3.putObject.callsArgWith(1, err, data);

Upvotes: 2

Related Questions