aftab
aftab

Reputation: 693

is there way in jasmine/sinon to stub nested fucntions call?

I am trying to test class so i have method in the class core that is calling another method getDrugsByName. I have wrote the unit test that will call core and then it should also call stubbed method getDrugByName. for some reason below test is passing but code coverage is not showing code covered inside core. Any idea what is implemented wrong and how to stubbed nested method.

DrugPriceApi.node.ts

    export class DrugPriceApi extends Types.ModuleBase<DrugPriceParam, DrugPriceResultSet[]> {
        core(args: DrugPriceParam, requestMethod: Interface.Core.RequestMethod, _dependencies: any): Promise<any> {
            this._dependencies = _dependencies;

            return new Promise<any>((resolve: Function, reject: Function) => {
                if (!_.isEmpty(args.drugName)) {
                    let drugSearchParam: any = _.cloneDeep(args);
                    drugSearchParam.searchText = args.drugName;

                    this.getDrugsByName(drugSearchParam, requestMethod).then((response: any) => {
                        if (response.header.statusCode === '0000' && _.has(response, 'detail.drugDetailsList.drug')) {
                            let drugObject = response.detail.drugDetailsList;
                            let drugFound: boolean = false;
                            drugObject.drug = Array.isArray(drugObject.drug) ? drugObject.drug : [drugObject.drug];
                            drugObject.drug.forEach((item: any) => {
                                if (!drugFound) {
                                    drugFound = ((item.mailDrug && item.mailDrug.ndcId === args.ndcId) || (item.retailDrug && item.retailDrug.ndcId === args.ndcId));
                                }
                            });

                            if (!drugFound) {
                                reject({
                                    statusDesc: "NDCID does not belong to the Drug Name provided.",
                                    statusCode: "5000",
                                    refId: response.header.refId
                                });
                            } else {
                                this.getDrugPrice(args, drugObject, requestMethod, resolve, reject, this.Handler);
                            }
                        } 
                    }).catch((_err: any) => {
                        reject({
                            statusCode: '9999',
                            refId: args.refId,
                            statusDesc: _err.statusDesc
                        });
                    });
                } 
            });
        }
    }

function getDrugsByName () {
    // return Response after making backend call 
}

DrugPriceApi.node.spec.ts

    import { } from 'jasmine';
    import { DrugPriceParam } from "./DrugPriceApi.interface";
    import { DrugPriceApi } from "./DrugPriceApi.node";
    import sinon from "sinon";

    describe("DrugPriceApi", () => {
 let stubbedHttp:any;
    const successResponse = {
        "details": {
            "drugDetailsList": {
                "drug": [{
                    "mailDrug": {
                        "ndcId": "71015523"
                    },
                    "drugForm": "Tab"
                }]
            }
        },
        "header": {
            "statusDesc": "Success",
            "statusCode": "0000"
        }
    };
    beforeEach(function() {
        // Below are the modules that are called by GetRxHistoryDetails
        // since this is a unit test, these modules should not be tested
        // these stubs will stop the real modules from executing
        stubbedHttp = sandbox.createStubInstance(HttpRequest);
        stubbedHttp.makeRequest.callsFake(function() {
            return new Promise<any>((resolve) => {
                resolve(successResponse);
            });
        });
    });
    it("should call Core", function (done) {
        let param = {
            tokenId: '123',
            appName: 'CMK_WEB',
            refId: '123'
        } as DrugPriceParam;
            param.drugName = 'ACITRETIN';
            let mockHttp: any;
            let _dependencies: any;
            let Service = DrugPriceApi.prototype;
            spyOn(Service, 'core').and.callFake(() => {
                return {
                    getDrugsByName: function() {
                        Promise.resolve(stubbedHttp);
                    }
                }
            });
            Service.core.call(param,mockHttp,_dependencies);
            expect(Service.core).toHaveBeenCalled(); 
            done();
            });
    };

Upvotes: 0

Views: 287

Answers (1)

Castro Roy
Castro Roy

Reputation: 7803

Your code coverage is showing you what you really have in your tests, and let me be honest, you are not testing your core function, it is not even being invoked, the function can be full of errors and your tests won't even note it. What you are invoking and testing is a stubbed function that is created in the line spyOn(Service, 'core').and.callFake, that line is completely overriding the original core function. For example, what you need to mock is getDrugsByName function, but, if it has a lot of business logic, you need to consider writing tests for that function too.

So, change your test like this

it("should call Core", function (done) {
    let param = {
        tokenId: '123',
        appName: 'CMK_WEB',
        refId: '123'
    } as DrugPriceParam;
        param.drugName = 'ACITRETIN';
        let mockHttp: any;
        let _dependencies: any;
        let Service = DrugPriceApi.prototype;

        // spyOn "core" using "callThrough" to track all calls to it but 
        // delegate to the actual implementation.
        spyOn(Service, 'core').and.callThrough();

        // spyOn "getDrugsByName" using "returnValue"
        spyOn(Service, 'getDrugsByName').and.returnValue(Promise.resolve(stubbedHttp));

        Service.core.call(param,mockHttp,_dependencies);
        expect(Service.core).toHaveBeenCalled(); 
        done();
        });
  };

Please, note the use of spyOn(Service, 'core').and.callThrough(); to track all calls to it but delegate to the actual implementation. These will give you full code coverage of the function.

That simple change will take you to the next step. But let me list a few details

  • Probably stubbedHttp is not what getDrugsByName should returns. You might need to adjust it.
  • mockHttp is undefined and you are passing it as argument to core. Be aware of errors.
  • _dependencies is undefined and you are passing it as argument to core. Be aware of errors.

Hope it helps

Upvotes: 1

Related Questions