From 29a96c6f2c6101377d4ba0db24c0221ebdf4a44d Mon Sep 17 00:00:00 2001 From: Allan Oricil Date: Thu, 17 Aug 2023 23:51:14 -0300 Subject: [PATCH 1/2] feat: improve code coverage percentage outputs and add yellow color --- src/coverageUtils.ts | 3 +- test/coverageUtils.test.ts | 355 +++++++++++++++++++++++-------------- 2 files changed, 223 insertions(+), 135 deletions(-) diff --git a/src/coverageUtils.ts b/src/coverageUtils.ts index 7bcf7f829..c28f55cfb 100644 --- a/src/coverageUtils.ts +++ b/src/coverageUtils.ts @@ -45,10 +45,9 @@ export function prepCoverageForDisplay(codeCoverage: CodeCoverage[]): CodeCovera coverage.forEach((cov: CodeCoverage & { lineNotCovered: string }) => { const numLocationsNum = parseInt(cov.numLocations, 10); const numLocationsNotCovered = parseInt(cov.numLocationsNotCovered, 10); - const color = numLocationsNotCovered > 0 ? chalk.red : chalk.green; - const coverageDecimal = parseFloat(((numLocationsNum - numLocationsNotCovered) / numLocationsNum).toFixed(2)); const pctCovered = numLocationsNum > 0 ? coverageDecimal * 100 : 100; + const color = pctCovered <= 75 ? chalk.red : pctCovered >= 90 ? chalk.green : chalk.yellow; cov.numLocations = color(`${pctCovered}%`); cov.lineNotCovered = cov.locationsNotCovered diff --git a/test/coverageUtils.test.ts b/test/coverageUtils.test.ts index 4ae501e79..6acaa5beb 100644 --- a/test/coverageUtils.test.ts +++ b/test/coverageUtils.test.ts @@ -8,182 +8,242 @@ import { expect } from 'chai'; import { MockTestOrgData, TestContext } from '@salesforce/core/lib/testSetup'; import { AuthInfo, Connection } from '@salesforce/core'; import { createSandbox, SinonSandbox } from 'sinon'; -import { transformCoverageToApexCoverage } from '../src/coverageUtils'; +import * as chalk from 'chalk'; +import { transformCoverageToApexCoverage, prepCoverageForDisplay } from '../src/coverageUtils'; import { transformDeployTestsResultsToTestResult } from '../src/coverageUtils'; -const sampleRunTestResult = { - codeCoverage: [ - { - id: '01p19000002uDLAAA2', - locationsNotCovered: { - column: '0', - line: '12', - numExecutions: '0', - time: '-1.0', +// methods are mutating the object instead of returning new ones +function getSampleTestResult() { + return { + codeCoverage: [ + { + id: '01p19000002uDLAAA2', + locationsNotCovered: { + column: '0', + line: '12', + numExecutions: '0', + time: '-1.0', + }, + name: 'PagedResult', + namespace: { + $: { + 'xsi:nil': 'true', + }, + }, + numLocations: '4', + numLocationsNotCovered: '1', + type: 'Class', }, - name: 'PagedResult', - namespace: { - $: { - 'xsi:nil': 'true', + { + id: '01p19000002uDLBAA2', + locationsNotCovered: [ + { + column: '0', + line: '26', + numExecutions: '0', + time: '-1.0', + }, + { + column: '0', + line: '31', + numExecutions: '0', + time: '-1.0', + }, + { + column: '0', + line: '78', + numExecutions: '0', + time: '-1.0', + }, + ], + name: 'PropertyController', + namespace: { + $: { + 'xsi:nil': 'true', + }, }, + numLocations: '44', + numLocationsNotCovered: '3', + type: 'Class', }, - numLocations: '4', - numLocationsNotCovered: '1', - type: 'Class', - }, - { - id: '01p19000002uDLBAA2', - locationsNotCovered: [ - { + { + id: '01p19000002uDLCAA2', + name: 'SampleDataController', + namespace: { + $: { + 'xsi:nil': 'true', + }, + }, + numLocations: '34', + numLocationsNotCovered: '0', + type: 'Class', + }, + { + id: '01p19000002uDL8AAM', + name: 'GeocodingService', + namespace: { + $: { + 'xsi:nil': 'true', + }, + }, + numLocations: '36', + numLocationsNotCovered: '0', + type: 'Class', + }, + { + id: '01p19000002uDLAAAN', + locationsNotCovered: { column: '0', - line: '26', + line: '12', numExecutions: '0', time: '-1.0', }, - { + name: 'A', + namespace: { + $: { + 'xsi:nil': 'true', + }, + }, + numLocations: '10', + numLocationsNotCovered: '1', + type: 'Class', + }, + { + id: '01p19000002uDLAABN', + locationsNotCovered: { column: '0', - line: '31', + line: '12', numExecutions: '0', time: '-1.0', }, - { + name: 'B', + namespace: { + $: { + 'xsi:nil': 'true', + }, + }, + numLocations: '4', + numLocationsNotCovered: '1', + type: 'Class', + }, + { + id: '01p19000002uDLAACN', + locationsNotCovered: { column: '0', - line: '78', + line: '12', numExecutions: '0', time: '-1.0', }, - ], - name: 'PropertyController', - namespace: { - $: { - 'xsi:nil': 'true', + name: 'C', + namespace: { + $: { + 'xsi:nil': 'true', + }, }, + numLocations: '10', + numLocationsNotCovered: '2', + type: 'Class', }, - numLocations: '44', - numLocationsNotCovered: '3', - type: 'Class', - }, - { - id: '01p19000002uDLCAA2', - name: 'SampleDataController', + ], + failures: { + id: '01p19000002uDLDAA2', + message: 'System.QueryException: Insufficient permissions: secure query included inaccessible field', + methodName: 'testGetPagedPropertyList', + name: 'TestPropertyController', namespace: { $: { 'xsi:nil': 'true', }, }, - numLocations: '34', - numLocationsNotCovered: '0', + packageName: 'TestPropertyController', + stackTrace: + 'Class.PropertyController.getPagedPropertyList: line 52, column 1\nClass.TestPropertyController.testGetPagedPropertyList: line 22, column 1', + time: '604.0', type: 'Class', }, - { - id: '01p19000002uDL8AAM', - name: 'GeocodingService', - namespace: { - $: { - 'xsi:nil': 'true', + numFailures: '1', + numTestsRun: '7', + successes: [ + { + id: '01p19000002uDL9AAM', + methodName: 'blankAddress', + name: 'GeocodingServiceTest', + namespace: { + $: { + 'xsi:nil': 'true', + }, }, + time: '26.0', }, - numLocations: '36', - numLocationsNotCovered: '0', - type: 'Class', - }, - ], - failures: { - id: '01p19000002uDLDAA2', - message: 'System.QueryException: Insufficient permissions: secure query included inaccessible field', - methodName: 'testGetPagedPropertyList', - name: 'TestPropertyController', - namespace: { - $: { - 'xsi:nil': 'true', - }, - }, - packageName: 'TestPropertyController', - stackTrace: - 'Class.PropertyController.getPagedPropertyList: line 52, column 1\nClass.TestPropertyController.testGetPagedPropertyList: line 22, column 1', - time: '604.0', - type: 'Class', - }, - numFailures: '1', - numTestsRun: '7', - successes: [ - { - id: '01p19000002uDL9AAM', - methodName: 'blankAddress', - name: 'GeocodingServiceTest', - namespace: { - $: { - 'xsi:nil': 'true', + { + id: '01p19000002uDL9AAM', + methodName: 'errorResponse', + name: 'GeocodingServiceTest', + namespace: { + $: { + 'xsi:nil': 'true', + }, }, + time: '77.0', }, - time: '26.0', - }, - { - id: '01p19000002uDL9AAM', - methodName: 'errorResponse', - name: 'GeocodingServiceTest', - namespace: { - $: { - 'xsi:nil': 'true', + { + id: '01p19000002uDL9AAM', + methodName: 'successResponse', + name: 'GeocodingServiceTest', + namespace: { + $: { + 'xsi:nil': 'true', + }, }, + time: '63.0', }, - time: '77.0', - }, - { - id: '01p19000002uDL9AAM', - methodName: 'successResponse', - name: 'GeocodingServiceTest', - namespace: { - $: { - 'xsi:nil': 'true', - }, - }, - time: '63.0', - }, - { - id: '01p19000002uDLDAA2', - methodName: 'testGetPicturesNoResults', - name: 'TestPropertyController', - namespace: { - $: { - 'xsi:nil': 'true', + { + id: '01p19000002uDLDAA2', + methodName: 'testGetPicturesNoResults', + name: 'TestPropertyController', + namespace: { + $: { + 'xsi:nil': 'true', + }, }, + time: '691.0', }, - time: '691.0', - }, - { - id: '01p19000002uDLDAA2', - methodName: 'testGetPicturesWithResults', - name: 'TestPropertyController', - namespace: { - $: { - 'xsi:nil': 'true', + { + id: '01p19000002uDLDAA2', + methodName: 'testGetPicturesWithResults', + name: 'TestPropertyController', + namespace: { + $: { + 'xsi:nil': 'true', + }, }, + time: '1873.0', }, - time: '1873.0', - }, - { - id: '01p19000002uDLEAA2', - methodName: 'importSampleData', - name: 'TestSampleDataController', - namespace: { - $: { - 'xsi:nil': 'true', + { + id: '01p19000002uDLEAA2', + methodName: 'importSampleData', + name: 'TestSampleDataController', + namespace: { + $: { + 'xsi:nil': 'true', + }, }, + time: '1535.0', }, - time: '1535.0', - }, - ], - totalTime: '4952.0', -}; + ], + totalTime: '4952.0', + }; +} describe('transform md RunTestResult', () => { const $$ = new TestContext(); let mockConnection: Connection; const testData = new MockTestOrgData(); + let sampleTestResult = getSampleTestResult(); let sandboxStub: SinonSandbox; beforeEach(async () => { + sampleTestResult = getSampleTestResult(); sandboxStub = createSandbox(); $$.setConfigStubContents('StateAggregator', { @@ -206,9 +266,10 @@ describe('transform md RunTestResult', () => { afterEach(() => { sandboxStub.restore(); }); + it('should transform md coverage to apex coverage format', () => { - const apexCoverage = transformCoverageToApexCoverage(sampleRunTestResult.codeCoverage); - expect(apexCoverage.records).to.have.length(4); + const apexCoverage = transformCoverageToApexCoverage(sampleTestResult.codeCoverage); + expect(apexCoverage.records).to.have.length(7); expect(apexCoverage.records[0].ApexClassOrTrigger.Name).to.equal('PagedResult'); expect(apexCoverage.records[1].ApexClassOrTrigger.Name).to.equal('PropertyController'); expect(apexCoverage.records[2].ApexClassOrTrigger.Name).to.equal('SampleDataController'); @@ -219,8 +280,36 @@ describe('transform md RunTestResult', () => { expect(apexCoverage.records[2].Coverage.uncoveredLines).to.have.lengthOf(apexCoverage.records[2].NumLinesUncovered); expect(apexCoverage.records[2].Coverage.coveredLines).to.have.lengthOf(apexCoverage.records[2].NumLinesCovered); }); + it('should transform md test results to apex test results format', () => { - const apexTestResults = transformDeployTestsResultsToTestResult(mockConnection, sampleRunTestResult); + const apexTestResults = transformDeployTestsResultsToTestResult(mockConnection, sampleTestResult); expect(apexTestResults).to.be.ok; }); + + it('should display code coverage classes ordered alphabetically', () => { + const codeCoverage = prepCoverageForDisplay(sampleTestResult.codeCoverage); + + expect(codeCoverage[0].name).to.equal('A'); + expect(codeCoverage[1].name).to.equal('B'); + expect(codeCoverage[2].name).to.equal('C'); + expect(codeCoverage[3].name).to.equal('GeocodingService'); + expect(codeCoverage[4].name).to.equal('PagedResult'); + expect(codeCoverage[5].name).to.equal('PropertyController'); + expect(codeCoverage[6].name).to.equal('SampleDataController'); + }); + + it('should display code coverage percentage with green color when its value is >= 90%', () => { + const codeCoverage = prepCoverageForDisplay(sampleTestResult.codeCoverage); + expect(codeCoverage[0].numLocations).to.equal(chalk.green('90%')); + }); + + it('should display code coverage percentage with red color when its value is <= 75%', () => { + const codeCoverage = prepCoverageForDisplay(sampleTestResult.codeCoverage); + expect(codeCoverage[1].numLocations).to.equal(chalk.red('75%')); + }); + + it('should display code coverage percentage with yellow color when its value is > 75% and < 90%', () => { + const codeCoverage = prepCoverageForDisplay(sampleTestResult.codeCoverage); + expect(codeCoverage[2].numLocations).to.equal(chalk.yellow('80%')); + }); }); From b44cf01dfd19f43e088a5dab2b74948971182de1 Mon Sep 17 00:00:00 2001 From: Allan Oricil Date: Fri, 18 Aug 2023 22:12:00 -0300 Subject: [PATCH 2/2] fix: use red for values lower than 75% --- src/coverageUtils.ts | 2 +- test/coverageUtils.test.ts | 98 ++++++++++++++++++++++++++++++-------- 2 files changed, 80 insertions(+), 20 deletions(-) diff --git a/src/coverageUtils.ts b/src/coverageUtils.ts index c28f55cfb..c65c3cf34 100644 --- a/src/coverageUtils.ts +++ b/src/coverageUtils.ts @@ -47,7 +47,7 @@ export function prepCoverageForDisplay(codeCoverage: CodeCoverage[]): CodeCovera const numLocationsNotCovered = parseInt(cov.numLocationsNotCovered, 10); const coverageDecimal = parseFloat(((numLocationsNum - numLocationsNotCovered) / numLocationsNum).toFixed(2)); const pctCovered = numLocationsNum > 0 ? coverageDecimal * 100 : 100; - const color = pctCovered <= 75 ? chalk.red : pctCovered >= 90 ? chalk.green : chalk.yellow; + const color = pctCovered < 75 ? chalk.red : pctCovered >= 90 ? chalk.green : chalk.yellow; cov.numLocations = color(`${pctCovered}%`); cov.lineNotCovered = cov.locationsNotCovered diff --git a/test/coverageUtils.test.ts b/test/coverageUtils.test.ts index 6acaa5beb..0d72ab209 100644 --- a/test/coverageUtils.test.ts +++ b/test/coverageUtils.test.ts @@ -104,12 +104,12 @@ function getSampleTestResult() { 'xsi:nil': 'true', }, }, - numLocations: '10', - numLocationsNotCovered: '1', + numLocations: '100', + numLocationsNotCovered: '100', type: 'Class', }, { - id: '01p19000002uDLAABN', + id: '01p19000002uDLAAAN', locationsNotCovered: { column: '0', line: '12', @@ -122,12 +122,12 @@ function getSampleTestResult() { 'xsi:nil': 'true', }, }, - numLocations: '4', - numLocationsNotCovered: '1', + numLocations: '100', + numLocationsNotCovered: '26', type: 'Class', }, { - id: '01p19000002uDLAACN', + id: '01p19000002uDLAABN', locationsNotCovered: { column: '0', line: '12', @@ -140,8 +140,62 @@ function getSampleTestResult() { 'xsi:nil': 'true', }, }, - numLocations: '10', - numLocationsNotCovered: '2', + numLocations: '100', + numLocationsNotCovered: '25', + type: 'Class', + }, + { + id: '01p19000002uDLAABN', + locationsNotCovered: { + column: '0', + line: '12', + numExecutions: '0', + time: '-1.0', + }, + name: 'D', + namespace: { + $: { + 'xsi:nil': 'true', + }, + }, + numLocations: '100', + numLocationsNotCovered: '11', + type: 'Class', + }, + { + id: '01p19000002uDLAABN', + locationsNotCovered: { + column: '0', + line: '12', + numExecutions: '0', + time: '-1.0', + }, + name: 'E', + namespace: { + $: { + 'xsi:nil': 'true', + }, + }, + numLocations: '100', + numLocationsNotCovered: '10', + type: 'Class', + }, + { + id: '01p19000002uDLAACN', + locationsNotCovered: { + column: '0', + line: '12', + numExecutions: '0', + time: '-1.0', + }, + name: 'F', + namespace: { + $: { + 'xsi:nil': 'true', + }, + }, + numLocations: '100', + numLocationsNotCovered: '0', type: 'Class', }, ], @@ -269,7 +323,7 @@ describe('transform md RunTestResult', () => { it('should transform md coverage to apex coverage format', () => { const apexCoverage = transformCoverageToApexCoverage(sampleTestResult.codeCoverage); - expect(apexCoverage.records).to.have.length(7); + expect(apexCoverage.records).to.have.length(10); expect(apexCoverage.records[0].ApexClassOrTrigger.Name).to.equal('PagedResult'); expect(apexCoverage.records[1].ApexClassOrTrigger.Name).to.equal('PropertyController'); expect(apexCoverage.records[2].ApexClassOrTrigger.Name).to.equal('SampleDataController'); @@ -292,24 +346,30 @@ describe('transform md RunTestResult', () => { expect(codeCoverage[0].name).to.equal('A'); expect(codeCoverage[1].name).to.equal('B'); expect(codeCoverage[2].name).to.equal('C'); - expect(codeCoverage[3].name).to.equal('GeocodingService'); - expect(codeCoverage[4].name).to.equal('PagedResult'); - expect(codeCoverage[5].name).to.equal('PropertyController'); - expect(codeCoverage[6].name).to.equal('SampleDataController'); + expect(codeCoverage[3].name).to.equal('D'); + expect(codeCoverage[4].name).to.equal('E'); + expect(codeCoverage[5].name).to.equal('F'); + expect(codeCoverage[6].name).to.equal('GeocodingService'); + expect(codeCoverage[7].name).to.equal('PagedResult'); + expect(codeCoverage[8].name).to.equal('PropertyController'); + expect(codeCoverage[9].name).to.equal('SampleDataController'); }); - it('should display code coverage percentage with green color when its value is >= 90%', () => { + it('should display code coverage percentage with red color when its value is < 75%', () => { const codeCoverage = prepCoverageForDisplay(sampleTestResult.codeCoverage); - expect(codeCoverage[0].numLocations).to.equal(chalk.green('90%')); + expect(codeCoverage[0].numLocations).to.equal(chalk.red('0%')); + expect(codeCoverage[1].numLocations).to.equal(chalk.red('74%')); }); - it('should display code coverage percentage with red color when its value is <= 75%', () => { + it('should display code coverage percentage with yellow color when its value is >= 75% and < 90%', () => { const codeCoverage = prepCoverageForDisplay(sampleTestResult.codeCoverage); - expect(codeCoverage[1].numLocations).to.equal(chalk.red('75%')); + expect(codeCoverage[2].numLocations).to.equal(chalk.yellow('75%')); + expect(codeCoverage[3].numLocations).to.equal(chalk.yellow('89%')); }); - it('should display code coverage percentage with yellow color when its value is > 75% and < 90%', () => { + it('should display code coverage percentage with green color when its value is >= 90%', () => { const codeCoverage = prepCoverageForDisplay(sampleTestResult.codeCoverage); - expect(codeCoverage[2].numLocations).to.equal(chalk.yellow('80%')); + expect(codeCoverage[4].numLocations).to.equal(chalk.green('90%')); + expect(codeCoverage[5].numLocations).to.equal(chalk.green('100%')); }); });