UNPKG

@salesforce/apex-node

Version:

Salesforce JS library for Apex

223 lines 11.5 kB
"use strict"; /* * Copyright (c) 2021, salesforce.com, inc. * All rights reserved. * Licensed under the BSD 3-Clause license. * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.CodeCoverage = void 0; const util = __importStar(require("util")); const utils_1 = require("./utils"); const constants_1 = require("./constants"); const utils_2 = require("../utils"); class CodeCoverage { connection; constructor(connection) { this.connection = connection; } /** * Returns the string representation of the org wide coverage percentage for a given username connection from OrgWideCoverage entity * @returns Org wide coverage percentage for a given username connection */ async getOrgWideCoverage() { utils_2.HeapMonitor.getInstance().checkHeapSize('codeCoverage.getOrgWideCoverage'); try { const orgWideCoverageResult = (await this.connection.tooling.query('SELECT PercentCovered FROM ApexOrgWideCoverage')); if (orgWideCoverageResult.records.length === 0) { return '0%'; } return `${orgWideCoverageResult.records[0].PercentCovered}%`; } finally { utils_2.HeapMonitor.getInstance().checkHeapSize('codeCoverage.getOrgWideCoverage'); } } /** * Returns the code coverage information for each Apex class covered by each Apex test method from ApexCodeCoverage entity * @param apexTestClassSet Set of Apex test classes * @returns The code coverage information associated with each Apex test class * NOTE: a test could cover more than one class, result map should contain a record for each covered class */ async getPerClassCodeCoverage(apexTestClassSet) { utils_2.HeapMonitor.getInstance().checkHeapSize('codeCoverage.getPerClassCodeCoverage'); try { if (apexTestClassSet.size === 0) { return new Map(); } const perClassCodeCovResults = await this.queryPerClassCodeCov(apexTestClassSet); const perClassCoverageMap = new Map(); perClassCodeCovResults.forEach((chunk) => { chunk.records.forEach((item) => { const totalLines = item.NumLinesCovered + item.NumLinesUncovered; const percentage = (0, utils_1.calculatePercentage)(item.NumLinesCovered, totalLines); const value = { apexClassOrTriggerName: item.ApexClassOrTrigger.Name, apexClassOrTriggerId: item.ApexClassOrTrigger.Id, apexTestClassId: item.ApexTestClassId, apexTestMethodName: item.TestMethodName, numLinesCovered: item.NumLinesCovered, numLinesUncovered: item.NumLinesUncovered, percentage, ...(item.Coverage ? { coverage: item.Coverage } : {}) }; const key = `${item.ApexTestClassId}-${item.TestMethodName}`; if (perClassCoverageMap.get(key)) { perClassCoverageMap.get(key).push(value); } else { perClassCoverageMap.set(`${item.ApexTestClassId}-${item.TestMethodName}`, [value]); } }); }); return perClassCoverageMap; } finally { utils_2.HeapMonitor.getInstance().checkHeapSize('codeCoverage.getPerClassCodeCoverage'); } } /** * Returns the aggregate code coverage information from ApexCodeCoverageAggregate entity for a given set of Apex classes * @param apexClassIdSet Set of ids for Apex classes * @returns The aggregate code coverage information for the given set of Apex classes */ async getAggregateCodeCoverage(apexClassIdSet) { utils_2.HeapMonitor.getInstance().checkHeapSize('codeCoverage.getAggregateCodeCoverage'); try { const codeCoverageAggregates = await this.queryAggregateCodeCov(apexClassIdSet); let totalLinesCovered = 0; let totalLinesUncovered = 0; const totalCodeCoverageResults = []; codeCoverageAggregates.forEach((chunk) => { const codeCoverageResults = chunk.records.map((item) => { totalLinesCovered += item.NumLinesCovered; totalLinesUncovered += item.NumLinesUncovered; const totalLines = item.NumLinesCovered + item.NumLinesUncovered; const percentage = (0, utils_1.calculatePercentage)(item.NumLinesCovered, totalLines); return { apexId: item.ApexClassOrTrigger.Id, name: item.ApexClassOrTrigger.Name, type: item.ApexClassOrTrigger.Id.startsWith('01p') ? 'ApexClass' : 'ApexTrigger', numLinesCovered: item.NumLinesCovered, numLinesUncovered: item.NumLinesUncovered, percentage, coveredLines: item.Coverage.coveredLines, uncoveredLines: item.Coverage.uncoveredLines }; }); totalCodeCoverageResults.push(...codeCoverageResults); }); return { codeCoverageResults: totalCodeCoverageResults, totalLines: totalLinesCovered + totalLinesUncovered, coveredLines: totalLinesCovered }; } finally { utils_2.HeapMonitor.getInstance().checkHeapSize('codeCoverage.getAggregateCodeCoverage'); } } async queryPerClassCodeCov(apexTestClassSet) { const perClassCodeCovQuery = 'SELECT ApexTestClassId, ApexClassOrTrigger.Id, ApexClassOrTrigger.Name, TestMethodName, NumLinesCovered, NumLinesUncovered, Coverage FROM ApexCodeCoverage WHERE ApexTestClassId IN (%s)'; return this.fetchResults(apexTestClassSet, perClassCodeCovQuery); } async queryAggregateCodeCov(apexClassIdSet) { // If the "Store Only Aggregate Code Coverage" setting is checked, then apexClassIdSet is empty and we should query all the Apex classes and triggers in the ApexCodeCoverageAggregate table. if (apexClassIdSet.size === 0) { const query = 'SELECT ApexClassOrTrigger.Id, ApexClassOrTrigger.Name, NumLinesCovered, NumLinesUncovered, Coverage FROM ApexCodeCoverageAggregate'; const result = await (0, utils_1.queryAll)(this.connection, query, true); return [result]; } // If the "Store Only Aggregate Code Coverage" setting is unchecked, we continue to query only the Apex classes and triggers in apexClassIdSet from the ApexCodeCoverageAggregate table, as those are the Apex classes and triggers touched by the Apex tests in the current run. else { const query = 'SELECT ApexClassOrTrigger.Id, ApexClassOrTrigger.Name, NumLinesCovered, NumLinesUncovered, Coverage FROM ApexCodeCoverageAggregate WHERE ApexClassorTriggerId IN (%s)'; return this.fetchResults(apexClassIdSet, query); } } async fetchResults(idSet, selectQuery) { const queries = this.createQueries(selectQuery, idSet); const queryPromises = queries.map((query) => // The query method returns a type QueryResult from jsforce // that has takes a type that extends the jsforce Record. // ApexCodeCoverageRecord and ApexCodeCoverageAggregateRecord // are the Records compatible types defined in this project. (0, utils_1.queryAll)(this.connection, query, true)); // Note here the result of the .all call is of type QueryResult<ApexCodeCoverageAggregateRecord | ApexCodeCoverageRecord>[] // Since QueryResult is compatible with ApexCodeCoverage and ApexCodeCoverageAggregate we can cast to T[] // and things work out. //TODO: figure out how to use the provided types from core instead of having to work around typescript here. return (await Promise.all(queryPromises)); } createQueries(selectQuery, idSet) { const queries = []; for (let i = 0; i < idSet.size; i += constants_1.QUERY_RECORD_LIMIT) { const recordSet = Array.from(idSet) .slice(i, i + constants_1.QUERY_RECORD_LIMIT) .map((id) => `'${id}'`); const query = util.format(selectQuery, recordSet.join(',')); queries.push(query); } return queries; } } exports.CodeCoverage = CodeCoverage; __decorate([ (0, utils_2.elapsedTime)() ], CodeCoverage.prototype, "getOrgWideCoverage", null); __decorate([ (0, utils_2.elapsedTime)() ], CodeCoverage.prototype, "getPerClassCodeCoverage", null); __decorate([ (0, utils_2.elapsedTime)() ], CodeCoverage.prototype, "getAggregateCodeCoverage", null); __decorate([ (0, utils_2.elapsedTime)() ], CodeCoverage.prototype, "queryPerClassCodeCov", null); __decorate([ (0, utils_2.elapsedTime)() ], CodeCoverage.prototype, "queryAggregateCodeCov", null); __decorate([ (0, utils_2.elapsedTime)() ], CodeCoverage.prototype, "fetchResults", null); //# sourceMappingURL=codeCoverage.js.map