Jest mock aws-sdk ReferenceError: Cannot access before initialization
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
grigori
Updated on June 24, 2022Comments
-
grigori almost 2 years
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.
-
grigori about 4 yearsHi @slideshowp2, this looks great but I've hit an issue because in my code I've got something like this
dynamodb.getItem(params).promise().then(onSuccess).catch(onError)
. Using your approach, I'm gettingTypeError: Cannot read property 'then' of undefined
. (I've updated my example above, just to be clearer). Thanks for your help. -
slideshowp2 about 4 years@grigori Updated answer based on your update. It works fine.
-
grigori about 4 yearsyou're right, I had a typo. Thanks a lot, this helped heaps!
-
amr ras almost 3 yearsIn other cases jest will complain that DynamoDB should be mocked with a function prefixed with 'mock'. So, this doesn't seem like a legit solution. Jest just seems buggy. I've done this in one file and it runs, then in another file it complains.