diff --git a/e2e/cli-e2e/tests/__snapshots__/collect.e2e.test.ts.snap b/e2e/cli-e2e/tests/__snapshots__/collect.e2e.test.ts.snap index 47a9e0f07..35945e037 100644 --- a/e2e/cli-e2e/tests/__snapshots__/collect.e2e.test.ts.snap +++ b/e2e/cli-e2e/tests/__snapshots__/collect.e2e.test.ts.snap @@ -1,425 +1,5 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`CLI collect > should run Code coverage plugin that runs coverage tool and creates report.json 1`] = ` -{ - "categories": [ - { - "refs": [ - { - "plugin": "coverage", - "slug": "coverage", - "type": "group", - "weight": 1, - }, - ], - "slug": "code-coverage", - "title": "Code coverage", - }, - ], - "packageName": "@code-pushup/core", - "plugins": [ - { - "audits": [ - { - "description": "Measures how many functions were called in at least one test.", - "details": { - "issues": [ - { - "message": "Function onSubmit is not called in any test case.", - "severity": "error", - "source": { - "file": "examples/react-todos-app/src/components/CreateTodo.jsx", - "position": { - "startLine": 13, - }, - }, - }, - { - "message": "Function onInput is not called in any test case.", - "severity": "error", - "source": { - "file": "examples/react-todos-app/src/components/CreateTodo.jsx", - "position": { - "startLine": 21, - }, - }, - }, - { - "message": "Function onInput is not called in any test case.", - "severity": "error", - "source": { - "file": "examples/react-todos-app/src/components/TodoFilter.jsx", - "position": { - "startLine": 9, - }, - }, - }, - { - "message": "Function onChange is not called in any test case.", - "severity": "error", - "source": { - "file": "examples/react-todos-app/src/components/TodoFilter.jsx", - "position": { - "startLine": 17, - }, - }, - }, - ], - }, - "displayValue": "55.6 %", - "score": 0.5556, - "slug": "function-coverage", - "title": "Function coverage", - "value": 55.55555555555556, - }, - { - "description": "Measures how many branches were executed after conditional statements in at least one test.", - "details": { - "issues": [ - { - "message": "1st branch is not taken in any test case.", - "severity": "error", - "source": { - "file": "examples/react-todos-app/src/index.jsx", - "position": { - "startLine": 1, - }, - }, - }, - ], - }, - "displayValue": "87.5 %", - "score": 0.875, - "slug": "branch-coverage", - "title": "Branch coverage", - "value": 87.5, - }, - { - "description": "Measures how many lines of code were executed in at least one test.", - "details": { - "issues": [ - { - "message": "Lines 1-6 are not covered in any test case.", - "severity": "warning", - "source": { - "file": "examples/react-todos-app/src/index.jsx", - "position": { - "endLine": 6, - "startLine": 1, - }, - }, - }, - { - "message": "Lines 14-17 are not covered in any test case.", - "severity": "warning", - "source": { - "file": "examples/react-todos-app/src/components/CreateTodo.jsx", - "position": { - "endLine": 17, - "startLine": 14, - }, - }, - }, - { - "message": "Lines 22-23 are not covered in any test case.", - "severity": "warning", - "source": { - "file": "examples/react-todos-app/src/components/CreateTodo.jsx", - "position": { - "endLine": 23, - "startLine": 22, - }, - }, - }, - { - "message": "Lines 10-11 are not covered in any test case.", - "severity": "warning", - "source": { - "file": "examples/react-todos-app/src/components/TodoFilter.jsx", - "position": { - "endLine": 11, - "startLine": 10, - }, - }, - }, - { - "message": "Lines 18-19 are not covered in any test case.", - "severity": "warning", - "source": { - "file": "examples/react-todos-app/src/components/TodoFilter.jsx", - "position": { - "endLine": 19, - "startLine": 18, - }, - }, - }, - { - "message": "Lines 7-28 are not covered in any test case.", - "severity": "warning", - "source": { - "file": "examples/react-todos-app/src/components/TodoList.jsx", - "position": { - "endLine": 28, - "startLine": 7, - }, - }, - }, - { - "message": "Lines 12-13 are not covered in any test case.", - "severity": "warning", - "source": { - "file": "examples/react-todos-app/src/hooks/useTodos.js", - "position": { - "endLine": 13, - "startLine": 12, - }, - }, - }, - { - "message": "Lines 18-37 are not covered in any test case.", - "severity": "warning", - "source": { - "file": "examples/react-todos-app/src/hooks/useTodos.js", - "position": { - "endLine": 37, - "startLine": 18, - }, - }, - }, - { - "message": "Lines 41-45 are not covered in any test case.", - "severity": "warning", - "source": { - "file": "examples/react-todos-app/src/hooks/useTodos.js", - "position": { - "endLine": 45, - "startLine": 41, - }, - }, - }, - { - "message": "Lines 54-60 are not covered in any test case.", - "severity": "warning", - "source": { - "file": "examples/react-todos-app/src/hooks/useTodos.js", - "position": { - "endLine": 60, - "startLine": 54, - }, - }, - }, - ], - }, - "displayValue": "62.1 %", - "score": 0.6211, - "slug": "line-coverage", - "title": "Line coverage", - "value": 62.10526315789474, - }, - ], - "description": "Official Code PushUp code coverage plugin.", - "docsUrl": "https://www.npmjs.com/package/@code-pushup/coverage-plugin/", - "groups": [ - { - "description": "Group containing all defined coverage types as audits.", - "refs": [ - { - "slug": "function-coverage", - "weight": 6, - }, - { - "slug": "branch-coverage", - "weight": 3, - }, - { - "slug": "line-coverage", - "weight": 1, - }, - ], - "slug": "coverage", - "title": "Code coverage metrics", - }, - ], - "icon": "folder-coverage-open", - "packageName": "@code-pushup/coverage-plugin", - "slug": "coverage", - "title": "Code coverage", - }, - ], -} -`; - -exports[`CLI collect > should run Code coverage plugin which collects passed results and creates report.json 1`] = ` -{ - "categories": [ - { - "refs": [ - { - "plugin": "coverage", - "slug": "coverage", - "type": "group", - "weight": 1, - }, - ], - "slug": "code-coverage", - "title": "Code coverage", - }, - ], - "packageName": "@code-pushup/core", - "plugins": [ - { - "audits": [ - { - "description": "Measures how many functions were called in at least one test.", - "details": { - "issues": [ - { - "message": "Function formatReportScore is not called in any test case.", - "severity": "error", - "source": { - "file": "src/lib/partly-covered/utils.ts", - "position": { - "startLine": 2, - }, - }, - }, - { - "message": "Function sortReport is not called in any test case.", - "severity": "error", - "source": { - "file": "src/lib/not-covered/sorting.ts", - "position": { - "startLine": 1, - }, - }, - }, - ], - }, - "displayValue": "60 %", - "score": 0.6, - "slug": "function-coverage", - "title": "Function coverage", - "value": 60, - }, - { - "description": "Measures how many branches were executed after conditional statements in at least one test.", - "details": { - "issues": [ - { - "message": "2nd branch is not taken in any test case.", - "severity": "error", - "source": { - "file": "src/lib/partly-covered/utils.ts", - "position": { - "startLine": 6, - }, - }, - }, - { - "message": "2nd branch is not taken in any test case.", - "severity": "error", - "source": { - "file": "src/lib/partly-covered/utils.ts", - "position": { - "startLine": 10, - }, - }, - }, - { - "message": "1st branch is not taken in any test case.", - "severity": "error", - "source": { - "file": "src/lib/not-covered/sorting.ts", - "position": { - "startLine": 7, - }, - }, - }, - { - "message": "2nd branch is not taken in any test case.", - "severity": "error", - "source": { - "file": "src/lib/not-covered/sorting.ts", - "position": { - "startLine": 7, - }, - }, - }, - ], - }, - "displayValue": "76.5 %", - "score": 0.7647, - "slug": "branch-coverage", - "title": "Branch coverage", - "value": 76.47058823529412, - }, - { - "description": "Measures how many lines of code were executed in at least one test.", - "details": { - "issues": [ - { - "message": "Lines 7-9 are not covered in any test case.", - "severity": "warning", - "source": { - "file": "src/lib/partly-covered/utils.ts", - "position": { - "endLine": 9, - "startLine": 7, - }, - }, - }, - { - "message": "Lines 1-5 are not covered in any test case.", - "severity": "warning", - "source": { - "file": "src/lib/not-covered/sorting.ts", - "position": { - "endLine": 5, - "startLine": 1, - }, - }, - }, - ], - }, - "displayValue": "68 %", - "score": 0.68, - "slug": "line-coverage", - "title": "Line coverage", - "value": 68, - }, - ], - "description": "Official Code PushUp code coverage plugin.", - "docsUrl": "https://www.npmjs.com/package/@code-pushup/coverage-plugin/", - "groups": [ - { - "description": "Group containing all defined coverage types as audits.", - "refs": [ - { - "slug": "function-coverage", - "weight": 6, - }, - { - "slug": "branch-coverage", - "weight": 3, - }, - { - "slug": "line-coverage", - "weight": 1, - }, - ], - "slug": "coverage", - "title": "Code coverage metrics", - }, - ], - "icon": "folder-coverage-open", - "packageName": "@code-pushup/coverage-plugin", - "slug": "coverage", - "title": "Code coverage", - }, - ], -} -`; - exports[`CLI collect > should run ESLint plugin and create report.json 1`] = ` { "categories": [ diff --git a/e2e/cli-e2e/tests/collect.e2e.test.ts b/e2e/cli-e2e/tests/collect.e2e.test.ts index 5e301ab29..269fae9fb 100644 --- a/e2e/cli-e2e/tests/collect.e2e.test.ts +++ b/e2e/cli-e2e/tests/collect.e2e.test.ts @@ -1,5 +1,3 @@ -import { dirname, join } from 'node:path'; -import { fileURLToPath } from 'node:url'; import { type AuditReport, type PluginReport, @@ -65,59 +63,6 @@ describe('CLI collect', () => { expect(omitVariableReportData(report as Report)).toMatchSnapshot(); }); - it('should run Code coverage plugin which collects passed results and creates report.json', async () => { - /** - * The stats passed in the fixture are as follows - * 3 files: one partially covered, one with no coverage, one with full coverage - * Functions: 2 + 1 + 2 found | 1 + 0 + 2 covered (60% coverage) - * Branches: 10 + 2 + 5 found | 8 + 0 + 5 covered (76% coverage) - * Lines: 10 + 5 + 10 found | 7 + 0 + 10 covered (68% coverage) - */ - - const configPath = join( - fileURLToPath(dirname(import.meta.url)), - '..', - 'mocks', - 'fixtures', - 'code-pushup.config.ts', - ); - - const { code, stderr } = await executeProcess({ - command: 'code-pushup', - args: [ - 'collect', - '--no-progress', - `--config=${configPath}`, - '--persist.outputDir=tmp/e2e', - '--onlyPlugins=coverage', - ], - }); - - expect(code).toBe(0); - expect(stderr).toBe(''); - - const report = await readJsonFile(join('tmp', 'e2e', 'report.json')); - - expect(() => reportSchema.parse(report)).not.toThrow(); - expect(omitVariableReportData(report as Report)).toMatchSnapshot(); - }); - - it('should run Code coverage plugin that runs coverage tool and creates report.json', async () => { - const { code, stderr } = await executeProcess({ - command: 'code-pushup', - args: ['collect', '--no-progress', '--onlyPlugins=coverage'], - cwd: 'examples/react-todos-app', - }); - - expect(code).toBe(0); - expect(stderr).toBe(''); - - const report = await readJsonFile('tmp/e2e/react-todos-app/report.json'); - - expect(() => reportSchema.parse(report)).not.toThrow(); - expect(omitVariableReportData(report as Report)).toMatchSnapshot(); - }); - it('should create report.md', async () => { const { code, stderr } = await executeProcess({ command: 'code-pushup', diff --git a/e2e/plugin-coverage-e2e/.eslintrc.json b/e2e/plugin-coverage-e2e/.eslintrc.json new file mode 100644 index 000000000..7ef7b6dc8 --- /dev/null +++ b/e2e/plugin-coverage-e2e/.eslintrc.json @@ -0,0 +1,12 @@ +{ + "extends": ["../../.eslintrc.json"], + "ignorePatterns": ["!**/*", "code-pushup.config*.ts"], + "overrides": [ + { + "files": ["*.ts", "*.tsx"], + "parserOptions": { + "project": ["e2e/plugin-coverage-e2e/tsconfig.*?.json"] + } + } + ] +} diff --git a/e2e/plugin-coverage-e2e/mocks/fixtures/basic-setup/code-pushup.config.ts b/e2e/plugin-coverage-e2e/mocks/fixtures/basic-setup/code-pushup.config.ts new file mode 100644 index 000000000..8d506c569 --- /dev/null +++ b/e2e/plugin-coverage-e2e/mocks/fixtures/basic-setup/code-pushup.config.ts @@ -0,0 +1,27 @@ +import coveragePlugin from '@code-pushup/coverage-plugin'; + +export default { + plugins: [ + await coveragePlugin({ + reports: ['coverage/lcov.info'], + coverageToolCommand: { + command: 'npm', + args: ['run', 'test'], + }, + }), + ], + categories: [ + { + slug: 'code-coverage', + title: 'Code coverage', + refs: [ + { + type: 'group', + plugin: 'coverage', + slug: 'coverage', + weight: 1, + }, + ], + }, + ], +}; diff --git a/e2e/plugin-coverage-e2e/mocks/fixtures/basic-setup/package.json b/e2e/plugin-coverage-e2e/mocks/fixtures/basic-setup/package.json new file mode 100644 index 000000000..61a96ca4c --- /dev/null +++ b/e2e/plugin-coverage-e2e/mocks/fixtures/basic-setup/package.json @@ -0,0 +1,14 @@ +{ + "name": "coverage-e2e-env", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "npx vitest run --coverage" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + }, + "description": "" +} diff --git a/e2e/plugin-coverage-e2e/mocks/fixtures/basic-setup/src/index.mjs b/e2e/plugin-coverage-e2e/mocks/fixtures/basic-setup/src/index.mjs new file mode 100644 index 000000000..b698a1fac --- /dev/null +++ b/e2e/plugin-coverage-e2e/mocks/fixtures/basic-setup/src/index.mjs @@ -0,0 +1,15 @@ +export function untested() { + console.log('This function is not tested'); +} + +export function get42() { + return 42; +} + +export function isEven(num) { + if (num === undefined) { + return false; + } + const parsedNumber = parseInt(num, 10); + return parsedNumber % 2 === 0; +} diff --git a/e2e/plugin-coverage-e2e/mocks/fixtures/basic-setup/src/index.test.mjs b/e2e/plugin-coverage-e2e/mocks/fixtures/basic-setup/src/index.test.mjs new file mode 100644 index 000000000..d02988166 --- /dev/null +++ b/e2e/plugin-coverage-e2e/mocks/fixtures/basic-setup/src/index.test.mjs @@ -0,0 +1,18 @@ +import { describe, expect, it } from 'vitest'; +import { get42, isEven, untested } from './index.mjs'; + +describe('get42', () => { + it('should return 42', async () => { + expect(get42()).toBe(42); + }); +}); + +describe('isEven', () => { + it('should return true for even number 42', async () => { + expect(isEven(42)).toBe(true); + }); + + it.todo('should return false for odd number 1'); +}); + +describe.todo('untested', () => {}); diff --git a/e2e/plugin-coverage-e2e/mocks/fixtures/basic-setup/vite.config.ts b/e2e/plugin-coverage-e2e/mocks/fixtures/basic-setup/vite.config.ts new file mode 100644 index 000000000..7a6636feb --- /dev/null +++ b/e2e/plugin-coverage-e2e/mocks/fixtures/basic-setup/vite.config.ts @@ -0,0 +1,25 @@ +/// +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + root: fileURLToPath(dirname(import.meta.url)), + cacheDir: 'node_modules/.vite/coverage-e2e-env', + + test: { + reporters: ['basic'], + globals: true, + cache: { + dir: 'node_modules/.vitest', + }, + coverage: { + reporter: ['lcov', 'text'], + provider: 'v8', + reportsDirectory: 'coverage', + include: ['src/**/*.{js,mjs}'], + }, + environment: 'node', + include: ['src/**/*.{test,spec}.{js,mjs}'], + }, +}); diff --git a/e2e/plugin-coverage-e2e/mocks/fixtures/existing-report/code-pushup.config.ts b/e2e/plugin-coverage-e2e/mocks/fixtures/existing-report/code-pushup.config.ts new file mode 100644 index 000000000..d955bbba0 --- /dev/null +++ b/e2e/plugin-coverage-e2e/mocks/fixtures/existing-report/code-pushup.config.ts @@ -0,0 +1,25 @@ +import { join } from 'node:path'; +import coveragePlugin from '@code-pushup/coverage-plugin'; +import type { CoreConfig } from '@code-pushup/models'; + +export default { + plugins: [ + await coveragePlugin({ + reports: [join('coverage', 'lcov.info')], + }), + ], + categories: [ + { + slug: 'code-coverage', + title: 'Code coverage', + refs: [ + { + type: 'group', + plugin: 'coverage', + slug: 'coverage', + weight: 1, + }, + ], + }, + ], +} satisfies CoreConfig; diff --git a/e2e/plugin-coverage-e2e/mocks/fixtures/existing-report/coverage/lcov.info b/e2e/plugin-coverage-e2e/mocks/fixtures/existing-report/coverage/lcov.info new file mode 100644 index 000000000..474ad74e7 --- /dev/null +++ b/e2e/plugin-coverage-e2e/mocks/fixtures/existing-report/coverage/lcov.info @@ -0,0 +1,78 @@ +TN: +SF:src\lib\partly-covered\utils.ts +FN:2,formatReportScore +FN:6,calcDuration +FNF:2 +FNH:1 +FNDA:0,formatReportScore +FNDA:6,calcDuration +DA:1,1 +DA:2,1 +DA:3,1 +DA:4,1 +DA:5,1 +DA:6,1 +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,1 +LF:10 +LH:7 +BRDA:1,0,0,6 +BRDA:1,1,0,5 +BRDA:2,4,0,1 +BRDA:4,5,0,17 +BRDA:5,6,0,4 +BRDA:6,7,0,13 +BRDA:6,10,1,0 +BRDA:7,11,0,3 +BRDA:10,12,0,12 +BRDA:10,13,1,0 +BRF:10 +BRH:8 +end_of_record +SF:src\lib\not-covered\sorting.ts +FN:1,sortReport +FNF:1 +FNH:0 +FNDA:0,sortReport +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +LF:5 +LH:0 +BRDA:7,1,0,0 +BRDA:7,2,1,0 +BRF:2 +BRH:0 +end_of_record +TN: +SF:src\lib\fully-covered\scoring.ts +FN:2,scoreReport +FN:8,calculateScore +FNF:2 +FNH:2 +FNDA:3,scoreReport +FNDA:5,calculateScore +DA:1,1 +DA:2,1 +DA:3,1 +DA:4,1 +DA:5,1 +DA:6,1 +DA:7,1 +DA:8,1 +DA:9,1 +DA:10,1 +LF:10 +LH:10 +BRDA:1,0,0,5 +BRDA:2,1,0,1 +BRDA:2,2,1,4 +BRDA:2,3,2,3 +BRDA:6,4,0,4 +BRF:5 +BRH:5 +end_of_record diff --git a/e2e/plugin-coverage-e2e/project.json b/e2e/plugin-coverage-e2e/project.json new file mode 100644 index 000000000..8a0932adf --- /dev/null +++ b/e2e/plugin-coverage-e2e/project.json @@ -0,0 +1,23 @@ +{ + "name": "plugin-coverage-e2e", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "e2e/plugin-coverage-e2e/src", + "projectType": "application", + "targets": { + "lint": { + "executor": "@nx/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["e2e/plugin-coverage-e2e/**/*.ts"] + } + }, + "e2e": { + "executor": "@nx/vite:test", + "options": { + "configFile": "e2e/plugin-coverage-e2e/vite.config.e2e.ts" + } + } + }, + "implicitDependencies": ["cli", "plugin-coverage"], + "tags": ["scope:plugin", "type:e2e"] +} diff --git a/e2e/plugin-coverage-e2e/tests/__snapshots__/collect.e2e.test.ts.snap b/e2e/plugin-coverage-e2e/tests/__snapshots__/collect.e2e.test.ts.snap new file mode 100644 index 000000000..d15a8626b --- /dev/null +++ b/e2e/plugin-coverage-e2e/tests/__snapshots__/collect.e2e.test.ts.snap @@ -0,0 +1,303 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`collect report with coverage-plugin NPM package > should run Code coverage plugin that runs coverage tool and creates report.json 1`] = ` +{ + "categories": [ + { + "refs": [ + { + "plugin": "coverage", + "slug": "coverage", + "type": "group", + "weight": 1, + }, + ], + "slug": "code-coverage", + "title": "Code coverage", + }, + ], + "packageName": "@code-pushup/core", + "plugins": [ + { + "audits": [ + { + "description": "Measures how many functions were called in at least one test.", + "details": { + "issues": [ + { + "message": "Function formatReportScore is not called in any test case.", + "severity": "error", + "source": { + "file": "tmp/e2e/plugin-coverage-e2e/existing-report/src/lib/partly-covered/utils.ts", + "position": { + "startLine": 2, + }, + }, + }, + { + "message": "Function sortReport is not called in any test case.", + "severity": "error", + "source": { + "file": "tmp/e2e/plugin-coverage-e2e/existing-report/src/lib/not-covered/sorting.ts", + "position": { + "startLine": 1, + }, + }, + }, + ], + }, + "displayValue": "60 %", + "score": 0.6, + "slug": "function-coverage", + "title": "Function coverage", + "value": 60, + }, + { + "description": "Measures how many branches were executed after conditional statements in at least one test.", + "details": { + "issues": [ + { + "message": "2nd branch is not taken in any test case.", + "severity": "error", + "source": { + "file": "tmp/e2e/plugin-coverage-e2e/existing-report/src/lib/partly-covered/utils.ts", + "position": { + "startLine": 6, + }, + }, + }, + { + "message": "2nd branch is not taken in any test case.", + "severity": "error", + "source": { + "file": "tmp/e2e/plugin-coverage-e2e/existing-report/src/lib/partly-covered/utils.ts", + "position": { + "startLine": 10, + }, + }, + }, + { + "message": "1st branch is not taken in any test case.", + "severity": "error", + "source": { + "file": "tmp/e2e/plugin-coverage-e2e/existing-report/src/lib/not-covered/sorting.ts", + "position": { + "startLine": 7, + }, + }, + }, + { + "message": "2nd branch is not taken in any test case.", + "severity": "error", + "source": { + "file": "tmp/e2e/plugin-coverage-e2e/existing-report/src/lib/not-covered/sorting.ts", + "position": { + "startLine": 7, + }, + }, + }, + ], + }, + "displayValue": "76.5 %", + "score": 0.7647, + "slug": "branch-coverage", + "title": "Branch coverage", + "value": 76.47058823529412, + }, + { + "description": "Measures how many lines of code were executed in at least one test.", + "details": { + "issues": [ + { + "message": "Lines 7-9 are not covered in any test case.", + "severity": "warning", + "source": { + "file": "tmp/e2e/plugin-coverage-e2e/existing-report/src/lib/partly-covered/utils.ts", + "position": { + "endLine": 9, + "startLine": 7, + }, + }, + }, + { + "message": "Lines 1-5 are not covered in any test case.", + "severity": "warning", + "source": { + "file": "tmp/e2e/plugin-coverage-e2e/existing-report/src/lib/not-covered/sorting.ts", + "position": { + "endLine": 5, + "startLine": 1, + }, + }, + }, + ], + }, + "displayValue": "68 %", + "score": 0.68, + "slug": "line-coverage", + "title": "Line coverage", + "value": 68, + }, + ], + "description": "Official Code PushUp code coverage plugin.", + "docsUrl": "https://www.npmjs.com/package/@code-pushup/coverage-plugin/", + "groups": [ + { + "description": "Group containing all defined coverage types as audits.", + "refs": [ + { + "slug": "function-coverage", + "weight": 6, + }, + { + "slug": "branch-coverage", + "weight": 3, + }, + { + "slug": "line-coverage", + "weight": 1, + }, + ], + "slug": "coverage", + "title": "Code coverage metrics", + }, + ], + "icon": "folder-coverage-open", + "packageName": "@code-pushup/coverage-plugin", + "slug": "coverage", + "title": "Code coverage", + }, + ], +} +`; + +exports[`collect report with coverage-plugin NPM package > should run Code coverage plugin which collects passed results and creates report.json 1`] = ` +{ + "categories": [ + { + "refs": [ + { + "plugin": "coverage", + "slug": "coverage", + "type": "group", + "weight": 1, + }, + ], + "slug": "code-coverage", + "title": "Code coverage", + }, + ], + "packageName": "@code-pushup/core", + "plugins": [ + { + "audits": [ + { + "description": "Measures how many functions were called in at least one test.", + "details": { + "issues": [ + { + "message": "Function untested is not called in any test case.", + "severity": "error", + "source": { + "file": "tmp/e2e/plugin-coverage-e2e/basic-setup/src/index.mjs", + "position": { + "startLine": 1, + }, + }, + }, + ], + }, + "displayValue": "66.7 %", + "score": 0.6667, + "slug": "function-coverage", + "title": "Function coverage", + "value": 66.66666666666666, + }, + { + "description": "Measures how many branches were executed after conditional statements in at least one test.", + "details": { + "issues": [ + { + "message": "1st branch is not taken in any test case.", + "severity": "error", + "source": { + "file": "tmp/e2e/plugin-coverage-e2e/basic-setup/src/index.mjs", + "position": { + "startLine": 10, + }, + }, + }, + ], + }, + "displayValue": "66.7 %", + "score": 0.6667, + "slug": "branch-coverage", + "title": "Branch coverage", + "value": 66.66666666666666, + }, + { + "description": "Measures how many lines of code were executed in at least one test.", + "details": { + "issues": [ + { + "message": "Lines 2-3 are not covered in any test case.", + "severity": "warning", + "source": { + "file": "tmp/e2e/plugin-coverage-e2e/basic-setup/src/index.mjs", + "position": { + "endLine": 3, + "startLine": 2, + }, + }, + }, + { + "message": "Lines 11-12 are not covered in any test case.", + "severity": "warning", + "source": { + "file": "tmp/e2e/plugin-coverage-e2e/basic-setup/src/index.mjs", + "position": { + "endLine": 12, + "startLine": 11, + }, + }, + }, + ], + }, + "displayValue": "73.3 %", + "score": 0.7333, + "slug": "line-coverage", + "title": "Line coverage", + "value": 73.33333333333333, + }, + ], + "description": "Official Code PushUp code coverage plugin.", + "docsUrl": "https://www.npmjs.com/package/@code-pushup/coverage-plugin/", + "groups": [ + { + "description": "Group containing all defined coverage types as audits.", + "refs": [ + { + "slug": "function-coverage", + "weight": 6, + }, + { + "slug": "branch-coverage", + "weight": 3, + }, + { + "slug": "line-coverage", + "weight": 1, + }, + ], + "slug": "coverage", + "title": "Code coverage metrics", + }, + ], + "icon": "folder-coverage-open", + "packageName": "@code-pushup/coverage-plugin", + "slug": "coverage", + "title": "Code coverage", + }, + ], +} +`; diff --git a/e2e/plugin-coverage-e2e/tests/collect.e2e.test.ts b/e2e/plugin-coverage-e2e/tests/collect.e2e.test.ts new file mode 100644 index 000000000..673c56d63 --- /dev/null +++ b/e2e/plugin-coverage-e2e/tests/collect.e2e.test.ts @@ -0,0 +1,60 @@ +import { cp } from 'node:fs/promises'; +import { join } from 'node:path'; +import { afterAll, afterEach, beforeAll } from 'vitest'; +import { type Report, reportSchema } from '@code-pushup/models'; +import { teardownTestFolder } from '@code-pushup/test-setup'; +import { omitVariableReportData } from '@code-pushup/test-utils'; +import { executeProcess, readJsonFile } from '@code-pushup/utils'; + +describe('collect report with coverage-plugin NPM package', () => { + const envRoot = 'tmp/e2e/plugin-coverage-e2e'; + const fixtureDir = join('e2e', 'plugin-coverage-e2e', 'mocks', 'fixtures'); + const basicDir = join(envRoot, 'basic-setup'); + const existingDir = join(envRoot, 'existing-report'); + + beforeAll(async () => { + await cp(fixtureDir, envRoot, { recursive: true }); + }); + afterAll(async () => { + await teardownTestFolder(basicDir); + await teardownTestFolder(existingDir); + }); + afterEach(async () => { + await teardownTestFolder(join(basicDir, '.code-pushup')); + await teardownTestFolder(join(existingDir, '.code-pushup')); + }); + + it('should run Code coverage plugin which collects passed results and creates report.json', async () => { + const { code } = await executeProcess({ + command: 'npx', + args: ['@code-pushup/cli', 'collect', '--no-progress'], + cwd: basicDir, + }); + + expect(code).toBe(0); + + const report = await readJsonFile( + join(basicDir, '.code-pushup', 'report.json'), + ); + + expect(() => reportSchema.parse(report)).not.toThrow(); + expect(omitVariableReportData(report as Report)).toMatchSnapshot(); + }); + + it('should run Code coverage plugin that runs coverage tool and creates report.json', async () => { + const { code } = await executeProcess({ + command: 'npx', + args: ['@code-pushup/cli', 'collect', '--no-progress'], + cwd: existingDir, + }); + + expect(code).toBe(0); + + const report = await readJsonFile( + join(existingDir, '.code-pushup', 'report.json'), + ); + + expect(() => reportSchema.parse(report)).not.toThrow(); + expect(omitVariableReportData(report as Report)).toMatchSnapshot(); + }); +}); diff --git a/e2e/plugin-coverage-e2e/tsconfig.json b/e2e/plugin-coverage-e2e/tsconfig.json new file mode 100644 index 000000000..f5a2f890a --- /dev/null +++ b/e2e/plugin-coverage-e2e/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "module": "ESNext", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "types": ["vitest"] + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.test.json" + } + ] +} diff --git a/e2e/plugin-coverage-e2e/tsconfig.test.json b/e2e/plugin-coverage-e2e/tsconfig.test.json new file mode 100644 index 000000000..22ad6e52a --- /dev/null +++ b/e2e/plugin-coverage-e2e/tsconfig.test.json @@ -0,0 +1,15 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["vitest/globals", "vitest/importMeta", "vite/client", "node"], + "target": "ES2020" + }, + "exclude": [], + "include": [ + "vite.config.e2e.ts", + "tests/**/*.e2e.test.ts", + "tests/**/*.d.ts", + "mocks/**/*.ts" + ] +} diff --git a/e2e/plugin-coverage-e2e/vite.config.e2e.ts b/e2e/plugin-coverage-e2e/vite.config.e2e.ts new file mode 100644 index 000000000..3956da52e --- /dev/null +++ b/e2e/plugin-coverage-e2e/vite.config.e2e.ts @@ -0,0 +1,21 @@ +/// +import { defineConfig } from 'vite'; +import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases'; + +export default defineConfig({ + cacheDir: '../../node_modules/.vite/plugin-lighthouse-e2e', + test: { + reporters: ['basic'], + testTimeout: 120_000, + globals: true, + alias: tsconfigPathAliases(), + pool: 'threads', + poolOptions: { threads: { singleThread: true } }, + cache: { + dir: '../../node_modules/.vitest', + }, + environment: 'node', + include: ['tests/**/*.e2e.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + setupFiles: ['../../testing/test-setup/src/lib/reset.mocks.ts'], + }, +}); diff --git a/examples/react-todos-app/code-pushup.config.js b/examples/react-todos-app/code-pushup.config.js index dcef94a7f..988dca804 100644 --- a/examples/react-todos-app/code-pushup.config.js +++ b/examples/react-todos-app/code-pushup.config.js @@ -1,4 +1,3 @@ -import coveragePlugin from '../../dist/packages/plugin-coverage'; import eslintPlugin from '../../dist/packages/plugin-eslint'; const eslintAuditRef = (slug, weight) => ({ @@ -13,31 +12,12 @@ export default { outputDir: '../../tmp/e2e/react-todos-app', }, plugins: [ - await coveragePlugin({ - reports: ['../../coverage/react-todos-app/lcov.info'], - coverageToolCommand: { - command: 'npx', - args: ['vitest', 'run', '--coverage'], - }, - }), await eslintPlugin({ eslintrc: '.eslintrc.js', patterns: ['src/**/*.js', 'src/**/*.jsx'], }), ], categories: [ - { - slug: 'code-coverage', - title: 'Code coverage', - refs: [ - { - type: 'group', - plugin: 'coverage', - slug: 'coverage', - weight: 1, - }, - ], - }, { slug: 'bug-prevention', title: 'Bug prevention', @@ -60,7 +40,6 @@ export default { eslintAuditRef('react-hooks-exhaustive-deps', 2), ], }, - { slug: 'code-style', title: 'Code style', diff --git a/nx.json b/nx.json index bebd69d65..299156fe9 100644 --- a/nx.json +++ b/nx.json @@ -28,6 +28,10 @@ "e2e": { "dependsOn": ["^build"] }, + "nxv-e2e": {}, + "nxv-env-setup": { + "executor": "@push-based/nx-verdaccio:env-setup" + }, "@nx/vite:test": { "cache": true, "inputs": ["default", "^production"], @@ -68,23 +72,7 @@ "appsDir": "examples", "libsDir": "packages" }, - "generators": { - "@nx/react": { - "application": { - "style": "css", - "linter": "eslint", - "bundler": "vite", - "babel": true - }, - "component": { - "style": "css" - }, - "library": { - "style": "css", - "linter": "eslint" - } - } - }, + "generators": {}, "release": { "projects": ["packages/*"], "projectsRelationship": "fixed", diff --git a/package-lock.json b/package-lock.json index 80639ae4b..960950fda 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,7 +49,7 @@ "@nx/react": "17.3.2", "@nx/vite": "17.3.2", "@nx/workspace": "17.3.2", - "@push-based/nx-verdaccio": "0.0.0-alpha.25", + "@push-based/nx-verdaccio": "0.0.0-alpha.26", "@swc-node/register": "^1.10.9", "@swc/cli": "~0.1.62", "@swc/core": "^1.3.99", @@ -5457,9 +5457,9 @@ } }, "node_modules/@push-based/nx-verdaccio": { - "version": "0.0.0-alpha.25", - "resolved": "https://registry.npmjs.org/@push-based/nx-verdaccio/-/nx-verdaccio-0.0.0-alpha.25.tgz", - "integrity": "sha512-5keAr9Gpw0TjUEwtMZVu/qweBYPPHHxHRNaRJgw94uOGSwcQwFcYn92w3+Z4/VdXhM0/RINALGc+/DgG1PV5fg==", + "version": "0.0.0-alpha.26", + "resolved": "https://registry.npmjs.org/@push-based/nx-verdaccio/-/nx-verdaccio-0.0.0-alpha.26.tgz", + "integrity": "sha512-Go11Dg+w5Ntl5Ig8YNzVVPbpOG85aVszjyBIK0FvVBX+/QllQY1F4fP8K8fYnMJnO9v5Tao3cryGFY5Zo9i+/g==", "dev": true, "dependencies": { "@nx/devkit": "19.8.0", diff --git a/package.json b/package.json index da4f9fb46..354f89a4b 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "@nx/react": "17.3.2", "@nx/vite": "17.3.2", "@nx/workspace": "17.3.2", - "@push-based/nx-verdaccio": "0.0.0-alpha.25", + "@push-based/nx-verdaccio": "0.0.0-alpha.26", "@swc-node/register": "^1.10.9", "@swc/cli": "~0.1.62", "@swc/core": "^1.3.99",