mocking private methods to test an exported method fails in jest - javascript

I'm having an actual class like this
my-file.js
const methodA = () => { return 'output-from-methodA'; }
const methodB = () => { const b = methodA(); b.c = "out-put bind"; return b; }
module.exports = {
methodB
}
my-file.test.js
const { methodA, methodB } = require('./my-file.js');
describe('methodB testing', () => {
it('should call methodA', () => {
methodB();
expect(methodA).toHaveBeenCalled()
}
});
here methodA is private method, so it is not explicit to the test file, then how i ensure it is called or not in the test files

There is no way to test the private function, only the alternative way found is to test the outputs like
const { methodA, methodB } = require('./my-file.js');
describe('methodB testing', () => {
it('should call methodA', () => {
const result = methodB();
expect(result.b.c).toBe("out-put bind")
}
});

Related

Using Jest with NodeJS, Function in imported module not being mocked without using 'this' in main

In the setup below, if I run the test as is, myFunc is not mocked when I debug into handler.
However, if instead I add this. in front of the myFunc call in handler, then the function is mocked and everything works as expected.
Can someone please explain why this is? I'm new to mocking and can't see it.
I know what this does, but why won't jest mock without it since I told it to mock that function in the module?
index.js
const aws = require('aws-sdk')
exports.handler = async function (event, context) {
let s;
switch (event.func) {
case "myFunc":
console.log('Executing myFunc');
//making the call: s = await this.myFunc.apply(null, [event.params]) will make the mock work.
s = await myFunc.apply(null, [event.params])
console.log(s);
return s;
/*cases...*/
default:
// default behaviour
}
async myFunc({p1, p2}){
/* do something */
return x
}
exports.myFunc = myFunc
}
index.spec.js
jest.mock('./index.js', () => {
const allAutoMocked = jest.createMockFromModule('./index.js')
const actual = jest.requireActual('./index.js')
return {
__esModules: true,
...allAutoMocked,
myFunc : jest.fn().mockImplementation(() => ({ mockedValue: 'test' })),
handler: actual.handler
}
})
let index = require("./index.js")
describe('Test myFunc', () => {
test('If myFunc function was called', async () => {
var event = { func: 'myFunc', params: { p1: xx, p2: false } };
const context = {};
const logMock = jest.fn((...args) => console.log(...args));
const data = await handler(event, context);
})
})

Mock a function and used it as UUT with Jest in JS

I want to test one function from exported object in one describe and mock it in another function from the same exported object since the second function is using the first function.
// funcs.js
const func1 = () => {
return true;
};
const func2 = () => {
const bool = func1();
if (bool) {
// do something
} else {
// do else
}
};
export const funcs = {func1, func2};
// funcs.spec.js
const {funcs as uut} from './funcs';
describe('unit', () => {
describe('func 1', () => {
test('', () => {
const bool = uut.func1();
expect(bool).toBeTruthy();
});
});
describe('func 2', () => {
test('', () => {
jest.mock(uut.func1).mockReturnValue(false);
uut.func2();
// rest of test
});
});
});
I tried using jest.requireActual but did not work. What is the best approach for this if even possible?

How to spyOn proxied objects with jest?

There is a scenario where a library exports a proxied object as a public API. Given that the API of the library can't be changed, I failed to find a way how to spyOn a proxied object using jest. Here is an example:
describe("spying on proxied objects with Jest", () => {
it("should pass", () => {
const foo = {
a() {
return 42;
}
};
const p = new Proxy(foo, {
get() {
return () => {
return 53;
};
}
});
const mock = jest.spyOn(foo, "a");
p.a(); // 53
expect(mock).toHaveBeenCalled();
});
});
the test case above fails with:
expect(jest.fn()).toHaveBeenCalled()
Expected number of calls: >= 1
Received number of calls: 0
Any ideas?
That's because foo.a is actually never called as your proxy doesn't call your target.
This test passes
describe("Foo", () => {
it("should pass", () => {
const foo = {
a() {
return 42;
},
};
const p = new Proxy(foo, {
get(target, prop) {
return () => {
target[prop](); /* <-- Calling target */
return 52;
};
},
});
const mock = jest.spyOn(foo, "a");
const result = p.a(); // 52
expect(mock).toHaveBeenCalled();
});
});

Mocking complex module using Jest.js

This is what the module I want to mock looks like:
class TheModule {
constructor() {
this.subClass = new SubClass();
}
}
class SubClass {
constructor() {
this.someMethod = () => 'Did Something great';
}
}
module.exports = TheModule;
This is TheModule usage I want to test:
const TheModule = require('./TheModule');
const method = () => {
const theModule = new TheModule();
return theModule.subClass.someMethod();
}
module.exports = method;
This is my test:
describe('method test', () => {
it('should return "Test pass"', () => {
jest.doMock('./TheModule');
const theModuleMock = require('./TheModule');
const method = require('./TheModuleUsage');
const mock = () => 'Test pass';
theModuleMock.subClass.someMethod.mockImplementation(() => mock);
expect(method()).toEqual('Test pass');
});
});
When I run this test I get TypeError: Cannot read property 'someMethod' of undefined
Is it possible to mock this module without changing TheModule implementation?
If you will export SubClass you can mock it without changing TheModule but in your case you should mock SubClass property in TheModule explicitly with factory for example:
describe('method test', () => {
it('should return "Test pass"', () => {
let mockedSomeMethod = jest.fn().mockImplementation(() => 'Test pass');
jest.doMock('./TheModule', () => {
// mock constructor
return jest.fn().mockImplementation(() => {
return { subClass: { someMethod: mockedSomeMethod } }
});
});
const method = require('./TheModuleUsage');
expect(method()).toEqual('Test pass');
});
});

sinon spy on function not working

I'm trying to write a standalone test for this simple middleware function
function onlyInternal (req, res, next) {
if (!ReqHelpers.isInternal(req)) {
return res.status(HttpStatus.FORBIDDEN).send()
}
next()
}
// Expose the middleware functions
module.exports = {
onlyInternal
}
This does not work
describe('success', () => {
let req = {
get: () => {return 'x-ciitizen-token'}
}
let res = {
status: () => {
return {
send: () => {}
}
}
}
function next() {}
let spy
before(() => {
spy = sinon.spy(next)
})
after(() => {
sinon.restore()
})
it('should call next', () => {
const result = middleware.onlyInternal(req, res, next)
expect(spy.called).to.be.true <-- SPY.CALLED IS ALWAYS FALSE EVEN IF I LOG IN THE NEXT FUNCTION SO I KNOW IT'S GETTING CALLED
})
})
but this does..
describe('success', () => {
let req = {
get: () => {return 'x-ciitizen-token'}
}
let res = {
status: () => {
return {
send: () => {}
}
}
}
let next = {
next: () => {}
}
let spy
before(() => {
spy = sinon.spy(next, 'next')
})
after(() => {
sinon.restore()
})
it('should call next', () => {
const result = middleware.onlyInternal(req, res, next.next)
expect(spy.called).to.be.true
})
})
Why isn't spying on just the function working?
Sinon cannot change content of existing function, so all spies it creates are just wrappers over existing function that count calls, memoize args etc.
So, your first example is equal to this:
function next() {}
let spy = sinon.spy(next);
next(); // assuming that middleware is just calling next
// spy is not used!
Your second example, equals to this:
let next = { next: () => {} }
next.next = sinon.spy(next.next); // sinon.spy(obj, 'name') just replaces obj.name with spy on it
next.next(); // you actually call spy which in in turn calls original next.next
//spy is called. YaY
So, they key to 'spying' and 'stubbing' in sinon is that you have to use spied/stubbed function in test. Your original code just used original, non-spied function.

Categories