In your example a is still using b directly. The spy can’t replace the variable reference that a already holds in a separate module. This is partially because imported values are immutable, and partially because const.
The easiest way around this is to have every function belong to a namespace / object / static class because properties of an object can be changed:
const NS = {}
NS.a = function () {
NS.b();
}
NS.b = function () {
console.log('on b function');
}
// export NS, which can be destructured into a and b
import NS from './ns.js';
it('Should have called b', function () {
const spyB = sinon.spy(NS, 'b');
NS.a();
console.log(spyB.callCount); // returns 1
sinon.assert.calledOnce(spyB);
spyB.restore() // remove spy from method
});
The more complicated way is to use dependency injection