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)
Related
I am trying to mock copyFile and stat method from fs modules(fs.promises). But the mocked function is not being called and instead the original functions are called though the test cases pass.
The testing function code is:
jest.doMock('fs', () => ({
promises: {
copyFile: (src = 'source', dest = 'destination') =>
jest.fn().mockImplementation(async () => {
console.log('Inside the mock function in copyFile, please get executed, got frustrated', src, dest);
return Promise.resolve(false);
}),
stat: () =>
jest.fn().mockImplementation(async () => {
console.log('Inside the mock function in stat method, please get executed, got frustrated');
return Promise.resolve(false); // Probably wrong datatype
}),
},
}));
describe('Testing implementation', () => {
const sample = new MainFunction()
test('Testing', async () => {
expect(sample.demo()).toEqual(Promise.resolve(true));
});
});
Actual Code which needs to be tested:
import * as fs from 'fs';
export class MainFunction {
async demo(): Promise<any> {
const fileName = 'C:/Users/Desktop/testing-file-dir/';
const fileName1 = '/destination/'
let filefound = (await fs.promises.stat(fileName)).isFile();
await fs.promises.copyFile(fileName,fileName1);
console.log(filefound, 'inside actual code');
return Promise.resolve(true);
}
}
Can someone please help regarding where I am going wrong ? I had thought of using jest.mock but it was also giving error so I followed this link https://github.com/facebook/jest/issues/2567 which suggested to try doMock. If someone knows better way to handle this mock function, it would be great.
Thanks !
You can use jest.mock(moduleName, factory, options), and you didn't mock the method chain call correctly. You should use mockFn.mockReturnThis() to return this context to the caller.
E.g.
index.ts:
import * as fs from 'fs';
export class MainFunction {
async demo(): Promise<any> {
const fileName = 'C:/Users/Desktop/testing-file-dir/';
const fileName1 = '/destination/';
let filefound = (await fs.promises.stat(fileName)).isFile();
await fs.promises.copyFile(fileName, fileName1);
console.log(filefound, 'inside actual code');
return Promise.resolve(true);
}
}
index.test.ts
import { MainFunction } from './';
jest.mock('fs', () => ({
promises: {
copyFile: jest.fn().mockImplementation((src = 'source', dest = 'destination') => {
console.log('Inside the mock function in copyFile, please get executed, got frustrated', src, dest);
return Promise.resolve(false);
}),
stat: jest.fn().mockReturnThis(),
isFile: jest.fn().mockImplementation(() => {
console.log('Inside the mock function in stat method, please get executed, got frustrated');
return Promise.resolve(false);
}),
},
}));
describe('Testing implementation', () => {
const sample = new MainFunction();
test('Testing', async () => {
const actual = await sample.demo();
expect(actual).toBeTruthy();
});
});
test result:
PASS examples/66429093/index.test.ts
Testing implementation
✓ Testing (10 ms)
console.log
Inside the mock function in stat method, please get executed, got frustrated
at Object.<anonymous> (examples/66429093/index.test.ts:12:15)
console.log
Inside the mock function in copyFile, please get executed, got frustrated C:/Users/Desktop/testing-file-dir/ /destination/
at Object.<anonymous> (examples/66429093/index.test.ts:7:15)
console.log
Promise { false } inside actual code
at MainFunction.<anonymous> (examples/66429093/index.ts:9:13)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 3.12 s, estimated 4 s
Based upon slideshowp2's solution, I had to do this change in order to avoid the error as stated in this https://github.com/facebook/jest/issues/2567.
The actual file remains same while test file changes to:
jest.mock('fs', () => {
const originalModule = jest.requireActual('fs'); // so as to not override other functions apart from below mentioned one's
return Object.assign({ __esModule: true }, originalModule, {
promises: {
copyFile: jest.fn().mockImplementation((src, dest) => {
// src, dest are parameters passed in copyFile from src to destination
let source = 'some source'; // sample source file
if (source === src) {
return true;
} else {
throw Error;
}
}),
stat: jest.fn().mockReturnThis(),
isFile: jest
.fn()
.mockImplementationOnce(() => { // I had series of test so for first one I wanted false hence this part, else we can remove this and directly use .mockImplementation()
return false;
})
.mockImplementation(() => {
return true;
}),
},
});
});
describe('Testing implementation', () => {
const sample = new MainFunction();
test('Testing', async () => {
const actual = await sample.demo();
expect(actual).toBeTruthy();
});
});
My NodeJS application has to do some API requests, so I'm mocking their return as my tests are just for my application's business logic. However, there's two things that I quite didn't understand.
I'm using jest's mockImplementation method to change the return of my service, but I can't make it work without calling jest.mock with the service beforehand.
Also, if I try to set automock: true in my jest.config.js, it returns me an error:|
TypeError: Cannot set property 'gracefulify' of undefined
Here's my test.js code in where I'm testing a function that calls automation.js, which has my application logic and make the calls for my services:
const automation = require('../automations/fake.automation');
// MOCKS
const mockedBlingProduct = require('../mocks/bling-product.mocks.json');
const mockedShopifyCreatedProduct = require('../mocks/shopify-created-product.mocks.json');
// SERVICES
const BlingProductService = require('../services/bling-product.service');
const ShopifyProductService = require('../services/shopify-product.service');
jest.mock('../services/bling-product.service');
jest.mock('../services/shopify-product.service');
describe('Automation test', () => {
beforeEach(() => {
const blingMockedReturn = jest.fn(() => {
return mockedBlingProduct;
});
const shopifyMockedReturn = jest.fn(() => {
return mockedShopifyCreatedProduct;
});
BlingProductService.mockImplementation(() => {
return {
list: blingMockedReturn
};
});
ShopifyProductService.mockImplementation(() => {
return {
create: shopifyMockedReturn
};
});
});
it('should return status SUCCESS', async () => {
const result = await
.run();
expect(result).toEqual({ status: 'SUCCESS' });
});
});
And here's the code of one of my services, keep in mind that the logic behind the API calls is abstracted from the service. In the mockImplementation I'm trying to overwrite the list and create functions inside them:
class BlingPriceService {
async list(query = {}) {
const httpMethod = 'GET';
const resource = 'produtos/page={pageNumber}/json';
const options = {
queryString: query,
urlParams: {
pageNumber: 1,
}
};
return blingComponent.request(httpMethod, resource, options);
}
}
module.exports = BlingPriceService;
const automation = require('../automations/fake.automation');
// MOCKS
const mockedBlingProduct = require('../mocks/bling-product.mocks.json');
const mockedShopifyCreatedProduct = require('../mocks/shopify-created-product.mocks.json');
// SERVICES
const BlingProductService = require('../services/bling-product.service');
const ShopifyProductService = require('../services/shopify-product.service');
describe('Automation test', () => {
beforeAll(() => {
jest.spyOn(BlingProductService.prototype, 'list').mockImplementation(() => Promise.resolve(mockedBlingProduct));
jest.spyOn(ShopifyProductService.prototype, 'list').mockImplementation(() => Promise.resolve(mockedShopifyCreatedProduct));
});
afterAll(() => {
jest.restoreAllMocks();
});
it('should return status SUCCESS', async () => {
const result = await automation.run();
expect(result).toEqual({ status: 'SUCCESS' });
});
});
I want to unit test the exported method in the code below. Trying to write unit tests for a function that is downloading a zip file from a localhost server.I will write my function bellow so you understand better:
export const downloadCdn = async (cdnUrl, out) => {
const download = (resolve, reject) => {
const req = request({
method: 'GET',
uri: cdnUrl
});
req.on('response', (data) => {
// do something
});
req.on('error', (data) => {
// do something
});
req.on('data', (chunk) => {
// do something
});
req.on('end', () => {
console.log('download done');
});
req.pipe(out);
out.on('close', () => {
resolve([null, 'done']);
});
};
const downloadSummary = new Promise(download);
return downloadSummary
.then(() => [null, 'Done'])
.catch(err => [err, null]);
};
Here are my test file, what I'm trying to achieve is to have unit test that validates the download of the zip file:
import request from 'request';
import * as Module from './downloadCdn';
jest.mock('request', () => {
const mockRequest = {
pipe: jest.fn(),
on: jest.fn(),
};
return function () {
return mockRequest;
};
});
describe('Downloading a file', () => {
it('Should find the module', () => {
expect(typeof Module.downloadCdn === 'function').toBeTruthy();
});
it('Should download the zip', async () => {
const [error, response] = await Module.downloadCdn(cdnUrl, out);
expect(response === 'Done').toBeTruthy();
expect(error === null).toBeTruthy();
});
});
The response from the Promise, I receive inside the test is null, no error catching. Here is the error received from jest:
expect(received).toBeTruthy()
Expected value to be truthy, instead received false
While mocking the request, you should resolve the promise. I think that promise is not resolving that's why it's not working. I hope that the below code will be fixed your problem.
jest.mock('request', () => {
const mockRequest = {
pipe: jest.fn(),
on: (parameter, callback) => {
callback();
},
};
return function () {
return mockRequest;
};
});
I need to test value of the url variable in the pullPackage() function in the TASK class.
class TASK {
constructor(taskData, done) {
//some code
}
// Generic Setup
pullPackage() {
return new Promise((resolve, reject) => {
fs.emptydir(this.taskDir, (err) => {
if (err) return reject(err);
const git = require('simple-git')(this.taskDir);
let url = '';
console.log(process.env.NODE_ENV);
if (process.env.NODE_ENV === 'test') {
// url = 'ssh://testuser#127.0.0.1:4000/testuser/test-repo-1.git'; // make this match the below format
url = '/git/testuser/test-repo-1';
} else {
const gitAddress = new URL(config.config.GIT_ADDRESS);
url = `${gitAddress.protocol}//runner:${this.taskData.gitJWT}#${gitAddress.hostname}:${gitAddress.port}${this.taskData.repo}.git`;
}
// console.log(url);
// const url = `${gitAddress.protocol}//runner:${this.taskData.gitJWT}#${gitAddress.hostname}:${gitAddress.port}${this.taskData.repo}.git`;
this.logger.log('Cloning from', url);
return git.clone(url, 'repo', (cloneErr) => {
if (cloneErr) return reject(cloneErr);
// console.log(url);
// console.log(resolve);
return resolve(true);
});
});
});
}
}
I'm using Mocha and Chai to do this. I have two test for this function, to check the variable and the promise. The second test runs as expected, but the first always return fails with AssertionError: expected undefined not to be undefined. I think the issue is how I'm accessing the variable during testing. Currently I'm doing it like this: expect(result.url).to.not.be.undefined; Am I going about this correctly?
describe('Test MenloLab Runner - Task Class', () => {
describe('Pull Package', () => {
it('Check URL constant.', () => task.pullPackage().then((result) => {
expect(result.url).to.not.be.undefined; // adjust the access method
}));
it('It should pull package from GIT.', () => task.pullPackage().then((result) => {
expect(result).to.be.true;
}));
});
});
The workaround to check the URL could be done by spying on git.clone method. To do that, we need to use Sinon
I haven't tested with your code but I give you a clue on the solution below:
const sinon = require('sinon');
const git = require('simple-git');
describe('Test MenloLab Runner - Task Class', () => {
describe('Pull Package', () => {
it('Check URL constant.', () => {
return task.pullPackage().then((result) => {
sinon.spy(git, 'clone'); // spying on git.clone method
expect(result.url).to.not.be.undefined; // adjust the access method
const expectedUrl = 'my-expected-not-undefined-url';
sinon.assertCalledWith(git.clone, expectedUrl); // we check whether git.clone is called with not undefined URL
});
});
it('It should pull package from GIT.', () => task.pullPackage().then((result) => {
expect(result).to.be.true;
}));
});
});
Hope it helps
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.