Search code examples
javascripttypescriptchaisinon

How to stub function that returns a promise?


I'm trying to stub a function using sinon. The function has the following signature

export function getIndexDocument(
    svc: MetaHTTPService | ServiceConfig
): MetaPromise<RepoResponseResult<IndexDocument>> {

Is this the right way to sub it

sandbox.stub(getIndexDocument).resolves({} as RepoResponseResult)

I tried that but it returns an error.

Here's how this function is called.

I have a class called AssetsController with the following functions

 public async exploreIndexDocument(): Promise<Asset | undefined> {      
    // it makes an HTTP request and returns a promise that resolves with the following info { repoId: "", assetId: "" }

     const {
            result: { assignedDirectories }
     } = await getIndexDocument(this.serviceConfig).catch(err => {
        throw new Error(`Bad repsonse`);
     });

     return {
        repoId: result.repoId;
        assetId: result.assetId
     }

}

public async function copyAsset(asset) {
   const res = await this.exploreIndexDocument();
   const repoId = res.repoId;
   return asset.copy(repoId);
}

I'm trying to test the function copyAsset, but it calls exploreIndexDocument which calls getIndexDocument. getIndexDocument is imported at the top of the file and lives in the module @ma/http. getIndexDocument makes an HTTP request.

How can I test copyAsset given that it calls getIndexDocument which makes an HTTP request?


Solution

  • According to the docs, you can't stub an existing function.

    You can:

    // Create an anonymous sstub function
    var stub = sinon.stub();
    
    // Replaces object.method with a stub function. An exception is thrown
    // if the property is not already a function.
    var stub = sinon.stub(object, "method");
    
    // Stubs all the object’s methods.
    var stub = sinon.stub(obj);
    

    What you can't do is stub just a function like:

    var stub = sinon.stub(myFunctionHere);
    

    This makes sense because if all you have is a reference to a function, then you can just create a new function to use instead, and then pass that into where ever your test needs it to go.


    I think you just want:

    const myStub = sandbox.stub().resolves({} as RepoResponseResult)
    

    In your update it sounds like you want to put the stub on the AssetsController class. See this answer for more info on that, but in this case I think you want:

    const myStub = sandbox
      .stub(AssetsController.prototype, 'exploreIndexDocument')
      .resolves({} as RepoResponseResult)
    

    Now anytime an instance of AssetsController calls its exploreIndexDocument method, the stub should be used instead.

    Playground