I have the following code
import {
getIndexDocument
} from "@assets";
class MetaController {
public async exploreIndexDocument(): Promise<Asset | undefined> {
const {
result: { assignedDirectories }
} = await getIndexDocument(this._serviceConfig).catch(err => {
throw new Error(`[AssetsController] Bad response on discovering index doc because ${err}`);
});
}
}
As you can see the exploreIndexDocument is calling function getIndexDocument. I want to write a test for exploreIndexDocument, but I can't stub getIndexDocument using sinon because sinon does not allow you to stub functions. How do I architecture this class to do so?
You need some way of injecting a stub so that your class instance calls that instead of the external library. This answer elaborates some alternatives. The alternative to injecting stubs is to replace the entire module you are importing. This is called using a link seam. This answer shows one way and lists various module loaders that help you do so.
Personally, I have slowly moved away from module mocking techniques and try to keep myself in the land of dependency injection (alternative 1), since that works regardless of the underlying environment and any beginning programmer can read the tests. The least invasive way could simply be something like this:
import {
getIndexDocument
} from "@assets";
class MetaController {
private getIndexDocument: (config:object) => Promise<{assignedDirectories:any> };
constructor(deps = {getIndexDocument}) {
this.getIndexDocument = getIndexDocument;
}
public async exploreIndexDocument(): Promise<Asset | undefined> {
const {
result: { assignedDirectories }
} = await this.getIndexDocument(this._serviceConfig).catch(err => {
throw new Error(`[AssetsController] Bad response on discovering index doc because ${err}`);
});
}
}
You can now very easily test this:
const fake = sinon.fake.resolves({ assignedDirectories: ['/foo/dir'] });
const controller = new MetaController({getIndexDocument: fake});
const promise = controller.exploreIndexDocument();
expect(fake.calledOnce).toBe(true);
// further assertions follow ... see https://sinonjs.org/releases/latest/fakes/