My module.ts
file has 2 functions:
export async function foo() {
var barVal = await bar();
doSomethingWithBarVal(barVal);
}
export async function bar(): Bar {
return await somethingAsync();
}
In my tests I want to stub
bar() and return a mock
for Bar
(the returned value of bar()
)
My current test looks like this:
var module = require('module.ts');
var myStub = sinon.stub(module, 'bar').resolves(myMock);
await foo();
expect(myStub.calledOnce);
However, the expect
always fails and the 'real' bar()
is called.
If I call bar()
directly from my test, then the stub is called but I want to test the whole flow.
The problem with your approach is that you are stubbing module object (exports
since you are using commonjs require
in your test) while your foo
function uses bar
available in module scope.
To fix this you have a few options here.
Use exports.bar
instead of bar
in foo
export async function foo() {
var barVal = await exports.bar();
doSomethingWithBarVal(barVal);
}
This approach is actually a hack that uses the fact that your module will be transpiled to commonjs format. Which might be not true someday but kinda works for now.
Embrace the fact that ES modules are static. Make your function "testable again" by explicitly allowing to specify bar
as its argument
export async function foo(_bar = bar) {
var barVal = await _bar();
doSomethingWithBarVal(barVal);
}
// test.js
await foo(mockBarImplementation)
Use some IoC/DI
implementation. For example typescript-ioc