diff --git a/packages/plugin-coverage/src/lib/config.ts b/packages/plugin-coverage/src/lib/config.ts index 02ed5a3d8..6719939c4 100644 --- a/packages/plugin-coverage/src/lib/config.ts +++ b/packages/plugin-coverage/src/lib/config.ts @@ -38,6 +38,12 @@ export const coveragePluginConfigSchema = z.object({ .optional(), }) .optional(), + continueOnCommandFail: z + .boolean({ + description: + 'Continue on coverage tool command failure or error. Defaults to true.', + }) + .default(true), coverageTypes: z .array(coverageTypeSchema, { description: 'Coverage types measured. Defaults to all available types.', diff --git a/packages/plugin-coverage/src/lib/runner/index.ts b/packages/plugin-coverage/src/lib/runner/index.ts index 95710201f..6f28d9940 100644 --- a/packages/plugin-coverage/src/lib/runner/index.ts +++ b/packages/plugin-coverage/src/lib/runner/index.ts @@ -24,7 +24,7 @@ export async function executeRunner({ runnerConfigPath, runnerOutputPath, }: RunnerFilesPaths): Promise { - const { reports, coverageToolCommand, coverageTypes } = + const { reports, coverageToolCommand, continueOnCommandFail, coverageTypes } = await readJsonFile(runnerConfigPath); // Run coverage tool if provided @@ -34,15 +34,20 @@ export async function executeRunner({ await executeProcess({ command, args }); } catch (error) { if (error instanceof ProcessError) { - ui().logger.error(bold('stdout from failed coverage tool process:')); - ui().logger.error(error.stdout); - ui().logger.error(bold('stderr from failed coverage tool process:')); - ui().logger.error(error.stderr); + const loggingFn = continueOnCommandFail + ? ui().logger.warning.bind(ui().logger) + : ui().logger.error.bind(ui().logger); + loggingFn(bold('stdout from failed coverage tool process:')); + loggingFn(error.stdout); + loggingFn(bold('stderr from failed coverage tool process:')); + loggingFn(error.stderr); } - throw new Error( - 'Coverage plugin: Running coverage tool failed. Make sure all your provided tests are passing.', - ); + if (!continueOnCommandFail) { + throw new Error( + 'Coverage plugin: Running coverage tool failed. Make sure all your provided tests are passing.', + ); + } } } diff --git a/packages/plugin-coverage/src/lib/runner/lcov/lcov-runner.ts b/packages/plugin-coverage/src/lib/runner/lcov/lcov-runner.ts index 3a5a2c447..79aec802e 100644 --- a/packages/plugin-coverage/src/lib/runner/lcov/lcov-runner.ts +++ b/packages/plugin-coverage/src/lib/runner/lcov/lcov-runner.ts @@ -55,37 +55,34 @@ export async function lcovResultsToAuditOutputs( export async function parseLcovFiles( results: CoverageResult[], ): Promise { - const parsedResults = await Promise.all( - results.map(async result => { - const resultsPath = - typeof result === 'string' ? result : result.resultsPath; - const lcovFileContent = await readTextFile(resultsPath); - if (lcovFileContent.trim() === '') { - ui().logger.warning( - `Coverage plugin: Empty lcov report file detected at ${resultsPath}.`, - ); - } - const parsedRecords = parseLcov(toUnixNewlines(lcovFileContent)); - return parsedRecords.map(record => ({ - ...record, - file: - typeof result === 'string' || result.pathToProject == null - ? record.file - : path.join(result.pathToProject, record.file), - })); - }), - ); - if (parsedResults.length !== results.length) { - throw new Error('Some provided LCOV results were not valid.'); - } - - const flatResults = parsedResults.flat(); + const parsedResults = ( + await Promise.all( + results.map(async result => { + const resultsPath = + typeof result === 'string' ? result : result.resultsPath; + const lcovFileContent = await readTextFile(resultsPath); + if (lcovFileContent.trim() === '') { + ui().logger.warning( + `Coverage plugin: Empty lcov report file detected at ${resultsPath}.`, + ); + } + const parsedRecords = parseLcov(toUnixNewlines(lcovFileContent)); + return parsedRecords.map(record => ({ + ...record, + file: + typeof result === 'string' || result.pathToProject == null + ? record.file + : path.join(result.pathToProject, record.file), + })); + }), + ) + ).flat(); - if (flatResults.length === 0) { - throw new Error('All provided results are empty.'); + if (parsedResults.length === 0) { + throw new Error('All provided coverage results are empty.'); } - return flatResults; + return parsedResults; } /** diff --git a/packages/plugin-coverage/src/lib/runner/lcov/lcov-runner.unit.test.ts b/packages/plugin-coverage/src/lib/runner/lcov/lcov-runner.unit.test.ts index 63be5307d..e5d8f2108 100644 --- a/packages/plugin-coverage/src/lib/runner/lcov/lcov-runner.unit.test.ts +++ b/packages/plugin-coverage/src/lib/runner/lcov/lcov-runner.unit.test.ts @@ -89,7 +89,7 @@ end_of_record it('should throw for only empty reports', async () => { await expect(() => parseLcovFiles([path.join('coverage', 'lcov.info')]), - ).rejects.toThrow('All provided results are empty.'); + ).rejects.toThrow('All provided coverage results are empty.'); }); it('should warn about an empty lcov file', async () => {