Skip to content
Advertisement

Jest skipping S3 Get Object call in function

Im testing a standard S3 Get Object Call, but when Jest tests my function, it skips the Get Object call and jumps to end of function, ending the execution and returning nothing. When I checked code coverage, all lines are covered expect the getObject call.

This is my s3 file being tested. I have checkpoints there to show that the s3.getObject call is being skipped by Jest.

const AWS = require('aws-sdk');

const s3 = new AWS.S3({ apiVersion: '2012-11-05 ' })

function getS3Object(bucket, file) {
  return new Promise((resolve, reject) => {
    console.log('Checkpoint 1')
    const parameters = {
      Bucket: bucket,
      Key: file
    }
    s3.getObject(parameters, (error, data) => {
      console.log('checkpoint 2')
      if (error) {
        console.log('error')
        reject(error)
      } else {
        console.log('success')
        resolve(data)
      }
    })
    console.log('Checkpoint 3')
  })
}
module.exports = {
  getS3Object
}

This is my test file.

const s3Handler = require('../s3')
const AWS = require('aws-sdk')


jest.mock('aws-sdk', () => {
  const mockS3 = {
    getObject: jest.fn().mockReturnThis(),
    promise: jest.fn()
  }
  return {
    config: {
      update() {
        return {};
      }
    },
    S3: jest.fn(() => mockS3)
  }
})

describe('S3 get object test', () => {
  test('test', async () => {

    const mockS3 = new AWS.S3();
    mockS3.getObject('test-bucket', 'test-key').promise.mockResolvedValueOnce('s3file.js');
    const output = s3Handler.getS3Object('test-bucket', 'test-key');
    expect(output).resolves.toEqual('blah')

  })

})

This test passes (even though the expect state is wrong. It should return ‘s3File.js’, not ‘blah’ but the test passes regardless). For the console logs, only checkpoints 1 and 3 are hit – the entire S3 call is ignored by the function. Is this an issue with how I mocked s3?

Answer

Since the s3.getObject() accepts an error-first callback, it’s NOT a JS promise, you should use .mockImplementation((params, callback) => callback(mockErr, mockData)) to mock the error-first callback and invoke it with mock data or error.

E.g.

s3.js:

const AWS = require('aws-sdk');

const s3 = new AWS.S3({ apiVersion: '2012-11-05 ' });

function getS3Object(bucket, file) {
  return new Promise((resolve, reject) => {
    console.log('Checkpoint 1');
    const parameters = {
      Bucket: bucket,
      Key: file,
    };
    s3.getObject(parameters, (error, data) => {
      console.log('checkpoint 2');
      if (error) {
        console.log('error');
        reject(error);
      } else {
        console.log('success');
        resolve(data);
      }
    });
    console.log('Checkpoint 3');
  });
}

module.exports = { getS3Object };

s3.test.js:

const s3Handler = require('./s3');
const AWS = require('aws-sdk');

jest.mock('aws-sdk', () => {
  const mockS3 = { getObject: jest.fn() };
  return {
    config: {
      update() {
        return {};
      },
    },
    S3: jest.fn(() => mockS3),
  };
});

describe('S3 get object test', () => {
  let mockS3;
  beforeAll(() => {
    mockS3 = new AWS.S3();
  });
  test('should get object', async () => {
    mockS3.getObject.mockImplementation((params, callback) => {
      callback(null, 's3file.js');
    });
    const output = s3Handler.getS3Object('test-bucket', 'test-key');
    await expect(output).resolves.toEqual('s3file.js');
  });

  test('should handle error', async () => {
    const mError = new Error('fake error');
    mockS3.getObject.mockImplementation((params, callback) => {
      callback(mError);
    });
    const output = s3Handler.getS3Object('test-bucket', 'test-key');
    await expect(output).rejects.toThrow(mError);
  });
});

Test result:

 PASS  stackoverflow/72694206/s3.test.js (10.902 s)
  S3 get object test
    ✓ should get object (18 ms)
    ✓ should handle error (4 ms)

  console.log
    Checkpoint 1

      at stackoverflow/72694206/s3.js:7:13

  console.log
    checkpoint 2

      at stackoverflow/72694206/s3.js:13:15

  console.log
    success

      at stackoverflow/72694206/s3.js:18:17

  console.log
    Checkpoint 3

      at stackoverflow/72694206/s3.js:22:13

  console.log
    Checkpoint 1

      at stackoverflow/72694206/s3.js:7:13

  console.log
    checkpoint 2

      at stackoverflow/72694206/s3.js:13:15

  console.log
    error

      at stackoverflow/72694206/s3.js:15:17

  console.log
    Checkpoint 3

      at stackoverflow/72694206/s3.js:22:13

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |     100 |      100 |     100 |     100 |                   
 s3.js    |     100 |      100 |     100 |     100 |                   
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        11.513 s, estimated 12 s
Advertisement