How do I mock a third party package with Jest? - javascript

I want to be able to test whether or not this Swal() function is called.
It's mocked but I'm not familiar with the Jest mocking library.
This is in my test set up file:
jest.mock('sweetalert2', () => {
return {
Swal: () => {},
};
});
So I just want this to return a function.
In my component, Swal is called like this:
doSomething = () => {
Swal({
title: 'Could not log in',
text: error.message,
type: 'error',
});
};
I think my mock needs to return a named method, so I can spyOn it and check that it was called.
My test:
import Swal from 'sweetalert2';
describe('Login Container', () => {
it('calls Swal', () => {
doSomething();
var swalSpy = jest.spyOn(Swal, 'Swal');
expect(swalSpy).toHaveBeenCalled();
});
});
Error:
expect(jest.fn()).tohavebeencalled();
How should I set up my mock and spy as the test fails

You can return a mock function jest.fn in your sweetalert.js mock:
module.exports = jest.fn();
And write your test like this:
import { doSomething } from './doSomething';
import Swal from 'sweetalert';
describe('Login Container', () => {
it('calls Swal', () => {
expect(Swal).toHaveBeenCalledTimes(0);
doSomething();
expect(Swal).toHaveBeenCalledTimes(1);
});
});
Note that I'm using sweetalert in my example code not sweetalert2.
Hope this help!

I would expect that the mock factory needs to return an object with default (because import Swal is importing the default module). Something like this (demoing sweetalert v1):
// extract mocked function
const mockAlert = jest.fn()
// export mocked function as default module
jest.mock('sweetalert', () => ({
default: mockAlert,
}))
// import the module that you are testing AFTER mocking
import doSomethingThatAlerts from './doSomethingThatAlerts'
// test suite loosely copied from OP
describe('Login Container', () => {
it('calls Swal', () => {
doSomethingThatAlerts();
// test mocked function here
expect(mockAlert).toHaveBeenCalled();
});
});

Related

How can I mock a function which is in other file and that return a promise?

I'm writing a Jest test. I need to test a function that calls a function in another .js file. This called function returns a promise that resolves to a string. When I start the test I get the error "file.function is not a function", where instead of "file" I have the name of the imported js file and instead of "function" I have the name of the function that return the promise.
Below my test:
test('test', () => {
jest.mock('../file', () => {
function: jest.fn().mockReturnValue('Returned String')
});
myFunction();
expect().toBe();
});
Explanation: first of all I mocked the module which contains the function that return a promise. With second parameter (of jest.mock) I mocked the function contained in mocked module. Next I call the function that I want to test (this function will call mocked function). Finally, I test the expectations. Someone can help me, please. I don't know how I can resolve, thanks to all.
jest.mock should be at the same level as imports. If you need to test multiple cases just mock the returned/resolved value each time.
import { myFunction } from './fn';
import { function } from '../file';
jest.mock('../file', () => {
function: jest.fn(),
});
describe('myFunction tests', () => {
describe('With returned string', () => {
beforeEach(() => {
function.mockReturnValue('Returned String');
});
it('should do sth', () => {
myFunction();
// expect(...).toBe(...);
});
});
describe('With returned number', () => {
beforeEach(() => {
function.mockReturnValue(7);
});
it('should do other thing', () => {
myFunction();
// expect(...).toBe(...);
});
});
});

JEST typeof function test is always false?

can someone help me out here real quick?
I'm trying to test if a function exists with JEST like this and it always gives me false as a result, why is that?
I tried to run the same logic in the formHandler.js and it works there, is something wrong with the way I write it?
const { handleSubmit } = '../client/js/formHandler';
import "babel-polyfill";
describe('Testing if function exists' , () => {
test('Should return true', async () => {
expect(typeof handleSubmit === "function").toBe(true);
});
});
Thank you!
Ciao, you could try this:
import { handleSubmit } from '../client/js/formHandler';
import "babel-polyfill";
describe('Testing if function exists' , () => {
test('Should return true', () => {
expect(typeof handleSubmit).toBe('function');
});
});

How to jest spyOn a commonJS default export

Is it possible to jest.spyOn a default export so that I can call the mockImplementation method to change what the function does before each test?
// code.js
module.exports = () => {
// some irrelevant code I want to rewrite with a mock
};
// test
const code = require('./code.js');
const mockCode = jest.spyOn(code, 'default'); // this line doesn't work with the error: "Cannot spy the default property because it is not a function; undefined given instead"
it('some test', async () => {
mockCode.mockImplementationOnce(() => { console.log('test') });
});
I've also tried to use jest.mock() unsuccessfully:
const code = require('./code');
jest.mock('./code',
() => () => {
console.log('test');
}
);
it('some test', async () => {
code.mockImplementationOnce(() => { console.log('test2') }); // error
});

Why is the Jest mock instance empty when mocking a Node.js module?

I'm having some problems with mocking, I've mocked a node module by adding a mocks/ssh2-sftp-client.ts file:
const mockSsh2SftpClient = jest.fn().mockImplementation(() => {
return {
connect: async () => {},
end: async () => {},
on: () => {}
}
})
export default mockSsh2SftpClient
This works, kinda. My tests run correctly using this mock, but in the tests SftpClient.mock.instances[0] is an empty mockConstructor {} object instead of this mock (ie. SftpClient.mock.instances[0].end is undefined). What am I doing wrong?
for reference, my testing code looks like this:
import { ConnectConfig } from 'ssh2'
import SftpClient from 'ssh2-sftp-client'
import { withSftp } from '../sftp'
// Type assertion to make TypeScript happy.
const MockSftpClient = SftpClient as jest.Mock<SftpClient>
describe(withSftp, () => {
const mockConnectionConfig: ConnectConfig = {}
beforeEach(() => {
// Clear all instances and calls to constructor and all methods:
MockSftpClient.mockClear()
})
it('should call the callback after successfully connecting', async () => {
const mockCallback = jest.fn()
// Instantiates SftpClient and calls connect, then the callback, then end.
await withSftp(mockConnectionConfig, mockCallback)
const mockInstance = MockSftpClient.mock.instances
expect(mockCallback).toHaveBeenCalledTimes(1)
expect(MockSftpClient.mock.instances[0].end).toHaveBeenCalledTimes(1)
})
})
The last fails because MockSftpClient.mock.instances[0].end is undefined, where it should be a function.
The mock constructor provided by Jest only records this as the instance so if your mock constructor returns a different object then that object won't be recorded in the instances array.
To get the behavior you are wanting just mock with a standard function and use this:
__mocks__/ssh2-sftp-client.ts
const mockSsh2SftpClient = jest.fn(function() {
this.connect = jest.fn();
this.end = jest.fn();
this.on = jest.fn();
});
export default mockSsh2SftpClient

sinon mock not catching calls

I am having a hard time understanding what I am doing wrong.
I have a JS class as such:
export default class A {
constructor(repository) {
this._repository = repository;
}
async process(date) {
// ...
this._repository.writeToTable(entry);
}
}
and I am attempting to write a test that mocks the repository using sinon.mock
This is what I have so far:
describe('A', () => {
describe('#process(date)', () => {
it('should work', async () => {
const repository = { writeToTable: () => {} };
const mock = sinon.mock(repository);
const a = new A(repository);
await a.process('2017-06-16');
mock.expects('writeToTable').once();
mock.verify();
});
});
});
but it always fails saying that
ExpectationError: Expected writeToTable([...]) once (never called)
I've checked (added a console.log) and it is calling the object I defined on the test.
I ran this locally and read the documentation on sinonjs.org and you seem to be doing everything right.
I tried re-writing your example using a spy and ended up with something like this to get a passing test:
import sinon from "sinon";
import { expect } from "chai";
import A from "./index.js";
describe("A", () => {
describe("#process(date)", () => {
it("should work", async () => {
const repository = { writeToTable: sinon.spy() };
const a = new A(repository);
await a.process("2017-06-16");
expect(repository.writeToTable.calledOnce).to.be.true;
});
});
});

Categories