Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jest mock aws-sdk ReferenceError: Cannot access before initialization

Jest 25.3.0

I am trying to mock DynamoDB dependency in my unit tests as follows:

const { findById } = require('./mymodule');

const mockDynamoDB = { getItem: jest.fn() };
jest.mock('aws-sdk', () => ({
  DynamoDB: jest.fn(() => mockDynamoDB)
}));

describe('.', () => {
  it('..', () => {
    findById('test');
    expect(mockDynamoDB.getItem).toBeCalledWith({
      TableName: 'table-name',
      Key: {
        id: { S: 'test' }
      }
    });
  });
});

Unfortunately, when I do that, I get the following error:

ReferenceError: Cannot access 'mockDynamoDB' before initialization

Strangely, if I do this, I can avoid the ReferenceError:

const mockGetItem = { promise: jest.fn() };
jest.mock('aws-sdk', () => ({
  DynamoDB: jest.fn(() => ({
    getItem: jest.fn(() => mockGetItem)
  })
}));

but this doesn't suit my test, as I can't validate the params passed to the getItem function.

The actual code under test is fairly simple, it looks something like this:

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

const dynamodb = new AWS.DynamoDB({apiVersion: '2012-08-10'});

const toRecord = (item) => ({
  id: item.id.S,
  name: item.name.S
});

const findById = (id) => (
  dynamodb.getItem({
    TableName: 'table-name',
    Key: {
      id: { S: id }
    }
  }).promise()
    .then(result => toRecord(result.Item))
    .catch(error => console.log(error)
);

module.exports = {
  findById
}

If anyone has seen this before, or can shed some light on why the first example fails while the second works, it would really help me out. Thank you.

like image 447
grigori Avatar asked Apr 11 '20 13:04

grigori


Video Answer


1 Answers

Here is the unit test solution:

index.js:

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

const dynamodb = new AWS.DynamoDB({ apiVersion: '2012-08-10' });
const toRecord = (item) => ({
  id: item.id.S,
  name: item.name.S,
});

const findById = (id) =>
  dynamodb
    .getItem({
      TableName: 'table-name',
      Key: {
        id: { S: id },
      },
    })
    .promise()
    .then((result) => toRecord(result.Item))
    .catch((error) => console.log(error));

module.exports = { findById };

index.test.js:

const { findById } = require('./');
const AWS = require('aws-sdk');

jest.mock('aws-sdk', () => {
  const mDynamoDB = { getItem: jest.fn().mockReturnThis(), promise: jest.fn() };
  return { DynamoDB: jest.fn(() => mDynamoDB) };
});

describe('61157392', () => {
  let dynamodb;
  beforeAll(() => {
    dynamodb = new AWS.DynamoDB();
  });
  afterAll(() => {
    jest.resetAllMocks();
  });
  it('should pass', async () => {
    dynamodb.getItem().promise.mockResolvedValueOnce({
      Item: {
        id: { S: '1' },
        name: { S: 'a' },
      },
    });
    const actual = await findById('1');
    expect(actual).toEqual({ id: '1', name: 'a' });
    expect(dynamodb.getItem).toBeCalledWith({
      TableName: 'table-name',
      Key: {
        id: { S: '1' },
      },
    });
    expect(dynamodb.getItem().promise).toBeCalledTimes(1);
  });
});

unit test results with 100% coverage:

 PASS  stackoverflow/61157392/index.test.js (8.216s)
  61157392
    ✓ should pass (4ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |   88.89 |      100 |      75 |    87.5 |                   
 index.js |   88.89 |      100 |      75 |    87.5 | 19                
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        9.559s

source code: https://github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/stackoverflow/61157392

like image 61
slideshowp2 Avatar answered Oct 13 '22 22:10

slideshowp2