简体   繁体   中英

How to get code coverage of nested promises in a method of a class in typescript with jest?

The method of the class has return type void and contains calls to multiple nested methods returning promises:-

export class OverviewModule implements ModuleExport {
    createTearSheetExcel = (data)=>
    {
        let overviewWorkbook = new Excel();
        let overviewWorksheet = overviewWorkbook.addWorksheet('TearSheet');

    let overviewStyleCaption = overviewWorkbook.createStyle({
        font: {
          color: '000000',
          size: 12,
          bold: true
        },
      });

      let overviewStyleNormalText = overviewWorkbook.createStyle({
        font: {
          color: '000000',
          size: 12,
        },
        alignment: {
            wrapText: true,
            vertical: 'center'
          },
      });
      /*let captionArray: string[] = ['Name', 'Domain','City','Country','Year Founded',
      'Description', 'Status', 'Total Funding', 'Revenue', 
      'Employees','Social', 'Sector/Industry','Categories','Phone', 'Contact'];*/
      let companyProfile = data.data.companyProfile || {};
      let generalProfile = data.data.generalProfile || {};
      let monetaryHeaders: string[] = [];
      let monetaryValues: string[] = [];
      if(companyProfile.type==='PUBLIC')
      {
        monetaryHeaders = ['Market Cap','Enterprise Value'];
        monetaryValues = [generalProfile.marketCap.toLocaleString('en-US', { style: 'currency', currency: generalProfile.currencyId }).slice(0,-3)
                        ,generalProfile.enterpriseValue.toLocaleString('en-US', { style: 'currency', currency: generalProfile.currencyId }).slice(0,-3)];
      }
      if(companyProfile.type==='PRIVATE')
      {
        monetaryHeaders = ['Total Funding'];
        monetaryValues = [companyProfile.totalFundingUsd.toLocaleString('en-US', { style: 'currency', currency: "USD" }).slice(0,-3)];
      }

      let headers = ['Name', 'Description','Status',monetaryHeaders,
      'Revenue', 'Employees', 'Domain', 'City', 'Country','Year Founded', 'Sector/Industry','Categories','Phone', 'Contact', 'Social'].reduce((acc: string[], val) => acc.concat(val), []);
      if(companyProfile.type==='PUBLIC')
      {
          headers.splice(1,0,"Ticker");
      }
      overviewWorkbook.addHeaders(headers,
      overviewWorksheet, overviewStyleCaption);

    let websites = data.data.websites || "";
    let socialMultiline = '';
    websites.forEach(webs => {
        if(webs.websiteType!=='homepage')
        {
            socialMultiline += webs.url + '\n';
        }
    });
    let revenueValue = generalProfile.revenueData ? generalProfile.revenueData.value.toLocaleString('en-US', { style: 'currency', currency: generalProfile.revenueData.currencyId }).slice(0,-3) : "";
    let dataArray: string[] = [companyProfile.name || "", companyProfile.description || "-",
                                (companyProfile.type.substr(0,1) || "") + (companyProfile.type.substr(1).toLowerCase() || ""),
                                monetaryValues,revenueValue,
                                (companyProfile.numEmployeesMin || "") + ' - ' + (companyProfile.numEmployeesMax.toString() || ""),
                                websites[0].url || "", data.data.headquarters[0].city, companyProfile.country || "",
                                companyProfile.foundedOn.substring(0,4) || "", companyProfile.sectorAndIndustry || "",
                                data.data.categories.map(cat=>cat.name).toString(),
                                companyProfile.phoneNumber || "", companyProfile.contactEmail || "",
                                socialMultiline
                                 ].reduce((acc: string[], val) => acc.concat(val), []);

    if(companyProfile.type==='PUBLIC')
    {
        dataArray.splice(1,0, data.data.companyProfile.tickerName);
    }                           
    for(let i=1; i<=dataArray.length;i++)
    {
        overviewWorkbook.fillCell(overviewWorksheet,2,i,dataArray[i-1],overviewStyleNormalText);//(1,i).string(captionArray[i-1]).style(styleCaption);
    }

    return overviewWorkbook.writeToBuffer();
    }

    processModule(id: string ,moduleName: string ,authToken :string, companyname: string, companyId: string, messageReceipt: string, clientId: string) {
        let filename = companyname + " Overview " + getCurrentDate() + ".xlsx";

        logger.info(`${filename} processing started`);
        Cache.add(id , jsonStringify({fileName: filename, status: Status.IN_PROGRESS}));
        logger.info(`${filename} added to cache`);

        process.send = process.send || function () {console.log("Process send is not a function")};
        process.send(Status.IN_PROGRESS);
        let cookie = formCookie(authToken, clientId);
        getModuleData(companyId , moduleName, authToken).then(data=>{
            getSectorAndIndustryData(cookie || '').then(secAndIndData => {
                data.data.companyProfile.sectorAndIndustry = data.data.companyProfile.type === 'PRIVATE' 
                ? "-" : fetchSectorAndIndustryName(secAndIndData,data.data.companyProfile.sectorCode, data.data.companyProfile.industryCode);
            getTickerName(authToken, companyId).then((tickerDetails) => {
                data.data.companyProfile.tickerName = tickerDetails.code || "";
                    this.createTearSheetExcel(data).then(buffer => {
                        logger.info(`${filename} is being saved to S3`);
                        S3.upload(APP_BUCKET_NAME,filename,buffer);
                        Cache.update(id , jsonStringify({fileName: filename, status: Status.AVAILABLE}));
                        Queue.deleteMessage(messageReceipt).catch(error =>{
                            Cache.update(id , jsonStringify({fileName: filename, status: Status.ERROR}));
                            logger.error(`${filename} error while creating excel sheet`);
                            logger.error(error);
                          });
                        logger.info(`${filename} processing complete`);
                }).catch(error =>{
                    Queue.deleteMessage(messageReceipt).catch(error =>{
                        Cache.update(id , jsonStringify({fileName: filename, status: Status.ERROR}));
                        logger.error(`${filename} error while deleting from Queue`);
                        logger.error(error);
                      });
                    Cache.update(id , jsonStringify({fileName: filename, status: Status.ERROR}));
                    logger.error(`${filename} error while creating excel sheet`);
                    logger.error(error);
                });
            }).catch(error =>{
                Queue.deleteMessage(messageReceipt).catch(error =>{
                    Cache.update(id , jsonStringify({fileName: filename, status: Status.ERROR}));
                    logger.error(`${filename} error while deleting from Queue`);
                    logger.error(error);
                  });
                Cache.update(id , jsonStringify({fileName: filename, status: Status.ERROR}));
                logger.error(`${filename} error while creating excel sheet`);
                logger.error(error);
              });
            }).catch(error =>{
                Queue.deleteMessage(messageReceipt).catch(error =>{
                    Cache.update(id , jsonStringify({fileName: filename, status: Status.ERROR}));
                    logger.error(`${filename} error while deleting from Queue`);
                    logger.error(error);
                  });
                Cache.update(id , jsonStringify({fileName: filename, status: Status.ERROR}));
                logger.error(`${filename} error while creating excel sheet`);
                logger.error(error);
              });
        })
        .catch(error =>{
            Queue.deleteMessage(messageReceipt).catch(error =>{
                Cache.update(id , jsonStringify({fileName: filename, status: Status.ERROR}));
                logger.error(`${filename} error while deleting from Queue`);
                logger.error(error);
              });
          Cache.update(id , jsonStringify({fileName: filename, status: Status.ERROR}));
          logger.error(`${filename} error while recieving data from graphql service`);
          logger.error(error);
        });
      }



}

The code coverage does not show after getModuleData. All the methods called after getModuleData are not covered in the code coverage even though they are getting called as I can see the output in logs.

Note;- getModuleData,getSectorAndIndustryData and getTickerName actually make api calls to a service which I capture using nock.

This is actually pretty difficult to read. If you can convert your promise chaining to 'await', possibly by bumping your babel a bit and converting processModule to async, then it will resolve your 'nesting' and simplify your jest issue. I think you're really serializing rather than nesting the promises here.. which i think is what you want. If there are any steps which would gain from being parallelized then you can wait on multiple promises at some point.. once you get this sorted out. In any case, hope it helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM