How to fix toArray is not undefined in Jest - javascript

I'm create a unit test with Jest and run the tests I get a error with the test: "TypeError: db.find(...).toArray is not a function". if someone can help me I'll be grateful.
greetings :)
'use strict';
const DB = require('../../../../app/databases/mongo');
jest.mock('../../../../app/databases/mongo');
const noteController = require('../../../../app/controllers/note');
function functionMock(returnValue) {
const find = jest.fn(() => Promise.resolve(returnValue));
return jest.fn(() => ({
find: () => ({ find })
}));
}
describe('noteController', () => {
beforeAll(() => {
DB.getDb.mockImplementation(functionMock(null));
});
describe('note controller', () => {
describe('find', () => {
it('note list', async done => {
const ctx = jest.fn();
await noteController.find(ctx)
.then(result => {
expect(result).toBeDefined();
});
done();
})
})
})
});
I expect the output with data in the promise resolve but i get: "TypeError: db.find(...).toArray is not a function"

Well, you don't show us where db comes from, but my guess is that db.find(...) does not return a result set.
Change your code to be:
var dbResult = db.find(...)
expect(dbResult.toArray).toBeDefined
That will allow you to assert that you have an object with the toArray method defined.
There's probably a better way to assert that, but you didn't include enough code to figure it out so I'm guessing.

Related

Mocking html-pdf using Jest

I am using the html-pdf package in my nodejs code (not in Typescript). Now, this package has a create() function which is chained with the toBuffer() function. I am unit testing my code using Jest and want to mock this call pdf.create(html).toBuffer().
var pdf = require('html-pdf');
pdf.create(html).toBuffer(function(htmlToPdfError, buffer){
if (htmlToPdfError) {
reject(htmlToPdfError);
}
resolve(buffer.toString('base64'));
});
EDIT:
I am trying to use the following code in my spec file to make the module:
jest.mock('html-pdf', () => ({
create: jest.fn(() => {
return Promise.resolve();
})
}));
This is helping me mock the create() function but I do not know how to return a object in Promise.resolve which would have a toBuffer function
I could mock it using the following code:
const mockToBuffer = {
toBuffer: jest.fn((callback: Function) => callback(null, null)),
}
jest.mock('html-pdf', () => ({
create: jest.fn(() => mockToBuffer),
}))
it('Should work', async () => {
const expectedResult = Buffer.from([10])
mockToBuffer.toBuffer.mockImplementation((callback: Function) => {
callback(null, expectedResult)
})
// const result = await yourFuncUsingHtmlPdf(/* fakePayload */)
// Comparing the buffer using the native function
// expect(expectedResult.equals(result)).toBe(true)
}
will this work?
and then assert that your "pdf" buffer contains "test string"?
jest.mock('html-pdf', () => ({
create: jest.fn(() => {
return Promise.resolve({
toBuffer: function(callback) {
callback(null, Buffer.from("test string", "utf-8"));
},
});
})
}));
(I haven't tried it)

Jest mock not allowing inner function to be resolved in individual test

I'm testing a cloud function named myCloudFn in my functions/send.js module. My tests are in functions/test/send.test.js:
// send.js
const { getCompareDate } = require('../utils.js');
async function myCloudFn(myTestDate) {
const compareDate = await getCompareDate(argToTest);
const isOlder = myTestDate < compareDate;
return isOlder ? 'older' : 'newer';
}
module.exports = { myCloudFn };
// send.test.js
const send = require('../send.js');
jest.mock('../utils', () => ({
getCompareDate: jest.fn(() => new Date('2020-01-31')) // default
.mockResolvedValueOnce(new Date('2020-04-04'))
.mockResolvedValueOnce(new Date('2020-02-02')),
}));
describe('send.js', () => {
it('returns date comparison from myCloudFn()', async () => {
const myTestDate = '2020-03-03';
const returnValues = ['older', 'newer'];
const responsePromises = returnValues.map(() => send.myCloudFn(myTestDate));
const responses = await Promise.all(responsePromises);
expect(responses[0]).toBe(returnValues[0]);
expect(responses[1]).toBe(returnValues[1]);
});
});
The test functions correctly and passes as expected when I mock getCompareDate in this way, but for flexibility, I would rather provide custom input values for getCompareDate inside my tests and not 'globally'. Here's what I've tried:
const mockGetCompareDate = jest.fn();
jest.mock('../utils', () => ({
getCompareDate: mockGetCompareDate,
}));
it('returns date comparison from myCloudFn()', async () => {
mockGetCompareDate
.mockResolvedValueOnce(new Date('2020-04-04'))
.mockResolvedValueOnce(new Date('2020-02-02'));
const myTestDate = '2020-03-03';
const returnValues = ['older', 'newer'];
const responsePromises = returnValues.map(() => send.myCloudFn(myTestDate));
const responses = await Promise.all(responsePromises);
expect(responses[0]).toBe(returnValues[0]);
expect(responses[1]).toBe(returnValues[1]);
});
This method, however, is not working and throws an error:
ReferenceError: Cannot access 'mockGetCompareDate' before initialization
I've used this method with other tests as noted in the solution in this question, but I am not seeing similar results here. What am I missing?
Jest is hoisting the mocked function to the top of the module, and hence throws this error. The mock should instead be used right before you run the test. Further reading.
Try this:
const { getCompareDate } = require('../utils.js');
const mockGetCompareDate = jest.fn(() => new Date('2020-01-31'));
jest.mock('../utils.js', () => ({
__esModule: true,
getCompareDate: jest.fn(),
default: jest.fn()
}));
beforeAll(() => {
getCompareDate.mockImplementation(mockGetCompareDate);
});
To provide custom values do as you did before, when initialising the mock function. Source
Like this:
const mockGetCompareDate = jest.fn()
.mockResolvedValueOnce(new Date('2020-04-04'))
.mockResolvedValueOnce(new Date('2020-02-02'));
Or do as you did before inside the test. Source
Like this:
it('returns date comparison from myCloudFn()', async () => {
mockGetCompareDate
.mockResolvedValueOnce(new Date('2020-04-04'))
.mockResolvedValueOnce(new Date('2020-02-02'));

Problem running Jest using CLS with async functions

I can't seem to get CLS to work with Jest.
The following code:
export {}
const { promises: fs } = require('fs')
describe('CLS tests', () => {
test('Can test CLS', async () => {
var createNamespace = require('cls-hooked').createNamespace
var session = createNamespace('session')
session.run(async function () {
await fs.readFile('package.json', 'utf-8')
console.log('I cant log this')
})
})
})
Results in the following error:
Cannot log after tests are done. Did you forget to wait for something
async in your test?
Attempted to log "I cant log this".
Why is it that my test appears to be exiting early?
Maybe you need to abstract out the asynchronous operations. I tried this on my system and it works.
const {promises: fs} = require('fs')
const runSession = () => new Promise((resolve, reject) => {
const createNamespace = require('cls-hooked').createNamespace
const session = createNamespace('session')
session.run(() => {
fs.readFile('package.json', 'utf-8')
.then(resolve)
})
})
describe('CLS tests', () => {
test('Can test CLS', async () => {
const result = await runSession()
console.log('hello')
console.log(result)
expect(result).toBeTruthy()
console.log('after expect...')
})
})
Good Luck...

Jest mocking a module

I'm trying to mock a module import using Jest and I'm struggling for some reason. I've got the following code:
src/elastic.js
const getRolesFunc = elasticClient => async username => {
// Do some stuff
}
module.exports = { getRolesFunc };
src/handlerFactory.js
const { getRolesFunc } = require("../src/elastic");
const handlerFactory = elasticClient =>
async (event) => {
const getRolesAsync = getRolesFunc(elasticClient);
const roles = await getRolesAsync();
}
}
My test file currently looks like:
tests/handlerFactory.unit.test.js
const { handlerFactory } = require("../src/handlerFactory");
const { getRolesFunc } = require("../src/elastic");
jest.mock("../src/elastic", () => ({
getRolesFunc: jest.fn(),
}));
describe("handlerFactory", () => {
it("handler returns correct response", async () => {
getRolesFunc.mockImplementation(() => "foo");
// Call the handler to get our actual result
const handlerAsync = handlerFactory({});
const result = await handlerAsync(event);
});
});
At the moment however I'm getting an error in my test:
TypeError: getRolesFunc.mockImplementation is not a function
I've tried a few things none of which worked, this feels like the closest but I can't work out why the jest.mock isn't working correctly. I've looked at a few examples and still can't work out why this I can't get mocking working. Can anyone help point out what I've done wrong?
As you have module.exports = { getRolesFunc }; you need to below change in your code:
const { handlerFactory } = require("../src/handlerFactory");
const elasticObj = require("../src/elastic");
jest.mock("..src/elastic");
// in your example, now put below code:
elasticObj.getRolesFunc.mockImplementation(() => "foo");

Locked it method in chai

I have a js file which supplies some db operations. This file works with promises only which can be chained. To test that class I work with an async function.
The problem is, that whenever I work with promises inside my test function the it function gets blocked for every other test later.
Here are two examples:
'use strict'
const exec = require('child_process').exec
const path = require('path')
const request = require('request')
const expect = require('chai').expect
const createTableStatements = require('../data')
test()
async function test () {
await testGetUser()
console.log('1')
await testGetFaculties()
}
function testGetUser () {
return new Promise((resolve1) => {
describe('test get user', function () {
const db = require('../dbInterface')
it('test get user should be complete', function () {
db.dbFunctions.dropAll()
.then(onResolve => {
return db.dbFunctions.createTable(createTableStatements.createTableStatements.user)
}
)
.then(() => {
console.log('success create user table')
return db.dbFunctions.addUser('1', 'firstName', 'lastName', 'email')
})
.then(resolve => {
return db.dbFunctions.getUser('email', undefined)
})
.then(result => {
expect(result.toString().includes('dummy')).to.equal(false)
})
.then(resolve => {
return db.dbFunctions.dropAll()
})
.then(resolve => {
console.log('resolve')
resolve1()
})
.catch(err => console.log(err))
})
})
})
}
function testGetFaculties () {
return new Promise(resolve => {
describe('test get faculties', function () {
let db
before(function () {
db = require('../dbInterface')
})
console.log('displayed')
it('should work', function () {
console.log('locked')
expect(db.dbFunctions.getFaculties('hsa')).to.be.an('array').that.does.include('Science')
resolve()
})
})
})
}
And this is the output
resolve
1
displayed
As you can see console.log('locked') is not being processed.
What i figured out so far, that I only have this issue when I call expect within a then function. But this is necessary for my tests.
The test () function should contain much more tests, only for this question I shortened it.
And for clarification: If I only test methods type of testGetFaculties () which don't contains another promise chain inside it works like it should.
Any idea why this is like it is?
Most probably the console.log( 'locked' ); doesn't do anything, because your previous test case was not finished at all.
Writing describe, it, before inside a Promise and containing unreturned Promises is something that you should not do.
Much better test case would look like :
'use strict'
const exec = require('child_process').exec
const path = require('path')
const request = require('request')
const expect = require('chai').expect
const createTableStatements = require('../data')
// You use this in both test cases anyway
const db = require('../dbInterface');
describe('test get user', function () {
it('test get user should be complete', function () {
return db
// ^ returning promise will make sure that the test ends when the promise ends.
.dbFunctions
.dropAll()
.then(onResolve => { ... } )
...
)
} );
} );
describe('test get faculties', function () {
it('should work', function () {
return db
// ^ returning promise will make sure that the test ends when the promise ends.
.dbFunctions
.getFaculties('hsa')
.then( value => {
// ^ You actually need to test the value of the resolve promise
expect( value ).to.be.an('array').that.does.include('Science');
} )
} );
} );

Categories