From 51e054c6900555b48091e1f87e9f5d8ab69e5684 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 7 Feb 2024 23:06:24 +0100 Subject: [PATCH 01/75] refactor: replace table with new logger --- code-pushup.config.ts | 72 ----------- packages/cli/package.json | 3 +- .../cli/src/lib/autorun/autorun-command.ts | 3 +- .../cli/src/lib/collect/collect-command.ts | 3 +- .../cli/src/lib/implementation/logging.ts | 16 +-- .../lib/implementation/logging.unit.test.ts | 8 -- .../lib/print-config/print-config-command.ts | 2 +- .../print-config-command.unit.test.ts | 2 +- packages/cli/src/lib/upload/upload-command.ts | 3 +- .../src/lib/implementation/execute-plugin.ts | 4 +- .../core/src/lib/implementation/persist.ts | 5 +- packages/utils/package.json | 2 +- packages/utils/src/index.ts | 4 +- packages/utils/src/lib/file-system.ts | 9 +- packages/utils/src/lib/git.ts | 3 +- packages/utils/src/lib/log-results.ts | 20 +-- .../utils/src/lib/log-results.unit.test.ts | 47 ++++---- packages/utils/src/lib/logging.ts | 53 ++++++++ ...g-stdout-summary.integration.test.ts.snap} | 76 +++++------- ...enerate-stdout-summary.integration.test.ts | 29 ----- .../lib/reports/generate-stdout-summary.ts | 114 ------------------ .../log-stdout-summary.integration.test.ts | 36 ++++++ .../src/lib/reports/log-stdout-summary.ts | 107 ++++++++++++++++ packages/utils/src/lib/verbose-utils.ts | 6 +- .../utils/src/lib/verbose-utils.unit.test.ts | 17 +-- 25 files changed, 298 insertions(+), 346 deletions(-) delete mode 100644 packages/cli/src/lib/implementation/logging.unit.test.ts rename packages/utils/src/lib/reports/__snapshots__/{generate-stdout-summary.integration.test.ts.snap => log-stdout-summary.integration.test.ts.snap} (76%) delete mode 100644 packages/utils/src/lib/reports/generate-stdout-summary.integration.test.ts delete mode 100644 packages/utils/src/lib/reports/generate-stdout-summary.ts create mode 100644 packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts create mode 100644 packages/utils/src/lib/reports/log-stdout-summary.ts diff --git a/code-pushup.config.ts b/code-pushup.config.ts index d5c1ccdf5..5220a4309 100644 --- a/code-pushup.config.ts +++ b/code-pushup.config.ts @@ -48,35 +48,6 @@ const config: CoreConfig = { }), plugins: [ - await eslintPlugin(await eslintConfigFromNxProjects()), - coveragePlugin({ - reports: [ - { - resultsPath: 'coverage/cli/unit-tests/lcov.info', - pathToProject: 'packages/cli', - }, - { - resultsPath: 'coverage/core/unit-tests/lcov.info', - pathToProject: 'packages/core', - }, - { - resultsPath: 'coverage/models/unit-tests/lcov.info', - pathToProject: 'packages/models', - }, - { - resultsPath: 'coverage/utils/unit-tests/lcov.info', - pathToProject: 'packages/utils', - }, - { - resultsPath: 'coverage/plugin-eslint/unit-tests/lcov.info', - pathToProject: 'packages/plugin-eslint', - }, - { - resultsPath: 'coverage/plugin-coverage/unit-tests/lcov.info', - pathToProject: 'packages/plugin-coverage', - }, - ], - }), fileSizePlugin({ directory: './dist/examples/react-todos-app', pattern: /\.js$/, @@ -88,51 +59,9 @@ const config: CoreConfig = { license: 'MIT', type: 'module', }), - - await lighthousePlugin({ - url: 'https://staging.code-pushup.dev/login', - outputPath: join('.code-pushup', LIGHTHOUSE_OUTPUT_FILE_DEFAULT), - headless: true, - }), ], categories: [ - { - slug: 'bug-prevention', - title: 'Bug prevention', - refs: [{ type: 'group', plugin: 'eslint', slug: 'problems', weight: 1 }], - }, - { - slug: 'code-style', - title: 'Code style', - refs: [ - { type: 'group', plugin: 'eslint', slug: 'suggestions', weight: 1 }, - ], - }, - { - slug: 'code-coverage', - title: 'Code coverage', - refs: [ - { - type: 'audit', - plugin: 'coverage', - slug: 'function-coverage', - weight: 1, - }, - { - type: 'audit', - plugin: 'coverage', - slug: 'branch-coverage', - weight: 1, - }, - { - type: 'audit', - plugin: 'coverage', - slug: 'line-coverage', - weight: 1, - }, - ], - }, { slug: 'custom-checks', title: 'Custom checks', @@ -140,7 +69,6 @@ const config: CoreConfig = { ...fileSizeRecommendedRefs, packageJsonPerformanceGroupRef, packageJsonDocumentationGroupRef, - ...lighthouseCorePerfGroupRefs, ], }, ], diff --git a/packages/cli/package.json b/packages/cli/package.json index db6d338db..156398f14 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -10,7 +10,6 @@ "@code-pushup/core": "*", "yargs": "^17.7.2", "chalk": "^5.3.0", - "@code-pushup/utils": "*", - "@poppinss/cliui": "^6.3.0" + "@code-pushup/utils": "*" } } diff --git a/packages/cli/src/lib/autorun/autorun-command.ts b/packages/cli/src/lib/autorun/autorun-command.ts index 81980b0bc..fed7f30ea 100644 --- a/packages/cli/src/lib/autorun/autorun-command.ts +++ b/packages/cli/src/lib/autorun/autorun-command.ts @@ -6,13 +6,12 @@ import { collectAndPersistReports, upload, } from '@code-pushup/core'; -import { getLatestCommit, validateCommitData } from '@code-pushup/utils'; +import { getLatestCommit, ui, validateCommitData } from '@code-pushup/utils'; import { CLI_NAME } from '../constants'; import { collectSuccessfulLog, renderConfigureCategoriesHint, renderIntegratePortalHint, - ui, uploadSuccessfulLog, } from '../implementation/logging'; import { yargsOnlyPluginsOptionsDefinition } from '../implementation/only-plugins.options'; diff --git a/packages/cli/src/lib/collect/collect-command.ts b/packages/cli/src/lib/collect/collect-command.ts index dba2e6ad2..183bef35e 100644 --- a/packages/cli/src/lib/collect/collect-command.ts +++ b/packages/cli/src/lib/collect/collect-command.ts @@ -4,12 +4,11 @@ import { CollectAndPersistReportsOptions, collectAndPersistReports, } from '@code-pushup/core'; -import { link } from '@code-pushup/utils'; +import { link, ui } from '@code-pushup/utils'; import { CLI_NAME } from '../constants'; import { collectSuccessfulLog, renderConfigureCategoriesHint, - ui, } from '../implementation/logging'; import { yargsOnlyPluginsOptionsDefinition } from '../implementation/only-plugins.options'; diff --git a/packages/cli/src/lib/implementation/logging.ts b/packages/cli/src/lib/implementation/logging.ts index c4c0b78b3..bad6d35a7 100644 --- a/packages/cli/src/lib/implementation/logging.ts +++ b/packages/cli/src/lib/implementation/logging.ts @@ -1,18 +1,6 @@ -import { cliui } from '@poppinss/cliui'; import chalk from 'chalk'; import { UploadConfig } from '@code-pushup/models'; -import { link, portalCommitDashboardLink } from '@code-pushup/utils'; - -export type CliUi = ReturnType; - -// eslint-disable-next-line import/no-mutable-exports,functional/no-let -export let singletonUiInstance: CliUi | undefined; -export function ui(): CliUi { - if (singletonUiInstance === undefined) { - singletonUiInstance = cliui(); - } - return singletonUiInstance; -} +import { link, portalCommitDashboardLink, ui } from '@code-pushup/utils'; export function renderConfigureCategoriesHint(): void { ui().logger.info( @@ -23,6 +11,7 @@ export function renderConfigureCategoriesHint(): void { ), ); } + export function uploadSuccessfulLog( options: UploadConfig, commit: string, @@ -38,6 +27,7 @@ export function uploadSuccessfulLog( ), ); } + export function collectSuccessfulLog(): void { ui().logger.success('Collecting report successful!'); } diff --git a/packages/cli/src/lib/implementation/logging.unit.test.ts b/packages/cli/src/lib/implementation/logging.unit.test.ts deleted file mode 100644 index be09addfc..000000000 --- a/packages/cli/src/lib/implementation/logging.unit.test.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { expect } from 'vitest'; -import { ui } from './logging'; - -describe('ui', () => { - it('should return singleton', () => { - expect(ui()).toBe(ui()); - }); -}); diff --git a/packages/cli/src/lib/print-config/print-config-command.ts b/packages/cli/src/lib/print-config/print-config-command.ts index 4e32b4e56..31217a20c 100644 --- a/packages/cli/src/lib/print-config/print-config-command.ts +++ b/packages/cli/src/lib/print-config/print-config-command.ts @@ -1,6 +1,6 @@ import { CommandModule } from 'yargs'; +import { ui } from '@code-pushup/utils'; import { filterKebabCaseKeys } from '../implementation/global.utils'; -import { ui } from '../implementation/logging'; import { onlyPluginsOption } from '../implementation/only-plugins.options'; export function yargsConfigCommandObject() { diff --git a/packages/cli/src/lib/print-config/print-config-command.unit.test.ts b/packages/cli/src/lib/print-config/print-config-command.unit.test.ts index c74c9e3c3..542020317 100644 --- a/packages/cli/src/lib/print-config/print-config-command.unit.test.ts +++ b/packages/cli/src/lib/print-config/print-config-command.unit.test.ts @@ -1,6 +1,6 @@ import { beforeAll, describe, expect } from 'vitest'; import { DEFAULT_CLI_CONFIGURATION } from '../../../mocks/constants'; -import { ui } from '../implementation/logging'; +import { ui } from '@code-pushup/utils'; import { yargsCli } from '../yargs-cli'; import { yargsConfigCommandObject } from './print-config-command'; diff --git a/packages/cli/src/lib/upload/upload-command.ts b/packages/cli/src/lib/upload/upload-command.ts index 1a14719a8..3d73c3640 100644 --- a/packages/cli/src/lib/upload/upload-command.ts +++ b/packages/cli/src/lib/upload/upload-command.ts @@ -1,11 +1,10 @@ import chalk from 'chalk'; import { ArgumentsCamelCase, CommandModule } from 'yargs'; import { UploadOptions, upload } from '@code-pushup/core'; -import { getLatestCommit, validateCommitData } from '@code-pushup/utils'; +import { getLatestCommit, ui, validateCommitData } from '@code-pushup/utils'; import { CLI_NAME } from '../constants'; import { renderIntegratePortalHint, - ui, uploadSuccessfulLog, } from '../implementation/logging'; diff --git a/packages/core/src/lib/implementation/execute-plugin.ts b/packages/core/src/lib/implementation/execute-plugin.ts index 98e430fd0..985d4ed38 100644 --- a/packages/core/src/lib/implementation/execute-plugin.ts +++ b/packages/core/src/lib/implementation/execute-plugin.ts @@ -139,9 +139,7 @@ export async function executePlugins( progressBar?.endProgress('Done running plugins'); - const errorsCallback = ({ reason }: PromiseRejectedResult) => { - console.error(reason); - }; + const errorsCallback = ({ reason }: PromiseRejectedResult) => reason as string; const results = await Promise.allSettled(pluginsResult); logMultipleResults(results, 'Plugins', undefined, errorsCallback); diff --git a/packages/core/src/lib/implementation/persist.ts b/packages/core/src/lib/implementation/persist.ts index a7bea048e..6dd2ac3e2 100644 --- a/packages/core/src/lib/implementation/persist.ts +++ b/packages/core/src/lib/implementation/persist.ts @@ -5,9 +5,9 @@ import { MultipleFileResults, directoryExists, generateMdReport, - generateStdoutSummary, getLatestCommit, logMultipleFileResults, + logStdoutSummary, scoreReport, sortReport, validateCommitData, @@ -32,7 +32,8 @@ export async function persistReport( const { outputDir, filename, format } = options; const sortedScoredReport = sortReport(scoreReport(report)); - console.info(generateStdoutSummary(sortedScoredReport)); + // terminal output + logStdoutSummary(sortedScoredReport); // collect physical format outputs const results = await Promise.all( diff --git a/packages/utils/package.json b/packages/utils/package.json index 80436cc6a..9be3b9346 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -8,6 +8,6 @@ "@isaacs/cliui": "^8.0.2", "simple-git": "^3.20.0", "multi-progress-bars": "^5.0.3", - "cli-table3": "^0.6.3" + "@poppinss/cliui": "^6.3.0" } } diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 932cde2d4..f223edb21 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -42,7 +42,7 @@ export { logMultipleResults } from './lib/log-results'; export { ProgressBar, getProgressBar } from './lib/progress'; export { TERMINAL_WIDTH } from './lib/reports/constants'; export { generateMdReport } from './lib/reports/generate-md-report'; -export { generateStdoutSummary } from './lib/reports/generate-stdout-summary'; +export { logStdoutSummary } from './lib/reports/log-stdout-summary'; export { ScoredReport, scoreReport } from './lib/reports/scoring'; export { sortReport } from './lib/reports/sorting'; export { @@ -70,7 +70,7 @@ export { toUnixPath, } from './lib/transform'; export { verboseUtils } from './lib/verbose-utils'; -export { link } from './lib/logging'; +export { link, ui, Column } from './lib/logging'; export { filterAuditsBySlug, filterGroupsByAuditSlug, diff --git a/packages/utils/src/lib/file-system.ts b/packages/utils/src/lib/file-system.ts index 3df771856..e2523d769 100644 --- a/packages/utils/src/lib/file-system.ts +++ b/packages/utils/src/lib/file-system.ts @@ -4,6 +4,7 @@ import { mkdir, readFile, readdir, stat } from 'node:fs/promises'; import { join } from 'node:path'; import { formatBytes } from './formatting'; import { logMultipleResults } from './log-results'; +import {ui} from "./logging"; export async function readTextFile(path: string): Promise { const buffer = await readFile(path); @@ -38,7 +39,7 @@ export async function ensureDirectoryExists(baseDir: string) { await mkdir(baseDir, { recursive: true }); return; } catch (error) { - console.error((error as { code: string; message: string }).message); + ui().logger.error((error as { code: string; message: string }).message); if ((error as { code: string }).code !== 'EEXIST') { throw error; } @@ -55,11 +56,9 @@ export function logMultipleFileResults( const succeededCallback = (result: PromiseFulfilledResult) => { const [fileName, size] = result.value; const formattedSize = size ? ` (${chalk.gray(formatBytes(size))})` : ''; - console.info(`- ${chalk.bold(fileName)}${formattedSize}`); - }; - const failedCallback = (result: PromiseRejectedResult) => { - console.warn(`- ${chalk.bold(result.reason)}`); + return `- ${chalk.bold(fileName)}${formattedSize}`; }; + const failedCallback = (result: PromiseRejectedResult) => `- ${chalk.bold(result.reason)}`; logMultipleResults( fileResults, diff --git a/packages/utils/src/lib/git.ts b/packages/utils/src/lib/git.ts index e0fcb9527..fab6b393d 100644 --- a/packages/utils/src/lib/git.ts +++ b/packages/utils/src/lib/git.ts @@ -1,4 +1,5 @@ import { simpleGit } from 'simple-git'; +import { ui } from './logging'; export type CommitData = { hash: string; @@ -28,7 +29,7 @@ export function validateCommitData( if (throwError) { throw new Error(msg); } else { - console.warn(msg); + ui().logger.warning(msg); return false; } } diff --git a/packages/utils/src/lib/log-results.ts b/packages/utils/src/lib/log-results.ts index 2d2466ba0..9f0fd1fec 100644 --- a/packages/utils/src/lib/log-results.ts +++ b/packages/utils/src/lib/log-results.ts @@ -1,10 +1,11 @@ import { isPromiseFulfilledResult, isPromiseRejectedResult } from './guards'; +import {ui} from "./logging"; export function logMultipleResults( results: PromiseSettledResult[], messagePrefix: string, - succeededCallback?: (result: PromiseFulfilledResult) => void, - failedCallback?: (result: PromiseRejectedResult) => void, + succeededCallback?: (result: PromiseFulfilledResult) => string, + failedCallback?: (result: PromiseRejectedResult) => string, ) { if (succeededCallback) { const succeededResults = results.filter(isPromiseFulfilledResult); @@ -29,14 +30,17 @@ export function logMultipleResults( export function logPromiseResults< T extends PromiseFulfilledResult | PromiseRejectedResult, ->(results: T[], logMessage: string, callback: (result: T) => void): void { +>(results: T[], logMessage: string, getMsg: (result: T) => string): void { if (results.length > 0) { - if (results[0]?.status === 'fulfilled') { - console.info(logMessage); - } else { - console.warn(logMessage); + const log = results[0]?.status === 'fulfilled' ? (m: string) => { + ui().logger.info(m) + } : (m: string) => { + ui().logger.warning(m); } - results.forEach(callback); + log(logMessage); + results.forEach((result) => { + log(getMsg(result)) + }); } } diff --git a/packages/utils/src/lib/log-results.unit.test.ts b/packages/utils/src/lib/log-results.unit.test.ts index 407d6b9d8..4c29e42ea 100644 --- a/packages/utils/src/lib/log-results.unit.test.ts +++ b/packages/utils/src/lib/log-results.unit.test.ts @@ -1,6 +1,7 @@ -import { describe, expect, it, vi } from 'vitest'; -import { FileResult } from './file-system'; -import { logMultipleResults, logPromiseResults } from './log-results'; +import {afterEach, describe, expect, it, vi} from 'vitest'; +import {FileResult} from './file-system'; +import {logMultipleResults, logPromiseResults} from './log-results'; +import {ui} from "./logging"; describe('logMultipleResults', () => { const succeededCallbackMock = vi.fn(); @@ -25,7 +26,7 @@ describe('logMultipleResults', () => { it('should call logPromiseResults with failed plugin result', () => { logMultipleResults( - [{ status: 'rejected', reason: 'fail' } as PromiseRejectedResult], + [{status: 'rejected', reason: 'fail'} as PromiseRejectedResult], 'Generated reports', succeededCallbackMock, failedCallbackMock, @@ -42,7 +43,7 @@ describe('logMultipleResults', () => { status: 'fulfilled', value: ['out.json', 10_000], } as PromiseFulfilledResult, - { status: 'rejected', reason: 'fail' } as PromiseRejectedResult, + {status: 'rejected', reason: 'fail'} as PromiseRejectedResult, ], 'Generated reports', succeededCallbackMock, @@ -55,6 +56,14 @@ describe('logMultipleResults', () => { }); describe('logPromiseResults', () => { + beforeAll(() => { + ui().switchMode('raw'); + }); + + afterEach(() => { + ui().flushLogs(); + }); + it('should log on success', () => { logPromiseResults( [ @@ -64,31 +73,21 @@ describe('logPromiseResults', () => { } as PromiseFulfilledResult, ], 'Uploaded reports successfully:', - result => { - console.info(result.value); - }, - ); - - expect(console.info).toHaveBeenNthCalledWith( - 1, - 'Uploaded reports successfully:', + (result): string => result.value.toString() ); - expect(console.info).toHaveBeenNthCalledWith(2, ['out.json']); + const logs = ui().logger.getRenderer().getLogs().map(({message}) => message); + expect(logs[0]).toBe('[ blue(info) ] Uploaded reports successfully:'); + expect(logs[1]).toBe('[ blue(info) ] out.json'); }); it('should log on fail', () => { logPromiseResults( - [{ status: 'rejected', reason: 'fail' } as PromiseRejectedResult], - 'Generated reports failed:', - result => { - console.warn(result.reason); - }, - ); - - expect(console.warn).toHaveBeenNthCalledWith( - 1, + [{status: 'rejected', reason: 'fail'} as PromiseRejectedResult], 'Generated reports failed:', + (result: {reason: string}) => result.reason.toString() ); - expect(console.warn).toHaveBeenNthCalledWith(2, 'fail'); + const logs = ui().logger.getRenderer().getLogs().map(({message}) => message); + expect(logs[0]).toBe('[ yellow(warn) ] Generated reports failed:'); + expect(logs[1]).toBe('[ yellow(warn) ] fail'); }); }); diff --git a/packages/utils/src/lib/logging.ts b/packages/utils/src/lib/logging.ts index 8b97fd0ae..6bead0cf5 100644 --- a/packages/utils/src/lib/logging.ts +++ b/packages/utils/src/lib/logging.ts @@ -1,4 +1,57 @@ +import isaacs_cliui from '@isaacs/cliui'; +import { cliui } from '@poppinss/cliui'; import chalk from 'chalk'; +import { TERMINAL_WIDTH } from './reports/constants'; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type ArgumentsType = T extends (...args: infer U) => any ? U : never; +export type CliUiBase = ReturnType; +type UI = ReturnType; +type CliExtension = { + row: (r: ArgumentsType) => void, + flushLogs: () => void; +}; +export type Column = { + text: string; + width?: number; + align?: 'right' | 'left' | 'center'; + padding: number[]; + border?: boolean; +} +export type CliUi = CliUiBase & CliExtension; + +// eslint-disable-next-line import/no-mutable-exports,functional/no-let +export let singletonUiInstance: CliUiBase | undefined; + +export function ui(): CliUi { + if (singletonUiInstance === undefined) { + singletonUiInstance = cliui(); + } + return { + ...singletonUiInstance, + flushLogs: () => { + const logs = singletonUiInstance?.logger.getRenderer().getLogs(); + // mutate internal array as there is no public API to reset the internal logs array. + // if we don't do it we carry items from across tests + // eslint-disable-next-line functional/immutable-data + logs?.splice(0, logs.length); + }, + row: args => { logListItem(args); } + }; +} + +// eslint-disable-next-line functional/no-let +let singletonisaacUi: UI | undefined; +export function logListItem(args: ArgumentsType) { + if (singletonisaacUi === undefined) { + singletonisaacUi = isaacs_cliui({ width: TERMINAL_WIDTH }); + } + singletonisaacUi.div(...args); + const content = singletonisaacUi.toString(); + // eslint-disable-next-line functional/immutable-data + singletonisaacUi.rows = []; + singletonUiInstance?.logger.log(content); +} export function link(text: string) { return chalk.underline(chalk.blueBright(text)); diff --git a/packages/utils/src/lib/reports/__snapshots__/generate-stdout-summary.integration.test.ts.snap b/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap similarity index 76% rename from packages/utils/src/lib/reports/__snapshots__/generate-stdout-summary.integration.test.ts.snap rename to packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap index 24950fb48..1058c1055 100644 --- a/packages/utils/src/lib/reports/__snapshots__/generate-stdout-summary.integration.test.ts.snap +++ b/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap @@ -7,17 +7,17 @@ exports[`generateStdoutSummary > should contain all sections when using the fixt ESLint audits ● Disallow missing props validation in a React component definition 6 warnings -● Disallow variable declarations from shadowing variables declared 3 warnings - in the outer scope -● Require or disallow method and property shorthand syntax for 3 warnings - object literals +● Disallow variable declarations from shadowing variables declared in 3 warnings +the outer scope +● Require or disallow method and property shorthand syntax for object 3 warnings +literals ● verifies the list of dependencies for Hooks like useEffect and 2 warnings - similar +similar ● Disallow missing \`key\` props in iterators/collection literals 1 warning ● Disallow unused variables 1 warning ● Enforce a maximum number of lines of code in a function 1 warning -● Require \`const\` declarations for variables that are never 1 warning - reassigned after declared +● Require \`const\` declarations for variables that are never reassigned1 warning +after declared ● Require braces around arrow function bodies 1 warning ● Require the use of \`===\` and \`!==\` 1 warning ● Disallow \`target=\\"_blank\\"\` attribute without \`rel=\\"noreferrer\\"\` passed @@ -25,8 +25,7 @@ ESLint audits ● Disallow comments from being inserted as text nodes passed ● Disallow direct mutation of this.state passed ● Disallow duplicate properties in JSX passed -● Disallow invalid regular expression strings in \`RegExp\` passed - constructors +● Disallow invalid regular expression strings in \`RegExp\` constructorspassed ● Disallow loops with a body that allows only one iteration passed ● Disallow missing displayName in a React component definition passed ● Disallow missing React when using JSX passed @@ -36,7 +35,7 @@ ESLint audits ● Disallow reassigning \`const\` variables passed ● Disallow the use of \`debugger\` passed ● Disallow the use of undeclared variables unless mentioned in passed - \`/*global */\` comments +\`/*global */\` comments ● Disallow undeclared variables in JSX passed ● Disallow unescaped HTML entities from appearing in markup passed ● Disallow usage of deprecated methods passed @@ -44,14 +43,14 @@ ESLint audits ● Disallow usage of isMounted passed ● Disallow usage of the return value of ReactDOM.render passed ● Disallow usage of unknown DOM property passed -● Disallow use of optional chaining in contexts where the passed - \`undefined\` value is not allowed +● Disallow use of optional chaining in contexts where the \`undefined\` passed +value is not allowed ● Disallow using Object.assign with an object literal as the first passed - argument and prefer the use of object spread instead +argument and prefer the use of object spread instead ● Disallow using string references passed ● Disallow variables used in JSX to be incorrectly marked as unused passed ● Disallow when a DOM element is using both children and passed - dangerouslySetInnerHTML +dangerouslySetInnerHTML ● Enforce a maximum number of lines per file passed ● Enforce camelcase naming convention passed ● Enforce comparing \`typeof\` expressions against valid strings passed @@ -72,21 +71,13 @@ Lighthouse audits ● Cumulative Layout Shift 0 ● Total Blocking Time 0 ms - Categories -┌─────────────────────────────────────────────────────────────┬───────┬────────┐ -│ Category │ Score │ Audits │ -├─────────────────────────────────────────────────────────────┼───────┼────────┤ -│ Performance │ 92 │ 6 │ -├─────────────────────────────────────────────────────────────┼───────┼────────┤ -│ Bug prevention │ 68 │ 16 │ -├─────────────────────────────────────────────────────────────┼───────┼────────┤ -│ Code style │ 54 │ 13 │ -└─────────────────────────────────────────────────────────────┴───────┴────────┘ - -Made with ❤ by code-pushup.dev -" +Category|Score|Audits +Performance|92|6 +Bug prevention|68|16 +Code style|54|13 +Made with ❤ by code-pushup.dev" `; exports[`generateStdoutSummary > should not contain category section when categories are empty 1`] = ` @@ -96,17 +87,17 @@ exports[`generateStdoutSummary > should not contain category section when catego ESLint audits ● Disallow missing props validation in a React component definition 6 warnings -● Disallow variable declarations from shadowing variables declared 3 warnings - in the outer scope -● Require or disallow method and property shorthand syntax for 3 warnings - object literals +● Disallow variable declarations from shadowing variables declared in 3 warnings +the outer scope +● Require or disallow method and property shorthand syntax for object 3 warnings +literals ● verifies the list of dependencies for Hooks like useEffect and 2 warnings - similar +similar ● Disallow missing \`key\` props in iterators/collection literals 1 warning ● Disallow unused variables 1 warning ● Enforce a maximum number of lines of code in a function 1 warning -● Require \`const\` declarations for variables that are never 1 warning - reassigned after declared +● Require \`const\` declarations for variables that are never reassigned1 warning +after declared ● Require braces around arrow function bodies 1 warning ● Require the use of \`===\` and \`!==\` 1 warning ● Disallow \`target=\\"_blank\\"\` attribute without \`rel=\\"noreferrer\\"\` passed @@ -114,8 +105,7 @@ ESLint audits ● Disallow comments from being inserted as text nodes passed ● Disallow direct mutation of this.state passed ● Disallow duplicate properties in JSX passed -● Disallow invalid regular expression strings in \`RegExp\` passed - constructors +● Disallow invalid regular expression strings in \`RegExp\` constructorspassed ● Disallow loops with a body that allows only one iteration passed ● Disallow missing displayName in a React component definition passed ● Disallow missing React when using JSX passed @@ -125,7 +115,7 @@ ESLint audits ● Disallow reassigning \`const\` variables passed ● Disallow the use of \`debugger\` passed ● Disallow the use of undeclared variables unless mentioned in passed - \`/*global */\` comments +\`/*global */\` comments ● Disallow undeclared variables in JSX passed ● Disallow unescaped HTML entities from appearing in markup passed ● Disallow usage of deprecated methods passed @@ -133,14 +123,14 @@ ESLint audits ● Disallow usage of isMounted passed ● Disallow usage of the return value of ReactDOM.render passed ● Disallow usage of unknown DOM property passed -● Disallow use of optional chaining in contexts where the passed - \`undefined\` value is not allowed +● Disallow use of optional chaining in contexts where the \`undefined\` passed +value is not allowed ● Disallow using Object.assign with an object literal as the first passed - argument and prefer the use of object spread instead +argument and prefer the use of object spread instead ● Disallow using string references passed ● Disallow variables used in JSX to be incorrectly marked as unused passed ● Disallow when a DOM element is using both children and passed - dangerouslySetInnerHTML +dangerouslySetInnerHTML ● Enforce a maximum number of lines per file passed ● Enforce camelcase naming convention passed ● Enforce comparing \`typeof\` expressions against valid strings passed @@ -161,7 +151,5 @@ Lighthouse audits ● Cumulative Layout Shift 0 ● Total Blocking Time 0 ms - -Made with ❤ by code-pushup.dev -" +Made with ❤ by code-pushup.dev" `; diff --git a/packages/utils/src/lib/reports/generate-stdout-summary.integration.test.ts b/packages/utils/src/lib/reports/generate-stdout-summary.integration.test.ts deleted file mode 100644 index 2989bc2a3..000000000 --- a/packages/utils/src/lib/reports/generate-stdout-summary.integration.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { describe } from 'vitest'; -import { reportMock } from '@code-pushup/testing-utils'; -import { generateStdoutSummary } from './generate-stdout-summary'; -import { scoreReport } from './scoring'; -import { sortReport } from './sorting'; - -describe('generateStdoutSummary', () => { - it('should contain all sections when using the fixture report', () => { - const logOutput = generateStdoutSummary( - sortReport(scoreReport(reportMock())), - ); - - expect(logOutput).toContain('Categories'); - // removes all color codes from the output for snapshot readability - // eslint-disable-next-line no-control-regex - expect(logOutput.replace(/\u001B\[\d+m/g, '')).toMatchSnapshot(); - }); - - it('should not contain category section when categories are empty', () => { - const logOutput = generateStdoutSummary( - sortReport(scoreReport({ ...reportMock(), categories: [] })), - ); - - expect(logOutput).not.toContain('Categories'); - // removes all color codes from the output for snapshot readability - // eslint-disable-next-line no-control-regex - expect(logOutput.replace(/\u001B\[\d+m/g, '')).toMatchSnapshot(); - }); -}); diff --git a/packages/utils/src/lib/reports/generate-stdout-summary.ts b/packages/utils/src/lib/reports/generate-stdout-summary.ts deleted file mode 100644 index 04af59a01..000000000 --- a/packages/utils/src/lib/reports/generate-stdout-summary.ts +++ /dev/null @@ -1,114 +0,0 @@ -import cliui from '@isaacs/cliui'; -import chalk from 'chalk'; -import CliTable3 from 'cli-table3'; -import { NEW_LINE, SCORE_COLOR_RANGE, TERMINAL_WIDTH } from './constants'; -import { ScoredReport } from './scoring'; -import { - CODE_PUSHUP_DOMAIN, - FOOTER_PREFIX, - countCategoryAudits, - formatReportScore, - reportHeadlineText, - reportRawOverviewTableHeaders, -} from './utils'; - -function addLine(line = ''): string { - return line + NEW_LINE; -} - -export function generateStdoutSummary(report: ScoredReport): string { - const printCategories = report.categories.length > 0; - return ( - addLine(reportToHeaderSection(report)) + - addLine() + - addLine(reportToDetailSection(report)) + - (printCategories ? addLine(reportToOverviewSection(report)) : '') + - addLine(`${FOOTER_PREFIX} ${CODE_PUSHUP_DOMAIN}`) - ); -} - -function reportToHeaderSection(report: ScoredReport): string { - const { packageName, version } = report; - return `${chalk.bold(reportHeadlineText)} - ${packageName}@${version}`; -} - -function reportToDetailSection(report: ScoredReport): string { - const { plugins } = report; - - return plugins.reduce((acc, plugin) => { - const { title, audits } = plugin; - const ui = cliui({ width: TERMINAL_WIDTH }); - - audits.forEach(audit => { - ui.div( - { - text: withColor({ score: audit.score, text: '●' }), - width: 2, - padding: [0, 1, 0, 0], - }, - { - text: audit.title, - // eslint-disable-next-line no-magic-numbers - padding: [0, 3, 0, 0], - }, - { - text: chalk.cyanBright(audit.displayValue || `${audit.value}`), - width: 10, - padding: [0, 0, 0, 0], - }, - ); - }); - return ( - acc + - addLine() + - addLine(chalk.magentaBright.bold(`${title} audits`)) + - addLine() + - addLine(ui.toString()) + - addLine() - ); - }, ''); -} - -function reportToOverviewSection({ - categories, - plugins, -}: ScoredReport): string { - const table = new CliTable3({ - // eslint-disable-next-line no-magic-numbers - colWidths: [TERMINAL_WIDTH - 7 - 8 - 4, 7, 8], - head: reportRawOverviewTableHeaders, - colAligns: ['left', 'right', 'right'], - style: { - head: ['cyan'], - }, - }); - - table.push( - ...categories.map(({ title, score, refs }) => [ - title, - withColor({ score }), - countCategoryAudits(refs, plugins), - ]), - ); - - return ( - addLine(chalk.magentaBright.bold('Categories')) + - addLine() + - addLine(table.toString()) - ); -} - -function withColor({ score, text }: { score: number; text?: string }) { - const formattedScore = text ?? formatReportScore(score); - const style = text ? chalk : chalk.bold; - - if (score >= SCORE_COLOR_RANGE.GREEN_MIN) { - return style.green(formattedScore); - } - - if (score >= SCORE_COLOR_RANGE.YELLOW_MIN) { - return style.yellow(formattedScore); - } - - return style.red(formattedScore); -} diff --git a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts new file mode 100644 index 000000000..10bebdd83 --- /dev/null +++ b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts @@ -0,0 +1,36 @@ +import {beforeAll, beforeEach, describe} from 'vitest'; +import { reportMock } from '@code-pushup/testing-utils'; +import { logStdoutSummary } from './log-stdout-summary'; +import { scoreReport } from './scoring'; +import { sortReport } from './sorting'; +import {ui} from "../logging"; + +describe('generateStdoutSummary', () => { + beforeAll(() => { + ui().switchMode('raw'); + }) + beforeEach(() => { + ui().flushLogs(); + }) + it('should contain all sections when using the fixture report', () => { + logStdoutSummary(sortReport(scoreReport(reportMock()))); + const output = ui().logger.getRenderer().getLogs().map(({message}) => message).join('\n'); + + expect(output).toContain('Categories'); + // removes all color codes from the output for snapshot readability + // eslint-disable-next-line no-control-regex + expect(output.replace(/\u001B\[\d+m/g, '')).toMatchSnapshot(); + }); + + it('should not contain category section when categories are empty', () => { + logStdoutSummary( + sortReport(scoreReport({ ...reportMock(), categories: [] })), + ); + const output = ui().logger.getRenderer().getLogs().map(({message}) => message).join('\n'); + + expect(output).not.toContain('Categories'); + // removes all color codes from the output for snapshot readability + // eslint-disable-next-line no-control-regex + expect(output.replace(/\u001B\[\d+m/g, '')).toMatchSnapshot(); + }); +}); diff --git a/packages/utils/src/lib/reports/log-stdout-summary.ts b/packages/utils/src/lib/reports/log-stdout-summary.ts new file mode 100644 index 000000000..3beaff485 --- /dev/null +++ b/packages/utils/src/lib/reports/log-stdout-summary.ts @@ -0,0 +1,107 @@ +import chalk from 'chalk'; +import { AuditReport } from '@code-pushup/models'; +import { ui } from '../logging'; +import { SCORE_COLOR_RANGE, TERMINAL_WIDTH } from './constants'; +import { ScoredReport } from './scoring'; +import { + CODE_PUSHUP_DOMAIN, + FOOTER_PREFIX, + countCategoryAudits, + formatReportScore, + reportHeadlineText, + reportRawOverviewTableHeaders, +} from './utils'; + +function log(msg = ''): void { + ui().logger.log(msg); +} + +export function logStdoutSummary(report: ScoredReport): void { + const printCategories = report.categories.length > 0; + + log(reportToHeaderSection(report)); + log(); + logPlugins(report); + if(printCategories) { + logCategories(report); + } + log(`${FOOTER_PREFIX} ${CODE_PUSHUP_DOMAIN}`); +} + +function reportToHeaderSection(report: ScoredReport): string { + const { packageName, version } = report; + return `${chalk.bold(reportHeadlineText)} - ${packageName}@${version}`; +} + +function logPlugins(report: ScoredReport): void { + const { plugins } = report; + + plugins.forEach(plugin => { + const { title, audits } = plugin; + log(); + log(chalk.magentaBright.bold(`${title} audits`)); + log(); + audits.forEach((audit: AuditReport) => { + const padding = [0, 0, 0, 0]; + ui().row([ + { + text: `${applyScoreColor({ score: audit.score, text: '●' })} ${ + audit.title + }`, + padding, + }, + { + text: chalk.cyanBright(audit.displayValue || `${audit.value}`), + width: 10, + padding, + }, + ]); + }); + log(); + }); +} + +function logCategories({ categories, plugins }: ScoredReport): void { + const hAlign = (idx: number) => (idx === 0 ? 'left' : 'right'); + const rows = categories.map(({ title, score, refs }) => [ + title, + applyScoreColor({ score }), + countCategoryAudits(refs, plugins), + ]); + const table = ui().table(); + // eslint-disable-next-line no-magic-numbers + table.columnWidths([TERMINAL_WIDTH - 7 - 8 - 8, 9, 10]); + table.head( + reportRawOverviewTableHeaders.map((heading, idx) => ({ + content: chalk.cyan(heading), + hAlign: hAlign(idx), + })), + ); + rows.forEach(row => + table.row( + row.map((content, idx) => ({ + content: content.toString(), + hAlign: hAlign(idx), + })), + ), + ); + + log(chalk.magentaBright.bold('Categories')); + log(); + table.render(); +} + +function applyScoreColor({ score, text }: { score: number; text?: string }) { + const formattedScore = text ?? formatReportScore(score); + const style = text ? chalk : chalk.bold; + + if (score >= SCORE_COLOR_RANGE.GREEN_MIN) { + return style.green(formattedScore); + } + + if (score >= SCORE_COLOR_RANGE.YELLOW_MIN) { + return style.yellow(formattedScore); + } + + return style.red(formattedScore); +} diff --git a/packages/utils/src/lib/verbose-utils.ts b/packages/utils/src/lib/verbose-utils.ts index e3055fef5..a0b42fbc3 100644 --- a/packages/utils/src/lib/verbose-utils.ts +++ b/packages/utils/src/lib/verbose-utils.ts @@ -1,7 +1,9 @@ +import { ui } from './logging'; + function getLogVerbose(verbose = false) { - return (...args: unknown[]) => { + return (msg: string) => { if (verbose) { - console.info(...args); + ui().logger.info(msg); } }; } diff --git a/packages/utils/src/lib/verbose-utils.unit.test.ts b/packages/utils/src/lib/verbose-utils.unit.test.ts index 6c74b1dad..523007e88 100644 --- a/packages/utils/src/lib/verbose-utils.unit.test.ts +++ b/packages/utils/src/lib/verbose-utils.unit.test.ts @@ -1,40 +1,41 @@ -import { describe, expect, it } from 'vitest'; -import { verboseUtils } from './verbose-utils'; +import {beforeAll, describe, expect, it} from 'vitest'; +import {ui} from './logging'; +import {verboseUtils} from './verbose-utils'; describe('verbose-utils', () => { + beforeAll(() => { + ui().switchMode('raw'); + }); it('exec should be off by default', () => { const spy = vi.fn(); verboseUtils().exec(spy); expect(spy).not.toHaveBeenCalled(); - expect(console.info).not.toHaveBeenCalled(); }); it('exec should work no-verbose', () => { const spy = vi.fn(); verboseUtils(false).exec(spy); expect(spy).not.toHaveBeenCalled(); - expect(console.info).not.toHaveBeenCalled(); }); it('exec should work verbose', () => { const spy = vi.fn(); verboseUtils(true).exec(spy); expect(spy).toHaveBeenCalled(); - expect(console.info).not.toHaveBeenCalled(); }); it('logs should be off by default', () => { verboseUtils(false).log('42'); - expect(console.info).not.toHaveBeenCalled(); + expect(ui().logger.getRenderer().getLogs()).toHaveLength(0); }); it('log should work no-verbose', () => { verboseUtils(false).log('42'); - expect(console.info).not.toHaveBeenCalled(); + expect(ui().logger.getRenderer().getLogs()).toHaveLength(0); }); it('log should work verbose', () => { verboseUtils(true).log('42'); - expect(console.info).toHaveBeenCalledWith('42'); + expect(ui().logger.getRenderer().getLogs()[0]?.message).toContain('42'); }); }); From 0f948ee8c9a48320e81edb8a5edbf779e024b804 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 8 Feb 2024 00:23:28 +0100 Subject: [PATCH 02/75] wip --- code-pushup.config.ts | 72 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/code-pushup.config.ts b/code-pushup.config.ts index 5220a4309..d5c1ccdf5 100644 --- a/code-pushup.config.ts +++ b/code-pushup.config.ts @@ -48,6 +48,35 @@ const config: CoreConfig = { }), plugins: [ + await eslintPlugin(await eslintConfigFromNxProjects()), + coveragePlugin({ + reports: [ + { + resultsPath: 'coverage/cli/unit-tests/lcov.info', + pathToProject: 'packages/cli', + }, + { + resultsPath: 'coverage/core/unit-tests/lcov.info', + pathToProject: 'packages/core', + }, + { + resultsPath: 'coverage/models/unit-tests/lcov.info', + pathToProject: 'packages/models', + }, + { + resultsPath: 'coverage/utils/unit-tests/lcov.info', + pathToProject: 'packages/utils', + }, + { + resultsPath: 'coverage/plugin-eslint/unit-tests/lcov.info', + pathToProject: 'packages/plugin-eslint', + }, + { + resultsPath: 'coverage/plugin-coverage/unit-tests/lcov.info', + pathToProject: 'packages/plugin-coverage', + }, + ], + }), fileSizePlugin({ directory: './dist/examples/react-todos-app', pattern: /\.js$/, @@ -59,9 +88,51 @@ const config: CoreConfig = { license: 'MIT', type: 'module', }), + + await lighthousePlugin({ + url: 'https://staging.code-pushup.dev/login', + outputPath: join('.code-pushup', LIGHTHOUSE_OUTPUT_FILE_DEFAULT), + headless: true, + }), ], categories: [ + { + slug: 'bug-prevention', + title: 'Bug prevention', + refs: [{ type: 'group', plugin: 'eslint', slug: 'problems', weight: 1 }], + }, + { + slug: 'code-style', + title: 'Code style', + refs: [ + { type: 'group', plugin: 'eslint', slug: 'suggestions', weight: 1 }, + ], + }, + { + slug: 'code-coverage', + title: 'Code coverage', + refs: [ + { + type: 'audit', + plugin: 'coverage', + slug: 'function-coverage', + weight: 1, + }, + { + type: 'audit', + plugin: 'coverage', + slug: 'branch-coverage', + weight: 1, + }, + { + type: 'audit', + plugin: 'coverage', + slug: 'line-coverage', + weight: 1, + }, + ], + }, { slug: 'custom-checks', title: 'Custom checks', @@ -69,6 +140,7 @@ const config: CoreConfig = { ...fileSizeRecommendedRefs, packageJsonPerformanceGroupRef, packageJsonDocumentationGroupRef, + ...lighthouseCorePerfGroupRefs, ], }, ], From d0114742e82979eb1fd001fc973b9d08a4e5fd66 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 8 Feb 2024 01:01:59 +0100 Subject: [PATCH 03/75] refactor(core): use new logger --- .../print-config-command.unit.test.ts | 2 +- .../src/lib/implementation/execute-plugin.ts | 3 +- .../execute-plugin.unit.test.ts | 18 +++- .../lib/implementation/persist.unit.test.ts | 97 ++++++++++--------- packages/utils/src/lib/file-system.ts | 5 +- packages/utils/src/lib/log-results.ts | 19 ++-- .../utils/src/lib/log-results.unit.test.ts | 28 +++--- packages/utils/src/lib/logging.ts | 8 +- .../log-stdout-summary.integration.test.ts | 22 +++-- .../src/lib/reports/log-stdout-summary.ts | 2 +- .../utils/src/lib/verbose-utils.unit.test.ts | 6 +- 11 files changed, 122 insertions(+), 88 deletions(-) diff --git a/packages/cli/src/lib/print-config/print-config-command.unit.test.ts b/packages/cli/src/lib/print-config/print-config-command.unit.test.ts index 542020317..cda5fd4dd 100644 --- a/packages/cli/src/lib/print-config/print-config-command.unit.test.ts +++ b/packages/cli/src/lib/print-config/print-config-command.unit.test.ts @@ -1,6 +1,6 @@ import { beforeAll, describe, expect } from 'vitest'; -import { DEFAULT_CLI_CONFIGURATION } from '../../../mocks/constants'; import { ui } from '@code-pushup/utils'; +import { DEFAULT_CLI_CONFIGURATION } from '../../../mocks/constants'; import { yargsCli } from '../yargs-cli'; import { yargsConfigCommandObject } from './print-config-command'; diff --git a/packages/core/src/lib/implementation/execute-plugin.ts b/packages/core/src/lib/implementation/execute-plugin.ts index 985d4ed38..8f1f86008 100644 --- a/packages/core/src/lib/implementation/execute-plugin.ts +++ b/packages/core/src/lib/implementation/execute-plugin.ts @@ -139,7 +139,8 @@ export async function executePlugins( progressBar?.endProgress('Done running plugins'); - const errorsCallback = ({ reason }: PromiseRejectedResult) => reason as string; + const errorsCallback = ({ reason }: PromiseRejectedResult) => + reason as string; const results = await Promise.allSettled(pluginsResult); logMultipleResults(results, 'Plugins', undefined, errorsCallback); diff --git a/packages/core/src/lib/implementation/execute-plugin.unit.test.ts b/packages/core/src/lib/implementation/execute-plugin.unit.test.ts index aea6671f1..294665d10 100644 --- a/packages/core/src/lib/implementation/execute-plugin.unit.test.ts +++ b/packages/core/src/lib/implementation/execute-plugin.unit.test.ts @@ -1,10 +1,11 @@ import { vol } from 'memfs'; -import { describe, expect, it } from 'vitest'; +import { afterEach, beforeAll, describe, expect, it } from 'vitest'; import { AuditOutputs, PluginConfig } from '@code-pushup/models'; import { MEMFS_VOLUME, MINIMAL_PLUGIN_CONFIG_MOCK, } from '@code-pushup/testing-utils'; +import { ui } from '@code-pushup/utils'; import { PluginOutputMissingAuditError, executePlugin, @@ -89,6 +90,12 @@ describe('executePlugin', () => { }); describe('executePlugins', () => { + beforeAll(() => { + ui().switchMode('raw'); + }); + afterEach(() => { + ui().flushLogs(); + }); it('should execute valid plugins', async () => { const pluginResult = await executePlugins( [ @@ -144,8 +151,13 @@ describe('executePlugins', () => { ).rejects.toThrow( 'Plugins failed: 2 errors: plugin 1 error, plugin 3 error', ); - expect(console.error).toHaveBeenCalledWith('plugin 1 error'); - expect(console.error).toHaveBeenCalledWith('plugin 3 error'); + const logs = ui() + .logger.getRenderer() + .getLogs() + .map(({ message }) => message); + expect(logs[0]).toBe('[ yellow(warn) ] Plugins failed: '); + expect(logs[1]).toBe('[ yellow(warn) ] plugin 1 error'); + expect(logs[2]).toBe('[ yellow(warn) ] plugin 3 error'); expect(pluginConfig.runner).toHaveBeenCalled(); expect(pluginConfig2.runner).toHaveBeenCalled(); expect(pluginConfig3.runner).toHaveBeenCalled(); diff --git a/packages/core/src/lib/implementation/persist.unit.test.ts b/packages/core/src/lib/implementation/persist.unit.test.ts index 600888e8a..b34fb695f 100644 --- a/packages/core/src/lib/implementation/persist.unit.test.ts +++ b/packages/core/src/lib/implementation/persist.unit.test.ts @@ -1,38 +1,53 @@ import { vol } from 'memfs'; import { readFile } from 'node:fs/promises'; import { join } from 'node:path'; -import { beforeEach, describe, expect, it } from 'vitest'; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest'; import { Report } from '@code-pushup/models'; import { MEMFS_VOLUME, MINIMAL_REPORT_MOCK, REPORT_MOCK, } from '@code-pushup/testing-utils'; +import { ui } from '@code-pushup/utils'; import { logPersistedResults, persistReport } from './persist'; describe('persistReport', () => { + beforeAll(() => { + ui().switchMode('raw'); + }); beforeEach(() => { vol.fromJSON({}, MEMFS_VOLUME); }); + afterEach(() => { + ui().flushLogs(); + }); - it('should print a summary to stdout when no format is specified`', async () => { + it('should print a summary to stdout when no format is specified', async () => { await persistReport(MINIMAL_REPORT_MOCK, { outputDir: MEMFS_VOLUME, filename: 'report', format: [], }); - expect(console.info).toHaveBeenCalledWith( + const logs = ui() + .logger.getRenderer() + .getLogs() + .map(({ message }) => message); + expect(logs.at(-1)).toEqual( expect.stringContaining('Made with ❤ by code-pushup.dev'), ); }); - it('should print a summary to stdout when all formats are specified`', async () => { + it('should print a summary to stdout when all formats are specified', async () => { await persistReport(MINIMAL_REPORT_MOCK, { outputDir: MEMFS_VOLUME, filename: 'report', format: ['md', 'json'], }); - expect(console.info).toHaveBeenCalledWith( + const logs = ui() + .logger.getRenderer() + .getLogs() + .map(({ message }) => message); + expect(logs.at(-1)).toEqual( expect.stringContaining('Made with ❤ by code-pushup.dev'), ); }); @@ -98,33 +113,31 @@ describe('persistReport', () => { }); describe('logPersistedResults', () => { + beforeAll(() => { + ui().switchMode('raw'); + }); + afterEach(() => { + ui().flushLogs(); + }); it('should log report sizes correctly`', () => { logPersistedResults([{ status: 'fulfilled', value: ['out.json', 10_000] }]); - expect(console.info).toHaveBeenNthCalledWith( - 1, - 'Generated reports successfully: ', - ); - expect(console.info).toHaveBeenNthCalledWith( - 2, - expect.stringContaining('9.77 kB'), - ); - expect(console.info).toHaveBeenNthCalledWith( - 2, - expect.stringContaining('out.json'), - ); + const logs = ui() + .logger.getRenderer() + .getLogs() + .map(({ message }) => message); + expect(logs[0]).toBe('[ blue(info) ] Generated reports successfully: '); + expect(logs[1]).toContain('9.77 kB'); + expect(logs[1]).toContain('out.json'); }); it('should log fails correctly`', () => { logPersistedResults([{ status: 'rejected', reason: 'fail' }]); - - expect(console.warn).toHaveBeenNthCalledWith( - 1, - 'Generated reports failed: ', - ); - expect(console.warn).toHaveBeenNthCalledWith( - 2, - expect.stringContaining('fail'), - ); + const logs = ui() + .logger.getRenderer() + .getLogs() + .map(({ message }) => message); + expect(logs[0]).toBe('[ yellow(warn) ] Generated reports failed: '); + expect(logs[1]).toContain('fail'); }); it('should log report sizes and fails correctly`', () => { @@ -132,27 +145,15 @@ describe('logPersistedResults', () => { { status: 'fulfilled', value: ['out.json', 10_000] }, { status: 'rejected', reason: 'fail' }, ]); - - expect(console.info).toHaveBeenNthCalledWith( - 1, - 'Generated reports successfully: ', - ); - expect(console.info).toHaveBeenNthCalledWith( - 2, - expect.stringContaining('out.json'), - ); - expect(console.info).toHaveBeenNthCalledWith( - 2, - expect.stringContaining('9.77 kB'), - ); - - expect(console.warn).toHaveBeenNthCalledWith( - 1, - 'Generated reports failed: ', - ); - expect(console.warn).toHaveBeenNthCalledWith( - 2, - expect.stringContaining('fail'), - ); + const logs = ui() + .logger.getRenderer() + .getLogs() + .map(({ message }) => message); + expect(logs[0]).toBe('[ blue(info) ] Generated reports successfully: '); + expect(logs[1]).toContain('out.json'); + expect(logs[1]).toContain('9.77 kB'); + + expect(logs[2]).toBe('[ yellow(warn) ] Generated reports failed: '); + expect(logs[3]).toContain('fail'); }); }); diff --git a/packages/utils/src/lib/file-system.ts b/packages/utils/src/lib/file-system.ts index e2523d769..cc2b9eb6a 100644 --- a/packages/utils/src/lib/file-system.ts +++ b/packages/utils/src/lib/file-system.ts @@ -4,7 +4,7 @@ import { mkdir, readFile, readdir, stat } from 'node:fs/promises'; import { join } from 'node:path'; import { formatBytes } from './formatting'; import { logMultipleResults } from './log-results'; -import {ui} from "./logging"; +import { ui } from './logging'; export async function readTextFile(path: string): Promise { const buffer = await readFile(path); @@ -58,7 +58,8 @@ export function logMultipleFileResults( const formattedSize = size ? ` (${chalk.gray(formatBytes(size))})` : ''; return `- ${chalk.bold(fileName)}${formattedSize}`; }; - const failedCallback = (result: PromiseRejectedResult) => `- ${chalk.bold(result.reason)}`; + const failedCallback = (result: PromiseRejectedResult) => + `- ${chalk.bold(result.reason)}`; logMultipleResults( fileResults, diff --git a/packages/utils/src/lib/log-results.ts b/packages/utils/src/lib/log-results.ts index 9f0fd1fec..e668d2a4c 100644 --- a/packages/utils/src/lib/log-results.ts +++ b/packages/utils/src/lib/log-results.ts @@ -1,5 +1,5 @@ import { isPromiseFulfilledResult, isPromiseRejectedResult } from './guards'; -import {ui} from "./logging"; +import { ui } from './logging'; export function logMultipleResults( results: PromiseSettledResult[], @@ -32,15 +32,18 @@ export function logPromiseResults< T extends PromiseFulfilledResult | PromiseRejectedResult, >(results: T[], logMessage: string, getMsg: (result: T) => string): void { if (results.length > 0) { - const log = results[0]?.status === 'fulfilled' ? (m: string) => { - ui().logger.info(m) - } : (m: string) => { - ui().logger.warning(m); - } + const log = + results[0]?.status === 'fulfilled' + ? (m: string) => { + ui().logger.info(m); + } + : (m: string) => { + ui().logger.warning(m); + }; log(logMessage); - results.forEach((result) => { - log(getMsg(result)) + results.forEach(result => { + log(getMsg(result)); }); } } diff --git a/packages/utils/src/lib/log-results.unit.test.ts b/packages/utils/src/lib/log-results.unit.test.ts index 4c29e42ea..ebe06be76 100644 --- a/packages/utils/src/lib/log-results.unit.test.ts +++ b/packages/utils/src/lib/log-results.unit.test.ts @@ -1,7 +1,7 @@ -import {afterEach, describe, expect, it, vi} from 'vitest'; -import {FileResult} from './file-system'; -import {logMultipleResults, logPromiseResults} from './log-results'; -import {ui} from "./logging"; +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { FileResult } from './file-system'; +import { logMultipleResults, logPromiseResults } from './log-results'; +import { ui } from './logging'; describe('logMultipleResults', () => { const succeededCallbackMock = vi.fn(); @@ -26,7 +26,7 @@ describe('logMultipleResults', () => { it('should call logPromiseResults with failed plugin result', () => { logMultipleResults( - [{status: 'rejected', reason: 'fail'} as PromiseRejectedResult], + [{ status: 'rejected', reason: 'fail' } as PromiseRejectedResult], 'Generated reports', succeededCallbackMock, failedCallbackMock, @@ -43,7 +43,7 @@ describe('logMultipleResults', () => { status: 'fulfilled', value: ['out.json', 10_000], } as PromiseFulfilledResult, - {status: 'rejected', reason: 'fail'} as PromiseRejectedResult, + { status: 'rejected', reason: 'fail' } as PromiseRejectedResult, ], 'Generated reports', succeededCallbackMock, @@ -73,20 +73,26 @@ describe('logPromiseResults', () => { } as PromiseFulfilledResult, ], 'Uploaded reports successfully:', - (result): string => result.value.toString() + (result): string => result.value.toString(), ); - const logs = ui().logger.getRenderer().getLogs().map(({message}) => message); + const logs = ui() + .logger.getRenderer() + .getLogs() + .map(({ message }) => message); expect(logs[0]).toBe('[ blue(info) ] Uploaded reports successfully:'); expect(logs[1]).toBe('[ blue(info) ] out.json'); }); it('should log on fail', () => { logPromiseResults( - [{status: 'rejected', reason: 'fail'} as PromiseRejectedResult], + [{ status: 'rejected', reason: 'fail' } as PromiseRejectedResult], 'Generated reports failed:', - (result: {reason: string}) => result.reason.toString() + (result: { reason: string }) => result.reason.toString(), ); - const logs = ui().logger.getRenderer().getLogs().map(({message}) => message); + const logs = ui() + .logger.getRenderer() + .getLogs() + .map(({ message }) => message); expect(logs[0]).toBe('[ yellow(warn) ] Generated reports failed:'); expect(logs[1]).toBe('[ yellow(warn) ] fail'); }); diff --git a/packages/utils/src/lib/logging.ts b/packages/utils/src/lib/logging.ts index 6bead0cf5..8c7a5f55e 100644 --- a/packages/utils/src/lib/logging.ts +++ b/packages/utils/src/lib/logging.ts @@ -8,7 +8,7 @@ type ArgumentsType = T extends (...args: infer U) => any ? U : never; export type CliUiBase = ReturnType; type UI = ReturnType; type CliExtension = { - row: (r: ArgumentsType) => void, + row: (r: ArgumentsType) => void; flushLogs: () => void; }; export type Column = { @@ -17,7 +17,7 @@ export type Column = { align?: 'right' | 'left' | 'center'; padding: number[]; border?: boolean; -} +}; export type CliUi = CliUiBase & CliExtension; // eslint-disable-next-line import/no-mutable-exports,functional/no-let @@ -36,7 +36,9 @@ export function ui(): CliUi { // eslint-disable-next-line functional/immutable-data logs?.splice(0, logs.length); }, - row: args => { logListItem(args); } + row: args => { + logListItem(args); + }, }; } diff --git a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts index 10bebdd83..21feed84c 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts @@ -1,20 +1,24 @@ -import {beforeAll, beforeEach, describe} from 'vitest'; +import { beforeAll, beforeEach, describe } from 'vitest'; import { reportMock } from '@code-pushup/testing-utils'; +import { ui } from '../logging'; import { logStdoutSummary } from './log-stdout-summary'; import { scoreReport } from './scoring'; import { sortReport } from './sorting'; -import {ui} from "../logging"; describe('generateStdoutSummary', () => { beforeAll(() => { ui().switchMode('raw'); - }) + }); beforeEach(() => { - ui().flushLogs(); - }) + ui().flushLogs(); + }); it('should contain all sections when using the fixture report', () => { logStdoutSummary(sortReport(scoreReport(reportMock()))); - const output = ui().logger.getRenderer().getLogs().map(({message}) => message).join('\n'); + const output = ui() + .logger.getRenderer() + .getLogs() + .map(({ message }) => message) + .join('\n'); expect(output).toContain('Categories'); // removes all color codes from the output for snapshot readability @@ -26,7 +30,11 @@ describe('generateStdoutSummary', () => { logStdoutSummary( sortReport(scoreReport({ ...reportMock(), categories: [] })), ); - const output = ui().logger.getRenderer().getLogs().map(({message}) => message).join('\n'); + const output = ui() + .logger.getRenderer() + .getLogs() + .map(({ message }) => message) + .join('\n'); expect(output).not.toContain('Categories'); // removes all color codes from the output for snapshot readability diff --git a/packages/utils/src/lib/reports/log-stdout-summary.ts b/packages/utils/src/lib/reports/log-stdout-summary.ts index 3beaff485..4c5b6af7e 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.ts @@ -22,7 +22,7 @@ export function logStdoutSummary(report: ScoredReport): void { log(reportToHeaderSection(report)); log(); logPlugins(report); - if(printCategories) { + if (printCategories) { logCategories(report); } log(`${FOOTER_PREFIX} ${CODE_PUSHUP_DOMAIN}`); diff --git a/packages/utils/src/lib/verbose-utils.unit.test.ts b/packages/utils/src/lib/verbose-utils.unit.test.ts index 523007e88..3e6dab296 100644 --- a/packages/utils/src/lib/verbose-utils.unit.test.ts +++ b/packages/utils/src/lib/verbose-utils.unit.test.ts @@ -1,6 +1,6 @@ -import {beforeAll, describe, expect, it} from 'vitest'; -import {ui} from './logging'; -import {verboseUtils} from './verbose-utils'; +import { beforeAll, describe, expect, it } from 'vitest'; +import { ui } from './logging'; +import { verboseUtils } from './verbose-utils'; describe('verbose-utils', () => { beforeAll(() => { From c36e4c608e50452114209563443c2bed45d1c0c1 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 8 Feb 2024 10:56:45 +0100 Subject: [PATCH 04/75] refactor(cli): use new logger --- .../lib/implementation/only-plugins.utils.ts | 5 +- .../only-plugins.utils.unit.test.ts | 83 +++++++++++-------- .../core/src/lib/implementation/persist.ts | 6 +- .../lib/implementation/persist.unit.test.ts | 8 +- .../src/generators/configuration/generator.ts | 3 +- packages/plugin-eslint/src/lib/meta/rules.ts | 4 +- .../plugin-eslint/src/lib/runner/transform.ts | 4 +- 7 files changed, 62 insertions(+), 51 deletions(-) diff --git a/packages/cli/src/lib/implementation/only-plugins.utils.ts b/packages/cli/src/lib/implementation/only-plugins.utils.ts index 1d04c3f98..1c4492105 100644 --- a/packages/cli/src/lib/implementation/only-plugins.utils.ts +++ b/packages/cli/src/lib/implementation/only-plugins.utils.ts @@ -1,5 +1,6 @@ import chalk from 'chalk'; import { CategoryConfig, CoreConfig } from '@code-pushup/models'; +import { ui } from '@code-pushup/utils'; export function filterPluginsBySlug( plugins: CoreConfig['plugins'], @@ -32,7 +33,7 @@ export function filterCategoryByPluginSlug( const isNotSkipped = onlyPlugins.includes(ref.slug); if (!isNotSkipped && verbose) { - console.info( + ui().logger.info( `${chalk.yellow('⚠')} Category "${ category.title }" is ignored because it references audits from skipped plugin "${ @@ -58,7 +59,7 @@ export function validateOnlyPluginsOption( : []; if (missingPlugins.length > 0 && verbose) { - console.warn( + ui().logger.warning( `${chalk.yellow( '⚠', )} The --onlyPlugin argument references plugins with "${missingPlugins.join( diff --git a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts index 694588ad1..90d3e3330 100644 --- a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts +++ b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts @@ -1,5 +1,6 @@ -import { describe, expect } from 'vitest'; -import { CategoryConfig, CoreConfig } from '@code-pushup/models'; +import {afterEach, beforeAll, describe, expect} from 'vitest'; +import {CategoryConfig, CoreConfig} from '@code-pushup/models'; +import {ui} from '@code-pushup/utils'; import { filterCategoryByPluginSlug, filterPluginsBySlug, @@ -7,46 +8,54 @@ import { } from './only-plugins.utils'; describe('filterPluginsBySlug', () => { + + it('should return all plugins if no onlyPlugins option is provided', () => { expect( filterPluginsBySlug( [ - { slug: 'plugin1' }, - { slug: 'plugin2' }, - { slug: 'plugin3' }, + {slug: 'plugin1'}, + {slug: 'plugin2'}, + {slug: 'plugin3'}, ] as CoreConfig['plugins'], {}, ), - ).toEqual([{ slug: 'plugin1' }, { slug: 'plugin2' }, { slug: 'plugin3' }]); + ).toEqual([{slug: 'plugin1'}, {slug: 'plugin2'}, {slug: 'plugin3'}]); }); it('should return only plugins with matching slugs', () => { expect( filterPluginsBySlug( [ - { slug: 'plugin1' }, - { slug: 'plugin2' }, - { slug: 'plugin3' }, + {slug: 'plugin1'}, + {slug: 'plugin2'}, + {slug: 'plugin3'}, ] as CoreConfig['plugins'], - { onlyPlugins: ['plugin1', 'plugin3'] }, + {onlyPlugins: ['plugin1', 'plugin3']}, ), - ).toEqual([{ slug: 'plugin1' }, { slug: 'plugin3' }]); + ).toEqual([{slug: 'plugin1'}, {slug: 'plugin3'}]); }); }); describe('filterCategoryByPluginSlug', () => { + beforeAll(() => { + ui().switchMode('raw'); + }); + afterEach(() => { + ui().flushLogs(); + }); it('should return all categories if no onlyPlugins option', () => { expect( filterCategoryByPluginSlug( [ - { refs: [{ slug: 'plugin1' }, { slug: 'plugin2' }] }, - { refs: [{ slug: 'plugin3' }] }, + {refs: [{slug: 'plugin1'}, {slug: 'plugin2'}]}, + {refs: [{slug: 'plugin3'}]}, ] as CategoryConfig[], {}, ), ).toEqual([ - { refs: [{ slug: 'plugin1' }, { slug: 'plugin2' }] }, - { refs: [{ slug: 'plugin3' }] }, + {refs: [{slug: 'plugin1'}, {slug: 'plugin2'}]}, + {refs: [{slug: 'plugin3'}]}, ]); }); @@ -54,12 +63,12 @@ describe('filterCategoryByPluginSlug', () => { expect( filterCategoryByPluginSlug( [ - { refs: [{ slug: 'plugin1' }, { slug: 'plugin2' }] }, - { refs: [{ slug: 'plugin3' }] }, + {refs: [{slug: 'plugin1'}, {slug: 'plugin2'}]}, + {refs: [{slug: 'plugin3'}]}, ] as CategoryConfig[], - { onlyPlugins: ['plugin1', 'plugin3'] }, + {onlyPlugins: ['plugin1', 'plugin3']}, ), - ).toEqual([{ refs: [{ slug: 'plugin3' }] }]); + ).toEqual([{refs: [{slug: 'plugin3'}]}]); }); it('should print ignored category and its first violating plugin', () => { @@ -67,48 +76,52 @@ describe('filterCategoryByPluginSlug', () => { [ { title: 'category1', - refs: [{ slug: 'plugin1' }, { slug: 'plugin2' }, { slug: 'plugin4' }], + refs: [{slug: 'plugin1'}, {slug: 'plugin2'}, {slug: 'plugin4'}], }, - { title: 'category2', refs: [{ slug: 'plugin3' }] }, + {title: 'category2', refs: [{slug: 'plugin3'}]}, ] as CategoryConfig[], { onlyPlugins: ['plugin1', 'plugin3'], verbose: true, }, - ); - expect(console.info).toHaveBeenCalledWith( - expect.stringContaining('"category1" is ignored'), - ); - expect(console.info).toHaveBeenCalledWith( - expect.stringContaining('skipped plugin "plugin2"'), - ); + ) + const logs = ui().logger.getRenderer().getLogs().map(({message}) => message); + expect(logs[0]).toBe('"category1" is ignored'); + expect(logs[0]).toBe('skipped plugin "plugin2"'); }); }); describe('validateOnlyPluginsOption', () => { + beforeAll(() => { + ui().switchMode('raw'); + }); + afterEach(() => { + ui().flushLogs(); + }); + it('should warn if onlyPlugins option contains non-existing plugin', () => { validateOnlyPluginsOption( - [{ slug: 'plugin1' }, { slug: 'plugin2' }] as CoreConfig['plugins'], + [{slug: 'plugin1'}, {slug: 'plugin2'}] as CoreConfig['plugins'], { onlyPlugins: ['plugin1', 'plugin3', 'plugin4'], verbose: true, }, ); - expect(console.warn).toHaveBeenCalledWith( - expect.stringContaining( - 'plugins with "plugin3", "plugin4" slugs, but no such plugins are present', - ), + const logs = ui().logger.getRenderer().getLogs().map(({message}) => message); + expect(logs[0]).toBe( + 'plugins with "plugin3", "plugin4" slugs, but no such plugins are present' ); }); it('should not log if onlyPlugins option contains only existing plugins', () => { validateOnlyPluginsOption( - [{ slug: 'plugin1' }, { slug: 'plugin2' }] as CoreConfig['plugins'], + [{slug: 'plugin1'}, {slug: 'plugin2'}] as CoreConfig['plugins'], { onlyPlugins: ['plugin1'], verbose: true, }, ); - expect(console.warn).not.toHaveBeenCalled(); + const logs = ui().logger.getRenderer().getLogs().map(({message}) => message); + expect(logs).toHaveLength(0); }); }); diff --git a/packages/core/src/lib/implementation/persist.ts b/packages/core/src/lib/implementation/persist.ts index 6dd2ac3e2..dcd9b16b7 100644 --- a/packages/core/src/lib/implementation/persist.ts +++ b/packages/core/src/lib/implementation/persist.ts @@ -10,7 +10,7 @@ import { logStdoutSummary, scoreReport, sortReport, - validateCommitData, + validateCommitData, ui, } from '@code-pushup/utils'; export class PersistDirError extends Error { @@ -59,7 +59,7 @@ export async function persistReport( try { await mkdir(outputDir, { recursive: true }); } catch (error) { - console.warn(error); + ui().logger.warning((error as Error).toString()); throw new PersistDirError(outputDir); } } @@ -82,7 +82,7 @@ async function persistResult(reportPath: string, content: string) { .then(() => stat(reportPath)) .then(stats => [reportPath, stats.size] as const) .catch(error => { - console.warn(error); + ui().logger.warning((error as Error).toString()); throw new PersistError(reportPath); }) ); diff --git a/packages/core/src/lib/implementation/persist.unit.test.ts b/packages/core/src/lib/implementation/persist.unit.test.ts index b34fb695f..71d739b18 100644 --- a/packages/core/src/lib/implementation/persist.unit.test.ts +++ b/packages/core/src/lib/implementation/persist.unit.test.ts @@ -12,15 +12,11 @@ import { ui } from '@code-pushup/utils'; import { logPersistedResults, persistReport } from './persist'; describe('persistReport', () => { - beforeAll(() => { - ui().switchMode('raw'); - }); + beforeEach(() => { vol.fromJSON({}, MEMFS_VOLUME); }); - afterEach(() => { - ui().flushLogs(); - }); + it('should print a summary to stdout when no format is specified', async () => { await persistReport(MINIMAL_REPORT_MOCK, { diff --git a/packages/nx-plugin/src/generators/configuration/generator.ts b/packages/nx-plugin/src/generators/configuration/generator.ts index 4591d10e7..235c70a53 100644 --- a/packages/nx-plugin/src/generators/configuration/generator.ts +++ b/packages/nx-plugin/src/generators/configuration/generator.ts @@ -8,6 +8,7 @@ import { import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; import { AddToProjectGeneratorSchema } from './schema'; +import {ui} from "@code-pushup/utils"; export async function addToProjectGenerator( tree: Tree, @@ -18,7 +19,7 @@ export async function addToProjectGenerator( const { root, targets } = projectConfiguration; if (tree.exists(join(root, 'code-pushup.config.ts'))) { - console.info('Code PushUp already configured for this project'); + ui().logger.info('Code PushUp already configured for this project'); return; } diff --git a/packages/plugin-eslint/src/lib/meta/rules.ts b/packages/plugin-eslint/src/lib/meta/rules.ts index 628d8e7dd..83f1c7fa3 100644 --- a/packages/plugin-eslint/src/lib/meta/rules.ts +++ b/packages/plugin-eslint/src/lib/meta/rules.ts @@ -1,5 +1,5 @@ import type { ESLint, Linter, Rule } from 'eslint'; -import { distinct, toArray } from '@code-pushup/utils'; +import {distinct, toArray, ui} from '@code-pushup/utils'; import { jsonHash } from './hash'; export type RuleData = { @@ -38,7 +38,7 @@ export async function listRules( (acc, [ruleId, ruleEntry]) => { const meta = rulesMeta[ruleId]; if (!meta) { - console.warn(`Metadata not found for ESLint rule ${ruleId}`); + ui().logger.warning(`Metadata not found for ESLint rule ${ruleId}`); return acc; } const options = toArray(ruleEntry).slice(1); diff --git a/packages/plugin-eslint/src/lib/runner/transform.ts b/packages/plugin-eslint/src/lib/runner/transform.ts index 5ba0a1f4f..f75a89118 100644 --- a/packages/plugin-eslint/src/lib/runner/transform.ts +++ b/packages/plugin-eslint/src/lib/runner/transform.ts @@ -5,7 +5,7 @@ import { countOccurrences, objectToEntries, pluralizeToken, - truncateIssueMessage, + truncateIssueMessage, ui, } from '@code-pushup/utils'; import { ruleIdToSlug } from '../meta/hash'; import type { LinterOutput } from './types'; @@ -25,7 +25,7 @@ export function lintResultsToAudits({ .reduce>((acc, issue) => { const { ruleId, message, relativeFilePath } = issue; if (!ruleId) { - console.warn(`ESLint core error - ${message}`); + ui().logger.warning(`ESLint core error - ${message}`); return acc; } const options = ruleOptionsPerFile[relativeFilePath]?.[ruleId] ?? []; From d05b6fba7eb64a0cf1ee33e1f600df2b3a51c6e5 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 8 Feb 2024 15:53:06 +0100 Subject: [PATCH 05/75] refactor(cli): use new logger in more places --- .../only-plugins.utils.unit.test.ts | 81 +++++++++++-------- .../core/src/lib/implementation/persist.ts | 3 +- .../lib/implementation/persist.unit.test.ts | 2 - .../src/generators/configuration/generator.ts | 2 +- packages/plugin-eslint/src/lib/meta/rules.ts | 2 +- .../plugin-eslint/src/lib/runner/transform.ts | 3 +- 6 files changed, 53 insertions(+), 40 deletions(-) diff --git a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts index 90d3e3330..eb2650b61 100644 --- a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts +++ b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts @@ -1,6 +1,6 @@ -import {afterEach, beforeAll, describe, expect} from 'vitest'; -import {CategoryConfig, CoreConfig} from '@code-pushup/models'; -import {ui} from '@code-pushup/utils'; +import { afterEach, beforeAll, describe, expect } from 'vitest'; +import { CategoryConfig, CoreConfig } from '@code-pushup/models'; +import { ui } from '@code-pushup/utils'; import { filterCategoryByPluginSlug, filterPluginsBySlug, @@ -8,32 +8,30 @@ import { } from './only-plugins.utils'; describe('filterPluginsBySlug', () => { - - it('should return all plugins if no onlyPlugins option is provided', () => { expect( filterPluginsBySlug( [ - {slug: 'plugin1'}, - {slug: 'plugin2'}, - {slug: 'plugin3'}, + { slug: 'plugin1' }, + { slug: 'plugin2' }, + { slug: 'plugin3' }, ] as CoreConfig['plugins'], {}, ), - ).toEqual([{slug: 'plugin1'}, {slug: 'plugin2'}, {slug: 'plugin3'}]); + ).toEqual([{ slug: 'plugin1' }, { slug: 'plugin2' }, { slug: 'plugin3' }]); }); it('should return only plugins with matching slugs', () => { expect( filterPluginsBySlug( [ - {slug: 'plugin1'}, - {slug: 'plugin2'}, - {slug: 'plugin3'}, + { slug: 'plugin1' }, + { slug: 'plugin2' }, + { slug: 'plugin3' }, ] as CoreConfig['plugins'], - {onlyPlugins: ['plugin1', 'plugin3']}, + { onlyPlugins: ['plugin1', 'plugin3'] }, ), - ).toEqual([{slug: 'plugin1'}, {slug: 'plugin3'}]); + ).toEqual([{ slug: 'plugin1' }, { slug: 'plugin3' }]); }); }); @@ -48,14 +46,14 @@ describe('filterCategoryByPluginSlug', () => { expect( filterCategoryByPluginSlug( [ - {refs: [{slug: 'plugin1'}, {slug: 'plugin2'}]}, - {refs: [{slug: 'plugin3'}]}, + { refs: [{ slug: 'plugin1' }, { slug: 'plugin2' }] }, + { refs: [{ slug: 'plugin3' }] }, ] as CategoryConfig[], {}, ), ).toEqual([ - {refs: [{slug: 'plugin1'}, {slug: 'plugin2'}]}, - {refs: [{slug: 'plugin3'}]}, + { refs: [{ slug: 'plugin1' }, { slug: 'plugin2' }] }, + { refs: [{ slug: 'plugin3' }] }, ]); }); @@ -63,12 +61,12 @@ describe('filterCategoryByPluginSlug', () => { expect( filterCategoryByPluginSlug( [ - {refs: [{slug: 'plugin1'}, {slug: 'plugin2'}]}, - {refs: [{slug: 'plugin3'}]}, + { refs: [{ slug: 'plugin1' }, { slug: 'plugin2' }] }, + { refs: [{ slug: 'plugin3' }] }, ] as CategoryConfig[], - {onlyPlugins: ['plugin1', 'plugin3']}, + { onlyPlugins: ['plugin1', 'plugin3'] }, ), - ).toEqual([{refs: [{slug: 'plugin3'}]}]); + ).toEqual([{ refs: [{ slug: 'plugin3' }] }]); }); it('should print ignored category and its first violating plugin', () => { @@ -76,18 +74,25 @@ describe('filterCategoryByPluginSlug', () => { [ { title: 'category1', - refs: [{slug: 'plugin1'}, {slug: 'plugin2'}, {slug: 'plugin4'}], + refs: [{ slug: 'plugin1' }, { slug: 'plugin2' }, { slug: 'plugin4' }], }, - {title: 'category2', refs: [{slug: 'plugin3'}]}, + { title: 'category2', refs: [{ slug: 'plugin3' }] }, ] as CategoryConfig[], { onlyPlugins: ['plugin1', 'plugin3'], verbose: true, }, - ) - const logs = ui().logger.getRenderer().getLogs().map(({message}) => message); - expect(logs[0]).toBe('"category1" is ignored'); - expect(logs[0]).toBe('skipped plugin "plugin2"'); + ); + const logs = ui() + .logger.getRenderer() + .getLogs() + .map(({ message }) => message); + expect(logs[0]).toEqual( + expect.stringContaining('Category "category1" is ignored'), + ); + expect(logs[0]).toEqual( + expect.stringContaining('skipped plugin "plugin2"'), + ); }); }); @@ -101,27 +106,35 @@ describe('validateOnlyPluginsOption', () => { it('should warn if onlyPlugins option contains non-existing plugin', () => { validateOnlyPluginsOption( - [{slug: 'plugin1'}, {slug: 'plugin2'}] as CoreConfig['plugins'], + [{ slug: 'plugin1' }, { slug: 'plugin2' }] as CoreConfig['plugins'], { onlyPlugins: ['plugin1', 'plugin3', 'plugin4'], verbose: true, }, ); - const logs = ui().logger.getRenderer().getLogs().map(({message}) => message); - expect(logs[0]).toBe( - 'plugins with "plugin3", "plugin4" slugs, but no such plugins are present' + const logs = ui() + .logger.getRenderer() + .getLogs() + .map(({ message }) => message); + expect(logs[0]).toEqual( + expect.stringContaining( + 'The --onlyPlugin argument references plugins with "plugin3", "plugin4" slugs', + ), ); }); it('should not log if onlyPlugins option contains only existing plugins', () => { validateOnlyPluginsOption( - [{slug: 'plugin1'}, {slug: 'plugin2'}] as CoreConfig['plugins'], + [{ slug: 'plugin1' }, { slug: 'plugin2' }] as CoreConfig['plugins'], { onlyPlugins: ['plugin1'], verbose: true, }, ); - const logs = ui().logger.getRenderer().getLogs().map(({message}) => message); + const logs = ui() + .logger.getRenderer() + .getLogs() + .map(({ message }) => message); expect(logs).toHaveLength(0); }); }); diff --git a/packages/core/src/lib/implementation/persist.ts b/packages/core/src/lib/implementation/persist.ts index dcd9b16b7..df52cb785 100644 --- a/packages/core/src/lib/implementation/persist.ts +++ b/packages/core/src/lib/implementation/persist.ts @@ -10,7 +10,8 @@ import { logStdoutSummary, scoreReport, sortReport, - validateCommitData, ui, + ui, + validateCommitData, } from '@code-pushup/utils'; export class PersistDirError extends Error { diff --git a/packages/core/src/lib/implementation/persist.unit.test.ts b/packages/core/src/lib/implementation/persist.unit.test.ts index 71d739b18..b6d25672c 100644 --- a/packages/core/src/lib/implementation/persist.unit.test.ts +++ b/packages/core/src/lib/implementation/persist.unit.test.ts @@ -12,12 +12,10 @@ import { ui } from '@code-pushup/utils'; import { logPersistedResults, persistReport } from './persist'; describe('persistReport', () => { - beforeEach(() => { vol.fromJSON({}, MEMFS_VOLUME); }); - it('should print a summary to stdout when no format is specified', async () => { await persistReport(MINIMAL_REPORT_MOCK, { outputDir: MEMFS_VOLUME, diff --git a/packages/nx-plugin/src/generators/configuration/generator.ts b/packages/nx-plugin/src/generators/configuration/generator.ts index 235c70a53..ca99324ee 100644 --- a/packages/nx-plugin/src/generators/configuration/generator.ts +++ b/packages/nx-plugin/src/generators/configuration/generator.ts @@ -7,8 +7,8 @@ import { } from '@nx/devkit'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; +import { ui } from '@code-pushup/utils'; import { AddToProjectGeneratorSchema } from './schema'; -import {ui} from "@code-pushup/utils"; export async function addToProjectGenerator( tree: Tree, diff --git a/packages/plugin-eslint/src/lib/meta/rules.ts b/packages/plugin-eslint/src/lib/meta/rules.ts index 83f1c7fa3..2a5d0d131 100644 --- a/packages/plugin-eslint/src/lib/meta/rules.ts +++ b/packages/plugin-eslint/src/lib/meta/rules.ts @@ -1,5 +1,5 @@ import type { ESLint, Linter, Rule } from 'eslint'; -import {distinct, toArray, ui} from '@code-pushup/utils'; +import { distinct, toArray, ui } from '@code-pushup/utils'; import { jsonHash } from './hash'; export type RuleData = { diff --git a/packages/plugin-eslint/src/lib/runner/transform.ts b/packages/plugin-eslint/src/lib/runner/transform.ts index f75a89118..ef42ebd7c 100644 --- a/packages/plugin-eslint/src/lib/runner/transform.ts +++ b/packages/plugin-eslint/src/lib/runner/transform.ts @@ -5,7 +5,8 @@ import { countOccurrences, objectToEntries, pluralizeToken, - truncateIssueMessage, ui, + truncateIssueMessage, + ui, } from '@code-pushup/utils'; import { ruleIdToSlug } from '../meta/hash'; import type { LinterOutput } from './types'; From 501d1dca599ed0ea860cadccd076c759ef3a55a5 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 15 Feb 2024 16:29:17 +0530 Subject: [PATCH 06/75] test(cli): fix unit tests --- .../print-config/print-config-command.unit.test.ts | 6 +++++- .../core/src/lib/implementation/persist.unit.test.ts | 11 +++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/lib/print-config/print-config-command.unit.test.ts b/packages/cli/src/lib/print-config/print-config-command.unit.test.ts index cda5fd4dd..5be5d4cc6 100644 --- a/packages/cli/src/lib/print-config/print-config-command.unit.test.ts +++ b/packages/cli/src/lib/print-config/print-config-command.unit.test.ts @@ -1,4 +1,4 @@ -import { beforeAll, describe, expect } from 'vitest'; +import { afterEach, beforeAll, describe, expect } from 'vitest'; import { ui } from '@code-pushup/utils'; import { DEFAULT_CLI_CONFIGURATION } from '../../../mocks/constants'; import { yargsCli } from '../yargs-cli'; @@ -19,6 +19,10 @@ describe('print-config-command', () => { // initialize it in raw mode ui().switchMode('raw'); }); + afterEach(() => { + // clean previous logs + ui().flushLogs(); + }); it('should filter out meta arguments and kebab duplicates', async () => { await yargsCli( diff --git a/packages/core/src/lib/implementation/persist.unit.test.ts b/packages/core/src/lib/implementation/persist.unit.test.ts index b6d25672c..af458c6f0 100644 --- a/packages/core/src/lib/implementation/persist.unit.test.ts +++ b/packages/core/src/lib/implementation/persist.unit.test.ts @@ -12,10 +12,20 @@ import { ui } from '@code-pushup/utils'; import { logPersistedResults, persistReport } from './persist'; describe('persistReport', () => { + beforeAll(() => { + // initialize it in raw mode + ui().switchMode('raw'); + }); + beforeEach(() => { vol.fromJSON({}, MEMFS_VOLUME); }); + afterEach(() => { + // clean previous logs + ui().flushLogs(); + }); + it('should print a summary to stdout when no format is specified', async () => { await persistReport(MINIMAL_REPORT_MOCK, { outputDir: MEMFS_VOLUME, @@ -41,6 +51,7 @@ describe('persistReport', () => { .logger.getRenderer() .getLogs() .map(({ message }) => message); + expect(logs.at(-1)).toEqual( expect.stringContaining('Made with ❤ by code-pushup.dev'), ); From 22e1b1b3ae7cf34c910977d79e9095a9ea2af009 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 15 Feb 2024 17:38:25 +0530 Subject: [PATCH 07/75] test: add setup script for cliui --- examples/plugins/code-pushup.config.ts | 12 +----------- .../only-plugins.utils.unit.test.ts | 15 +-------------- .../print-config-command.unit.test.ts | 11 +---------- packages/cli/vite.config.unit.ts | 1 + .../implementation/execute-plugin.unit.test.ts | 8 +------- .../lib/implementation/persist.unit.test.ts | 18 +----------------- packages/core/vite.config.unit.ts | 1 + testing-utils/src/lib/setup/cliui.mock.ts | 12 ++++++++++++ 8 files changed, 19 insertions(+), 59 deletions(-) create mode 100644 testing-utils/src/lib/setup/cliui.mock.ts diff --git a/examples/plugins/code-pushup.config.ts b/examples/plugins/code-pushup.config.ts index ad61ae851..8f750b3ec 100644 --- a/examples/plugins/code-pushup.config.ts +++ b/examples/plugins/code-pushup.config.ts @@ -36,22 +36,12 @@ const config = { zod: '^3.22.4', }, }), - await lighthousePlugin({ - url: 'https://staging.code-pushup.dev/login', - outputPath: join('.code-pushup', LIGHTHOUSE_OUTPUT_FILE_DEFAULT), - headless: false, - verbose: true, - }), ], categories: [ { slug: 'performance', title: 'Performance', - refs: [ - ...fileSizeRecommendedRefs, - packageJsonPerformanceGroupRef, - ...lighthouseCorePerfGroupRefs, - ], + refs: [...fileSizeRecommendedRefs, packageJsonPerformanceGroupRef], }, { slug: 'bug-prevention', diff --git a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts index eb2650b61..d5740227c 100644 --- a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts +++ b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts @@ -1,4 +1,4 @@ -import { afterEach, beforeAll, describe, expect } from 'vitest'; +import { describe, expect } from 'vitest'; import { CategoryConfig, CoreConfig } from '@code-pushup/models'; import { ui } from '@code-pushup/utils'; import { @@ -36,12 +36,6 @@ describe('filterPluginsBySlug', () => { }); describe('filterCategoryByPluginSlug', () => { - beforeAll(() => { - ui().switchMode('raw'); - }); - afterEach(() => { - ui().flushLogs(); - }); it('should return all categories if no onlyPlugins option', () => { expect( filterCategoryByPluginSlug( @@ -97,13 +91,6 @@ describe('filterCategoryByPluginSlug', () => { }); describe('validateOnlyPluginsOption', () => { - beforeAll(() => { - ui().switchMode('raw'); - }); - afterEach(() => { - ui().flushLogs(); - }); - it('should warn if onlyPlugins option contains non-existing plugin', () => { validateOnlyPluginsOption( [{ slug: 'plugin1' }, { slug: 'plugin2' }] as CoreConfig['plugins'], diff --git a/packages/cli/src/lib/print-config/print-config-command.unit.test.ts b/packages/cli/src/lib/print-config/print-config-command.unit.test.ts index 5be5d4cc6..1489127f6 100644 --- a/packages/cli/src/lib/print-config/print-config-command.unit.test.ts +++ b/packages/cli/src/lib/print-config/print-config-command.unit.test.ts @@ -1,4 +1,4 @@ -import { afterEach, beforeAll, describe, expect } from 'vitest'; +import { describe, expect } from 'vitest'; import { ui } from '@code-pushup/utils'; import { DEFAULT_CLI_CONFIGURATION } from '../../../mocks/constants'; import { yargsCli } from '../yargs-cli'; @@ -15,15 +15,6 @@ vi.mock('@code-pushup/core', async () => { }); describe('print-config-command', () => { - beforeAll(() => { - // initialize it in raw mode - ui().switchMode('raw'); - }); - afterEach(() => { - // clean previous logs - ui().flushLogs(); - }); - it('should filter out meta arguments and kebab duplicates', async () => { await yargsCli( [ diff --git a/packages/cli/vite.config.unit.ts b/packages/cli/vite.config.unit.ts index cd12cf9e2..4806a3484 100644 --- a/packages/cli/vite.config.unit.ts +++ b/packages/cli/vite.config.unit.ts @@ -21,6 +21,7 @@ export default defineConfig({ '../../testing-utils/src/lib/setup/console.mock.ts', '../../testing-utils/src/lib/setup/portal-client.mock.ts', '../../testing-utils/src/lib/setup/reset.mocks.ts', + '../../testing-utils/src/lib/setup/cliui.mock.ts', ], }, }); diff --git a/packages/core/src/lib/implementation/execute-plugin.unit.test.ts b/packages/core/src/lib/implementation/execute-plugin.unit.test.ts index 294665d10..1663308fe 100644 --- a/packages/core/src/lib/implementation/execute-plugin.unit.test.ts +++ b/packages/core/src/lib/implementation/execute-plugin.unit.test.ts @@ -1,5 +1,5 @@ import { vol } from 'memfs'; -import { afterEach, beforeAll, describe, expect, it } from 'vitest'; +import { describe, expect, it } from 'vitest'; import { AuditOutputs, PluginConfig } from '@code-pushup/models'; import { MEMFS_VOLUME, @@ -90,12 +90,6 @@ describe('executePlugin', () => { }); describe('executePlugins', () => { - beforeAll(() => { - ui().switchMode('raw'); - }); - afterEach(() => { - ui().flushLogs(); - }); it('should execute valid plugins', async () => { const pluginResult = await executePlugins( [ diff --git a/packages/core/src/lib/implementation/persist.unit.test.ts b/packages/core/src/lib/implementation/persist.unit.test.ts index af458c6f0..00f8207da 100644 --- a/packages/core/src/lib/implementation/persist.unit.test.ts +++ b/packages/core/src/lib/implementation/persist.unit.test.ts @@ -1,7 +1,7 @@ import { vol } from 'memfs'; import { readFile } from 'node:fs/promises'; import { join } from 'node:path'; -import { afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest'; +import { beforeEach, describe, expect, it } from 'vitest'; import { Report } from '@code-pushup/models'; import { MEMFS_VOLUME, @@ -12,20 +12,10 @@ import { ui } from '@code-pushup/utils'; import { logPersistedResults, persistReport } from './persist'; describe('persistReport', () => { - beforeAll(() => { - // initialize it in raw mode - ui().switchMode('raw'); - }); - beforeEach(() => { vol.fromJSON({}, MEMFS_VOLUME); }); - afterEach(() => { - // clean previous logs - ui().flushLogs(); - }); - it('should print a summary to stdout when no format is specified', async () => { await persistReport(MINIMAL_REPORT_MOCK, { outputDir: MEMFS_VOLUME, @@ -118,12 +108,6 @@ describe('persistReport', () => { }); describe('logPersistedResults', () => { - beforeAll(() => { - ui().switchMode('raw'); - }); - afterEach(() => { - ui().flushLogs(); - }); it('should log report sizes correctly`', () => { logPersistedResults([{ status: 'fulfilled', value: ['out.json', 10_000] }]); const logs = ui() diff --git a/packages/core/vite.config.unit.ts b/packages/core/vite.config.unit.ts index 782ca7434..6a32b4fb5 100644 --- a/packages/core/vite.config.unit.ts +++ b/packages/core/vite.config.unit.ts @@ -21,6 +21,7 @@ export default defineConfig({ '../../testing-utils/src/lib/setup/console.mock.ts', '../../testing-utils/src/lib/setup/reset.mocks.ts', '../../testing-utils/src/lib/setup/portal-client.mock.ts', + '../../testing-utils/src/lib/setup/cliui.mock.ts', ], }, }); diff --git a/testing-utils/src/lib/setup/cliui.mock.ts b/testing-utils/src/lib/setup/cliui.mock.ts new file mode 100644 index 000000000..09898910e --- /dev/null +++ b/testing-utils/src/lib/setup/cliui.mock.ts @@ -0,0 +1,12 @@ +import { afterEach, beforeAll } from 'vitest'; +import { ui } from '@code-pushup/utils'; + +beforeAll(() => { + // initialize it in raw mode + ui().switchMode('raw'); +}); + +afterEach(() => { + // clean previous logs + ui().flushLogs(); +}); From d15aedef071814841d4774ff3a10a3f4dd711d17 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 15 Feb 2024 17:43:04 +0530 Subject: [PATCH 08/75] revert --- examples/plugins/code-pushup.config.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/examples/plugins/code-pushup.config.ts b/examples/plugins/code-pushup.config.ts index 8f750b3ec..ad61ae851 100644 --- a/examples/plugins/code-pushup.config.ts +++ b/examples/plugins/code-pushup.config.ts @@ -36,12 +36,22 @@ const config = { zod: '^3.22.4', }, }), + await lighthousePlugin({ + url: 'https://staging.code-pushup.dev/login', + outputPath: join('.code-pushup', LIGHTHOUSE_OUTPUT_FILE_DEFAULT), + headless: false, + verbose: true, + }), ], categories: [ { slug: 'performance', title: 'Performance', - refs: [...fileSizeRecommendedRefs, packageJsonPerformanceGroupRef], + refs: [ + ...fileSizeRecommendedRefs, + packageJsonPerformanceGroupRef, + ...lighthouseCorePerfGroupRefs, + ], }, { slug: 'bug-prevention', From a13b9cdb1063d193a426f1102f764452bcb0a85e Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 15 Feb 2024 17:54:18 +0530 Subject: [PATCH 09/75] fix merge --- packages/utils/src/index.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 88750d46b..7f1b3610a 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -22,10 +22,6 @@ export { readTextFile, removeDirectoryIfExists, } from './lib/file-system'; -export { - filterAuditsBySlug, - filterGroupsByAuditSlug, -} from './lib/filter-by-slug'; export { formatBytes, formatDuration, @@ -50,7 +46,6 @@ export { isPromiseRejectedResult, } from './lib/guards'; export { logMultipleResults } from './lib/log-results'; -export { link } from './lib/logging'; export { ProgressBar, getProgressBar } from './lib/progress'; export { TERMINAL_WIDTH } from './lib/reports/constants'; export { generateMdReport } from './lib/reports/generate-md-report'; From df12a115aefce8575b1bef613c6ce9f174f15026 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 17 Feb 2024 21:51:58 +0530 Subject: [PATCH 10/75] test: use setup scripts for cliui tests --- package-lock.json | 14 ++++----- package.json | 2 +- .../cli/src/lib/implementation/logging.ts | 13 +-------- packages/cli/vite.config.unit.ts | 2 +- packages/core/vite.config.unit.ts | 2 +- .../utils/src/lib/log-results.unit.test.ts | 10 +------ packages/utils/src/lib/logging.ts | 8 ----- ...enerate-stdout-summary.integration.test.ts | 29 ------------------- .../log-stdout-summary.integration.test.ts | 10 ++----- .../utils/src/lib/verbose-utils.unit.test.ts | 5 +--- packages/utils/vite.config.integration.ts | 1 + packages/utils/vite.config.unit.ts | 1 + testing/test-setup/src/lib/cliui.mock.ts | 9 ++++++ 13 files changed, 26 insertions(+), 80 deletions(-) delete mode 100644 packages/utils/src/lib/reports/generate-stdout-summary.integration.test.ts diff --git a/package-lock.json b/package-lock.json index c72789fe3..edb6d7b90 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,17 @@ { "name": "@code-pushup/cli-source", - "version": "0.20.1", + "version": "0.21.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@code-pushup/cli-source", - "version": "0.20.1", + "version": "0.21.1", "license": "MIT", "dependencies": { "@code-pushup/portal-client": "^0.6.1", "@isaacs/cliui": "^8.0.2", - "@poppinss/cliui": "^6.3.0", + "@poppinss/cliui": "^6.4.0", "@swc/helpers": "0.5.3", "bundle-require": "^4.0.1", "chalk": "^5.3.0", @@ -5020,9 +5020,9 @@ "license": "MIT" }, "node_modules/@poppinss/cliui": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@poppinss/cliui/-/cliui-6.3.0.tgz", - "integrity": "sha512-GEu/IsJ9SanzAGa9NaHsHneumwlScLfhBJHU8uYcB6GyaTvQQg38OuiGnn5U95Wk3a/roUOSsrEVU1bnVvYtoQ==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@poppinss/cliui/-/cliui-6.4.0.tgz", + "integrity": "sha512-8exOqpXxjQfJeHORAkbqzsQL2ybjKh22PD2UUq2poBemhxCH5KEe6qqu5nKc4KM3lhXc8QizlPMDxOIP+Pyt/w==", "dependencies": { "@poppinss/colors": "^4.1.2", "cli-boxes": "^3.0.0", @@ -5030,7 +5030,7 @@ "cli-truncate": "^4.0.0", "log-update": "^6.0.0", "pretty-hrtime": "^1.0.3", - "string-width": "^7.0.0", + "string-width": "^7.1.0", "supports-color": "^9.4.0", "terminal-size": "^4.0.0", "wordwrap": "^1.0.0" diff --git a/package.json b/package.json index bcb242cac..112f6e4dc 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "dependencies": { "@code-pushup/portal-client": "^0.6.1", "@isaacs/cliui": "^8.0.2", - "@poppinss/cliui": "^6.3.0", + "@poppinss/cliui": "^6.4.0", "@swc/helpers": "0.5.3", "bundle-require": "^4.0.1", "chalk": "^5.3.0", diff --git a/packages/cli/src/lib/implementation/logging.ts b/packages/cli/src/lib/implementation/logging.ts index 27eadc23c..ca958b0d9 100644 --- a/packages/cli/src/lib/implementation/logging.ts +++ b/packages/cli/src/lib/implementation/logging.ts @@ -1,16 +1,5 @@ import chalk from 'chalk'; -import { link, portalCommitDashboardLink, ui } from '@code-pushup/utils'; - -export type CliUi = ReturnType; - -// eslint-disable-next-line import/no-mutable-exports,functional/no-let -export let singletonUiInstance: CliUi | undefined; -export function ui(): CliUi { - if (singletonUiInstance === undefined) { - singletonUiInstance = cliui(); - } - return singletonUiInstance; -} +import { link, ui } from '@code-pushup/utils'; export function renderConfigureCategoriesHint(): void { ui().logger.info( diff --git a/packages/cli/vite.config.unit.ts b/packages/cli/vite.config.unit.ts index 79bafcdab..4b7005e21 100644 --- a/packages/cli/vite.config.unit.ts +++ b/packages/cli/vite.config.unit.ts @@ -22,7 +22,7 @@ export default defineConfig({ '../../testing/test-setup/src/lib/console.mock.ts', '../../testing/test-setup/src/lib/portal-client.mock.ts', '../../testing/test-setup/src/lib/reset.mocks.ts', - '../../testing/test-setup/src/lib/setup/cliui.mock.ts', + '../../testing/test-setup/src/lib/cliui.mock.ts', ], }, }); diff --git a/packages/core/vite.config.unit.ts b/packages/core/vite.config.unit.ts index d3ba8424d..36708b782 100644 --- a/packages/core/vite.config.unit.ts +++ b/packages/core/vite.config.unit.ts @@ -22,7 +22,7 @@ export default defineConfig({ '../../testing/test-setup/src/lib/console.mock.ts', '../../testing/test-setup/src/lib/reset.mocks.ts', '../../testing/test-setup/src/lib/portal-client.mock.ts', - '../../testing/test-setup/src/lib/setup/cliui.mock.ts', + '../../testing/test-setup/src/lib/cliui.mock.ts', ], }, }); diff --git a/packages/utils/src/lib/log-results.unit.test.ts b/packages/utils/src/lib/log-results.unit.test.ts index ebe06be76..fecde5520 100644 --- a/packages/utils/src/lib/log-results.unit.test.ts +++ b/packages/utils/src/lib/log-results.unit.test.ts @@ -1,4 +1,4 @@ -import { afterEach, describe, expect, it, vi } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; import { FileResult } from './file-system'; import { logMultipleResults, logPromiseResults } from './log-results'; import { ui } from './logging'; @@ -56,14 +56,6 @@ describe('logMultipleResults', () => { }); describe('logPromiseResults', () => { - beforeAll(() => { - ui().switchMode('raw'); - }); - - afterEach(() => { - ui().flushLogs(); - }); - it('should log on success', () => { logPromiseResults( [ diff --git a/packages/utils/src/lib/logging.ts b/packages/utils/src/lib/logging.ts index 8c7a5f55e..25a64d24e 100644 --- a/packages/utils/src/lib/logging.ts +++ b/packages/utils/src/lib/logging.ts @@ -9,7 +9,6 @@ export type CliUiBase = ReturnType; type UI = ReturnType; type CliExtension = { row: (r: ArgumentsType) => void; - flushLogs: () => void; }; export type Column = { text: string; @@ -29,13 +28,6 @@ export function ui(): CliUi { } return { ...singletonUiInstance, - flushLogs: () => { - const logs = singletonUiInstance?.logger.getRenderer().getLogs(); - // mutate internal array as there is no public API to reset the internal logs array. - // if we don't do it we carry items from across tests - // eslint-disable-next-line functional/immutable-data - logs?.splice(0, logs.length); - }, row: args => { logListItem(args); }, diff --git a/packages/utils/src/lib/reports/generate-stdout-summary.integration.test.ts b/packages/utils/src/lib/reports/generate-stdout-summary.integration.test.ts deleted file mode 100644 index b48f459f8..000000000 --- a/packages/utils/src/lib/reports/generate-stdout-summary.integration.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { describe } from 'vitest'; -import { reportMock } from '@code-pushup/test-utils'; -import { generateStdoutSummary } from './generate-stdout-summary'; -import { scoreReport } from './scoring'; -import { sortReport } from './sorting'; - -describe('generateStdoutSummary', () => { - it('should contain all sections when using the fixture report', () => { - const logOutput = generateStdoutSummary( - sortReport(scoreReport(reportMock())), - ); - - expect(logOutput).toContain('Categories'); - // removes all color codes from the output for snapshot readability - // eslint-disable-next-line no-control-regex - expect(logOutput.replace(/\u001B\[\d+m/g, '')).toMatchSnapshot(); - }); - - it('should not contain category section when categories are empty', () => { - const logOutput = generateStdoutSummary( - sortReport(scoreReport({ ...reportMock(), categories: [] })), - ); - - expect(logOutput).not.toContain('Categories'); - // removes all color codes from the output for snapshot readability - // eslint-disable-next-line no-control-regex - expect(logOutput.replace(/\u001B\[\d+m/g, '')).toMatchSnapshot(); - }); -}); diff --git a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts index 21feed84c..64c6276d8 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts @@ -1,17 +1,11 @@ -import { beforeAll, beforeEach, describe } from 'vitest'; -import { reportMock } from '@code-pushup/testing-utils'; +import { describe } from 'vitest'; +import { reportMock } from '@code-pushup/test-utils'; import { ui } from '../logging'; import { logStdoutSummary } from './log-stdout-summary'; import { scoreReport } from './scoring'; import { sortReport } from './sorting'; describe('generateStdoutSummary', () => { - beforeAll(() => { - ui().switchMode('raw'); - }); - beforeEach(() => { - ui().flushLogs(); - }); it('should contain all sections when using the fixture report', () => { logStdoutSummary(sortReport(scoreReport(reportMock()))); const output = ui() diff --git a/packages/utils/src/lib/verbose-utils.unit.test.ts b/packages/utils/src/lib/verbose-utils.unit.test.ts index 3e6dab296..34cadeaf5 100644 --- a/packages/utils/src/lib/verbose-utils.unit.test.ts +++ b/packages/utils/src/lib/verbose-utils.unit.test.ts @@ -1,11 +1,8 @@ -import { beforeAll, describe, expect, it } from 'vitest'; +import { describe, expect, it } from 'vitest'; import { ui } from './logging'; import { verboseUtils } from './verbose-utils'; describe('verbose-utils', () => { - beforeAll(() => { - ui().switchMode('raw'); - }); it('exec should be off by default', () => { const spy = vi.fn(); verboseUtils().exec(spy); diff --git a/packages/utils/vite.config.integration.ts b/packages/utils/vite.config.integration.ts index b06dc4bfc..b51a9e606 100644 --- a/packages/utils/vite.config.integration.ts +++ b/packages/utils/vite.config.integration.ts @@ -19,6 +19,7 @@ export default defineConfig({ setupFiles: [ '../../testing/test-setup/src/lib/console.mock.ts', '../../testing/test-setup/src/lib/reset.mocks.ts', + '../../testing/test-setup/src/lib/cliui.mock.ts', ], }, }); diff --git a/packages/utils/vite.config.unit.ts b/packages/utils/vite.config.unit.ts index dc72c0ac0..c67fdc960 100644 --- a/packages/utils/vite.config.unit.ts +++ b/packages/utils/vite.config.unit.ts @@ -20,6 +20,7 @@ export default defineConfig({ '../../testing/test-setup/src/lib/fs.mock.ts', '../../testing/test-setup/src/lib/console.mock.ts', '../../testing/test-setup/src/lib/reset.mocks.ts', + '../../testing/test-setup/src/lib/cliui.mock.ts', ], }, }); diff --git a/testing/test-setup/src/lib/cliui.mock.ts b/testing/test-setup/src/lib/cliui.mock.ts index e69de29bb..22be59e06 100644 --- a/testing/test-setup/src/lib/cliui.mock.ts +++ b/testing/test-setup/src/lib/cliui.mock.ts @@ -0,0 +1,9 @@ +import { beforeAll, beforeEach } from 'vitest'; +import { ui } from '@code-pushup/utils'; + +beforeAll(() => { + ui().switchMode('raw'); +}); +beforeEach(() => { + ui().logger.flushLogs(); +}); From 9aa946d26dac0b87dbb0ed6842bd857b131c2fc3 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 18 Feb 2024 13:16:53 +0530 Subject: [PATCH 11/75] fix(cli): typing --- .../core/src/lib/implementation/collect.integration.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/lib/implementation/collect.integration.test.ts b/packages/core/src/lib/implementation/collect.integration.test.ts index 4bf90ec82..50bb5ff2b 100644 --- a/packages/core/src/lib/implementation/collect.integration.test.ts +++ b/packages/core/src/lib/implementation/collect.integration.test.ts @@ -1,13 +1,13 @@ import { vol } from 'memfs'; import { describe, expect, it } from 'vitest'; import { MEMFS_VOLUME, MINIMAL_CONFIG_MOCK } from '@code-pushup/test-utils'; -import { collect } from './collect'; +import { CollectOptions, collect } from './collect'; describe('collect', () => { it('should execute with valid options', async () => { vol.fromJSON({}, MEMFS_VOLUME); const report = await collect({ - ...MINIMAL_CONFIG_MOCK, + ...(MINIMAL_CONFIG_MOCK as CollectOptions), verbose: true, progress: false, }); From a09095a171d60ce0d0245b2e0391b73783a60599 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Chalk?= Date: Thu, 29 Feb 2024 12:46:12 +0100 Subject: [PATCH 12/75] test(utils): fix flaky toGitPath tests --- packages/utils/src/lib/git.integration.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/utils/src/lib/git.integration.test.ts b/packages/utils/src/lib/git.integration.test.ts index 468761a1a..ebddf6e37 100644 --- a/packages/utils/src/lib/git.integration.test.ts +++ b/packages/utils/src/lib/git.integration.test.ts @@ -67,19 +67,19 @@ describe('git utils in a git repo with a branch and commits', () => { it('should convert absolute path to relative Git path', async () => { await expect( - toGitPath(join(process.cwd(), 'src', 'utils.ts')), + toGitPath(join(baseDir, 'src', 'utils.ts'), git), ).resolves.toBe('src/utils.ts'); }); it('should convert relative Windows path to relative Git path', async () => { - await expect(toGitPath('Backend\\API\\Startup.cs')).resolves.toBe( - 'Backend/API/Startup.cs', + await expect(toGitPath('Backend\\API\\Startup.cs', git)).resolves.toBe( + '../../Backend/API/Startup.cs', ); }); it('should keep relative Unix path as is (already a Git path)', async () => { - await expect(toGitPath('Backend/API/Startup.cs')).resolves.toBe( - 'Backend/API/Startup.cs', + await expect(toGitPath('Backend/API/Startup.cs', git)).resolves.toBe( + '../../Backend/API/Startup.cs', ); }); From 1c7e2a224c327994d2cc424dbbf0aa2902effa07 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 29 Feb 2024 18:02:59 +0100 Subject: [PATCH 13/75] marge main --- packages/utils/src/index.ts | 10 +--------- .../utils/src/lib/reports/generate-stdout-summary.ts | 0 packages/utils/src/lib/reports/log-stdout-summary.ts | 11 +++++++---- 3 files changed, 8 insertions(+), 13 deletions(-) delete mode 100644 packages/utils/src/lib/reports/generate-stdout-summary.ts diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 2f0df963d..e6a0259a4 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -48,11 +48,7 @@ export { } from './lib/guards'; export { logMultipleResults } from './lib/log-results'; export { ProgressBar, getProgressBar } from './lib/progress'; -export { TERMINAL_WIDTH } from './lib/reports/constants'; -export { generateMdReport } from './lib/reports/generate-md-report'; export { logStdoutSummary } from './lib/reports/log-stdout-summary'; -export { ScoredReport, scoreReport } from './lib/reports/scoring'; -export { sortReport } from './lib/reports/sorting'; export { CODE_PUSHUP_DOMAIN, FOOTER_PREFIX, @@ -60,7 +56,6 @@ export { TERMINAL_WIDTH, } from './lib/reports/constants'; export { generateMdReport } from './lib/reports/generate-md-report'; -export { generateStdoutSummary } from './lib/reports/generate-stdout-summary'; export { scoreReport } from './lib/reports/scoring'; export { sortReport } from './lib/reports/sorting'; export { ScoredReport } from './lib/reports/types'; @@ -86,7 +81,4 @@ export { } from './lib/transform'; export { verboseUtils } from './lib/verbose-utils'; export { link, ui, Column } from './lib/logging'; -export { - filterAuditsBySlug, - filterGroupsByAuditSlug, -} from './lib/filter-by-slug'; + diff --git a/packages/utils/src/lib/reports/generate-stdout-summary.ts b/packages/utils/src/lib/reports/generate-stdout-summary.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/utils/src/lib/reports/log-stdout-summary.ts b/packages/utils/src/lib/reports/log-stdout-summary.ts index 4c5b6af7e..3f14a4de2 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.ts @@ -1,15 +1,18 @@ import chalk from 'chalk'; import { AuditReport } from '@code-pushup/models'; import { ui } from '../logging'; -import { SCORE_COLOR_RANGE, TERMINAL_WIDTH } from './constants'; -import { ScoredReport } from './scoring'; import { CODE_PUSHUP_DOMAIN, FOOTER_PREFIX, - countCategoryAudits, - formatReportScore, reportHeadlineText, reportRawOverviewTableHeaders, + SCORE_COLOR_RANGE, + TERMINAL_WIDTH +} from './constants'; +import { ScoredReport } from './types'; +import { + countCategoryAudits, + formatReportScore, } from './utils'; function log(msg = ''): void { From 58c483a4e526239d08baf6fa3ffd0687c01b5bf4 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 1 Mar 2024 11:12:41 +0100 Subject: [PATCH 14/75] marge main --- packages/utils/src/index.ts | 1 - .../lib/reports/log-stdout-summary.integration.test.ts | 2 +- packages/utils/src/lib/reports/log-stdout-summary.ts | 9 +++------ 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index e6a0259a4..01acc9c8c 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -81,4 +81,3 @@ export { } from './lib/transform'; export { verboseUtils } from './lib/verbose-utils'; export { link, ui, Column } from './lib/logging'; - diff --git a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts index 64c6276d8..4dcd50b16 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts @@ -5,7 +5,7 @@ import { logStdoutSummary } from './log-stdout-summary'; import { scoreReport } from './scoring'; import { sortReport } from './sorting'; -describe('generateStdoutSummary', () => { +describe('logStdoutSummary', () => { it('should contain all sections when using the fixture report', () => { logStdoutSummary(sortReport(scoreReport(reportMock()))); const output = ui() diff --git a/packages/utils/src/lib/reports/log-stdout-summary.ts b/packages/utils/src/lib/reports/log-stdout-summary.ts index 3f14a4de2..ce7659544 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.ts @@ -4,16 +4,13 @@ import { ui } from '../logging'; import { CODE_PUSHUP_DOMAIN, FOOTER_PREFIX, + SCORE_COLOR_RANGE, + TERMINAL_WIDTH, reportHeadlineText, reportRawOverviewTableHeaders, - SCORE_COLOR_RANGE, - TERMINAL_WIDTH } from './constants'; import { ScoredReport } from './types'; -import { - countCategoryAudits, - formatReportScore, -} from './utils'; +import { countCategoryAudits, formatReportScore } from './utils'; function log(msg = ''): void { ui().logger.log(msg); From 54fabe416fbccbc52af05adb046b6d930fd350a6 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 1 Mar 2024 11:47:25 +0100 Subject: [PATCH 15/75] wip --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fb57b83c5..2136f762c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -170,6 +170,8 @@ jobs: cache: npm - name: Install dependencies run: npm ci + - name: Check git version + run: git -v - name: Collect Code PushUp report run: npx nx run-collect - name: Upload Code PushUp report to portal From 1de146c11453c75a953b415051382d93bc85d942 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 2 Mar 2024 12:51:04 +0100 Subject: [PATCH 16/75] test(utils): added test folder per describe --- .../plugin-coverage/src/lib/runner/index.ts | 2 +- packages/utils/src/lib/execute-process.ts | 1 + .../utils/src/lib/git.integration.test.ts | 196 +++++++++++------- 3 files changed, 120 insertions(+), 79 deletions(-) diff --git a/packages/plugin-coverage/src/lib/runner/index.ts b/packages/plugin-coverage/src/lib/runner/index.ts index a41f1588c..d34dcf135 100644 --- a/packages/plugin-coverage/src/lib/runner/index.ts +++ b/packages/plugin-coverage/src/lib/runner/index.ts @@ -36,7 +36,7 @@ export async function executeRunner(): Promise { } } - // Caculate coverage from LCOV results + // Calculate coverage from LCOV results const auditOutputs = await lcovResultsToAuditOutputs(reports, coverageTypes); await ensureDirectoryExists(dirname(RUNNER_OUTPUT_PATH)); diff --git a/packages/utils/src/lib/execute-process.ts b/packages/utils/src/lib/execute-process.ts index 970081d6f..1ec568437 100644 --- a/packages/utils/src/lib/execute-process.ts +++ b/packages/utils/src/lib/execute-process.ts @@ -138,6 +138,7 @@ export function executeProcess(cfg: ProcessConfig): Promise { const start = performance.now(); return new Promise((resolve, reject) => { + // @TODO add logging `Spawn process ${command} with args ${args?.join(' ')}` // shell:true tells Windows to use shell command for spawning a child process const process = spawn(command, args, { cwd, shell: true }); // eslint-disable-next-line functional/no-let diff --git a/packages/utils/src/lib/git.integration.test.ts b/packages/utils/src/lib/git.integration.test.ts index ebddf6e37..76d955ea8 100644 --- a/packages/utils/src/lib/git.integration.test.ts +++ b/packages/utils/src/lib/git.integration.test.ts @@ -1,7 +1,7 @@ -import { mkdir, rm, writeFile } from 'node:fs/promises'; +import { mkdir, rm, stat, writeFile } from 'node:fs/promises'; import { join } from 'node:path'; import { type SimpleGit, simpleGit } from 'simple-git'; -import { expect } from 'vitest'; +import { beforeAll, beforeEach, expect } from 'vitest'; import { getCurrentBranchOrTag, getGitRoot, @@ -12,48 +12,65 @@ import { } from './git'; import { toUnixPath } from './transform'; -describe('git utils in a git repo with a branch and commits', () => { - const baseDir = join(process.cwd(), 'tmp', 'testing-git-repo'); - const changesDir = join(baseDir, 'changes-dir'); - let git: SimpleGit; +describe('git utils in a git repo without a branch and commits', () => { + const baseDir = join( + process.cwd(), + 'tmp', + 'testing-git-repo-without-branch-and-commits', + ); + let emptyGit: SimpleGit; beforeAll(async () => { await mkdir(baseDir, { recursive: true }); - await writeFile(join(baseDir, 'README.md'), '# hello-world\n'); - - git = simpleGit(baseDir); - await git.init(); - - await git.addConfig('user.name', 'John Doe'); - await git.addConfig('user.email', 'john.doe@example.com'); - - await git.add('README.md'); - await git.commit('Create README'); - - await git.checkout(['master']); + emptyGit = simpleGit(baseDir); + await emptyGit.init(); }); afterAll(async () => { await rm(baseDir, { recursive: true, force: true }); }); - beforeEach(async () => { - await git.checkout(['-b', 'feature-branch']); - await git.checkout(['master']); + it('getCurrentBranchOrTag should throw if no branch or tag is given', async () => { + await expect(getCurrentBranchOrTag(emptyGit)).rejects.toThrow( + 'Could not get current tag or branch.', + ); }); +}); - afterEach(async () => { - // @TODO try why restore/stash/clean/reset hard etc does not work - await rm(changesDir, { recursive: true, force: true }); - await git.checkout(['master']); - await git.deleteLocalBranch('feature-branch'); +describe('git utils in a git repo with a branch and commits clean', () => { + const baseDir = join( + process.cwd(), + 'tmp', + 'testing-git-repo-with-branch-and-commits-clean', + ); + let intiGit: SimpleGit; + + beforeAll(async () => { + await mkdir(baseDir, { recursive: true }); + + intiGit = simpleGit(baseDir); + await intiGit.init(); + + await intiGit.addConfig('user.name', 'John Doe'); + await intiGit.addConfig('user.email', 'john.doe@example.com'); + + await writeFile(join(baseDir, 'README.md'), '# hello-world\n'); + await intiGit.add('README.md'); + await intiGit.commit('Create README'); + + await intiGit.branch(['feature-branch']); + await intiGit.checkout(['master']); + }); + + afterAll(async () => { + await rm(baseDir, { recursive: true, force: true }); }); it('should log latest commit', async () => { const gitCommitDateRegex = /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{1,2} \d{2}:\d{2}:\d{2} \d{4} [+|-]\d{4}$/; - await expect(getLatestCommit(git)).resolves.toEqual({ + await expect(getLatestCommit(intiGit)).resolves.toEqual({ hash: expect.stringMatching(/^[\da-f]{40}$/), message: 'Create README', author: 'John Doe', @@ -62,99 +79,122 @@ describe('git utils in a git repo with a branch and commits', () => { }); it('should find Git root', async () => { - await expect(getGitRoot(git)).resolves.toBe(toUnixPath(baseDir)); + await expect(getGitRoot(intiGit)).resolves.toBe(toUnixPath(baseDir)); }); it('should convert absolute path to relative Git path', async () => { await expect( - toGitPath(join(baseDir, 'src', 'utils.ts'), git), + toGitPath(join(baseDir, 'src', 'utils.ts'), intiGit), ).resolves.toBe('src/utils.ts'); }); it('should convert relative Windows path to relative Git path', async () => { - await expect(toGitPath('Backend\\API\\Startup.cs', git)).resolves.toBe( + await expect(toGitPath('Backend\\API\\Startup.cs', intiGit)).resolves.toBe( '../../Backend/API/Startup.cs', ); }); it('should keep relative Unix path as is (already a Git path)', async () => { - await expect(toGitPath('Backend/API/Startup.cs', git)).resolves.toBe( + await expect(toGitPath('Backend/API/Startup.cs', intiGit)).resolves.toBe( '../../Backend/API/Startup.cs', ); }); - it('guardAgainstLocalChanges should throw if history is dirty', async () => { - await mkdir(changesDir, { recursive: true }); - await writeFile(join(changesDir, 'change.md'), '# hello-change\n'); - await expect(guardAgainstLocalChanges(git)).rejects.toThrow( - 'Working directory needs to be clean before we you can proceed. Commit your local changes or stash them.', - ); + it('getCurrentBranchOrTag should log current branch', async () => { + await expect(getCurrentBranchOrTag(intiGit)).resolves.toBe('master'); }); it('guardAgainstLocalChanges should not throw if history is clean', async () => { - await expect(guardAgainstLocalChanges(git)).resolves.toBeUndefined(); + await expect(guardAgainstLocalChanges(intiGit)).resolves.toBeUndefined(); }); - it('safeCheckout should checkout target branch in clean state', async () => { - await expect(git.branch()).resolves.toEqual( - expect.objectContaining({ current: 'master' }), - ); + it('safeCheckout should checkout feature-branch in clean state', async () => { await expect( - safeCheckout('feature-branch', {}, git), + safeCheckout('feature-branch', {}, intiGit), ).resolves.toBeUndefined(); - await expect(git.branch()).resolves.toEqual( + await expect(intiGit.branch()).resolves.toEqual( expect.objectContaining({ current: 'feature-branch' }), ); }); - it('safeCheckout should throw if history is dirty', async () => { - await mkdir(changesDir, { recursive: true }); - await writeFile(join(changesDir, 'change.md'), '# hello-change\n'); - await expect(safeCheckout('master', {}, git)).rejects.toThrow( - 'Working directory needs to be clean before we you can proceed. Commit your local changes or stash them.', - ); - }); - - it('safeCheckout should clean local changes and check out to feature-branch', async () => { - // needs to get reset to be clean - await mkdir(changesDir, { recursive: true }); - await writeFile(join(changesDir, 'change.md'), '# hello-change\n'); - // needs to get cleaned to be clean - await writeFile(join(baseDir, 'README.md'), '# hello-world-2\n'); - + it('safeCheckout should throw if a given branch does not exist', async () => { await expect( - safeCheckout('feature-branch', { forceCleanStatus: true }, git), - ).resolves.toBeUndefined(); - await expect(git.branch()).resolves.toEqual( - expect.objectContaining({ current: 'feature-branch' }), - ); - await expect(git.status()).resolves.toEqual( - expect.objectContaining({ files: [] }), + safeCheckout('non-existing-branch', {}, intiGit), + ).rejects.toThrow( + "pathspec 'non-existing-branch' did not match any file(s) known to git", ); }); - - it('getCurrentBranchOrTag should log current branch', async () => { - await expect(getCurrentBranchOrTag(git)).resolves.toBe('master'); - }); }); -describe('git utils in a git repo without a branch and commits', () => { - const baseDir = join(process.cwd(), 'tmp', 'testing-git-repo'); - let git: SimpleGit; +describe('git utils in a git repo with a branch and commits dirty', () => { + const baseDir = join( + process.cwd(), + 'tmp', + 'testing-git-repo-with-branch-and-commits-dirty', + ); + const newFilePath = join(baseDir, 'new-file.md'); + let dirtyGt: SimpleGit; beforeAll(async () => { await mkdir(baseDir, { recursive: true }); - git = simpleGit(baseDir); - await git.init(); + + dirtyGt = simpleGit(baseDir); + await dirtyGt.init(); + + await dirtyGt.addConfig('user.name', 'John Doe'); + await dirtyGt.addConfig('user.email', 'john.doe@example.com'); + + await dirtyGt.addConfig('user.name', 'John Doe'); + await dirtyGt.addConfig('user.email', 'john.doe@example.com'); + + await writeFile(join(baseDir, 'README.md'), '# hello-world\n'); + await dirtyGt.add('README.md'); + await dirtyGt.commit('Create README'); + + await dirtyGt.branch(['feature-branch']); + await dirtyGt.checkout(['master']); + }); + + beforeEach(async () => { + await writeFile(newFilePath, '# New File\n'); + }); + + afterEach(async () => { + try { + const s = await stat(newFilePath); + if (s.isFile()) { + await rm(newFilePath); + } + } catch { + // file not present (already cleaned) + } }); afterAll(async () => { await rm(baseDir, { recursive: true, force: true }); }); - it('getCurrentBranchOrTag should throw if no branch is given', async () => { - await expect(getCurrentBranchOrTag(git)).rejects.toThrow( - 'Could not get current tag or branch.', + it('guardAgainstLocalChanges should throw if history is dirty', async () => { + await expect(guardAgainstLocalChanges(dirtyGt)).rejects.toThrow( + 'Working directory needs to be clean before we you can proceed. Commit your local changes or stash them.', + ); + }); + + it('safeCheckout should throw if history is dirty', async () => { + await expect(safeCheckout('master', {}, dirtyGt)).rejects.toThrow( + 'Working directory needs to be clean before we you can proceed. Commit your local changes or stash them.', + ); + }); + + it('safeCheckout should clean local changes and check out to feature-branch', async () => { + await expect( + safeCheckout('feature-branch', { forceCleanStatus: true }, dirtyGt), + ).resolves.toBeUndefined(); + await expect(dirtyGt.branch()).resolves.toEqual( + expect.objectContaining({ current: 'feature-branch' }), + ); + await expect(dirtyGt.status()).resolves.toEqual( + expect.objectContaining({ files: [] }), ); }); }); From cde964d24715c2c6d03173afe4f472e4ed2337bd Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 2 Mar 2024 13:18:04 +0100 Subject: [PATCH 17/75] test(utils): move git tests folder out of tmp --- .../utils/src/lib/git.integration.test.ts | 39 +++++++++---------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/packages/utils/src/lib/git.integration.test.ts b/packages/utils/src/lib/git.integration.test.ts index 76d955ea8..578c58b37 100644 --- a/packages/utils/src/lib/git.integration.test.ts +++ b/packages/utils/src/lib/git.integration.test.ts @@ -12,10 +12,13 @@ import { } from './git'; import { toUnixPath } from './transform'; +// we need a separate folder that is not cleaned in `global-setup.ts`, otherwise the tests can't execute in parallel +const gitTestFolder = 'git-test'; + describe('git utils in a git repo without a branch and commits', () => { const baseDir = join( process.cwd(), - 'tmp', + gitTestFolder, 'testing-git-repo-without-branch-and-commits', ); let emptyGit: SimpleGit; @@ -40,7 +43,7 @@ describe('git utils in a git repo without a branch and commits', () => { describe('git utils in a git repo with a branch and commits clean', () => { const baseDir = join( process.cwd(), - 'tmp', + gitTestFolder, 'testing-git-repo-with-branch-and-commits-clean', ); let intiGit: SimpleGit; @@ -129,7 +132,7 @@ describe('git utils in a git repo with a branch and commits clean', () => { describe('git utils in a git repo with a branch and commits dirty', () => { const baseDir = join( process.cwd(), - 'tmp', + gitTestFolder, 'testing-git-repo-with-branch-and-commits-dirty', ); const newFilePath = join(baseDir, 'new-file.md'); @@ -141,12 +144,6 @@ describe('git utils in a git repo with a branch and commits dirty', () => { dirtyGt = simpleGit(baseDir); await dirtyGt.init(); - await dirtyGt.addConfig('user.name', 'John Doe'); - await dirtyGt.addConfig('user.email', 'john.doe@example.com'); - - await dirtyGt.addConfig('user.name', 'John Doe'); - await dirtyGt.addConfig('user.email', 'john.doe@example.com'); - await writeFile(join(baseDir, 'README.md'), '# hello-world\n'); await dirtyGt.add('README.md'); await dirtyGt.commit('Create README'); @@ -174,18 +171,6 @@ describe('git utils in a git repo with a branch and commits dirty', () => { await rm(baseDir, { recursive: true, force: true }); }); - it('guardAgainstLocalChanges should throw if history is dirty', async () => { - await expect(guardAgainstLocalChanges(dirtyGt)).rejects.toThrow( - 'Working directory needs to be clean before we you can proceed. Commit your local changes or stash them.', - ); - }); - - it('safeCheckout should throw if history is dirty', async () => { - await expect(safeCheckout('master', {}, dirtyGt)).rejects.toThrow( - 'Working directory needs to be clean before we you can proceed. Commit your local changes or stash them.', - ); - }); - it('safeCheckout should clean local changes and check out to feature-branch', async () => { await expect( safeCheckout('feature-branch', { forceCleanStatus: true }, dirtyGt), @@ -197,4 +182,16 @@ describe('git utils in a git repo with a branch and commits dirty', () => { expect.objectContaining({ files: [] }), ); }); + + it('safeCheckout should throw if history is dirty', async () => { + await expect(safeCheckout('master', {}, dirtyGt)).rejects.toThrow( + 'Working directory needs to be clean before we you can proceed. Commit your local changes or stash them.', + ); + }); + + it('guardAgainstLocalChanges should throw if history is dirty', async () => { + await expect(guardAgainstLocalChanges(dirtyGt)).rejects.toThrow( + 'Working directory needs to be clean before we you can proceed. Commit your local changes or stash them.', + ); + }); }); From 974a724ee8c504ea4871efaf390b177a65ef9060 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 2 Mar 2024 13:25:13 +0100 Subject: [PATCH 18/75] test(utils): add config --- packages/utils/src/lib/git.integration.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/utils/src/lib/git.integration.test.ts b/packages/utils/src/lib/git.integration.test.ts index 578c58b37..874fb48e4 100644 --- a/packages/utils/src/lib/git.integration.test.ts +++ b/packages/utils/src/lib/git.integration.test.ts @@ -143,6 +143,8 @@ describe('git utils in a git repo with a branch and commits dirty', () => { dirtyGt = simpleGit(baseDir); await dirtyGt.init(); + await dirtyGt.addConfig('user.name', 'John Doe'); + await dirtyGt.addConfig('user.email', 'john.doe@example.com'); await writeFile(join(baseDir, 'README.md'), '# hello-world\n'); await dirtyGt.add('README.md'); From 09fc11bf55799691170b2c1396ea28597bb09e45 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 2 Mar 2024 18:48:34 +0100 Subject: [PATCH 19/75] wip --- .../src/lib/implementation/execute-plugin.ts | 5 +- ...it.test.ts => execute-plugin.unit-test.ts} | 6 +- .../lib/implementation/persist.unit.test.ts | 84 +++++++++++-------- packages/core/vite.config.unit.ts | 1 - .../log-stdout-summary.integration.test.ts | 9 +- packages/utils/vite.config.unit.ts | 1 - testing/test-setup/src/lib/cliui.mock.ts | 9 -- 7 files changed, 61 insertions(+), 54 deletions(-) rename packages/core/src/lib/implementation/{execute-plugin.unit.test.ts => execute-plugin.unit-test.ts} (98%) delete mode 100644 testing/test-setup/src/lib/cliui.mock.ts diff --git a/packages/core/src/lib/implementation/execute-plugin.ts b/packages/core/src/lib/implementation/execute-plugin.ts index 89cdaff2f..6633889d4 100644 --- a/packages/core/src/lib/implementation/execute-plugin.ts +++ b/packages/core/src/lib/implementation/execute-plugin.ts @@ -142,8 +142,9 @@ export async function executePlugins( progressBar?.endProgress('Done running plugins'); - const errorsCallback = ({ reason }: PromiseRejectedResult) => - reason as string; + const errorsCallback = ({ reason }: PromiseRejectedResult) => { + console.error(reason); + }; const results = await Promise.allSettled(pluginsResult); logMultipleResults(results, 'Plugins', undefined, errorsCallback); diff --git a/packages/core/src/lib/implementation/execute-plugin.unit.test.ts b/packages/core/src/lib/implementation/execute-plugin.unit-test.ts similarity index 98% rename from packages/core/src/lib/implementation/execute-plugin.unit.test.ts rename to packages/core/src/lib/implementation/execute-plugin.unit-test.ts index b9f3d5ade..f1ad1d0ea 100644 --- a/packages/core/src/lib/implementation/execute-plugin.unit.test.ts +++ b/packages/core/src/lib/implementation/execute-plugin.unit-test.ts @@ -1,5 +1,5 @@ import { vol } from 'memfs'; -import { describe, expect, it } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; import { AuditOutputs, PluginConfig } from '@code-pushup/models'; import { MEMFS_VOLUME, @@ -49,8 +49,8 @@ describe('executePlugin', () => { runner: () => [ { slug: 'node-version', - score: 0.3, - value: 16, + score: 0.1, + value: 1, }, ], }); diff --git a/packages/core/src/lib/implementation/persist.unit.test.ts b/packages/core/src/lib/implementation/persist.unit.test.ts index dd433c531..f5844d226 100644 --- a/packages/core/src/lib/implementation/persist.unit.test.ts +++ b/packages/core/src/lib/implementation/persist.unit.test.ts @@ -8,7 +8,6 @@ import { MINIMAL_REPORT_MOCK, REPORT_MOCK, } from '@code-pushup/test-utils'; -import { ui } from '@code-pushup/utils'; import { logPersistedResults, persistReport } from './persist'; describe('persistReport', () => { @@ -16,33 +15,24 @@ describe('persistReport', () => { vol.fromJSON({}, MEMFS_VOLUME); }); - it('should print a summary to stdout when no format is specified', async () => { + it('should print a summary to stdout when no format is specified`', async () => { await persistReport(MINIMAL_REPORT_MOCK, { outputDir: MEMFS_VOLUME, filename: 'report', format: [], }); - const logs = ui() - .logger.getRenderer() - .getLogs() - .map(({ message }) => message); - expect(logs.at(-1)).toEqual( + expect(console.info).toHaveBeenCalledWith( expect.stringContaining('Made with ❤ by code-pushup.dev'), ); }); - it('should print a summary to stdout when all formats are specified', async () => { + it('should print a summary to stdout when all formats are specified`', async () => { await persistReport(MINIMAL_REPORT_MOCK, { outputDir: MEMFS_VOLUME, filename: 'report', format: ['md', 'json'], }); - const logs = ui() - .logger.getRenderer() - .getLogs() - .map(({ message }) => message); - - expect(logs.at(-1)).toEqual( + expect(console.info).toHaveBeenCalledWith( expect.stringContaining('Made with ❤ by code-pushup.dev'), ); }); @@ -110,23 +100,31 @@ describe('persistReport', () => { describe('logPersistedResults', () => { it('should log report sizes correctly`', () => { logPersistedResults([{ status: 'fulfilled', value: ['out.json', 10_000] }]); - const logs = ui() - .logger.getRenderer() - .getLogs() - .map(({ message }) => message); - expect(logs[0]).toBe('[ blue(info) ] Generated reports successfully: '); - expect(logs[1]).toContain('9.77 kB'); - expect(logs[1]).toContain('out.json'); + expect(console.info).toHaveBeenNthCalledWith( + 1, + 'Generated reports successfully: ', + ); + expect(console.info).toHaveBeenNthCalledWith( + 2, + expect.stringContaining('9.77 kB'), + ); + expect(console.info).toHaveBeenNthCalledWith( + 2, + expect.stringContaining('out.json'), + ); }); it('should log fails correctly`', () => { logPersistedResults([{ status: 'rejected', reason: 'fail' }]); - const logs = ui() - .logger.getRenderer() - .getLogs() - .map(({ message }) => message); - expect(logs[0]).toBe('[ yellow(warn) ] Generated reports failed: '); - expect(logs[1]).toContain('fail'); + + expect(console.warn).toHaveBeenNthCalledWith( + 1, + 'Generated reports failed: ', + ); + expect(console.warn).toHaveBeenNthCalledWith( + 2, + expect.stringContaining('fail'), + ); }); it('should log report sizes and fails correctly`', () => { @@ -134,15 +132,27 @@ describe('logPersistedResults', () => { { status: 'fulfilled', value: ['out.json', 10_000] }, { status: 'rejected', reason: 'fail' }, ]); - const logs = ui() - .logger.getRenderer() - .getLogs() - .map(({ message }) => message); - expect(logs[0]).toBe('[ blue(info) ] Generated reports successfully: '); - expect(logs[1]).toContain('out.json'); - expect(logs[1]).toContain('9.77 kB'); - - expect(logs[2]).toBe('[ yellow(warn) ] Generated reports failed: '); - expect(logs[3]).toContain('fail'); + + expect(console.info).toHaveBeenNthCalledWith( + 1, + 'Generated reports successfully: ', + ); + expect(console.info).toHaveBeenNthCalledWith( + 2, + expect.stringContaining('out.json'), + ); + expect(console.info).toHaveBeenNthCalledWith( + 2, + expect.stringContaining('9.77 kB'), + ); + + expect(console.warn).toHaveBeenNthCalledWith( + 1, + 'Generated reports failed: ', + ); + expect(console.warn).toHaveBeenNthCalledWith( + 2, + expect.stringContaining('fail'), + ); }); }); diff --git a/packages/core/vite.config.unit.ts b/packages/core/vite.config.unit.ts index 36708b782..fdc426cf4 100644 --- a/packages/core/vite.config.unit.ts +++ b/packages/core/vite.config.unit.ts @@ -22,7 +22,6 @@ export default defineConfig({ '../../testing/test-setup/src/lib/console.mock.ts', '../../testing/test-setup/src/lib/reset.mocks.ts', '../../testing/test-setup/src/lib/portal-client.mock.ts', - '../../testing/test-setup/src/lib/cliui.mock.ts', ], }, }); diff --git a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts index 4dcd50b16..1cf58834a 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts @@ -1,4 +1,4 @@ -import { describe } from 'vitest'; +import { beforeAll, beforeEach, describe } from 'vitest'; import { reportMock } from '@code-pushup/test-utils'; import { ui } from '../logging'; import { logStdoutSummary } from './log-stdout-summary'; @@ -6,6 +6,13 @@ import { scoreReport } from './scoring'; import { sortReport } from './sorting'; describe('logStdoutSummary', () => { + beforeAll(() => { + ui().switchMode('raw'); + }); + beforeEach(() => { + ui().logger.flushLogs(); + }); + it('should contain all sections when using the fixture report', () => { logStdoutSummary(sortReport(scoreReport(reportMock()))); const output = ui() diff --git a/packages/utils/vite.config.unit.ts b/packages/utils/vite.config.unit.ts index c67fdc960..dc72c0ac0 100644 --- a/packages/utils/vite.config.unit.ts +++ b/packages/utils/vite.config.unit.ts @@ -20,7 +20,6 @@ export default defineConfig({ '../../testing/test-setup/src/lib/fs.mock.ts', '../../testing/test-setup/src/lib/console.mock.ts', '../../testing/test-setup/src/lib/reset.mocks.ts', - '../../testing/test-setup/src/lib/cliui.mock.ts', ], }, }); diff --git a/testing/test-setup/src/lib/cliui.mock.ts b/testing/test-setup/src/lib/cliui.mock.ts deleted file mode 100644 index 22be59e06..000000000 --- a/testing/test-setup/src/lib/cliui.mock.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { beforeAll, beforeEach } from 'vitest'; -import { ui } from '@code-pushup/utils'; - -beforeAll(() => { - ui().switchMode('raw'); -}); -beforeEach(() => { - ui().logger.flushLogs(); -}); From 76aefb4b74fb12cc3f5ea30eeda2de160031d1eb Mon Sep 17 00:00:00 2001 From: Katerina Pilatova Date: Mon, 4 Mar 2024 11:06:24 +0100 Subject: [PATCH 20/75] test: use nested describe within tmp folder --- .../utils/src/lib/git.integration.test.ts | 301 +++++++++--------- 1 file changed, 150 insertions(+), 151 deletions(-) diff --git a/packages/utils/src/lib/git.integration.test.ts b/packages/utils/src/lib/git.integration.test.ts index 874fb48e4..0a36cfa0c 100644 --- a/packages/utils/src/lib/git.integration.test.ts +++ b/packages/utils/src/lib/git.integration.test.ts @@ -12,188 +12,187 @@ import { } from './git'; import { toUnixPath } from './transform'; -// we need a separate folder that is not cleaned in `global-setup.ts`, otherwise the tests can't execute in parallel -const gitTestFolder = 'git-test'; - -describe('git utils in a git repo without a branch and commits', () => { - const baseDir = join( - process.cwd(), - gitTestFolder, - 'testing-git-repo-without-branch-and-commits', - ); - let emptyGit: SimpleGit; - - beforeAll(async () => { - await mkdir(baseDir, { recursive: true }); - emptyGit = simpleGit(baseDir); - await emptyGit.init(); - }); +describe('git helper tests', () => { + describe('git utils in a git repo without a branch and commits', () => { + const baseDir = join( + process.cwd(), + 'tmp', + 'testing-git-repo-without-branch-and-commits', + ); + let emptyGit: SimpleGit; + + beforeAll(async () => { + await mkdir(baseDir, { recursive: true }); + emptyGit = simpleGit(baseDir); + await emptyGit.init(); + }); - afterAll(async () => { - await rm(baseDir, { recursive: true, force: true }); + afterAll(async () => { + await rm(baseDir, { recursive: true, force: true }); + }); + + it('getCurrentBranchOrTag should throw if no branch or tag is given', async () => { + await expect(getCurrentBranchOrTag(emptyGit)).rejects.toThrow( + 'Could not get current tag or branch.', + ); + }); }); - it('getCurrentBranchOrTag should throw if no branch or tag is given', async () => { - await expect(getCurrentBranchOrTag(emptyGit)).rejects.toThrow( - 'Could not get current tag or branch.', + describe('git utils in a git repo with a branch and commits clean', () => { + const baseDir = join( + process.cwd(), + 'tmp', + 'testing-git-repo-with-branch-and-commits-clean', ); - }); -}); + let cleanGit: SimpleGit; -describe('git utils in a git repo with a branch and commits clean', () => { - const baseDir = join( - process.cwd(), - gitTestFolder, - 'testing-git-repo-with-branch-and-commits-clean', - ); - let intiGit: SimpleGit; + beforeAll(async () => { + await mkdir(baseDir, { recursive: true }); - beforeAll(async () => { - await mkdir(baseDir, { recursive: true }); + cleanGit = simpleGit(baseDir); + await cleanGit.init(); - intiGit = simpleGit(baseDir); - await intiGit.init(); + await cleanGit.addConfig('user.name', 'John Doe'); + await cleanGit.addConfig('user.email', 'john.doe@example.com'); - await intiGit.addConfig('user.name', 'John Doe'); - await intiGit.addConfig('user.email', 'john.doe@example.com'); + await writeFile(join(baseDir, 'README.md'), '# hello-world\n'); + await cleanGit.add('README.md'); + await cleanGit.commit('Create README'); - await writeFile(join(baseDir, 'README.md'), '# hello-world\n'); - await intiGit.add('README.md'); - await intiGit.commit('Create README'); + await cleanGit.branch(['feature-branch']); + await cleanGit.checkout(['master']); + }); - await intiGit.branch(['feature-branch']); - await intiGit.checkout(['master']); - }); + afterAll(async () => { + await rm(baseDir, { recursive: true, force: true }); + }); - afterAll(async () => { - await rm(baseDir, { recursive: true, force: true }); - }); + it('should log latest commit', async () => { + const gitCommitDateRegex = + /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{1,2} \d{2}:\d{2}:\d{2} \d{4} [+|-]\d{4}$/; - it('should log latest commit', async () => { - const gitCommitDateRegex = - /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{1,2} \d{2}:\d{2}:\d{2} \d{4} [+|-]\d{4}$/; + await expect(getLatestCommit(cleanGit)).resolves.toEqual({ + hash: expect.stringMatching(/^[\da-f]{40}$/), + message: 'Create README', + author: 'John Doe', + date: expect.stringMatching(gitCommitDateRegex), + }); + }); - await expect(getLatestCommit(intiGit)).resolves.toEqual({ - hash: expect.stringMatching(/^[\da-f]{40}$/), - message: 'Create README', - author: 'John Doe', - date: expect.stringMatching(gitCommitDateRegex), + it('should find Git root', async () => { + await expect(getGitRoot(cleanGit)).resolves.toBe(toUnixPath(baseDir)); }); - }); - it('should find Git root', async () => { - await expect(getGitRoot(intiGit)).resolves.toBe(toUnixPath(baseDir)); - }); + it('should convert absolute path to relative Git path', async () => { + await expect( + toGitPath(join(baseDir, 'src', 'utils.ts'), cleanGit), + ).resolves.toBe('src/utils.ts'); + }); - it('should convert absolute path to relative Git path', async () => { - await expect( - toGitPath(join(baseDir, 'src', 'utils.ts'), intiGit), - ).resolves.toBe('src/utils.ts'); - }); + it('should convert relative Windows path to relative Git path', async () => { + await expect( + toGitPath('Backend\\API\\Startup.cs', cleanGit), + ).resolves.toBe('../../Backend/API/Startup.cs'); + }); - it('should convert relative Windows path to relative Git path', async () => { - await expect(toGitPath('Backend\\API\\Startup.cs', intiGit)).resolves.toBe( - '../../Backend/API/Startup.cs', - ); - }); + it('should keep relative Unix path as is (already a Git path)', async () => { + await expect(toGitPath('Backend/API/Startup.cs', cleanGit)).resolves.toBe( + '../../Backend/API/Startup.cs', + ); + }); - it('should keep relative Unix path as is (already a Git path)', async () => { - await expect(toGitPath('Backend/API/Startup.cs', intiGit)).resolves.toBe( - '../../Backend/API/Startup.cs', - ); - }); + it('getCurrentBranchOrTag should log current branch', async () => { + await expect(getCurrentBranchOrTag(cleanGit)).resolves.toBe('master'); + }); - it('getCurrentBranchOrTag should log current branch', async () => { - await expect(getCurrentBranchOrTag(intiGit)).resolves.toBe('master'); - }); + it('guardAgainstLocalChanges should not throw if history is clean', async () => { + await expect(guardAgainstLocalChanges(cleanGit)).resolves.toBeUndefined(); + }); - it('guardAgainstLocalChanges should not throw if history is clean', async () => { - await expect(guardAgainstLocalChanges(intiGit)).resolves.toBeUndefined(); - }); + it('safeCheckout should checkout feature-branch in clean state', async () => { + await expect( + safeCheckout('feature-branch', {}, cleanGit), + ).resolves.toBeUndefined(); + await expect(cleanGit.branch()).resolves.toEqual( + expect.objectContaining({ current: 'feature-branch' }), + ); + }); - it('safeCheckout should checkout feature-branch in clean state', async () => { - await expect( - safeCheckout('feature-branch', {}, intiGit), - ).resolves.toBeUndefined(); - await expect(intiGit.branch()).resolves.toEqual( - expect.objectContaining({ current: 'feature-branch' }), - ); + it('safeCheckout should throw if a given branch does not exist', async () => { + await expect( + safeCheckout('non-existing-branch', {}, cleanGit), + ).rejects.toThrow( + "pathspec 'non-existing-branch' did not match any file(s) known to git", + ); + }); }); - it('safeCheckout should throw if a given branch does not exist', async () => { - await expect( - safeCheckout('non-existing-branch', {}, intiGit), - ).rejects.toThrow( - "pathspec 'non-existing-branch' did not match any file(s) known to git", + describe('git utils in a git repo with a branch and commits dirty', () => { + const baseDir = join( + process.cwd(), + 'tmp', + 'testing-git-repo-with-branch-and-commits-dirty', ); - }); -}); + const newFilePath = join(baseDir, 'new-file.md'); + let dirtyGit: SimpleGit; -describe('git utils in a git repo with a branch and commits dirty', () => { - const baseDir = join( - process.cwd(), - gitTestFolder, - 'testing-git-repo-with-branch-and-commits-dirty', - ); - const newFilePath = join(baseDir, 'new-file.md'); - let dirtyGt: SimpleGit; - - beforeAll(async () => { - await mkdir(baseDir, { recursive: true }); - - dirtyGt = simpleGit(baseDir); - await dirtyGt.init(); - await dirtyGt.addConfig('user.name', 'John Doe'); - await dirtyGt.addConfig('user.email', 'john.doe@example.com'); - - await writeFile(join(baseDir, 'README.md'), '# hello-world\n'); - await dirtyGt.add('README.md'); - await dirtyGt.commit('Create README'); - - await dirtyGt.branch(['feature-branch']); - await dirtyGt.checkout(['master']); - }); + beforeAll(async () => { + await mkdir(baseDir, { recursive: true }); - beforeEach(async () => { - await writeFile(newFilePath, '# New File\n'); - }); + dirtyGit = simpleGit(baseDir); + await dirtyGit.init(); + await dirtyGit.addConfig('user.name', 'John Doe'); + await dirtyGit.addConfig('user.email', 'john.doe@example.com'); + + await writeFile(join(baseDir, 'README.md'), '# hello-world\n'); + await dirtyGit.add('README.md'); + await dirtyGit.commit('Create README'); + + await dirtyGit.branch(['feature-branch']); + await dirtyGit.checkout(['master']); + }); + + beforeEach(async () => { + await writeFile(newFilePath, '# New File\n'); + }); - afterEach(async () => { - try { - const s = await stat(newFilePath); - if (s.isFile()) { - await rm(newFilePath); + afterEach(async () => { + try { + const s = await stat(newFilePath); + if (s.isFile()) { + await rm(newFilePath); + } + } catch { + // file not present (already cleaned) } - } catch { - // file not present (already cleaned) - } - }); + }); - afterAll(async () => { - await rm(baseDir, { recursive: true, force: true }); - }); + afterAll(async () => { + await rm(baseDir, { recursive: true, force: true }); + }); - it('safeCheckout should clean local changes and check out to feature-branch', async () => { - await expect( - safeCheckout('feature-branch', { forceCleanStatus: true }, dirtyGt), - ).resolves.toBeUndefined(); - await expect(dirtyGt.branch()).resolves.toEqual( - expect.objectContaining({ current: 'feature-branch' }), - ); - await expect(dirtyGt.status()).resolves.toEqual( - expect.objectContaining({ files: [] }), - ); - }); + it('safeCheckout should clean local changes and check out to feature-branch', async () => { + await expect( + safeCheckout('feature-branch', { forceCleanStatus: true }, dirtyGit), + ).resolves.toBeUndefined(); + await expect(dirtyGit.branch()).resolves.toEqual( + expect.objectContaining({ current: 'feature-branch' }), + ); + await expect(dirtyGit.status()).resolves.toEqual( + expect.objectContaining({ files: [] }), + ); + }); - it('safeCheckout should throw if history is dirty', async () => { - await expect(safeCheckout('master', {}, dirtyGt)).rejects.toThrow( - 'Working directory needs to be clean before we you can proceed. Commit your local changes or stash them.', - ); - }); + it('safeCheckout should throw if history is dirty', async () => { + await expect(safeCheckout('master', {}, dirtyGit)).rejects.toThrow( + 'Working directory needs to be clean before we you can proceed. Commit your local changes or stash them.', + ); + }); - it('guardAgainstLocalChanges should throw if history is dirty', async () => { - await expect(guardAgainstLocalChanges(dirtyGt)).rejects.toThrow( - 'Working directory needs to be clean before we you can proceed. Commit your local changes or stash them.', - ); + it('guardAgainstLocalChanges should throw if history is dirty', async () => { + await expect(guardAgainstLocalChanges(dirtyGit)).rejects.toThrow( + 'Working directory needs to be clean before we you can proceed. Commit your local changes or stash them.', + ); + }); }); }); From 0f8aee3820aa0e2dbadceceba74181ffa91052b7 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 6 Mar 2024 15:48:35 +0100 Subject: [PATCH 21/75] refactor(utils): fix tests --- packages/utils/mocks/setup/cliui.mock.ts | 13 +++++++++++++ packages/utils/src/lib/log-results.ts | 2 +- packages/utils/src/lib/log-results.unit.test.ts | 4 ++-- packages/utils/vite.config.unit.ts | 1 + 4 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 packages/utils/mocks/setup/cliui.mock.ts diff --git a/packages/utils/mocks/setup/cliui.mock.ts b/packages/utils/mocks/setup/cliui.mock.ts new file mode 100644 index 000000000..4011a2910 --- /dev/null +++ b/packages/utils/mocks/setup/cliui.mock.ts @@ -0,0 +1,13 @@ +import {afterEach, vi} from "vitest"; +import {ui} from "../../src/lib/logging"; + +vi.mock('../../src/lib/logging', async () => { + const module = await vi.importActual('../../src/lib/logging'); + + module.ui().switchMode('raw') + return module; +}); + +afterEach(() => { + ui().logger.flushLogs(); +}) diff --git a/packages/utils/src/lib/log-results.ts b/packages/utils/src/lib/log-results.ts index e668d2a4c..04bd028aa 100644 --- a/packages/utils/src/lib/log-results.ts +++ b/packages/utils/src/lib/log-results.ts @@ -35,7 +35,7 @@ export function logPromiseResults< const log = results[0]?.status === 'fulfilled' ? (m: string) => { - ui().logger.info(m); + ui().logger.success(m); } : (m: string) => { ui().logger.warning(m); diff --git a/packages/utils/src/lib/log-results.unit.test.ts b/packages/utils/src/lib/log-results.unit.test.ts index 250ca019d..d036938da 100644 --- a/packages/utils/src/lib/log-results.unit.test.ts +++ b/packages/utils/src/lib/log-results.unit.test.ts @@ -71,8 +71,8 @@ describe('logPromiseResults', () => { .logger.getRenderer() .getLogs() .map(({ message }) => message); - expect(logs[0]).toBe('[ blue(info) ] Uploaded reports successfully:'); - expect(logs[1]).toBe('[ blue(info) ] out.json'); + expect(logs[0]).toBe('[ green(success) ] Uploaded reports successfully:'); + expect(logs[1]).toBe('[ green(success) ] out.json'); }); it('should log on fail', () => { diff --git a/packages/utils/vite.config.unit.ts b/packages/utils/vite.config.unit.ts index ebbf224fd..610ba8e69 100644 --- a/packages/utils/vite.config.unit.ts +++ b/packages/utils/vite.config.unit.ts @@ -21,6 +21,7 @@ export default defineConfig({ include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], globalSetup: ['../../global-setup.ts'], setupFiles: [ + './mocks/setup/cliui.mock.ts', '../../testing/test-setup/src/lib/fs.mock.ts', '../../testing/test-setup/src/lib/console.mock.ts', '../../testing/test-setup/src/lib/reset.mocks.ts', From e0b6d6bef1653d7f75515a33f575d561d12eeb1a Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 6 Mar 2024 15:48:54 +0100 Subject: [PATCH 22/75] refactor(core): fix tests in persist --- packages/core/mocks/setup/cliui.mock.ts | 13 ++++ .../lib/implementation/persist.unit.test.ts | 69 +++++++------------ packages/core/vite.config.unit.ts | 1 + 3 files changed, 40 insertions(+), 43 deletions(-) create mode 100644 packages/core/mocks/setup/cliui.mock.ts diff --git a/packages/core/mocks/setup/cliui.mock.ts b/packages/core/mocks/setup/cliui.mock.ts new file mode 100644 index 000000000..178d6ce7d --- /dev/null +++ b/packages/core/mocks/setup/cliui.mock.ts @@ -0,0 +1,13 @@ +import { afterEach, vi } from 'vitest'; +import { ui } from '@code-pushup/utils'; + +vi.mock('@code-pushup/utils', async () => { + const module = await vi.importActual('@code-pushup/utils'); + + module.ui().switchMode('raw'); + return module; +}); + +afterEach(() => { + ui().logger.flushLogs(); +}); diff --git a/packages/core/src/lib/implementation/persist.unit.test.ts b/packages/core/src/lib/implementation/persist.unit.test.ts index f5844d226..7d07bd1a5 100644 --- a/packages/core/src/lib/implementation/persist.unit.test.ts +++ b/packages/core/src/lib/implementation/persist.unit.test.ts @@ -8,6 +8,7 @@ import { MINIMAL_REPORT_MOCK, REPORT_MOCK, } from '@code-pushup/test-utils'; +import { ui } from '@code-pushup/utils'; import { logPersistedResults, persistReport } from './persist'; describe('persistReport', () => { @@ -100,31 +101,23 @@ describe('persistReport', () => { describe('logPersistedResults', () => { it('should log report sizes correctly`', () => { logPersistedResults([{ status: 'fulfilled', value: ['out.json', 10_000] }]); - expect(console.info).toHaveBeenNthCalledWith( - 1, - 'Generated reports successfully: ', - ); - expect(console.info).toHaveBeenNthCalledWith( - 2, - expect.stringContaining('9.77 kB'), - ); - expect(console.info).toHaveBeenNthCalledWith( - 2, - expect.stringContaining('out.json'), - ); + const logs = ui() + .logger.getRenderer() + .getLogs() + .map(({ message }) => message); + expect(logs[0]).toBe('[ green(success) ] Generated reports successfully: '); + expect(logs[1]).toEqual(expect.stringContaining('9.77 kB')); + expect(logs[1]).toEqual(expect.stringContaining('out.json')); }); it('should log fails correctly`', () => { logPersistedResults([{ status: 'rejected', reason: 'fail' }]); - - expect(console.warn).toHaveBeenNthCalledWith( - 1, - 'Generated reports failed: ', - ); - expect(console.warn).toHaveBeenNthCalledWith( - 2, - expect.stringContaining('fail'), - ); + const logs = ui() + .logger.getRenderer() + .getLogs() + .map(({ message }) => message); + expect(logs[0]).toBe('[ yellow(warn) ] Generated reports failed: '); + expect(logs[1]).toEqual(expect.stringContaining('fail')); }); it('should log report sizes and fails correctly`', () => { @@ -132,27 +125,17 @@ describe('logPersistedResults', () => { { status: 'fulfilled', value: ['out.json', 10_000] }, { status: 'rejected', reason: 'fail' }, ]); - - expect(console.info).toHaveBeenNthCalledWith( - 1, - 'Generated reports successfully: ', - ); - expect(console.info).toHaveBeenNthCalledWith( - 2, - expect.stringContaining('out.json'), - ); - expect(console.info).toHaveBeenNthCalledWith( - 2, - expect.stringContaining('9.77 kB'), - ); - - expect(console.warn).toHaveBeenNthCalledWith( - 1, - 'Generated reports failed: ', - ); - expect(console.warn).toHaveBeenNthCalledWith( - 2, - expect.stringContaining('fail'), - ); + const logs = ui() + .logger.getRenderer() + .getLogs() + .map(({ message }) => message); + expect(logs[0]).toBe('[ green(success) ] Generated reports successfully: '); + expect(logs[1]).toEqual(expect.stringContaining('out.json')); + expect(logs[1]).toEqual(expect.stringContaining('9.77 kB')); + + expect(logs[2]).toEqual( + expect.stringContaining('Generated reports failed: '), + ); + expect(logs[2]).toEqual(expect.stringContaining('fail')); }); }); diff --git a/packages/core/vite.config.unit.ts b/packages/core/vite.config.unit.ts index 1b494190a..e847fd2f6 100644 --- a/packages/core/vite.config.unit.ts +++ b/packages/core/vite.config.unit.ts @@ -21,6 +21,7 @@ export default defineConfig({ include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], globalSetup: ['../../global-setup.ts'], setupFiles: [ + './mocks/setup/cliui.mock.ts', '../../testing/test-setup/src/lib/fs.mock.ts', '../../testing/test-setup/src/lib/git.mock.ts', '../../testing/test-setup/src/lib/console.mock.ts', From 58b60f31d087cada714ffe96ef5a20fbc138c2d1 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 7 Mar 2024 19:36:09 +0100 Subject: [PATCH 23/75] refactor: fix tests --- packages/cli/mocks/setup/cliui.mock.ts | 6 + .../only-plugins.utils.unit.test.ts | 14 +- .../print-config-command.unit.test.ts | 11 +- packages/cli/vite.config.unit.ts | 2 +- packages/core/mocks/setup/cliui.mock.ts | 13 -- packages/core/package.json | 4 +- .../execute-plugin.unit-test.ts | 24 +-- .../lib/implementation/persist.unit.test.ts | 28 +++- .../utils/src/lib/git.integration.test.ts | 2 +- .../utils/src/lib/log-results.unit.test.ts | 13 +- ...og-stdout-summary.integration.test.ts.snap | 154 ++++++++++++++++++ .../utils/src/lib/verbose-utils.unit.test.ts | 12 +- packages/utils/vite.config.integration.ts | 1 - packages/utils/vite.config.unit.ts | 1 - 14 files changed, 248 insertions(+), 37 deletions(-) create mode 100644 packages/cli/mocks/setup/cliui.mock.ts delete mode 100644 packages/core/mocks/setup/cliui.mock.ts diff --git a/packages/cli/mocks/setup/cliui.mock.ts b/packages/cli/mocks/setup/cliui.mock.ts new file mode 100644 index 000000000..400973955 --- /dev/null +++ b/packages/cli/mocks/setup/cliui.mock.ts @@ -0,0 +1,6 @@ +import {afterEach, vi} from "vitest"; +import {ui} from "@code-pushup/utils"; + +afterEach(() => { + ui().logger.flushLogs(); +}) diff --git a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts index ddb836f81..81368a344 100644 --- a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts +++ b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts @@ -1,4 +1,4 @@ -import { describe, expect } from 'vitest'; +import { afterEach, describe, expect, vi } from 'vitest'; import { CategoryConfig, CoreConfig } from '@code-pushup/models'; import { ui } from '@code-pushup/utils'; import { @@ -7,6 +7,15 @@ import { validateOnlyPluginsOption, } from './only-plugins.utils'; +vi.mock('@code-pushup/utils', async () => { + const module = await vi.importActual('@code-pushup/utils'); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + module.ui().switchMode('raw'); + + return module; +}); + describe('filterPluginsBySlug', () => { it('should return all plugins if no onlyPlugins option is provided', () => { expect( @@ -36,6 +45,9 @@ describe('filterPluginsBySlug', () => { }); describe('filterCategoryByPluginSlug', () => { + afterEach(() => { + ui().logger.flushLogs(); + }); it('should return all categories if no onlyPlugins option', () => { expect( filterCategoryByPluginSlug( diff --git a/packages/cli/src/lib/print-config/print-config-command.unit.test.ts b/packages/cli/src/lib/print-config/print-config-command.unit.test.ts index 339485aa3..8fe2fd10d 100644 --- a/packages/cli/src/lib/print-config/print-config-command.unit.test.ts +++ b/packages/cli/src/lib/print-config/print-config-command.unit.test.ts @@ -1,4 +1,4 @@ -import { describe, expect } from 'vitest'; +import { describe, expect, vi } from 'vitest'; import { ui } from '@code-pushup/utils'; import { DEFAULT_CLI_CONFIGURATION } from '../../../mocks/constants'; import { yargsCli } from '../yargs-cli'; @@ -14,6 +14,15 @@ vi.mock('@code-pushup/core', async () => { }; }); +vi.mock('@code-pushup/utils', async () => { + const module = await vi.importActual('@code-pushup/utils'); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + module.ui().switchMode('raw'); + + return module; +}); + describe('print-config-command', () => { it('should filter out meta arguments and kebab duplicates', async () => { await yargsCli( diff --git a/packages/cli/vite.config.unit.ts b/packages/cli/vite.config.unit.ts index cbedbeeaf..917523c68 100644 --- a/packages/cli/vite.config.unit.ts +++ b/packages/cli/vite.config.unit.ts @@ -26,7 +26,7 @@ export default defineConfig({ '../../testing/test-setup/src/lib/console.mock.ts', '../../testing/test-setup/src/lib/portal-client.mock.ts', '../../testing/test-setup/src/lib/reset.mocks.ts', - '../../testing/test-setup/src/lib/cliui.mock.ts', + './mocks/setup/cliui.mock.ts', ], }, }); diff --git a/packages/core/mocks/setup/cliui.mock.ts b/packages/core/mocks/setup/cliui.mock.ts deleted file mode 100644 index 178d6ce7d..000000000 --- a/packages/core/mocks/setup/cliui.mock.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { afterEach, vi } from 'vitest'; -import { ui } from '@code-pushup/utils'; - -vi.mock('@code-pushup/utils', async () => { - const module = await vi.importActual('@code-pushup/utils'); - - module.ui().switchMode('raw'); - return module; -}); - -afterEach(() => { - ui().logger.flushLogs(); -}); diff --git a/packages/core/package.json b/packages/core/package.json index cbdc139aa..1bc17c150 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -6,7 +6,9 @@ "@code-pushup/models": "*", "@code-pushup/utils": "*", "@code-pushup/portal-client": "^0.6.1", - "chalk": "^5.3.0" + "chalk": "^5.3.0", + "memfs": "^4.5.0", + "vitest": "1.3.1" }, "type": "commonjs", "main": "./index.cjs" diff --git a/packages/core/src/lib/implementation/execute-plugin.unit-test.ts b/packages/core/src/lib/implementation/execute-plugin.unit-test.ts index f1ad1d0ea..640785a23 100644 --- a/packages/core/src/lib/implementation/execute-plugin.unit-test.ts +++ b/packages/core/src/lib/implementation/execute-plugin.unit-test.ts @@ -24,8 +24,8 @@ describe('executePlugin', () => { 'output.json': JSON.stringify([ { slug: 'node-version', - score: 0.3, - value: 16, + score: 1, + value: 2, }, ]), }, @@ -49,7 +49,7 @@ describe('executePlugin', () => { runner: () => [ { slug: 'node-version', - score: 0.1, + score: 0, value: 1, }, ], @@ -58,8 +58,8 @@ describe('executePlugin', () => { expect.objectContaining({ slug: 'node-version', title: 'Node version', - score: 0.3, - value: 16, + score: 0, + value: 2, }), ]); }); @@ -163,8 +163,8 @@ describe('executePlugins', () => { 'output.json': JSON.stringify([ { slug: 'node-version', - score: 0.3, - value: 16, + score: 1, + value: 2, }, ]), }, @@ -182,10 +182,10 @@ describe('executePlugins', () => { outputTransform: (outputs: unknown): Promise => Promise.resolve([ { - slug: (outputs as AuditOutputs)[0]!.slug, - score: 0.3, - value: 16, - displayValue: '16.0.0', + slug: (outputs as AuditOutputs)[0]?.slug || '', + score: 1, + value: 2, + displayValue: '2.0.0', }, ]), }, @@ -194,6 +194,6 @@ describe('executePlugins', () => { { progress: false }, ); expect(pluginResult[0]?.audits[0]?.slug).toBe('node-version'); - expect(pluginResult[0]?.audits[0]?.displayValue).toBe('16.0.0'); + expect(pluginResult[0]?.audits[0]?.displayValue).toBe('2.0.0'); }); }); diff --git a/packages/core/src/lib/implementation/persist.unit.test.ts b/packages/core/src/lib/implementation/persist.unit.test.ts index 7d07bd1a5..9481360d6 100644 --- a/packages/core/src/lib/implementation/persist.unit.test.ts +++ b/packages/core/src/lib/implementation/persist.unit.test.ts @@ -1,7 +1,7 @@ import { vol } from 'memfs'; import { readFile } from 'node:fs/promises'; import { join } from 'node:path'; -import { beforeEach, describe, expect, it } from 'vitest'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { Report } from '@code-pushup/models'; import { MEMFS_VOLUME, @@ -11,10 +11,20 @@ import { import { ui } from '@code-pushup/utils'; import { logPersistedResults, persistReport } from './persist'; +vi.mock('@code-pushup/utils', async () => { + const module = await vi.importActual('@code-pushup/utils'); + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + module.ui().switchMode('raw'); + return module; +}); + describe('persistReport', () => { beforeEach(() => { vol.fromJSON({}, MEMFS_VOLUME); }); + afterEach(() => { + ui().logger.flushLogs(); + }); it('should print a summary to stdout when no format is specified`', async () => { await persistReport(MINIMAL_REPORT_MOCK, { @@ -22,7 +32,11 @@ describe('persistReport', () => { filename: 'report', format: [], }); - expect(console.info).toHaveBeenCalledWith( + const logs = ui() + .logger.getRenderer() + .getLogs() + .map(({ message }) => message); + expect(logs.at(-1)).toEqual( expect.stringContaining('Made with ❤ by code-pushup.dev'), ); }); @@ -33,7 +47,11 @@ describe('persistReport', () => { filename: 'report', format: ['md', 'json'], }); - expect(console.info).toHaveBeenCalledWith( + const logs = ui() + .logger.getRenderer() + .getLogs() + .map(({ message }) => message); + expect(logs.at(-1)).toEqual( expect.stringContaining('Made with ❤ by code-pushup.dev'), ); }); @@ -99,6 +117,10 @@ describe('persistReport', () => { }); describe('logPersistedResults', () => { + afterEach(() => { + ui().logger.flushLogs(); + }); + it('should log report sizes correctly`', () => { logPersistedResults([{ status: 'fulfilled', value: ['out.json', 10_000] }]); const logs = ui() diff --git a/packages/utils/src/lib/git.integration.test.ts b/packages/utils/src/lib/git.integration.test.ts index 3a00eb304..53fd727ce 100644 --- a/packages/utils/src/lib/git.integration.test.ts +++ b/packages/utils/src/lib/git.integration.test.ts @@ -1,4 +1,4 @@ -import { mkdir, rm, writeFile } from 'node:fs/promises'; +import { mkdir, rm, stat, writeFile } from 'node:fs/promises'; import { join } from 'node:path'; import { type SimpleGit, simpleGit } from 'simple-git'; import { afterAll, beforeAll, beforeEach, expect } from 'vitest'; diff --git a/packages/utils/src/lib/log-results.unit.test.ts b/packages/utils/src/lib/log-results.unit.test.ts index d036938da..8a0401f57 100644 --- a/packages/utils/src/lib/log-results.unit.test.ts +++ b/packages/utils/src/lib/log-results.unit.test.ts @@ -1,8 +1,15 @@ -import { describe, expect, it, vi } from 'vitest'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; import { FileResult } from './file-system'; import { logMultipleResults, logPromiseResults } from './log-results'; import { ui } from './logging'; +vi.mock('./logging', async () => { + const module: typeof import('./logging') = await vi.importActual('./logging'); + + module.ui().switchMode('raw'); + return module; +}); + describe('logMultipleResults', () => { const succeededCallbackMock = vi.fn(); const failedCallbackMock = vi.fn(); @@ -56,6 +63,10 @@ describe('logMultipleResults', () => { }); describe('logPromiseResults', () => { + beforeEach(() => { + ui().logger.flushLogs(); + }); + it('should log on success', () => { logPromiseResults( [ diff --git a/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap b/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap index b79c8ea66..c93c129ac 100644 --- a/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap +++ b/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap @@ -150,6 +150,160 @@ dangerouslySetInnerHTML ● Require using arrow functions for callbacks passed +Lighthouse audits + +● First Contentful Paint 1.2 s +● Largest Contentful Paint 1.5 s +● Speed Index 1.2 s +● Cumulative Layout Shift 0 +● Total Blocking Time 0 ms + +Made with ❤ by code-pushup.dev" +`; + +exports[`logStdoutSummary > should contain all sections when using the fixture report 1`] = ` +"Code PushUp Report - @code-pushup/core@0.0.1 + + +ESLint audits + +● Disallow missing props validation in a React component definition 6 warnings +● Disallow variable declarations from shadowing variables declared in 3 warnings +the outer scope +● Require or disallow method and property shorthand syntax for object 3 warnings +literals +● verifies the list of dependencies for Hooks like useEffect and 2 warnings +similar +● Disallow missing \`key\` props in iterators/collection literals 1 warning +● Disallow unused variables 1 warning +● Enforce a maximum number of lines of code in a function 1 warning +● Require \`const\` declarations for variables that are never reassigned1 warning +after declared +● Require braces around arrow function bodies 1 warning +● Require the use of \`===\` and \`!==\` 1 warning +● Disallow \`target="_blank"\` attribute without \`rel="noreferrer"\` passed +● Disallow assignment operators in conditional expressions passed +● Disallow comments from being inserted as text nodes passed +● Disallow direct mutation of this.state passed +● Disallow duplicate properties in JSX passed +● Disallow invalid regular expression strings in \`RegExp\` constructorspassed +● Disallow loops with a body that allows only one iteration passed +● Disallow missing displayName in a React component definition passed +● Disallow missing React when using JSX passed +● Disallow negating the left operand of relational operators passed +● Disallow passing of children as props passed +● Disallow React to be incorrectly marked as unused passed +● Disallow reassigning \`const\` variables passed +● Disallow the use of \`debugger\` passed +● Disallow the use of undeclared variables unless mentioned in passed +\`/*global */\` comments +● Disallow undeclared variables in JSX passed +● Disallow unescaped HTML entities from appearing in markup passed +● Disallow usage of deprecated methods passed +● Disallow usage of findDOMNode passed +● Disallow usage of isMounted passed +● Disallow usage of the return value of ReactDOM.render passed +● Disallow usage of unknown DOM property passed +● Disallow use of optional chaining in contexts where the \`undefined\` passed +value is not allowed +● Disallow using Object.assign with an object literal as the first passed +argument and prefer the use of object spread instead +● Disallow using string references passed +● Disallow variables used in JSX to be incorrectly marked as unused passed +● Disallow when a DOM element is using both children and passed +dangerouslySetInnerHTML +● Enforce a maximum number of lines per file passed +● Enforce camelcase naming convention passed +● Enforce comparing \`typeof\` expressions against valid strings passed +● Enforce consistent brace style for all control statements passed +● Enforce ES5 or ES6 class for returning value in render function passed +● enforces the Rules of Hooks passed +● Require \`let\` or \`const\` instead of \`var\` passed +● Require calls to \`isNaN()\` when checking for \`NaN\` passed +● Require or disallow "Yoda" conditions passed +● Require using arrow functions for callbacks passed + + +Lighthouse audits + +● First Contentful Paint 1.2 s +● Largest Contentful Paint 1.5 s +● Speed Index 1.2 s +● Cumulative Layout Shift 0 +● Total Blocking Time 0 ms + +Categories + +Category|Score|Audits +Performance|92|8 +Bug prevention|68|16 +Code style|54|13 +Made with ❤ by code-pushup.dev" +`; + +exports[`logStdoutSummary > should not contain category section when categories are empty 1`] = ` +"Code PushUp Report - @code-pushup/core@0.0.1 + + +ESLint audits + +● Disallow missing props validation in a React component definition 6 warnings +● Disallow variable declarations from shadowing variables declared in 3 warnings +the outer scope +● Require or disallow method and property shorthand syntax for object 3 warnings +literals +● verifies the list of dependencies for Hooks like useEffect and 2 warnings +similar +● Disallow missing \`key\` props in iterators/collection literals 1 warning +● Disallow unused variables 1 warning +● Enforce a maximum number of lines of code in a function 1 warning +● Require \`const\` declarations for variables that are never reassigned1 warning +after declared +● Require braces around arrow function bodies 1 warning +● Require the use of \`===\` and \`!==\` 1 warning +● Disallow \`target="_blank"\` attribute without \`rel="noreferrer"\` passed +● Disallow assignment operators in conditional expressions passed +● Disallow comments from being inserted as text nodes passed +● Disallow direct mutation of this.state passed +● Disallow duplicate properties in JSX passed +● Disallow invalid regular expression strings in \`RegExp\` constructorspassed +● Disallow loops with a body that allows only one iteration passed +● Disallow missing displayName in a React component definition passed +● Disallow missing React when using JSX passed +● Disallow negating the left operand of relational operators passed +● Disallow passing of children as props passed +● Disallow React to be incorrectly marked as unused passed +● Disallow reassigning \`const\` variables passed +● Disallow the use of \`debugger\` passed +● Disallow the use of undeclared variables unless mentioned in passed +\`/*global */\` comments +● Disallow undeclared variables in JSX passed +● Disallow unescaped HTML entities from appearing in markup passed +● Disallow usage of deprecated methods passed +● Disallow usage of findDOMNode passed +● Disallow usage of isMounted passed +● Disallow usage of the return value of ReactDOM.render passed +● Disallow usage of unknown DOM property passed +● Disallow use of optional chaining in contexts where the \`undefined\` passed +value is not allowed +● Disallow using Object.assign with an object literal as the first passed +argument and prefer the use of object spread instead +● Disallow using string references passed +● Disallow variables used in JSX to be incorrectly marked as unused passed +● Disallow when a DOM element is using both children and passed +dangerouslySetInnerHTML +● Enforce a maximum number of lines per file passed +● Enforce camelcase naming convention passed +● Enforce comparing \`typeof\` expressions against valid strings passed +● Enforce consistent brace style for all control statements passed +● Enforce ES5 or ES6 class for returning value in render function passed +● enforces the Rules of Hooks passed +● Require \`let\` or \`const\` instead of \`var\` passed +● Require calls to \`isNaN()\` when checking for \`NaN\` passed +● Require or disallow "Yoda" conditions passed +● Require using arrow functions for callbacks passed + + Lighthouse audits ● First Contentful Paint 1.2 s diff --git a/packages/utils/src/lib/verbose-utils.unit.test.ts b/packages/utils/src/lib/verbose-utils.unit.test.ts index 34cadeaf5..1cc90fb47 100644 --- a/packages/utils/src/lib/verbose-utils.unit.test.ts +++ b/packages/utils/src/lib/verbose-utils.unit.test.ts @@ -1,8 +1,18 @@ -import { describe, expect, it } from 'vitest'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; import { ui } from './logging'; import { verboseUtils } from './verbose-utils'; +vi.mock('./logging', async () => { + const module: typeof import('./logging') = await vi.importActual('./logging'); + + module.ui().switchMode('raw'); + return module; +}); + describe('verbose-utils', () => { + beforeEach(() => { + ui().logger.flushLogs(); + }); it('exec should be off by default', () => { const spy = vi.fn(); verboseUtils().exec(spy); diff --git a/packages/utils/vite.config.integration.ts b/packages/utils/vite.config.integration.ts index 0793c5623..12142b182 100644 --- a/packages/utils/vite.config.integration.ts +++ b/packages/utils/vite.config.integration.ts @@ -23,7 +23,6 @@ export default defineConfig({ setupFiles: [ '../../testing/test-setup/src/lib/console.mock.ts', '../../testing/test-setup/src/lib/reset.mocks.ts', - '../../testing/test-setup/src/lib/cliui.mock.ts', ], }, }); diff --git a/packages/utils/vite.config.unit.ts b/packages/utils/vite.config.unit.ts index 610ba8e69..ebbf224fd 100644 --- a/packages/utils/vite.config.unit.ts +++ b/packages/utils/vite.config.unit.ts @@ -21,7 +21,6 @@ export default defineConfig({ include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], globalSetup: ['../../global-setup.ts'], setupFiles: [ - './mocks/setup/cliui.mock.ts', '../../testing/test-setup/src/lib/fs.mock.ts', '../../testing/test-setup/src/lib/console.mock.ts', '../../testing/test-setup/src/lib/reset.mocks.ts', From 35f6071f8ce038baf5b190a672f10807ed6d32e0 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 7 Mar 2024 23:08:53 +0100 Subject: [PATCH 24/75] refactor(core): fix lint --- package-lock.json | 4 ++-- .../collect.integration.test.ts | 9 +++++++- .../src/lib/implementation/execute-plugin.ts | 5 ++--- .../execute-plugin.unit-test.ts | 22 +++++++++++-------- packages/core/vite.config.unit.ts | 2 +- packages/utils/src/lib/git.ts | 3 +-- 6 files changed, 27 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3e9571d9f..f9004c903 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@code-pushup/cli-source", - "version": "0.23.4", + "version": "0.26.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@code-pushup/cli-source", - "version": "0.23.4", + "version": "0.26.1", "license": "MIT", "dependencies": { "@code-pushup/portal-client": "^0.6.1", diff --git a/packages/core/src/lib/implementation/collect.integration.test.ts b/packages/core/src/lib/implementation/collect.integration.test.ts index a0437f16f..d33de1c74 100644 --- a/packages/core/src/lib/implementation/collect.integration.test.ts +++ b/packages/core/src/lib/implementation/collect.integration.test.ts @@ -1,9 +1,16 @@ import { vol } from 'memfs'; -import { describe, expect, it } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; import { commitSchema } from '@code-pushup/models'; import { MEMFS_VOLUME, MINIMAL_CONFIG_MOCK } from '@code-pushup/test-utils'; import { collect } from './collect'; +vi.mock('@code-pushup/utils', async () => { + const module = await vi.importActual('@code-pushup/utils'); + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + module.ui().switchMode('raw'); + return module; +}); + describe('collect', () => { it('should execute with valid options', async () => { vol.fromJSON({}, MEMFS_VOLUME); diff --git a/packages/core/src/lib/implementation/execute-plugin.ts b/packages/core/src/lib/implementation/execute-plugin.ts index 6633889d4..89cdaff2f 100644 --- a/packages/core/src/lib/implementation/execute-plugin.ts +++ b/packages/core/src/lib/implementation/execute-plugin.ts @@ -142,9 +142,8 @@ export async function executePlugins( progressBar?.endProgress('Done running plugins'); - const errorsCallback = ({ reason }: PromiseRejectedResult) => { - console.error(reason); - }; + const errorsCallback = ({ reason }: PromiseRejectedResult) => + reason as string; const results = await Promise.allSettled(pluginsResult); logMultipleResults(results, 'Plugins', undefined, errorsCallback); diff --git a/packages/core/src/lib/implementation/execute-plugin.unit-test.ts b/packages/core/src/lib/implementation/execute-plugin.unit-test.ts index 640785a23..d0510cc95 100644 --- a/packages/core/src/lib/implementation/execute-plugin.unit-test.ts +++ b/packages/core/src/lib/implementation/execute-plugin.unit-test.ts @@ -12,10 +12,13 @@ import { executePlugins, } from './execute-plugin'; +const nodePluginSlug = MINIMAL_PLUGIN_CONFIG_MOCK.slug; + +// eslint-disable-next-line max-lines-per-function describe('executePlugin', () => { it('should execute a valid plugin config', async () => { const pluginResult = await executePlugin(MINIMAL_PLUGIN_CONFIG_MOCK); - expect(pluginResult.audits[0]?.slug).toBe('node-version'); + expect(pluginResult.audits[0]?.slug).toBe(nodePluginSlug); }); it('should yield audit outputs for valid runner config', async () => { @@ -23,7 +26,7 @@ describe('executePlugin', () => { { 'output.json': JSON.stringify([ { - slug: 'node-version', + slug: nodePluginSlug, score: 1, value: 2, }, @@ -40,7 +43,7 @@ describe('executePlugin', () => { outputFile: 'output.json', }, }); - expect(pluginResult.audits[0]?.slug).toBe('node-version'); + expect(pluginResult.audits[0]?.slug).toBe(nodePluginSlug); }); it('should yield audit outputs for a valid runner function', async () => { @@ -48,7 +51,7 @@ describe('executePlugin', () => { ...MINIMAL_PLUGIN_CONFIG_MOCK, runner: () => [ { - slug: 'node-version', + slug: nodePluginSlug, score: 0, value: 1, }, @@ -56,7 +59,7 @@ describe('executePlugin', () => { }); expect(pluginResult.audits).toEqual([ expect.objectContaining({ - slug: 'node-version', + slug: nodePluginSlug, title: 'Node version', score: 0, value: 2, @@ -70,7 +73,7 @@ describe('executePlugin', () => { ...MINIMAL_PLUGIN_CONFIG_MOCK, audits: [{ slug: '-invalid-slug', title: 'Invalid audit' }], }), - ).rejects.toThrow(new PluginOutputMissingAuditError('node-version')); + ).rejects.toThrow(new PluginOutputMissingAuditError(nodePluginSlug)); }); it('should throw if invalid runnerOutput is produced', async () => { @@ -89,6 +92,7 @@ describe('executePlugin', () => { }); }); +// eslint-disable-next-line max-lines-per-function describe('executePlugins', () => { it('should execute valid plugins', async () => { const pluginResult = await executePlugins( @@ -104,7 +108,7 @@ describe('executePlugins', () => { expect(pluginResult[0]?.icon).toBe('javascript'); expect(pluginResult[1]?.icon).toBe('nodejs'); - expect(pluginResult[0]?.audits[0]?.slug).toBe('node-version'); + expect(pluginResult[0]?.audits[0]?.slug).toBe(nodePluginSlug); }); it('should throw for invalid plugins', async () => { @@ -162,7 +166,7 @@ describe('executePlugins', () => { { 'output.json': JSON.stringify([ { - slug: 'node-version', + slug: nodePluginSlug, score: 1, value: 2, }, @@ -193,7 +197,7 @@ describe('executePlugins', () => { ], { progress: false }, ); - expect(pluginResult[0]?.audits[0]?.slug).toBe('node-version'); + expect(pluginResult[0]?.audits[0]?.slug).toBe(nodePluginSlug); expect(pluginResult[0]?.audits[0]?.displayValue).toBe('2.0.0'); }); }); diff --git a/packages/core/vite.config.unit.ts b/packages/core/vite.config.unit.ts index e847fd2f6..6f3586c7c 100644 --- a/packages/core/vite.config.unit.ts +++ b/packages/core/vite.config.unit.ts @@ -21,7 +21,7 @@ export default defineConfig({ include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], globalSetup: ['../../global-setup.ts'], setupFiles: [ - './mocks/setup/cliui.mock.ts', + // './mocks/setup/cliui.mock.ts', '../../testing/test-setup/src/lib/fs.mock.ts', '../../testing/test-setup/src/lib/git.mock.ts', '../../testing/test-setup/src/lib/console.mock.ts', diff --git a/packages/utils/src/lib/git.ts b/packages/utils/src/lib/git.ts index 0b3248b41..2fb430e1c 100644 --- a/packages/utils/src/lib/git.ts +++ b/packages/utils/src/lib/git.ts @@ -80,8 +80,7 @@ export async function safeCheckout( if (options.forceCleanStatus) { await git.raw(['reset', '--hard']); await git.clean(['f', 'd']); - // @TODO replace with ui().logger.info - console.info(`git status cleaned`); + ui().logger.info(`git status cleaned`); } await guardAgainstLocalChanges(git); await git.checkout(branchOrHash); From ec151666b35d58c7cf3249d2c70858c99f9835b0 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 7 Mar 2024 23:39:10 +0100 Subject: [PATCH 25/75] test: use setup scripts for logger mode --- packages/cli/mocks/setup/cliui.mock.ts | 6 ------ .../only-plugins.utils.unit.test.ts | 16 +++++----------- .../print-config-command.unit.test.ts | 9 --------- packages/cli/vite.config.unit.ts | 2 +- .../implementation/collect.integration.test.ts | 9 +-------- .../src/lib/implementation/persist.unit.test.ts | 11 +---------- packages/core/vite.config.unit.ts | 2 +- packages/utils/mocks/setup/cliui.mock.ts | 4 ++-- testing/test-setup/src/lib/cliui.mock.ts | 9 +++++++++ 9 files changed, 20 insertions(+), 48 deletions(-) delete mode 100644 packages/cli/mocks/setup/cliui.mock.ts create mode 100644 testing/test-setup/src/lib/cliui.mock.ts diff --git a/packages/cli/mocks/setup/cliui.mock.ts b/packages/cli/mocks/setup/cliui.mock.ts deleted file mode 100644 index 400973955..000000000 --- a/packages/cli/mocks/setup/cliui.mock.ts +++ /dev/null @@ -1,6 +0,0 @@ -import {afterEach, vi} from "vitest"; -import {ui} from "@code-pushup/utils"; - -afterEach(() => { - ui().logger.flushLogs(); -}) diff --git a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts index 81368a344..5dad3bdbf 100644 --- a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts +++ b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts @@ -1,4 +1,4 @@ -import { afterEach, describe, expect, vi } from 'vitest'; +import { beforeEach, describe, expect, vi } from 'vitest'; import { CategoryConfig, CoreConfig } from '@code-pushup/models'; import { ui } from '@code-pushup/utils'; import { @@ -7,15 +7,6 @@ import { validateOnlyPluginsOption, } from './only-plugins.utils'; -vi.mock('@code-pushup/utils', async () => { - const module = await vi.importActual('@code-pushup/utils'); - - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - module.ui().switchMode('raw'); - - return module; -}); - describe('filterPluginsBySlug', () => { it('should return all plugins if no onlyPlugins option is provided', () => { expect( @@ -45,7 +36,7 @@ describe('filterPluginsBySlug', () => { }); describe('filterCategoryByPluginSlug', () => { - afterEach(() => { + beforeEach(() => { ui().logger.flushLogs(); }); it('should return all categories if no onlyPlugins option', () => { @@ -119,6 +110,9 @@ describe('filterCategoryByPluginSlug', () => { }); describe('validateOnlyPluginsOption', () => { + beforeEach(() => { + ui().logger.flushLogs(); + }); it('should warn if onlyPlugins option contains non-existing plugin', () => { validateOnlyPluginsOption( [{ slug: 'plugin1' }, { slug: 'plugin2' }] as CoreConfig['plugins'], diff --git a/packages/cli/src/lib/print-config/print-config-command.unit.test.ts b/packages/cli/src/lib/print-config/print-config-command.unit.test.ts index 8fe2fd10d..26f94fe0a 100644 --- a/packages/cli/src/lib/print-config/print-config-command.unit.test.ts +++ b/packages/cli/src/lib/print-config/print-config-command.unit.test.ts @@ -14,15 +14,6 @@ vi.mock('@code-pushup/core', async () => { }; }); -vi.mock('@code-pushup/utils', async () => { - const module = await vi.importActual('@code-pushup/utils'); - - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - module.ui().switchMode('raw'); - - return module; -}); - describe('print-config-command', () => { it('should filter out meta arguments and kebab duplicates', async () => { await yargsCli( diff --git a/packages/cli/vite.config.unit.ts b/packages/cli/vite.config.unit.ts index 917523c68..451dec359 100644 --- a/packages/cli/vite.config.unit.ts +++ b/packages/cli/vite.config.unit.ts @@ -21,12 +21,12 @@ export default defineConfig({ include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], globalSetup: ['../../global-setup.ts'], setupFiles: [ + '../../testing/test-setup/src/lib/cliui.mock.ts', '../../testing/test-setup/src/lib/fs.mock.ts', '../../testing/test-setup/src/lib/git.mock.ts', '../../testing/test-setup/src/lib/console.mock.ts', '../../testing/test-setup/src/lib/portal-client.mock.ts', '../../testing/test-setup/src/lib/reset.mocks.ts', - './mocks/setup/cliui.mock.ts', ], }, }); diff --git a/packages/core/src/lib/implementation/collect.integration.test.ts b/packages/core/src/lib/implementation/collect.integration.test.ts index d33de1c74..a0437f16f 100644 --- a/packages/core/src/lib/implementation/collect.integration.test.ts +++ b/packages/core/src/lib/implementation/collect.integration.test.ts @@ -1,16 +1,9 @@ import { vol } from 'memfs'; -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, it } from 'vitest'; import { commitSchema } from '@code-pushup/models'; import { MEMFS_VOLUME, MINIMAL_CONFIG_MOCK } from '@code-pushup/test-utils'; import { collect } from './collect'; -vi.mock('@code-pushup/utils', async () => { - const module = await vi.importActual('@code-pushup/utils'); - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - module.ui().switchMode('raw'); - return module; -}); - describe('collect', () => { it('should execute with valid options', async () => { vol.fromJSON({}, MEMFS_VOLUME); diff --git a/packages/core/src/lib/implementation/persist.unit.test.ts b/packages/core/src/lib/implementation/persist.unit.test.ts index 9481360d6..425ac946d 100644 --- a/packages/core/src/lib/implementation/persist.unit.test.ts +++ b/packages/core/src/lib/implementation/persist.unit.test.ts @@ -11,18 +11,9 @@ import { import { ui } from '@code-pushup/utils'; import { logPersistedResults, persistReport } from './persist'; -vi.mock('@code-pushup/utils', async () => { - const module = await vi.importActual('@code-pushup/utils'); - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - module.ui().switchMode('raw'); - return module; -}); - describe('persistReport', () => { beforeEach(() => { vol.fromJSON({}, MEMFS_VOLUME); - }); - afterEach(() => { ui().logger.flushLogs(); }); @@ -117,7 +108,7 @@ describe('persistReport', () => { }); describe('logPersistedResults', () => { - afterEach(() => { + beforeEach(() => { ui().logger.flushLogs(); }); diff --git a/packages/core/vite.config.unit.ts b/packages/core/vite.config.unit.ts index 6f3586c7c..5bee4c406 100644 --- a/packages/core/vite.config.unit.ts +++ b/packages/core/vite.config.unit.ts @@ -21,7 +21,7 @@ export default defineConfig({ include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], globalSetup: ['../../global-setup.ts'], setupFiles: [ - // './mocks/setup/cliui.mock.ts', + '../../testing/test-setup/src/lib/cliui.mock.ts', '../../testing/test-setup/src/lib/fs.mock.ts', '../../testing/test-setup/src/lib/git.mock.ts', '../../testing/test-setup/src/lib/console.mock.ts', diff --git a/packages/utils/mocks/setup/cliui.mock.ts b/packages/utils/mocks/setup/cliui.mock.ts index 4011a2910..21df924d7 100644 --- a/packages/utils/mocks/setup/cliui.mock.ts +++ b/packages/utils/mocks/setup/cliui.mock.ts @@ -1,4 +1,4 @@ -import {afterEach, vi} from "vitest"; +import {beforeEach, vi} from "vitest"; import {ui} from "../../src/lib/logging"; vi.mock('../../src/lib/logging', async () => { @@ -8,6 +8,6 @@ vi.mock('../../src/lib/logging', async () => { return module; }); -afterEach(() => { +beforeEach(() => { ui().logger.flushLogs(); }) diff --git a/testing/test-setup/src/lib/cliui.mock.ts b/testing/test-setup/src/lib/cliui.mock.ts new file mode 100644 index 000000000..9b43677ff --- /dev/null +++ b/testing/test-setup/src/lib/cliui.mock.ts @@ -0,0 +1,9 @@ +import { vi } from 'vitest'; + +vi.mock('@code-pushup/utils', async () => { + const module = await vi.importActual('@code-pushup/utils'); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + module.ui().switchMode('raw'); + return module; +}); From dad96ba6ede355a6868031524c02dd078d8dcfc9 Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Thu, 7 Mar 2024 23:47:41 +0100 Subject: [PATCH 26/75] Update .github/workflows/ci.yml --- .github/workflows/ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 65e69643b..0ae82c677 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -170,8 +170,6 @@ jobs: cache: npm - name: Install dependencies run: npm ci - - name: Check git version - run: git -v - name: Collect Code PushUp report run: npx nx run-collect - name: Upload Code PushUp report to portal From 41f6253d5b740c152a540b7303542c96c1e5cdac Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Thu, 7 Mar 2024 23:50:39 +0100 Subject: [PATCH 27/75] Update packages/utils/src/lib/execute-process.ts --- packages/utils/src/lib/execute-process.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/utils/src/lib/execute-process.ts b/packages/utils/src/lib/execute-process.ts index 1ec568437..970081d6f 100644 --- a/packages/utils/src/lib/execute-process.ts +++ b/packages/utils/src/lib/execute-process.ts @@ -138,7 +138,6 @@ export function executeProcess(cfg: ProcessConfig): Promise { const start = performance.now(); return new Promise((resolve, reject) => { - // @TODO add logging `Spawn process ${command} with args ${args?.join(' ')}` // shell:true tells Windows to use shell command for spawning a child process const process = spawn(command, args, { cwd, shell: true }); // eslint-disable-next-line functional/no-let From dcea0c91bb4e1c91bff4764011049df4e78074e9 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 7 Mar 2024 23:58:17 +0100 Subject: [PATCH 28/75] test(utils): refactor setup scripts --- packages/utils/src/lib/log-results.unit.test.ts | 7 ------- .../src/lib/reports/log-stdout-summary.integration.test.ts | 3 --- packages/utils/src/lib/verbose-utils.unit.test.ts | 7 ------- packages/utils/vite.config.unit.ts | 1 + 4 files changed, 1 insertion(+), 17 deletions(-) diff --git a/packages/utils/src/lib/log-results.unit.test.ts b/packages/utils/src/lib/log-results.unit.test.ts index 8a0401f57..ac187c225 100644 --- a/packages/utils/src/lib/log-results.unit.test.ts +++ b/packages/utils/src/lib/log-results.unit.test.ts @@ -3,13 +3,6 @@ import { FileResult } from './file-system'; import { logMultipleResults, logPromiseResults } from './log-results'; import { ui } from './logging'; -vi.mock('./logging', async () => { - const module: typeof import('./logging') = await vi.importActual('./logging'); - - module.ui().switchMode('raw'); - return module; -}); - describe('logMultipleResults', () => { const succeededCallbackMock = vi.fn(); const failedCallbackMock = vi.fn(); diff --git a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts index 1cf58834a..bb338c9ac 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts @@ -6,9 +6,6 @@ import { scoreReport } from './scoring'; import { sortReport } from './sorting'; describe('logStdoutSummary', () => { - beforeAll(() => { - ui().switchMode('raw'); - }); beforeEach(() => { ui().logger.flushLogs(); }); diff --git a/packages/utils/src/lib/verbose-utils.unit.test.ts b/packages/utils/src/lib/verbose-utils.unit.test.ts index 1cc90fb47..6092a413a 100644 --- a/packages/utils/src/lib/verbose-utils.unit.test.ts +++ b/packages/utils/src/lib/verbose-utils.unit.test.ts @@ -2,13 +2,6 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import { ui } from './logging'; import { verboseUtils } from './verbose-utils'; -vi.mock('./logging', async () => { - const module: typeof import('./logging') = await vi.importActual('./logging'); - - module.ui().switchMode('raw'); - return module; -}); - describe('verbose-utils', () => { beforeEach(() => { ui().logger.flushLogs(); diff --git a/packages/utils/vite.config.unit.ts b/packages/utils/vite.config.unit.ts index ebbf224fd..610ba8e69 100644 --- a/packages/utils/vite.config.unit.ts +++ b/packages/utils/vite.config.unit.ts @@ -21,6 +21,7 @@ export default defineConfig({ include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], globalSetup: ['../../global-setup.ts'], setupFiles: [ + './mocks/setup/cliui.mock.ts', '../../testing/test-setup/src/lib/fs.mock.ts', '../../testing/test-setup/src/lib/console.mock.ts', '../../testing/test-setup/src/lib/reset.mocks.ts', From 35adb48fb64c64c3277052ccaa9e19aaa73d3ec2 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 8 Mar 2024 00:09:48 +0100 Subject: [PATCH 29/75] test(utils): refactor setup scripts --- .../cli/src/lib/implementation/only-plugins.utils.unit.test.ts | 2 +- packages/core/src/lib/implementation/persist.unit.test.ts | 2 +- .../src/lib/reports/log-stdout-summary.integration.test.ts | 2 +- packages/utils/vite.config.integration.ts | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts index 5dad3bdbf..7a60a1307 100644 --- a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts +++ b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, vi } from 'vitest'; +import { beforeEach, describe, expect } from 'vitest'; import { CategoryConfig, CoreConfig } from '@code-pushup/models'; import { ui } from '@code-pushup/utils'; import { diff --git a/packages/core/src/lib/implementation/persist.unit.test.ts b/packages/core/src/lib/implementation/persist.unit.test.ts index 425ac946d..1e9c8e168 100644 --- a/packages/core/src/lib/implementation/persist.unit.test.ts +++ b/packages/core/src/lib/implementation/persist.unit.test.ts @@ -1,7 +1,7 @@ import { vol } from 'memfs'; import { readFile } from 'node:fs/promises'; import { join } from 'node:path'; -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { beforeEach, describe, expect, it } from 'vitest'; import { Report } from '@code-pushup/models'; import { MEMFS_VOLUME, diff --git a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts index bb338c9ac..4beb2f270 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts @@ -1,4 +1,4 @@ -import { beforeAll, beforeEach, describe } from 'vitest'; +import { beforeEach, describe } from 'vitest'; import { reportMock } from '@code-pushup/test-utils'; import { ui } from '../logging'; import { logStdoutSummary } from './log-stdout-summary'; diff --git a/packages/utils/vite.config.integration.ts b/packages/utils/vite.config.integration.ts index 12142b182..2e728c4f4 100644 --- a/packages/utils/vite.config.integration.ts +++ b/packages/utils/vite.config.integration.ts @@ -21,6 +21,7 @@ export default defineConfig({ include: ['src/**/*.integration.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], globalSetup: ['../../global-setup.ts'], setupFiles: [ + './mocks/setup/cliui.mock.ts', '../../testing/test-setup/src/lib/console.mock.ts', '../../testing/test-setup/src/lib/reset.mocks.ts', ], From aa37c21ccac726fd848ae8f94e14f3b2baf8cc1e Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 8 Mar 2024 15:29:35 +0100 Subject: [PATCH 30/75] refactor(utils): rename errorCallback to errorsTransform --- packages/core/src/lib/implementation/execute-plugin.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/lib/implementation/execute-plugin.ts b/packages/core/src/lib/implementation/execute-plugin.ts index 89cdaff2f..29fbfe75a 100644 --- a/packages/core/src/lib/implementation/execute-plugin.ts +++ b/packages/core/src/lib/implementation/execute-plugin.ts @@ -142,11 +142,11 @@ export async function executePlugins( progressBar?.endProgress('Done running plugins'); - const errorsCallback = ({ reason }: PromiseRejectedResult) => + const errorsTransform = ({ reason }: PromiseRejectedResult) => reason as string; const results = await Promise.allSettled(pluginsResult); - logMultipleResults(results, 'Plugins', undefined, errorsCallback); + logMultipleResults(results, 'Plugins', undefined, errorsTransform); const { fulfilled, rejected } = groupByStatus(results); if (rejected.length > 0) { From 5b893e68b21ce0a2c20454c382758762f8ad8d31 Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Fri, 8 Mar 2024 15:32:57 +0100 Subject: [PATCH 31/75] Update packages/core/src/lib/implementation/execute-plugin.unit-test.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matěj Chalk <34691111+matejchalk@users.noreply.github.com> --- .../core/src/lib/implementation/execute-plugin.unit-test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/lib/implementation/execute-plugin.unit-test.ts b/packages/core/src/lib/implementation/execute-plugin.unit-test.ts index d0510cc95..afafc9c8d 100644 --- a/packages/core/src/lib/implementation/execute-plugin.unit-test.ts +++ b/packages/core/src/lib/implementation/execute-plugin.unit-test.ts @@ -186,7 +186,7 @@ describe('executePlugins', () => { outputTransform: (outputs: unknown): Promise => Promise.resolve([ { - slug: (outputs as AuditOutputs)[0]?.slug || '', + slug: (outputs as AuditOutputs)[0]!.slug, score: 1, value: 2, displayValue: '2.0.0', From 0eeb75e8a2cc458447dab19bf8f3a9e57a4c53b2 Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Fri, 8 Mar 2024 15:33:18 +0100 Subject: [PATCH 32/75] Update packages/utils/package.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matěj Chalk <34691111+matejchalk@users.noreply.github.com> --- packages/utils/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/package.json b/packages/utils/package.json index e752b9a21..e482db0ad 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -8,6 +8,6 @@ "@isaacs/cliui": "^8.0.2", "simple-git": "^3.20.0", "multi-progress-bars": "^5.0.3", - "@poppinss/cliui": "^6.3.0" + "@poppinss/cliui": "^6.4.0" } } From 82fb9d7083f14e16158157bb70878d4fd31be0ac Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 8 Mar 2024 15:37:35 +0100 Subject: [PATCH 33/75] refactor(utils): rename Callback to Transform --- packages/utils/src/lib/file-system.ts | 8 ++++---- packages/utils/src/lib/log-results.ts | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/utils/src/lib/file-system.ts b/packages/utils/src/lib/file-system.ts index 9f7a0ea47..9903a83ff 100644 --- a/packages/utils/src/lib/file-system.ts +++ b/packages/utils/src/lib/file-system.ts @@ -59,19 +59,19 @@ export function logMultipleFileResults( fileResults: MultipleFileResults, messagePrefix: string, ): void { - const succeededCallback = (result: PromiseFulfilledResult) => { + const succeededTransform = (result: PromiseFulfilledResult) => { const [fileName, size] = result.value; const formattedSize = size ? ` (${chalk.gray(formatBytes(size))})` : ''; return `- ${chalk.bold(fileName)}${formattedSize}`; }; - const failedCallback = (result: PromiseRejectedResult) => + const failedTransform = (result: PromiseRejectedResult) => `- ${chalk.bold(result.reason)}`; logMultipleResults( fileResults, messagePrefix, - succeededCallback, - failedCallback, + succeededTransform, + failedTransform, ); } diff --git a/packages/utils/src/lib/log-results.ts b/packages/utils/src/lib/log-results.ts index 04bd028aa..e848114ef 100644 --- a/packages/utils/src/lib/log-results.ts +++ b/packages/utils/src/lib/log-results.ts @@ -4,26 +4,26 @@ import { ui } from './logging'; export function logMultipleResults( results: PromiseSettledResult[], messagePrefix: string, - succeededCallback?: (result: PromiseFulfilledResult) => string, - failedCallback?: (result: PromiseRejectedResult) => string, + succeededTransform?: (result: PromiseFulfilledResult) => string, + failedTransform?: (result: PromiseRejectedResult) => string, ) { - if (succeededCallback) { + if (succeededTransform) { const succeededResults = results.filter(isPromiseFulfilledResult); logPromiseResults( succeededResults, `${messagePrefix} successfully: `, - succeededCallback, + succeededTransform, ); } - if (failedCallback) { + if (failedTransform) { const failedResults = results.filter(isPromiseRejectedResult); logPromiseResults( failedResults, `${messagePrefix} failed: `, - failedCallback, + failedTransform, ); } } From ef9661fc65bdc778a5369accdedf302fc2dfd9ed Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Fri, 8 Mar 2024 15:40:02 +0100 Subject: [PATCH 34/75] Update packages/utils/src/lib/log-results.unit.test.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Katka Pilátová --- packages/utils/src/lib/log-results.unit.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/lib/log-results.unit.test.ts b/packages/utils/src/lib/log-results.unit.test.ts index ac187c225..305e90759 100644 --- a/packages/utils/src/lib/log-results.unit.test.ts +++ b/packages/utils/src/lib/log-results.unit.test.ts @@ -83,7 +83,7 @@ describe('logPromiseResults', () => { logPromiseResults( [{ status: 'rejected', reason: 'fail' } as PromiseRejectedResult], 'Generated reports failed:', - (result: { reason: string }) => result.reason.toString(), + (result: { reason: string }) => result.reason, ); const logs = ui() .logger.getRenderer() From b71f907b8a52697284b0cd8b077a2ed5846eec16 Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Fri, 8 Mar 2024 15:42:22 +0100 Subject: [PATCH 35/75] Update packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Katka Pilátová --- .../src/lib/implementation/only-plugins.utils.unit.test.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts index 7a60a1307..2a111033d 100644 --- a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts +++ b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts @@ -140,10 +140,6 @@ describe('validateOnlyPluginsOption', () => { verbose: true, }, ); - const logs = ui() - .logger.getRenderer() - .getLogs() - .map(({ message }) => message); - expect(logs).toHaveLength(0); + expect(ui().logger.getRenderer().getLogs()).toHaveLength(0); }); }); From 16a0f4436d44fe3d215144717c50d37fff871954 Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Fri, 8 Mar 2024 15:42:36 +0100 Subject: [PATCH 36/75] Update packages/core/src/lib/implementation/execute-plugin.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Katka Pilátová --- packages/core/src/lib/implementation/execute-plugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/lib/implementation/execute-plugin.ts b/packages/core/src/lib/implementation/execute-plugin.ts index 0531d6644..731f77679 100644 --- a/packages/core/src/lib/implementation/execute-plugin.ts +++ b/packages/core/src/lib/implementation/execute-plugin.ts @@ -143,7 +143,7 @@ export async function executePlugins( progressBar?.endProgress('Done running plugins'); const errorsTransform = ({ reason }: PromiseRejectedResult) => - reason as string; + String(reason); const results = await Promise.allSettled(pluginsResult); logMultipleResults(results, 'Plugins', undefined, errorsTransform); From 72a04c2e1bf4d7566061d2420d5d640d6addf951 Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Fri, 8 Mar 2024 16:21:16 +0100 Subject: [PATCH 37/75] Update packages/utils/src/lib/log-results.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matěj Chalk <34691111+matejchalk@users.noreply.github.com> --- packages/utils/src/lib/log-results.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/utils/src/lib/log-results.ts b/packages/utils/src/lib/log-results.ts index e848114ef..4289d768d 100644 --- a/packages/utils/src/lib/log-results.ts +++ b/packages/utils/src/lib/log-results.ts @@ -34,12 +34,8 @@ export function logPromiseResults< if (results.length > 0) { const log = results[0]?.status === 'fulfilled' - ? (m: string) => { - ui().logger.success(m); - } - : (m: string) => { - ui().logger.warning(m); - }; + ? ui().logger.success + : ui().logger.warning; log(logMessage); results.forEach(result => { From 28717cf88af2c8fddb1d600b7ce628345d5d611f Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 8 Mar 2024 16:35:10 +0100 Subject: [PATCH 38/75] test(core): fix tests --- packages/core/package.json | 4 +- .../src/lib/implementation/execute-plugin.ts | 3 +- ...it-test.ts => execute-plugin.unit.test.ts} | 42 +++++++++---------- 3 files changed, 23 insertions(+), 26 deletions(-) rename packages/core/src/lib/implementation/{execute-plugin.unit-test.ts => execute-plugin.unit.test.ts} (83%) diff --git a/packages/core/package.json b/packages/core/package.json index c45c6dcc1..2a228c939 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -6,9 +6,7 @@ "@code-pushup/models": "*", "@code-pushup/utils": "*", "@code-pushup/portal-client": "^0.6.1", - "chalk": "^5.3.0", - "memfs": "^4.5.0", - "vitest": "1.3.1" + "chalk": "^5.3.0" }, "type": "commonjs", "main": "./index.cjs" diff --git a/packages/core/src/lib/implementation/execute-plugin.ts b/packages/core/src/lib/implementation/execute-plugin.ts index 731f77679..f4cbb42c1 100644 --- a/packages/core/src/lib/implementation/execute-plugin.ts +++ b/packages/core/src/lib/implementation/execute-plugin.ts @@ -142,8 +142,7 @@ export async function executePlugins( progressBar?.endProgress('Done running plugins'); - const errorsTransform = ({ reason }: PromiseRejectedResult) => - String(reason); + const errorsTransform = ({ reason }: PromiseRejectedResult) => String(reason); const results = await Promise.allSettled(pluginsResult); logMultipleResults(results, 'Plugins', undefined, errorsTransform); diff --git a/packages/core/src/lib/implementation/execute-plugin.unit-test.ts b/packages/core/src/lib/implementation/execute-plugin.unit.test.ts similarity index 83% rename from packages/core/src/lib/implementation/execute-plugin.unit-test.ts rename to packages/core/src/lib/implementation/execute-plugin.unit.test.ts index afafc9c8d..992e1bbd2 100644 --- a/packages/core/src/lib/implementation/execute-plugin.unit-test.ts +++ b/packages/core/src/lib/implementation/execute-plugin.unit.test.ts @@ -12,13 +12,10 @@ import { executePlugins, } from './execute-plugin'; -const nodePluginSlug = MINIMAL_PLUGIN_CONFIG_MOCK.slug; - -// eslint-disable-next-line max-lines-per-function describe('executePlugin', () => { it('should execute a valid plugin config', async () => { const pluginResult = await executePlugin(MINIMAL_PLUGIN_CONFIG_MOCK); - expect(pluginResult.audits[0]?.slug).toBe(nodePluginSlug); + expect(pluginResult.audits[0]?.slug).toBe('node-version'); }); it('should yield audit outputs for valid runner config', async () => { @@ -26,9 +23,9 @@ describe('executePlugin', () => { { 'output.json': JSON.stringify([ { - slug: nodePluginSlug, + slug: 'node-version', score: 1, - value: 2, + value: 1, }, ]), }, @@ -43,7 +40,7 @@ describe('executePlugin', () => { outputFile: 'output.json', }, }); - expect(pluginResult.audits[0]?.slug).toBe(nodePluginSlug); + expect(pluginResult.audits[0]?.slug).toBe('node-version'); }); it('should yield audit outputs for a valid runner function', async () => { @@ -51,7 +48,7 @@ describe('executePlugin', () => { ...MINIMAL_PLUGIN_CONFIG_MOCK, runner: () => [ { - slug: nodePluginSlug, + slug: 'node-version', score: 0, value: 1, }, @@ -59,10 +56,10 @@ describe('executePlugin', () => { }); expect(pluginResult.audits).toEqual([ expect.objectContaining({ - slug: nodePluginSlug, + slug: 'node-version', title: 'Node version', score: 0, - value: 2, + value: 1, }), ]); }); @@ -73,7 +70,7 @@ describe('executePlugin', () => { ...MINIMAL_PLUGIN_CONFIG_MOCK, audits: [{ slug: '-invalid-slug', title: 'Invalid audit' }], }), - ).rejects.toThrow(new PluginOutputMissingAuditError(nodePluginSlug)); + ).rejects.toThrow(new PluginOutputMissingAuditError('node-version')); }); it('should throw if invalid runnerOutput is produced', async () => { @@ -92,7 +89,6 @@ describe('executePlugin', () => { }); }); -// eslint-disable-next-line max-lines-per-function describe('executePlugins', () => { it('should execute valid plugins', async () => { const pluginResult = await executePlugins( @@ -108,7 +104,7 @@ describe('executePlugins', () => { expect(pluginResult[0]?.icon).toBe('javascript'); expect(pluginResult[1]?.icon).toBe('nodejs'); - expect(pluginResult[0]?.audits[0]?.slug).toBe(nodePluginSlug); + expect(pluginResult[0]?.audits[0]?.slug).toBe('node-version'); }); it('should throw for invalid plugins', async () => { @@ -131,7 +127,9 @@ describe('executePlugins', () => { it('should print invalid plugin errors and throw', async () => { const pluginConfig = { ...MINIMAL_PLUGIN_CONFIG_MOCK, - runner: vi.fn().mockRejectedValue('plugin 1 error'), + runner: vi + .fn() + .mockRejectedValue('Audit metadata not found for slug node-version'), }; const pluginConfig2 = { ...MINIMAL_PLUGIN_CONFIG_MOCK, @@ -147,15 +145,17 @@ describe('executePlugins', () => { progress: false, }), ).rejects.toThrow( - 'Plugins failed: 2 errors: plugin 1 error, plugin 3 error', + 'Plugins failed: 2 errors: Audit metadata not found for slug node-version, plugin 3 error', ); const logs = ui() .logger.getRenderer() .getLogs() .map(({ message }) => message); expect(logs[0]).toBe('[ yellow(warn) ] Plugins failed: '); - expect(logs[1]).toBe('[ yellow(warn) ] plugin 1 error'); - expect(logs[2]).toBe('[ yellow(warn) ] plugin 3 error'); + expect(logs[1]).toBe( + '[ yellow(warn) ] Audit metadata not found for slug node-version', + ); + expect(pluginConfig.runner).toHaveBeenCalled(); expect(pluginConfig2.runner).toHaveBeenCalled(); expect(pluginConfig3.runner).toHaveBeenCalled(); @@ -166,9 +166,9 @@ describe('executePlugins', () => { { 'output.json': JSON.stringify([ { - slug: nodePluginSlug, + slug: 'node-version', score: 1, - value: 2, + value: 1, }, ]), }, @@ -188,7 +188,7 @@ describe('executePlugins', () => { { slug: (outputs as AuditOutputs)[0]!.slug, score: 1, - value: 2, + value: 1, displayValue: '2.0.0', }, ]), @@ -197,7 +197,7 @@ describe('executePlugins', () => { ], { progress: false }, ); - expect(pluginResult[0]?.audits[0]?.slug).toBe(nodePluginSlug); + expect(pluginResult[0]?.audits[0]?.slug).toBe('node-version'); expect(pluginResult[0]?.audits[0]?.displayValue).toBe('2.0.0'); }); }); From 36306dc3434796dd08b911eb56b30a4d671b885c Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 8 Mar 2024 16:48:50 +0100 Subject: [PATCH 39/75] test(core): fix tests --- packages/utils/mocks/setup/cliui.mock.ts | 4 ++-- testing/test-setup/src/lib/cliui.mock.ts | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/utils/mocks/setup/cliui.mock.ts b/packages/utils/mocks/setup/cliui.mock.ts index 21df924d7..708013602 100644 --- a/packages/utils/mocks/setup/cliui.mock.ts +++ b/packages/utils/mocks/setup/cliui.mock.ts @@ -4,10 +4,10 @@ import {ui} from "../../src/lib/logging"; vi.mock('../../src/lib/logging', async () => { const module = await vi.importActual('../../src/lib/logging'); - module.ui().switchMode('raw') + (module['ui'] as () => {switchMode: (mode: string) => void})().switchMode('raw'); return module; }); beforeEach(() => { - ui().logger.flushLogs(); + ui().logger.flushLogs(); }) diff --git a/testing/test-setup/src/lib/cliui.mock.ts b/testing/test-setup/src/lib/cliui.mock.ts index 9b43677ff..d2d741873 100644 --- a/testing/test-setup/src/lib/cliui.mock.ts +++ b/testing/test-setup/src/lib/cliui.mock.ts @@ -3,7 +3,8 @@ import { vi } from 'vitest'; vi.mock('@code-pushup/utils', async () => { const module = await vi.importActual('@code-pushup/utils'); - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - module.ui().switchMode('raw'); + (module['ui'] as () => { switchMode: (mode: string) => void })().switchMode( + 'raw', + ); return module; }); From c243904de3daf6f409737f5497172fc8104bbf05 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 8 Mar 2024 16:57:14 +0100 Subject: [PATCH 40/75] wip --- packages/utils/mocks/setup/cliui.mock.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/utils/mocks/setup/cliui.mock.ts b/packages/utils/mocks/setup/cliui.mock.ts index 708013602..eabca3c48 100644 --- a/packages/utils/mocks/setup/cliui.mock.ts +++ b/packages/utils/mocks/setup/cliui.mock.ts @@ -1,8 +1,8 @@ import {beforeEach, vi} from "vitest"; -import {ui} from "../../src/lib/logging"; +import {ui} from "../../src"; vi.mock('../../src/lib/logging', async () => { - const module = await vi.importActual('../../src/lib/logging'); + const module = await vi.importActual('../../src'); (module['ui'] as () => {switchMode: (mode: string) => void})().switchMode('raw'); return module; From 46649cff2bf058044d894feb505a1856599ab014 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 8 Mar 2024 22:35:51 +0100 Subject: [PATCH 41/75] refactor: use log helper --- .../only-plugins.utils.unit.test.ts | 13 +++----- .../print-config-command.unit.test.ts | 30 ++++--------------- .../execute-plugin.unit.test.ts | 6 ++-- .../lib/implementation/persist.unit.test.ts | 26 ++++------------ packages/utils/mocks/setup/cliui.mock.ts | 10 ++----- packages/utils/src/lib/log-results.ts | 4 +-- .../utils/src/lib/log-results.unit.test.ts | 11 ++----- .../log-stdout-summary.integration.test.ts | 12 ++------ .../utils/src/lib/verbose-utils.unit.test.ts | 7 +++-- testing/test-utils/src/index.ts | 1 + testing/test-utils/src/lib/utils/logging.ts | 7 +++++ 11 files changed, 40 insertions(+), 87 deletions(-) create mode 100644 testing/test-utils/src/lib/utils/logging.ts diff --git a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts index 2a111033d..97026afb0 100644 --- a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts +++ b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts @@ -6,6 +6,7 @@ import { filterPluginsBySlug, validateOnlyPluginsOption, } from './only-plugins.utils'; +import {getLogMessages} from "@code-pushup/test-utils"; describe('filterPluginsBySlug', () => { it('should return all plugins if no onlyPlugins option is provided', () => { @@ -90,10 +91,7 @@ describe('filterCategoryByPluginSlug', () => { verbose: true, }, ); - const logs = ui() - .logger.getRenderer() - .getLogs() - .map(({ message }) => message); + const logs = getLogMessages(ui().logger); expect(logs[0]).toEqual( expect.stringContaining('Category "category1" is ignored'), ); @@ -121,10 +119,7 @@ describe('validateOnlyPluginsOption', () => { verbose: true, }, ); - const logs = ui() - .logger.getRenderer() - .getLogs() - .map(({ message }) => message); + const logs = getLogMessages(ui().logger); expect(logs[0]).toEqual( expect.stringContaining( 'The --onlyPlugin argument references plugins with "plugin3", "plugin4" slugs', @@ -140,6 +135,6 @@ describe('validateOnlyPluginsOption', () => { verbose: true, }, ); - expect(ui().logger.getRenderer().getLogs()).toHaveLength(0); + expect(getLogMessages(ui().logger)).toHaveLength(0); }); }); diff --git a/packages/cli/src/lib/print-config/print-config-command.unit.test.ts b/packages/cli/src/lib/print-config/print-config-command.unit.test.ts index 26f94fe0a..88be16b96 100644 --- a/packages/cli/src/lib/print-config/print-config-command.unit.test.ts +++ b/packages/cli/src/lib/print-config/print-config-command.unit.test.ts @@ -3,6 +3,7 @@ import { ui } from '@code-pushup/utils'; import { DEFAULT_CLI_CONFIGURATION } from '../../../mocks/constants'; import { yargsCli } from '../yargs-cli'; import { yargsConfigCommandObject } from './print-config-command'; +import {getLogMessages} from "@code-pushup/test-utils"; vi.mock('@code-pushup/core', async () => { const { CORE_CONFIG_MOCK }: typeof import('@code-pushup/test-utils') = @@ -26,30 +27,11 @@ describe('print-config-command', () => { { ...DEFAULT_CLI_CONFIGURATION, commands: [yargsConfigCommandObject()] }, ).parseAsync(); - const log = ui().logger.getLogs()[0]; + const log = getLogMessages(ui().logger)[0]; + expect(log).toEqual(expect.not.stringContaining('"$0":')); + expect(log).toEqual(expect.not.stringContaining('"_":')); - expect(log).toEqual( - expect.objectContaining({ - message: expect.not.stringContaining('"$0":'), - }), - ); - - expect(log).toEqual( - expect.objectContaining({ - message: expect.not.stringContaining('"_":'), - }), - ); - - expect(log).toEqual( - expect.objectContaining({ - message: expect.stringContaining('"outputDir": "destinationDir"'), - }), - ); - - expect(log).toEqual( - expect.objectContaining({ - message: expect.not.stringContaining('"output-dir":'), - }), - ); + expect(log).toEqual(expect.stringContaining('"outputDir": "destinationDir"')); + expect(log).toEqual(expect.not.stringContaining('"output-dir":')); }); }); diff --git a/packages/core/src/lib/implementation/execute-plugin.unit.test.ts b/packages/core/src/lib/implementation/execute-plugin.unit.test.ts index 992e1bbd2..8ffea0793 100644 --- a/packages/core/src/lib/implementation/execute-plugin.unit.test.ts +++ b/packages/core/src/lib/implementation/execute-plugin.unit.test.ts @@ -2,6 +2,7 @@ import { vol } from 'memfs'; import { describe, expect, it, vi } from 'vitest'; import { AuditOutputs, PluginConfig } from '@code-pushup/models'; import { + getLogMessages, MEMFS_VOLUME, MINIMAL_PLUGIN_CONFIG_MOCK, } from '@code-pushup/test-utils'; @@ -147,10 +148,7 @@ describe('executePlugins', () => { ).rejects.toThrow( 'Plugins failed: 2 errors: Audit metadata not found for slug node-version, plugin 3 error', ); - const logs = ui() - .logger.getRenderer() - .getLogs() - .map(({ message }) => message); + const logs = getLogMessages(ui().logger); expect(logs[0]).toBe('[ yellow(warn) ] Plugins failed: '); expect(logs[1]).toBe( '[ yellow(warn) ] Audit metadata not found for slug node-version', diff --git a/packages/core/src/lib/implementation/persist.unit.test.ts b/packages/core/src/lib/implementation/persist.unit.test.ts index 1e9c8e168..92ac37393 100644 --- a/packages/core/src/lib/implementation/persist.unit.test.ts +++ b/packages/core/src/lib/implementation/persist.unit.test.ts @@ -4,6 +4,7 @@ import { join } from 'node:path'; import { beforeEach, describe, expect, it } from 'vitest'; import { Report } from '@code-pushup/models'; import { + getLogMessages, MEMFS_VOLUME, MINIMAL_REPORT_MOCK, REPORT_MOCK, @@ -23,10 +24,7 @@ describe('persistReport', () => { filename: 'report', format: [], }); - const logs = ui() - .logger.getRenderer() - .getLogs() - .map(({ message }) => message); + const logs = getLogMessages(ui().logger); expect(logs.at(-1)).toEqual( expect.stringContaining('Made with ❤ by code-pushup.dev'), ); @@ -38,10 +36,7 @@ describe('persistReport', () => { filename: 'report', format: ['md', 'json'], }); - const logs = ui() - .logger.getRenderer() - .getLogs() - .map(({ message }) => message); + const logs = getLogMessages(ui().logger); expect(logs.at(-1)).toEqual( expect.stringContaining('Made with ❤ by code-pushup.dev'), ); @@ -114,10 +109,7 @@ describe('logPersistedResults', () => { it('should log report sizes correctly`', () => { logPersistedResults([{ status: 'fulfilled', value: ['out.json', 10_000] }]); - const logs = ui() - .logger.getRenderer() - .getLogs() - .map(({ message }) => message); + const logs = getLogMessages(ui().logger); expect(logs[0]).toBe('[ green(success) ] Generated reports successfully: '); expect(logs[1]).toEqual(expect.stringContaining('9.77 kB')); expect(logs[1]).toEqual(expect.stringContaining('out.json')); @@ -125,10 +117,7 @@ describe('logPersistedResults', () => { it('should log fails correctly`', () => { logPersistedResults([{ status: 'rejected', reason: 'fail' }]); - const logs = ui() - .logger.getRenderer() - .getLogs() - .map(({ message }) => message); + const logs = getLogMessages(ui().logger); expect(logs[0]).toBe('[ yellow(warn) ] Generated reports failed: '); expect(logs[1]).toEqual(expect.stringContaining('fail')); }); @@ -138,10 +127,7 @@ describe('logPersistedResults', () => { { status: 'fulfilled', value: ['out.json', 10_000] }, { status: 'rejected', reason: 'fail' }, ]); - const logs = ui() - .logger.getRenderer() - .getLogs() - .map(({ message }) => message); + const logs = getLogMessages(ui().logger); expect(logs[0]).toBe('[ green(success) ] Generated reports successfully: '); expect(logs[1]).toEqual(expect.stringContaining('out.json')); expect(logs[1]).toEqual(expect.stringContaining('9.77 kB')); diff --git a/packages/utils/mocks/setup/cliui.mock.ts b/packages/utils/mocks/setup/cliui.mock.ts index eabca3c48..d2ae798d8 100644 --- a/packages/utils/mocks/setup/cliui.mock.ts +++ b/packages/utils/mocks/setup/cliui.mock.ts @@ -1,13 +1,7 @@ -import {beforeEach, vi} from "vitest"; -import {ui} from "../../src"; +import {vi} from "vitest"; vi.mock('../../src/lib/logging', async () => { - const module = await vi.importActual('../../src'); - + const module = await vi.importActual('../../src/lib/logging'); (module['ui'] as () => {switchMode: (mode: string) => void})().switchMode('raw'); return module; }); - -beforeEach(() => { - ui().logger.flushLogs(); -}) diff --git a/packages/utils/src/lib/log-results.ts b/packages/utils/src/lib/log-results.ts index 4289d768d..62a0467e2 100644 --- a/packages/utils/src/lib/log-results.ts +++ b/packages/utils/src/lib/log-results.ts @@ -34,8 +34,8 @@ export function logPromiseResults< if (results.length > 0) { const log = results[0]?.status === 'fulfilled' - ? ui().logger.success - : ui().logger.warning; + ? (m: string) => { ui().logger.success(m); } + : (m: string) => { ui().logger.warning(m); }; log(logMessage); results.forEach(result => { diff --git a/packages/utils/src/lib/log-results.unit.test.ts b/packages/utils/src/lib/log-results.unit.test.ts index 305e90759..4b4aecff8 100644 --- a/packages/utils/src/lib/log-results.unit.test.ts +++ b/packages/utils/src/lib/log-results.unit.test.ts @@ -2,6 +2,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import { FileResult } from './file-system'; import { logMultipleResults, logPromiseResults } from './log-results'; import { ui } from './logging'; +import {getLogMessages} from "@code-pushup/test-utils"; describe('logMultipleResults', () => { const succeededCallbackMock = vi.fn(); @@ -71,10 +72,7 @@ describe('logPromiseResults', () => { 'Uploaded reports successfully:', (result): string => result.value.toString(), ); - const logs = ui() - .logger.getRenderer() - .getLogs() - .map(({ message }) => message); + const logs = getLogMessages(ui().logger); expect(logs[0]).toBe('[ green(success) ] Uploaded reports successfully:'); expect(logs[1]).toBe('[ green(success) ] out.json'); }); @@ -85,10 +83,7 @@ describe('logPromiseResults', () => { 'Generated reports failed:', (result: { reason: string }) => result.reason, ); - const logs = ui() - .logger.getRenderer() - .getLogs() - .map(({ message }) => message); + const logs = getLogMessages(ui().logger); expect(logs[0]).toBe('[ yellow(warn) ] Generated reports failed:'); expect(logs[1]).toBe('[ yellow(warn) ] fail'); }); diff --git a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts index 4beb2f270..933767fad 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts @@ -1,5 +1,5 @@ import { beforeEach, describe } from 'vitest'; -import { reportMock } from '@code-pushup/test-utils'; +import {getLogMessages, reportMock} from '@code-pushup/test-utils'; import { ui } from '../logging'; import { logStdoutSummary } from './log-stdout-summary'; import { scoreReport } from './scoring'; @@ -12,10 +12,7 @@ describe('logStdoutSummary', () => { it('should contain all sections when using the fixture report', () => { logStdoutSummary(sortReport(scoreReport(reportMock()))); - const output = ui() - .logger.getRenderer() - .getLogs() - .map(({ message }) => message) + const output = getLogMessages(ui().logger) .join('\n'); expect(output).toContain('Categories'); @@ -28,10 +25,7 @@ describe('logStdoutSummary', () => { logStdoutSummary( sortReport(scoreReport({ ...reportMock(), categories: [] })), ); - const output = ui() - .logger.getRenderer() - .getLogs() - .map(({ message }) => message) + const output = getLogMessages(ui().logger) .join('\n'); expect(output).not.toContain('Categories'); diff --git a/packages/utils/src/lib/verbose-utils.unit.test.ts b/packages/utils/src/lib/verbose-utils.unit.test.ts index 6092a413a..f709bb17a 100644 --- a/packages/utils/src/lib/verbose-utils.unit.test.ts +++ b/packages/utils/src/lib/verbose-utils.unit.test.ts @@ -1,6 +1,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import { ui } from './logging'; import { verboseUtils } from './verbose-utils'; +import {getLogMessages} from "@code-pushup/test-utils"; describe('verbose-utils', () => { beforeEach(() => { @@ -26,16 +27,16 @@ describe('verbose-utils', () => { it('logs should be off by default', () => { verboseUtils(false).log('42'); - expect(ui().logger.getRenderer().getLogs()).toHaveLength(0); + expect(getLogMessages(ui().logger)).toHaveLength(0); }); it('log should work no-verbose', () => { verboseUtils(false).log('42'); - expect(ui().logger.getRenderer().getLogs()).toHaveLength(0); + expect(getLogMessages(ui().logger)).toHaveLength(0); }); it('log should work verbose', () => { verboseUtils(true).log('42'); - expect(ui().logger.getRenderer().getLogs()[0]?.message).toContain('42'); + expect(getLogMessages(ui().logger)[0]).toContain('42'); }); }); diff --git a/testing/test-utils/src/index.ts b/testing/test-utils/src/index.ts index 7cf110924..03ebf88fd 100644 --- a/testing/test-utils/src/index.ts +++ b/testing/test-utils/src/index.ts @@ -1,6 +1,7 @@ export * from './lib/constants'; export * from './lib/utils/execute-process-helper.mock'; export * from './lib/utils/os-agnostic-paths'; +export * from './lib/utils/logging'; // static mocks export * from './lib/utils/core-config.mock'; diff --git a/testing/test-utils/src/lib/utils/logging.ts b/testing/test-utils/src/lib/utils/logging.ts new file mode 100644 index 000000000..b710c752d --- /dev/null +++ b/testing/test-utils/src/lib/utils/logging.ts @@ -0,0 +1,7 @@ +import type {Logger} from "@poppinss/cliui"; + +export function getLogMessages(logger: Logger): string[] { + return logger.getRenderer() + .getLogs() + .map(({ message }) => message); +} From a681f9669ea227668031c192e27f6c0beebe305f Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 8 Mar 2024 22:40:53 +0100 Subject: [PATCH 42/75] refactor: format --- .../lib/implementation/only-plugins.utils.unit.test.ts | 2 +- .../lib/print-config/print-config-command.unit.test.ts | 6 ++++-- .../src/lib/implementation/execute-plugin.unit.test.ts | 2 +- packages/core/src/lib/implementation/persist.unit.test.ts | 2 +- packages/utils/src/lib/log-results.ts | 8 ++++++-- packages/utils/src/lib/log-results.unit.test.ts | 2 +- .../lib/reports/log-stdout-summary.integration.test.ts | 8 +++----- packages/utils/src/lib/verbose-utils.unit.test.ts | 2 +- testing/test-utils/src/lib/utils/logging.ts | 5 +++-- 9 files changed, 21 insertions(+), 16 deletions(-) diff --git a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts index 97026afb0..592bbdf37 100644 --- a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts +++ b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts @@ -1,12 +1,12 @@ import { beforeEach, describe, expect } from 'vitest'; import { CategoryConfig, CoreConfig } from '@code-pushup/models'; +import { getLogMessages } from '@code-pushup/test-utils'; import { ui } from '@code-pushup/utils'; import { filterCategoryByPluginSlug, filterPluginsBySlug, validateOnlyPluginsOption, } from './only-plugins.utils'; -import {getLogMessages} from "@code-pushup/test-utils"; describe('filterPluginsBySlug', () => { it('should return all plugins if no onlyPlugins option is provided', () => { diff --git a/packages/cli/src/lib/print-config/print-config-command.unit.test.ts b/packages/cli/src/lib/print-config/print-config-command.unit.test.ts index 88be16b96..27a852cb0 100644 --- a/packages/cli/src/lib/print-config/print-config-command.unit.test.ts +++ b/packages/cli/src/lib/print-config/print-config-command.unit.test.ts @@ -1,9 +1,9 @@ import { describe, expect, vi } from 'vitest'; +import { getLogMessages } from '@code-pushup/test-utils'; import { ui } from '@code-pushup/utils'; import { DEFAULT_CLI_CONFIGURATION } from '../../../mocks/constants'; import { yargsCli } from '../yargs-cli'; import { yargsConfigCommandObject } from './print-config-command'; -import {getLogMessages} from "@code-pushup/test-utils"; vi.mock('@code-pushup/core', async () => { const { CORE_CONFIG_MOCK }: typeof import('@code-pushup/test-utils') = @@ -31,7 +31,9 @@ describe('print-config-command', () => { expect(log).toEqual(expect.not.stringContaining('"$0":')); expect(log).toEqual(expect.not.stringContaining('"_":')); - expect(log).toEqual(expect.stringContaining('"outputDir": "destinationDir"')); + expect(log).toEqual( + expect.stringContaining('"outputDir": "destinationDir"'), + ); expect(log).toEqual(expect.not.stringContaining('"output-dir":')); }); }); diff --git a/packages/core/src/lib/implementation/execute-plugin.unit.test.ts b/packages/core/src/lib/implementation/execute-plugin.unit.test.ts index 8ffea0793..06b13a31d 100644 --- a/packages/core/src/lib/implementation/execute-plugin.unit.test.ts +++ b/packages/core/src/lib/implementation/execute-plugin.unit.test.ts @@ -2,9 +2,9 @@ import { vol } from 'memfs'; import { describe, expect, it, vi } from 'vitest'; import { AuditOutputs, PluginConfig } from '@code-pushup/models'; import { - getLogMessages, MEMFS_VOLUME, MINIMAL_PLUGIN_CONFIG_MOCK, + getLogMessages, } from '@code-pushup/test-utils'; import { ui } from '@code-pushup/utils'; import { diff --git a/packages/core/src/lib/implementation/persist.unit.test.ts b/packages/core/src/lib/implementation/persist.unit.test.ts index 92ac37393..911dfdf2a 100644 --- a/packages/core/src/lib/implementation/persist.unit.test.ts +++ b/packages/core/src/lib/implementation/persist.unit.test.ts @@ -4,10 +4,10 @@ import { join } from 'node:path'; import { beforeEach, describe, expect, it } from 'vitest'; import { Report } from '@code-pushup/models'; import { - getLogMessages, MEMFS_VOLUME, MINIMAL_REPORT_MOCK, REPORT_MOCK, + getLogMessages, } from '@code-pushup/test-utils'; import { ui } from '@code-pushup/utils'; import { logPersistedResults, persistReport } from './persist'; diff --git a/packages/utils/src/lib/log-results.ts b/packages/utils/src/lib/log-results.ts index 62a0467e2..e848114ef 100644 --- a/packages/utils/src/lib/log-results.ts +++ b/packages/utils/src/lib/log-results.ts @@ -34,8 +34,12 @@ export function logPromiseResults< if (results.length > 0) { const log = results[0]?.status === 'fulfilled' - ? (m: string) => { ui().logger.success(m); } - : (m: string) => { ui().logger.warning(m); }; + ? (m: string) => { + ui().logger.success(m); + } + : (m: string) => { + ui().logger.warning(m); + }; log(logMessage); results.forEach(result => { diff --git a/packages/utils/src/lib/log-results.unit.test.ts b/packages/utils/src/lib/log-results.unit.test.ts index 4b4aecff8..3e66c9f9e 100644 --- a/packages/utils/src/lib/log-results.unit.test.ts +++ b/packages/utils/src/lib/log-results.unit.test.ts @@ -1,8 +1,8 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { getLogMessages } from '@code-pushup/test-utils'; import { FileResult } from './file-system'; import { logMultipleResults, logPromiseResults } from './log-results'; import { ui } from './logging'; -import {getLogMessages} from "@code-pushup/test-utils"; describe('logMultipleResults', () => { const succeededCallbackMock = vi.fn(); diff --git a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts index 933767fad..5c2a4c5f3 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts @@ -1,5 +1,5 @@ import { beforeEach, describe } from 'vitest'; -import {getLogMessages, reportMock} from '@code-pushup/test-utils'; +import { getLogMessages, reportMock } from '@code-pushup/test-utils'; import { ui } from '../logging'; import { logStdoutSummary } from './log-stdout-summary'; import { scoreReport } from './scoring'; @@ -12,8 +12,7 @@ describe('logStdoutSummary', () => { it('should contain all sections when using the fixture report', () => { logStdoutSummary(sortReport(scoreReport(reportMock()))); - const output = getLogMessages(ui().logger) - .join('\n'); + const output = getLogMessages(ui().logger).join('\n'); expect(output).toContain('Categories'); // removes all color codes from the output for snapshot readability @@ -25,8 +24,7 @@ describe('logStdoutSummary', () => { logStdoutSummary( sortReport(scoreReport({ ...reportMock(), categories: [] })), ); - const output = getLogMessages(ui().logger) - .join('\n'); + const output = getLogMessages(ui().logger).join('\n'); expect(output).not.toContain('Categories'); // removes all color codes from the output for snapshot readability diff --git a/packages/utils/src/lib/verbose-utils.unit.test.ts b/packages/utils/src/lib/verbose-utils.unit.test.ts index f709bb17a..0b458e507 100644 --- a/packages/utils/src/lib/verbose-utils.unit.test.ts +++ b/packages/utils/src/lib/verbose-utils.unit.test.ts @@ -1,7 +1,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { getLogMessages } from '@code-pushup/test-utils'; import { ui } from './logging'; import { verboseUtils } from './verbose-utils'; -import {getLogMessages} from "@code-pushup/test-utils"; describe('verbose-utils', () => { beforeEach(() => { diff --git a/testing/test-utils/src/lib/utils/logging.ts b/testing/test-utils/src/lib/utils/logging.ts index b710c752d..43ab1d6c3 100644 --- a/testing/test-utils/src/lib/utils/logging.ts +++ b/testing/test-utils/src/lib/utils/logging.ts @@ -1,7 +1,8 @@ -import type {Logger} from "@poppinss/cliui"; +import type { Logger } from '@poppinss/cliui'; export function getLogMessages(logger: Logger): string[] { - return logger.getRenderer() + return logger + .getRenderer() .getLogs() .map(({ message }) => message); } From df57b736b56aee30bf78d2a2fdf378cc8bf05938 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 8 Mar 2024 22:50:52 +0100 Subject: [PATCH 43/75] refactor(utils): adjust setup scripts --- packages/utils/mocks/setup/cliui.mock.ts | 12 +++++++++--- packages/utils/src/lib/log-results.unit.test.ts | 6 +----- .../reports/log-stdout-summary.integration.test.ts | 6 +----- packages/utils/src/lib/verbose-utils.unit.test.ts | 5 +---- 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/packages/utils/mocks/setup/cliui.mock.ts b/packages/utils/mocks/setup/cliui.mock.ts index d2ae798d8..0746515a7 100644 --- a/packages/utils/mocks/setup/cliui.mock.ts +++ b/packages/utils/mocks/setup/cliui.mock.ts @@ -1,7 +1,13 @@ -import {vi} from "vitest"; +import {beforeEach, vi} from "vitest"; +import { type CliUi } from "../../src/lib/logging"; vi.mock('../../src/lib/logging', async () => { - const module = await vi.importActual('../../src/lib/logging'); - (module['ui'] as () => {switchMode: (mode: string) => void})().switchMode('raw'); + const module = await vi.importActual<{ui: () => CliUi}>('../../src/lib/logging'); + module.ui().switchMode('raw'); return module; }); + +beforeEach(async () => { + const module = await vi.importActual<{ui: () => CliUi}>('../../src/lib/logging'); + module.ui().logger.flushLogs(); +}); diff --git a/packages/utils/src/lib/log-results.unit.test.ts b/packages/utils/src/lib/log-results.unit.test.ts index 3e66c9f9e..1a2b4acec 100644 --- a/packages/utils/src/lib/log-results.unit.test.ts +++ b/packages/utils/src/lib/log-results.unit.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; import { getLogMessages } from '@code-pushup/test-utils'; import { FileResult } from './file-system'; import { logMultipleResults, logPromiseResults } from './log-results'; @@ -57,10 +57,6 @@ describe('logMultipleResults', () => { }); describe('logPromiseResults', () => { - beforeEach(() => { - ui().logger.flushLogs(); - }); - it('should log on success', () => { logPromiseResults( [ diff --git a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts index 5c2a4c5f3..1ec0347dd 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe } from 'vitest'; +import { describe } from 'vitest'; import { getLogMessages, reportMock } from '@code-pushup/test-utils'; import { ui } from '../logging'; import { logStdoutSummary } from './log-stdout-summary'; @@ -6,10 +6,6 @@ import { scoreReport } from './scoring'; import { sortReport } from './sorting'; describe('logStdoutSummary', () => { - beforeEach(() => { - ui().logger.flushLogs(); - }); - it('should contain all sections when using the fixture report', () => { logStdoutSummary(sortReport(scoreReport(reportMock()))); const output = getLogMessages(ui().logger).join('\n'); diff --git a/packages/utils/src/lib/verbose-utils.unit.test.ts b/packages/utils/src/lib/verbose-utils.unit.test.ts index 0b458e507..b369077d7 100644 --- a/packages/utils/src/lib/verbose-utils.unit.test.ts +++ b/packages/utils/src/lib/verbose-utils.unit.test.ts @@ -1,12 +1,9 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; import { getLogMessages } from '@code-pushup/test-utils'; import { ui } from './logging'; import { verboseUtils } from './verbose-utils'; describe('verbose-utils', () => { - beforeEach(() => { - ui().logger.flushLogs(); - }); it('exec should be off by default', () => { const spy = vi.fn(); verboseUtils().exec(spy); From ca7014963e3da7871f56b9e6ce3f2938b87489b2 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 8 Mar 2024 22:56:07 +0100 Subject: [PATCH 44/75] refactor: adjust setup scripts --- .../only-plugins.utils.unit.test.ts | 8 +------- .../lib/implementation/persist.unit.test.ts | 5 ----- packages/utils/src/index.ts | 2 +- testing/test-setup/src/lib/cliui.mock.ts | 18 +++++++++++++----- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts index 592bbdf37..9ecd3e9ec 100644 --- a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts +++ b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect } from 'vitest'; +import { describe, expect } from 'vitest'; import { CategoryConfig, CoreConfig } from '@code-pushup/models'; import { getLogMessages } from '@code-pushup/test-utils'; import { ui } from '@code-pushup/utils'; @@ -37,9 +37,6 @@ describe('filterPluginsBySlug', () => { }); describe('filterCategoryByPluginSlug', () => { - beforeEach(() => { - ui().logger.flushLogs(); - }); it('should return all categories if no onlyPlugins option', () => { expect( filterCategoryByPluginSlug( @@ -108,9 +105,6 @@ describe('filterCategoryByPluginSlug', () => { }); describe('validateOnlyPluginsOption', () => { - beforeEach(() => { - ui().logger.flushLogs(); - }); it('should warn if onlyPlugins option contains non-existing plugin', () => { validateOnlyPluginsOption( [{ slug: 'plugin1' }, { slug: 'plugin2' }] as CoreConfig['plugins'], diff --git a/packages/core/src/lib/implementation/persist.unit.test.ts b/packages/core/src/lib/implementation/persist.unit.test.ts index 911dfdf2a..7cdb318f7 100644 --- a/packages/core/src/lib/implementation/persist.unit.test.ts +++ b/packages/core/src/lib/implementation/persist.unit.test.ts @@ -15,7 +15,6 @@ import { logPersistedResults, persistReport } from './persist'; describe('persistReport', () => { beforeEach(() => { vol.fromJSON({}, MEMFS_VOLUME); - ui().logger.flushLogs(); }); it('should print a summary to stdout when no format is specified`', async () => { @@ -103,10 +102,6 @@ describe('persistReport', () => { }); describe('logPersistedResults', () => { - beforeEach(() => { - ui().logger.flushLogs(); - }); - it('should log report sizes correctly`', () => { logPersistedResults([{ status: 'fulfilled', value: ['out.json', 10_000] }]); const logs = getLogMessages(ui().logger); diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 007234221..9379eac8f 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -79,4 +79,4 @@ export { toUnixPath, } from './lib/transform'; export { verboseUtils } from './lib/verbose-utils'; -export { link, ui, Column } from './lib/logging'; +export { link, ui, CliUi, Column } from './lib/logging'; diff --git a/testing/test-setup/src/lib/cliui.mock.ts b/testing/test-setup/src/lib/cliui.mock.ts index d2d741873..3e9e48808 100644 --- a/testing/test-setup/src/lib/cliui.mock.ts +++ b/testing/test-setup/src/lib/cliui.mock.ts @@ -1,10 +1,18 @@ -import { vi } from 'vitest'; +import { beforeEach, vi } from 'vitest'; +import type { CliUi } from '@code-pushup/utils'; vi.mock('@code-pushup/utils', async () => { - const module = await vi.importActual('@code-pushup/utils'); - - (module['ui'] as () => { switchMode: (mode: string) => void })().switchMode( - 'raw', + const module = await vi.importActual<{ ui: () => CliUi }>( + '@code-pushup/utils', ); + + module.ui().switchMode('raw'); return module; }); + +beforeEach(async () => { + const module = await vi.importActual<{ ui: () => CliUi }>( + '@code-pushup/utils', + ); + module.ui().logger.flushLogs(); +}); From 158823e1095a9de14cac1ea7a08188ecec1c1d06 Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Fri, 8 Mar 2024 23:04:02 +0100 Subject: [PATCH 45/75] Update packages/utils/src/lib/verbose-utils.unit.test.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Katka Pilátová --- packages/utils/src/lib/verbose-utils.unit.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/lib/verbose-utils.unit.test.ts b/packages/utils/src/lib/verbose-utils.unit.test.ts index b369077d7..76d6b0ba9 100644 --- a/packages/utils/src/lib/verbose-utils.unit.test.ts +++ b/packages/utils/src/lib/verbose-utils.unit.test.ts @@ -27,7 +27,7 @@ describe('verbose-utils', () => { expect(getLogMessages(ui().logger)).toHaveLength(0); }); - it('log should work no-verbose', () => { + it('should not print any logs when verbose is off', () => { verboseUtils(false).log('42'); expect(getLogMessages(ui().logger)).toHaveLength(0); }); From c59133154d0b86f49e293bc1719d99df25a87b34 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 8 Mar 2024 23:15:39 +0100 Subject: [PATCH 46/75] refactor: update snapshots --- ...og-stdout-summary.integration.test.ts.snap | 316 ------------------ 1 file changed, 316 deletions(-) delete mode 100644 packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap diff --git a/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap b/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap deleted file mode 100644 index c93c129ac..000000000 --- a/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap +++ /dev/null @@ -1,316 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`generateStdoutSummary > should contain all sections when using the fixture report 1`] = ` -"Code PushUp Report - @code-pushup/core@0.0.1 - - -ESLint audits - -● Disallow missing props validation in a React component definition 6 warnings -● Disallow variable declarations from shadowing variables declared in 3 warnings -the outer scope -● Require or disallow method and property shorthand syntax for object 3 warnings -literals -● verifies the list of dependencies for Hooks like useEffect and 2 warnings -similar -● Disallow missing \`key\` props in iterators/collection literals 1 warning -● Disallow unused variables 1 warning -● Enforce a maximum number of lines of code in a function 1 warning -● Require \`const\` declarations for variables that are never reassigned1 warning -after declared -● Require braces around arrow function bodies 1 warning -● Require the use of \`===\` and \`!==\` 1 warning -● Disallow \`target="_blank"\` attribute without \`rel="noreferrer"\` passed -● Disallow assignment operators in conditional expressions passed -● Disallow comments from being inserted as text nodes passed -● Disallow direct mutation of this.state passed -● Disallow duplicate properties in JSX passed -● Disallow invalid regular expression strings in \`RegExp\` constructorspassed -● Disallow loops with a body that allows only one iteration passed -● Disallow missing displayName in a React component definition passed -● Disallow missing React when using JSX passed -● Disallow negating the left operand of relational operators passed -● Disallow passing of children as props passed -● Disallow React to be incorrectly marked as unused passed -● Disallow reassigning \`const\` variables passed -● Disallow the use of \`debugger\` passed -● Disallow the use of undeclared variables unless mentioned in passed -\`/*global */\` comments -● Disallow undeclared variables in JSX passed -● Disallow unescaped HTML entities from appearing in markup passed -● Disallow usage of deprecated methods passed -● Disallow usage of findDOMNode passed -● Disallow usage of isMounted passed -● Disallow usage of the return value of ReactDOM.render passed -● Disallow usage of unknown DOM property passed -● Disallow use of optional chaining in contexts where the \`undefined\` passed -value is not allowed -● Disallow using Object.assign with an object literal as the first passed -argument and prefer the use of object spread instead -● Disallow using string references passed -● Disallow variables used in JSX to be incorrectly marked as unused passed -● Disallow when a DOM element is using both children and passed -dangerouslySetInnerHTML -● Enforce a maximum number of lines per file passed -● Enforce camelcase naming convention passed -● Enforce comparing \`typeof\` expressions against valid strings passed -● Enforce consistent brace style for all control statements passed -● Enforce ES5 or ES6 class for returning value in render function passed -● enforces the Rules of Hooks passed -● Require \`let\` or \`const\` instead of \`var\` passed -● Require calls to \`isNaN()\` when checking for \`NaN\` passed -● Require or disallow "Yoda" conditions passed -● Require using arrow functions for callbacks passed - - -Lighthouse audits - -● First Contentful Paint 1.2 s -● Largest Contentful Paint 1.5 s -● Speed Index 1.2 s -● Cumulative Layout Shift 0 -● Total Blocking Time 0 ms - -Categories - -┌─────────────────────────────────────────────────────────────┬───────┬────────┐ -│ Category │ Score │ Audits │ -├─────────────────────────────────────────────────────────────┼───────┼────────┤ -│ Performance │ 92 │ 8 │ -├─────────────────────────────────────────────────────────────┼───────┼────────┤ -│ Bug prevention │ 68 │ 16 │ -├─────────────────────────────────────────────────────────────┼───────┼────────┤ -│ Code style │ 54 │ 13 │ -└─────────────────────────────────────────────────────────────┴───────┴────────┘ - -Made with ❤ by code-pushup.dev -" -`; - -exports[`generateStdoutSummary > should not contain category section when categories are empty 1`] = ` -"Code PushUp Report - @code-pushup/core@0.0.1 - - -ESLint audits - -● Disallow missing props validation in a React component definition 6 warnings -● Disallow variable declarations from shadowing variables declared in 3 warnings -the outer scope -● Require or disallow method and property shorthand syntax for object 3 warnings -literals -● verifies the list of dependencies for Hooks like useEffect and 2 warnings -similar -● Disallow missing \`key\` props in iterators/collection literals 1 warning -● Disallow unused variables 1 warning -● Enforce a maximum number of lines of code in a function 1 warning -● Require \`const\` declarations for variables that are never reassigned1 warning -after declared -● Require braces around arrow function bodies 1 warning -● Require the use of \`===\` and \`!==\` 1 warning -● Disallow \`target="_blank"\` attribute without \`rel="noreferrer"\` passed -● Disallow assignment operators in conditional expressions passed -● Disallow comments from being inserted as text nodes passed -● Disallow direct mutation of this.state passed -● Disallow duplicate properties in JSX passed -● Disallow invalid regular expression strings in \`RegExp\` constructorspassed -● Disallow loops with a body that allows only one iteration passed -● Disallow missing displayName in a React component definition passed -● Disallow missing React when using JSX passed -● Disallow negating the left operand of relational operators passed -● Disallow passing of children as props passed -● Disallow React to be incorrectly marked as unused passed -● Disallow reassigning \`const\` variables passed -● Disallow the use of \`debugger\` passed -● Disallow the use of undeclared variables unless mentioned in passed -\`/*global */\` comments -● Disallow undeclared variables in JSX passed -● Disallow unescaped HTML entities from appearing in markup passed -● Disallow usage of deprecated methods passed -● Disallow usage of findDOMNode passed -● Disallow usage of isMounted passed -● Disallow usage of the return value of ReactDOM.render passed -● Disallow usage of unknown DOM property passed -● Disallow use of optional chaining in contexts where the \`undefined\` passed -value is not allowed -● Disallow using Object.assign with an object literal as the first passed -argument and prefer the use of object spread instead -● Disallow using string references passed -● Disallow variables used in JSX to be incorrectly marked as unused passed -● Disallow when a DOM element is using both children and passed -dangerouslySetInnerHTML -● Enforce a maximum number of lines per file passed -● Enforce camelcase naming convention passed -● Enforce comparing \`typeof\` expressions against valid strings passed -● Enforce consistent brace style for all control statements passed -● Enforce ES5 or ES6 class for returning value in render function passed -● enforces the Rules of Hooks passed -● Require \`let\` or \`const\` instead of \`var\` passed -● Require calls to \`isNaN()\` when checking for \`NaN\` passed -● Require or disallow "Yoda" conditions passed -● Require using arrow functions for callbacks passed - - -Lighthouse audits - -● First Contentful Paint 1.2 s -● Largest Contentful Paint 1.5 s -● Speed Index 1.2 s -● Cumulative Layout Shift 0 -● Total Blocking Time 0 ms - -Made with ❤ by code-pushup.dev" -`; - -exports[`logStdoutSummary > should contain all sections when using the fixture report 1`] = ` -"Code PushUp Report - @code-pushup/core@0.0.1 - - -ESLint audits - -● Disallow missing props validation in a React component definition 6 warnings -● Disallow variable declarations from shadowing variables declared in 3 warnings -the outer scope -● Require or disallow method and property shorthand syntax for object 3 warnings -literals -● verifies the list of dependencies for Hooks like useEffect and 2 warnings -similar -● Disallow missing \`key\` props in iterators/collection literals 1 warning -● Disallow unused variables 1 warning -● Enforce a maximum number of lines of code in a function 1 warning -● Require \`const\` declarations for variables that are never reassigned1 warning -after declared -● Require braces around arrow function bodies 1 warning -● Require the use of \`===\` and \`!==\` 1 warning -● Disallow \`target="_blank"\` attribute without \`rel="noreferrer"\` passed -● Disallow assignment operators in conditional expressions passed -● Disallow comments from being inserted as text nodes passed -● Disallow direct mutation of this.state passed -● Disallow duplicate properties in JSX passed -● Disallow invalid regular expression strings in \`RegExp\` constructorspassed -● Disallow loops with a body that allows only one iteration passed -● Disallow missing displayName in a React component definition passed -● Disallow missing React when using JSX passed -● Disallow negating the left operand of relational operators passed -● Disallow passing of children as props passed -● Disallow React to be incorrectly marked as unused passed -● Disallow reassigning \`const\` variables passed -● Disallow the use of \`debugger\` passed -● Disallow the use of undeclared variables unless mentioned in passed -\`/*global */\` comments -● Disallow undeclared variables in JSX passed -● Disallow unescaped HTML entities from appearing in markup passed -● Disallow usage of deprecated methods passed -● Disallow usage of findDOMNode passed -● Disallow usage of isMounted passed -● Disallow usage of the return value of ReactDOM.render passed -● Disallow usage of unknown DOM property passed -● Disallow use of optional chaining in contexts where the \`undefined\` passed -value is not allowed -● Disallow using Object.assign with an object literal as the first passed -argument and prefer the use of object spread instead -● Disallow using string references passed -● Disallow variables used in JSX to be incorrectly marked as unused passed -● Disallow when a DOM element is using both children and passed -dangerouslySetInnerHTML -● Enforce a maximum number of lines per file passed -● Enforce camelcase naming convention passed -● Enforce comparing \`typeof\` expressions against valid strings passed -● Enforce consistent brace style for all control statements passed -● Enforce ES5 or ES6 class for returning value in render function passed -● enforces the Rules of Hooks passed -● Require \`let\` or \`const\` instead of \`var\` passed -● Require calls to \`isNaN()\` when checking for \`NaN\` passed -● Require or disallow "Yoda" conditions passed -● Require using arrow functions for callbacks passed - - -Lighthouse audits - -● First Contentful Paint 1.2 s -● Largest Contentful Paint 1.5 s -● Speed Index 1.2 s -● Cumulative Layout Shift 0 -● Total Blocking Time 0 ms - -Categories - -Category|Score|Audits -Performance|92|8 -Bug prevention|68|16 -Code style|54|13 -Made with ❤ by code-pushup.dev" -`; - -exports[`logStdoutSummary > should not contain category section when categories are empty 1`] = ` -"Code PushUp Report - @code-pushup/core@0.0.1 - - -ESLint audits - -● Disallow missing props validation in a React component definition 6 warnings -● Disallow variable declarations from shadowing variables declared in 3 warnings -the outer scope -● Require or disallow method and property shorthand syntax for object 3 warnings -literals -● verifies the list of dependencies for Hooks like useEffect and 2 warnings -similar -● Disallow missing \`key\` props in iterators/collection literals 1 warning -● Disallow unused variables 1 warning -● Enforce a maximum number of lines of code in a function 1 warning -● Require \`const\` declarations for variables that are never reassigned1 warning -after declared -● Require braces around arrow function bodies 1 warning -● Require the use of \`===\` and \`!==\` 1 warning -● Disallow \`target="_blank"\` attribute without \`rel="noreferrer"\` passed -● Disallow assignment operators in conditional expressions passed -● Disallow comments from being inserted as text nodes passed -● Disallow direct mutation of this.state passed -● Disallow duplicate properties in JSX passed -● Disallow invalid regular expression strings in \`RegExp\` constructorspassed -● Disallow loops with a body that allows only one iteration passed -● Disallow missing displayName in a React component definition passed -● Disallow missing React when using JSX passed -● Disallow negating the left operand of relational operators passed -● Disallow passing of children as props passed -● Disallow React to be incorrectly marked as unused passed -● Disallow reassigning \`const\` variables passed -● Disallow the use of \`debugger\` passed -● Disallow the use of undeclared variables unless mentioned in passed -\`/*global */\` comments -● Disallow undeclared variables in JSX passed -● Disallow unescaped HTML entities from appearing in markup passed -● Disallow usage of deprecated methods passed -● Disallow usage of findDOMNode passed -● Disallow usage of isMounted passed -● Disallow usage of the return value of ReactDOM.render passed -● Disallow usage of unknown DOM property passed -● Disallow use of optional chaining in contexts where the \`undefined\` passed -value is not allowed -● Disallow using Object.assign with an object literal as the first passed -argument and prefer the use of object spread instead -● Disallow using string references passed -● Disallow variables used in JSX to be incorrectly marked as unused passed -● Disallow when a DOM element is using both children and passed -dangerouslySetInnerHTML -● Enforce a maximum number of lines per file passed -● Enforce camelcase naming convention passed -● Enforce comparing \`typeof\` expressions against valid strings passed -● Enforce consistent brace style for all control statements passed -● Enforce ES5 or ES6 class for returning value in render function passed -● enforces the Rules of Hooks passed -● Require \`let\` or \`const\` instead of \`var\` passed -● Require calls to \`isNaN()\` when checking for \`NaN\` passed -● Require or disallow "Yoda" conditions passed -● Require using arrow functions for callbacks passed - - -Lighthouse audits - -● First Contentful Paint 1.2 s -● Largest Contentful Paint 1.5 s -● Speed Index 1.2 s -● Cumulative Layout Shift 0 -● Total Blocking Time 0 ms - -Made with ❤ by code-pushup.dev" -`; From ac4197291741156222a56091d52e21609b33eb1b Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 8 Mar 2024 23:15:47 +0100 Subject: [PATCH 47/75] refactor: update snapshots --- ...og-stdout-summary.integration.test.ts.snap | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap diff --git a/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap b/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap new file mode 100644 index 000000000..e612e9016 --- /dev/null +++ b/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap @@ -0,0 +1,155 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`logStdoutSummary > should contain all sections when using the fixture report 1`] = ` +"Code PushUp Report - @code-pushup/core@0.0.1 + + +ESLint audits + +● Disallow missing props validation in a React component definition 6 warnings +● Disallow variable declarations from shadowing variables declared in 3 warnings +the outer scope +● Require or disallow method and property shorthand syntax for object 3 warnings +literals +● verifies the list of dependencies for Hooks like useEffect and 2 warnings +similar +● Disallow missing \`key\` props in iterators/collection literals 1 warning +● Disallow unused variables 1 warning +● Enforce a maximum number of lines of code in a function 1 warning +● Require \`const\` declarations for variables that are never reassigned1 warning +after declared +● Require braces around arrow function bodies 1 warning +● Require the use of \`===\` and \`!==\` 1 warning +● Disallow \`target="_blank"\` attribute without \`rel="noreferrer"\` passed +● Disallow assignment operators in conditional expressions passed +● Disallow comments from being inserted as text nodes passed +● Disallow direct mutation of this.state passed +● Disallow duplicate properties in JSX passed +● Disallow invalid regular expression strings in \`RegExp\` constructorspassed +● Disallow loops with a body that allows only one iteration passed +● Disallow missing displayName in a React component definition passed +● Disallow missing React when using JSX passed +● Disallow negating the left operand of relational operators passed +● Disallow passing of children as props passed +● Disallow React to be incorrectly marked as unused passed +● Disallow reassigning \`const\` variables passed +● Disallow the use of \`debugger\` passed +● Disallow the use of undeclared variables unless mentioned in passed +\`/*global */\` comments +● Disallow undeclared variables in JSX passed +● Disallow unescaped HTML entities from appearing in markup passed +● Disallow usage of deprecated methods passed +● Disallow usage of findDOMNode passed +● Disallow usage of isMounted passed +● Disallow usage of the return value of ReactDOM.render passed +● Disallow usage of unknown DOM property passed +● Disallow use of optional chaining in contexts where the \`undefined\` passed +value is not allowed +● Disallow using Object.assign with an object literal as the first passed +argument and prefer the use of object spread instead +● Disallow using string references passed +● Disallow variables used in JSX to be incorrectly marked as unused passed +● Disallow when a DOM element is using both children and passed +dangerouslySetInnerHTML +● Enforce a maximum number of lines per file passed +● Enforce camelcase naming convention passed +● Enforce comparing \`typeof\` expressions against valid strings passed +● Enforce consistent brace style for all control statements passed +● Enforce ES5 or ES6 class for returning value in render function passed +● enforces the Rules of Hooks passed +● Require \`let\` or \`const\` instead of \`var\` passed +● Require calls to \`isNaN()\` when checking for \`NaN\` passed +● Require or disallow "Yoda" conditions passed +● Require using arrow functions for callbacks passed + + +Lighthouse audits + +● First Contentful Paint 1.2 s +● Largest Contentful Paint 1.5 s +● Speed Index 1.2 s +● Cumulative Layout Shift 0 +● Total Blocking Time 0 ms + +Categories + +Category|Score|Audits +Performance|92|8 +Bug prevention|68|16 +Code style|54|13 +Made with ❤ by code-pushup.dev" +`; + +exports[`logStdoutSummary > should not contain category section when categories are empty 1`] = ` +"Code PushUp Report - @code-pushup/core@0.0.1 + + +ESLint audits + +● Disallow missing props validation in a React component definition 6 warnings +● Disallow variable declarations from shadowing variables declared in 3 warnings +the outer scope +● Require or disallow method and property shorthand syntax for object 3 warnings +literals +● verifies the list of dependencies for Hooks like useEffect and 2 warnings +similar +● Disallow missing \`key\` props in iterators/collection literals 1 warning +● Disallow unused variables 1 warning +● Enforce a maximum number of lines of code in a function 1 warning +● Require \`const\` declarations for variables that are never reassigned1 warning +after declared +● Require braces around arrow function bodies 1 warning +● Require the use of \`===\` and \`!==\` 1 warning +● Disallow \`target="_blank"\` attribute without \`rel="noreferrer"\` passed +● Disallow assignment operators in conditional expressions passed +● Disallow comments from being inserted as text nodes passed +● Disallow direct mutation of this.state passed +● Disallow duplicate properties in JSX passed +● Disallow invalid regular expression strings in \`RegExp\` constructorspassed +● Disallow loops with a body that allows only one iteration passed +● Disallow missing displayName in a React component definition passed +● Disallow missing React when using JSX passed +● Disallow negating the left operand of relational operators passed +● Disallow passing of children as props passed +● Disallow React to be incorrectly marked as unused passed +● Disallow reassigning \`const\` variables passed +● Disallow the use of \`debugger\` passed +● Disallow the use of undeclared variables unless mentioned in passed +\`/*global */\` comments +● Disallow undeclared variables in JSX passed +● Disallow unescaped HTML entities from appearing in markup passed +● Disallow usage of deprecated methods passed +● Disallow usage of findDOMNode passed +● Disallow usage of isMounted passed +● Disallow usage of the return value of ReactDOM.render passed +● Disallow usage of unknown DOM property passed +● Disallow use of optional chaining in contexts where the \`undefined\` passed +value is not allowed +● Disallow using Object.assign with an object literal as the first passed +argument and prefer the use of object spread instead +● Disallow using string references passed +● Disallow variables used in JSX to be incorrectly marked as unused passed +● Disallow when a DOM element is using both children and passed +dangerouslySetInnerHTML +● Enforce a maximum number of lines per file passed +● Enforce camelcase naming convention passed +● Enforce comparing \`typeof\` expressions against valid strings passed +● Enforce consistent brace style for all control statements passed +● Enforce ES5 or ES6 class for returning value in render function passed +● enforces the Rules of Hooks passed +● Require \`let\` or \`const\` instead of \`var\` passed +● Require calls to \`isNaN()\` when checking for \`NaN\` passed +● Require or disallow "Yoda" conditions passed +● Require using arrow functions for callbacks passed + + +Lighthouse audits + +● First Contentful Paint 1.2 s +● Largest Contentful Paint 1.5 s +● Speed Index 1.2 s +● Cumulative Layout Shift 0 +● Total Blocking Time 0 ms + +Made with ❤ by code-pushup.dev" +`; From b0846c39d0f6941143513e7b062b00b1840d34e7 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 8 Mar 2024 23:20:47 +0100 Subject: [PATCH 48/75] refactor: adjust setup scripts --- packages/utils/mocks/setup/cliui.mock.ts | 6 ++++-- testing/test-setup/src/lib/cliui.mock.ts | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/utils/mocks/setup/cliui.mock.ts b/packages/utils/mocks/setup/cliui.mock.ts index 0746515a7..3f9b73b52 100644 --- a/packages/utils/mocks/setup/cliui.mock.ts +++ b/packages/utils/mocks/setup/cliui.mock.ts @@ -8,6 +8,8 @@ vi.mock('../../src/lib/logging', async () => { }); beforeEach(async () => { - const module = await vi.importActual<{ui: () => CliUi}>('../../src/lib/logging'); - module.ui().logger.flushLogs(); + const {ui} = await vi.importActual<{ ui: () => CliUi }>( + '../../src/lib/logging', + ); + ui().logger.flushLogs(); }); diff --git a/testing/test-setup/src/lib/cliui.mock.ts b/testing/test-setup/src/lib/cliui.mock.ts index 3e9e48808..158456017 100644 --- a/testing/test-setup/src/lib/cliui.mock.ts +++ b/testing/test-setup/src/lib/cliui.mock.ts @@ -11,8 +11,8 @@ vi.mock('@code-pushup/utils', async () => { }); beforeEach(async () => { - const module = await vi.importActual<{ ui: () => CliUi }>( + const {ui} = await vi.importActual<{ ui: () => CliUi }>( '@code-pushup/utils', ); - module.ui().logger.flushLogs(); + ui().logger.flushLogs(); }); From fc14474221dedfb0e075fa79d424c971af8ed36d Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 8 Mar 2024 23:29:37 +0100 Subject: [PATCH 49/75] refactor: revert report log logic for detail section --- ...og-stdout-summary.integration.test.ts.snap | 80 +++++++++++-------- .../src/lib/reports/log-stdout-summary.ts | 15 ++-- testing/test-setup/src/lib/cliui.mock.ts | 2 +- 3 files changed, 56 insertions(+), 41 deletions(-) diff --git a/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap b/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap index e612e9016..89d840321 100644 --- a/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap +++ b/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap @@ -1,23 +1,23 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`logStdoutSummary > should contain all sections when using the fixture report 1`] = ` +exports[`generateStdoutSummary > should contain all sections when using the fixture report 1`] = ` "Code PushUp Report - @code-pushup/core@0.0.1 ESLint audits ● Disallow missing props validation in a React component definition 6 warnings -● Disallow variable declarations from shadowing variables declared in 3 warnings -the outer scope -● Require or disallow method and property shorthand syntax for object 3 warnings -literals +● Disallow variable declarations from shadowing variables declared 3 warnings + in the outer scope +● Require or disallow method and property shorthand syntax for 3 warnings + object literals ● verifies the list of dependencies for Hooks like useEffect and 2 warnings -similar + similar ● Disallow missing \`key\` props in iterators/collection literals 1 warning ● Disallow unused variables 1 warning ● Enforce a maximum number of lines of code in a function 1 warning -● Require \`const\` declarations for variables that are never reassigned1 warning -after declared +● Require \`const\` declarations for variables that are never 1 warning + reassigned after declared ● Require braces around arrow function bodies 1 warning ● Require the use of \`===\` and \`!==\` 1 warning ● Disallow \`target="_blank"\` attribute without \`rel="noreferrer"\` passed @@ -25,7 +25,8 @@ after declared ● Disallow comments from being inserted as text nodes passed ● Disallow direct mutation of this.state passed ● Disallow duplicate properties in JSX passed -● Disallow invalid regular expression strings in \`RegExp\` constructorspassed +● Disallow invalid regular expression strings in \`RegExp\` passed + constructors ● Disallow loops with a body that allows only one iteration passed ● Disallow missing displayName in a React component definition passed ● Disallow missing React when using JSX passed @@ -35,7 +36,7 @@ after declared ● Disallow reassigning \`const\` variables passed ● Disallow the use of \`debugger\` passed ● Disallow the use of undeclared variables unless mentioned in passed -\`/*global */\` comments + \`/*global */\` comments ● Disallow undeclared variables in JSX passed ● Disallow unescaped HTML entities from appearing in markup passed ● Disallow usage of deprecated methods passed @@ -43,14 +44,14 @@ after declared ● Disallow usage of isMounted passed ● Disallow usage of the return value of ReactDOM.render passed ● Disallow usage of unknown DOM property passed -● Disallow use of optional chaining in contexts where the \`undefined\` passed -value is not allowed +● Disallow use of optional chaining in contexts where the passed + \`undefined\` value is not allowed ● Disallow using Object.assign with an object literal as the first passed -argument and prefer the use of object spread instead + argument and prefer the use of object spread instead ● Disallow using string references passed ● Disallow variables used in JSX to be incorrectly marked as unused passed ● Disallow when a DOM element is using both children and passed -dangerouslySetInnerHTML + dangerouslySetInnerHTML ● Enforce a maximum number of lines per file passed ● Enforce camelcase naming convention passed ● Enforce comparing \`typeof\` expressions against valid strings passed @@ -71,33 +72,41 @@ Lighthouse audits ● Cumulative Layout Shift 0 ● Total Blocking Time 0 ms + Categories -Category|Score|Audits -Performance|92|8 -Bug prevention|68|16 -Code style|54|13 -Made with ❤ by code-pushup.dev" +┌─────────────────────────────────────────────────────────────┬───────┬────────┐ +│ Category │ Score │ Audits │ +├─────────────────────────────────────────────────────────────┼───────┼────────┤ +│ Performance │ 92 │ 8 │ +├─────────────────────────────────────────────────────────────┼───────┼────────┤ +│ Bug prevention │ 68 │ 16 │ +├─────────────────────────────────────────────────────────────┼───────┼────────┤ +│ Code style │ 54 │ 13 │ +└─────────────────────────────────────────────────────────────┴───────┴────────┘ + +Made with ❤ by code-pushup.dev +" `; -exports[`logStdoutSummary > should not contain category section when categories are empty 1`] = ` +exports[`generateStdoutSummary > should not contain category section when categories are empty 1`] = ` "Code PushUp Report - @code-pushup/core@0.0.1 ESLint audits ● Disallow missing props validation in a React component definition 6 warnings -● Disallow variable declarations from shadowing variables declared in 3 warnings -the outer scope -● Require or disallow method and property shorthand syntax for object 3 warnings -literals +● Disallow variable declarations from shadowing variables declared 3 warnings + in the outer scope +● Require or disallow method and property shorthand syntax for 3 warnings + object literals ● verifies the list of dependencies for Hooks like useEffect and 2 warnings -similar + similar ● Disallow missing \`key\` props in iterators/collection literals 1 warning ● Disallow unused variables 1 warning ● Enforce a maximum number of lines of code in a function 1 warning -● Require \`const\` declarations for variables that are never reassigned1 warning -after declared +● Require \`const\` declarations for variables that are never 1 warning + reassigned after declared ● Require braces around arrow function bodies 1 warning ● Require the use of \`===\` and \`!==\` 1 warning ● Disallow \`target="_blank"\` attribute without \`rel="noreferrer"\` passed @@ -105,7 +114,8 @@ after declared ● Disallow comments from being inserted as text nodes passed ● Disallow direct mutation of this.state passed ● Disallow duplicate properties in JSX passed -● Disallow invalid regular expression strings in \`RegExp\` constructorspassed +● Disallow invalid regular expression strings in \`RegExp\` passed + constructors ● Disallow loops with a body that allows only one iteration passed ● Disallow missing displayName in a React component definition passed ● Disallow missing React when using JSX passed @@ -115,7 +125,7 @@ after declared ● Disallow reassigning \`const\` variables passed ● Disallow the use of \`debugger\` passed ● Disallow the use of undeclared variables unless mentioned in passed -\`/*global */\` comments + \`/*global */\` comments ● Disallow undeclared variables in JSX passed ● Disallow unescaped HTML entities from appearing in markup passed ● Disallow usage of deprecated methods passed @@ -123,14 +133,14 @@ after declared ● Disallow usage of isMounted passed ● Disallow usage of the return value of ReactDOM.render passed ● Disallow usage of unknown DOM property passed -● Disallow use of optional chaining in contexts where the \`undefined\` passed -value is not allowed +● Disallow use of optional chaining in contexts where the passed + \`undefined\` value is not allowed ● Disallow using Object.assign with an object literal as the first passed -argument and prefer the use of object spread instead + argument and prefer the use of object spread instead ● Disallow using string references passed ● Disallow variables used in JSX to be incorrectly marked as unused passed ● Disallow when a DOM element is using both children and passed -dangerouslySetInnerHTML + dangerouslySetInnerHTML ● Enforce a maximum number of lines per file passed ● Enforce camelcase naming convention passed ● Enforce comparing \`typeof\` expressions against valid strings passed @@ -151,5 +161,7 @@ Lighthouse audits ● Cumulative Layout Shift 0 ● Total Blocking Time 0 ms -Made with ❤ by code-pushup.dev" + +Made with ❤ by code-pushup.dev +" `; diff --git a/packages/utils/src/lib/reports/log-stdout-summary.ts b/packages/utils/src/lib/reports/log-stdout-summary.ts index ce7659544..1ac737216 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.ts @@ -42,18 +42,21 @@ function logPlugins(report: ScoredReport): void { log(chalk.magentaBright.bold(`${title} audits`)); log(); audits.forEach((audit: AuditReport) => { - const padding = [0, 0, 0, 0]; ui().row([ { - text: `${applyScoreColor({ score: audit.score, text: '●' })} ${ - audit.title - }`, - padding, + text: applyScoreColor({ score: audit.score, text: '●' }), + width: 2, + padding: [0, 1, 0, 0], + }, + { + text: audit.title, + // eslint-disable-next-line no-magic-numbers + padding: [0, 3, 0, 0], }, { text: chalk.cyanBright(audit.displayValue || `${audit.value}`), width: 10, - padding, + padding: [0, 0, 0, 0], }, ]); }); diff --git a/testing/test-setup/src/lib/cliui.mock.ts b/testing/test-setup/src/lib/cliui.mock.ts index 158456017..72de45984 100644 --- a/testing/test-setup/src/lib/cliui.mock.ts +++ b/testing/test-setup/src/lib/cliui.mock.ts @@ -11,7 +11,7 @@ vi.mock('@code-pushup/utils', async () => { }); beforeEach(async () => { - const {ui} = await vi.importActual<{ ui: () => CliUi }>( + const { ui } = await vi.importActual<{ ui: () => CliUi }>( '@code-pushup/utils', ); ui().logger.flushLogs(); From e77c6b4903cc0ea3b885f68d8c2b52ea1156e4ac Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 8 Mar 2024 23:32:47 +0100 Subject: [PATCH 50/75] update snapshots --- ...og-stdout-summary.integration.test.ts.snap | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap b/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap index 89d840321..18e001f1c 100644 --- a/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap +++ b/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap @@ -165,3 +165,159 @@ Lighthouse audits Made with ❤ by code-pushup.dev " `; + +exports[`logStdoutSummary > should contain all sections when using the fixture report 1`] = ` +"Code PushUp Report - @code-pushup/core@0.0.1 + + +ESLint audits + +● Disallow missing props validation in a React component definition 6 warnings +● Disallow variable declarations from shadowing variables declared 3 warnings + in the outer scope +● Require or disallow method and property shorthand syntax for 3 warnings + object literals +● verifies the list of dependencies for Hooks like useEffect and 2 warnings + similar +● Disallow missing \`key\` props in iterators/collection literals 1 warning +● Disallow unused variables 1 warning +● Enforce a maximum number of lines of code in a function 1 warning +● Require \`const\` declarations for variables that are never 1 warning + reassigned after declared +● Require braces around arrow function bodies 1 warning +● Require the use of \`===\` and \`!==\` 1 warning +● Disallow \`target="_blank"\` attribute without \`rel="noreferrer"\` passed +● Disallow assignment operators in conditional expressions passed +● Disallow comments from being inserted as text nodes passed +● Disallow direct mutation of this.state passed +● Disallow duplicate properties in JSX passed +● Disallow invalid regular expression strings in \`RegExp\` passed + constructors +● Disallow loops with a body that allows only one iteration passed +● Disallow missing displayName in a React component definition passed +● Disallow missing React when using JSX passed +● Disallow negating the left operand of relational operators passed +● Disallow passing of children as props passed +● Disallow React to be incorrectly marked as unused passed +● Disallow reassigning \`const\` variables passed +● Disallow the use of \`debugger\` passed +● Disallow the use of undeclared variables unless mentioned in passed + \`/*global */\` comments +● Disallow undeclared variables in JSX passed +● Disallow unescaped HTML entities from appearing in markup passed +● Disallow usage of deprecated methods passed +● Disallow usage of findDOMNode passed +● Disallow usage of isMounted passed +● Disallow usage of the return value of ReactDOM.render passed +● Disallow usage of unknown DOM property passed +● Disallow use of optional chaining in contexts where the passed + \`undefined\` value is not allowed +● Disallow using Object.assign with an object literal as the first passed + argument and prefer the use of object spread instead +● Disallow using string references passed +● Disallow variables used in JSX to be incorrectly marked as unused passed +● Disallow when a DOM element is using both children and passed + dangerouslySetInnerHTML +● Enforce a maximum number of lines per file passed +● Enforce camelcase naming convention passed +● Enforce comparing \`typeof\` expressions against valid strings passed +● Enforce consistent brace style for all control statements passed +● Enforce ES5 or ES6 class for returning value in render function passed +● enforces the Rules of Hooks passed +● Require \`let\` or \`const\` instead of \`var\` passed +● Require calls to \`isNaN()\` when checking for \`NaN\` passed +● Require or disallow "Yoda" conditions passed +● Require using arrow functions for callbacks passed + + +Lighthouse audits + +● First Contentful Paint 1.2 s +● Largest Contentful Paint 1.5 s +● Speed Index 1.2 s +● Cumulative Layout Shift 0 +● Total Blocking Time 0 ms + +Categories + +Category|Score|Audits +Performance|92|8 +Bug prevention|68|16 +Code style|54|13 +Made with ❤ by code-pushup.dev" +`; + +exports[`logStdoutSummary > should not contain category section when categories are empty 1`] = ` +"Code PushUp Report - @code-pushup/core@0.0.1 + + +ESLint audits + +● Disallow missing props validation in a React component definition 6 warnings +● Disallow variable declarations from shadowing variables declared 3 warnings + in the outer scope +● Require or disallow method and property shorthand syntax for 3 warnings + object literals +● verifies the list of dependencies for Hooks like useEffect and 2 warnings + similar +● Disallow missing \`key\` props in iterators/collection literals 1 warning +● Disallow unused variables 1 warning +● Enforce a maximum number of lines of code in a function 1 warning +● Require \`const\` declarations for variables that are never 1 warning + reassigned after declared +● Require braces around arrow function bodies 1 warning +● Require the use of \`===\` and \`!==\` 1 warning +● Disallow \`target="_blank"\` attribute without \`rel="noreferrer"\` passed +● Disallow assignment operators in conditional expressions passed +● Disallow comments from being inserted as text nodes passed +● Disallow direct mutation of this.state passed +● Disallow duplicate properties in JSX passed +● Disallow invalid regular expression strings in \`RegExp\` passed + constructors +● Disallow loops with a body that allows only one iteration passed +● Disallow missing displayName in a React component definition passed +● Disallow missing React when using JSX passed +● Disallow negating the left operand of relational operators passed +● Disallow passing of children as props passed +● Disallow React to be incorrectly marked as unused passed +● Disallow reassigning \`const\` variables passed +● Disallow the use of \`debugger\` passed +● Disallow the use of undeclared variables unless mentioned in passed + \`/*global */\` comments +● Disallow undeclared variables in JSX passed +● Disallow unescaped HTML entities from appearing in markup passed +● Disallow usage of deprecated methods passed +● Disallow usage of findDOMNode passed +● Disallow usage of isMounted passed +● Disallow usage of the return value of ReactDOM.render passed +● Disallow usage of unknown DOM property passed +● Disallow use of optional chaining in contexts where the passed + \`undefined\` value is not allowed +● Disallow using Object.assign with an object literal as the first passed + argument and prefer the use of object spread instead +● Disallow using string references passed +● Disallow variables used in JSX to be incorrectly marked as unused passed +● Disallow when a DOM element is using both children and passed + dangerouslySetInnerHTML +● Enforce a maximum number of lines per file passed +● Enforce camelcase naming convention passed +● Enforce comparing \`typeof\` expressions against valid strings passed +● Enforce consistent brace style for all control statements passed +● Enforce ES5 or ES6 class for returning value in render function passed +● enforces the Rules of Hooks passed +● Require \`let\` or \`const\` instead of \`var\` passed +● Require calls to \`isNaN()\` when checking for \`NaN\` passed +● Require or disallow "Yoda" conditions passed +● Require using arrow functions for callbacks passed + + +Lighthouse audits + +● First Contentful Paint 1.2 s +● Largest Contentful Paint 1.5 s +● Speed Index 1.2 s +● Cumulative Layout Shift 0 +● Total Blocking Time 0 ms + +Made with ❤ by code-pushup.dev" +`; From dec81c9998a417dd813b270155f6b5e89aa142ba Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 9 Mar 2024 01:05:36 +0100 Subject: [PATCH 51/75] update snapshots --- ...og-stdout-summary.integration.test.ts.snap | 166 ------------------ 1 file changed, 166 deletions(-) diff --git a/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap b/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap index 18e001f1c..7fe027366 100644 --- a/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap +++ b/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap @@ -1,171 +1,5 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`generateStdoutSummary > should contain all sections when using the fixture report 1`] = ` -"Code PushUp Report - @code-pushup/core@0.0.1 - - -ESLint audits - -● Disallow missing props validation in a React component definition 6 warnings -● Disallow variable declarations from shadowing variables declared 3 warnings - in the outer scope -● Require or disallow method and property shorthand syntax for 3 warnings - object literals -● verifies the list of dependencies for Hooks like useEffect and 2 warnings - similar -● Disallow missing \`key\` props in iterators/collection literals 1 warning -● Disallow unused variables 1 warning -● Enforce a maximum number of lines of code in a function 1 warning -● Require \`const\` declarations for variables that are never 1 warning - reassigned after declared -● Require braces around arrow function bodies 1 warning -● Require the use of \`===\` and \`!==\` 1 warning -● Disallow \`target="_blank"\` attribute without \`rel="noreferrer"\` passed -● Disallow assignment operators in conditional expressions passed -● Disallow comments from being inserted as text nodes passed -● Disallow direct mutation of this.state passed -● Disallow duplicate properties in JSX passed -● Disallow invalid regular expression strings in \`RegExp\` passed - constructors -● Disallow loops with a body that allows only one iteration passed -● Disallow missing displayName in a React component definition passed -● Disallow missing React when using JSX passed -● Disallow negating the left operand of relational operators passed -● Disallow passing of children as props passed -● Disallow React to be incorrectly marked as unused passed -● Disallow reassigning \`const\` variables passed -● Disallow the use of \`debugger\` passed -● Disallow the use of undeclared variables unless mentioned in passed - \`/*global */\` comments -● Disallow undeclared variables in JSX passed -● Disallow unescaped HTML entities from appearing in markup passed -● Disallow usage of deprecated methods passed -● Disallow usage of findDOMNode passed -● Disallow usage of isMounted passed -● Disallow usage of the return value of ReactDOM.render passed -● Disallow usage of unknown DOM property passed -● Disallow use of optional chaining in contexts where the passed - \`undefined\` value is not allowed -● Disallow using Object.assign with an object literal as the first passed - argument and prefer the use of object spread instead -● Disallow using string references passed -● Disallow variables used in JSX to be incorrectly marked as unused passed -● Disallow when a DOM element is using both children and passed - dangerouslySetInnerHTML -● Enforce a maximum number of lines per file passed -● Enforce camelcase naming convention passed -● Enforce comparing \`typeof\` expressions against valid strings passed -● Enforce consistent brace style for all control statements passed -● Enforce ES5 or ES6 class for returning value in render function passed -● enforces the Rules of Hooks passed -● Require \`let\` or \`const\` instead of \`var\` passed -● Require calls to \`isNaN()\` when checking for \`NaN\` passed -● Require or disallow "Yoda" conditions passed -● Require using arrow functions for callbacks passed - - -Lighthouse audits - -● First Contentful Paint 1.2 s -● Largest Contentful Paint 1.5 s -● Speed Index 1.2 s -● Cumulative Layout Shift 0 -● Total Blocking Time 0 ms - - -Categories - -┌─────────────────────────────────────────────────────────────┬───────┬────────┐ -│ Category │ Score │ Audits │ -├─────────────────────────────────────────────────────────────┼───────┼────────┤ -│ Performance │ 92 │ 8 │ -├─────────────────────────────────────────────────────────────┼───────┼────────┤ -│ Bug prevention │ 68 │ 16 │ -├─────────────────────────────────────────────────────────────┼───────┼────────┤ -│ Code style │ 54 │ 13 │ -└─────────────────────────────────────────────────────────────┴───────┴────────┘ - -Made with ❤ by code-pushup.dev -" -`; - -exports[`generateStdoutSummary > should not contain category section when categories are empty 1`] = ` -"Code PushUp Report - @code-pushup/core@0.0.1 - - -ESLint audits - -● Disallow missing props validation in a React component definition 6 warnings -● Disallow variable declarations from shadowing variables declared 3 warnings - in the outer scope -● Require or disallow method and property shorthand syntax for 3 warnings - object literals -● verifies the list of dependencies for Hooks like useEffect and 2 warnings - similar -● Disallow missing \`key\` props in iterators/collection literals 1 warning -● Disallow unused variables 1 warning -● Enforce a maximum number of lines of code in a function 1 warning -● Require \`const\` declarations for variables that are never 1 warning - reassigned after declared -● Require braces around arrow function bodies 1 warning -● Require the use of \`===\` and \`!==\` 1 warning -● Disallow \`target="_blank"\` attribute without \`rel="noreferrer"\` passed -● Disallow assignment operators in conditional expressions passed -● Disallow comments from being inserted as text nodes passed -● Disallow direct mutation of this.state passed -● Disallow duplicate properties in JSX passed -● Disallow invalid regular expression strings in \`RegExp\` passed - constructors -● Disallow loops with a body that allows only one iteration passed -● Disallow missing displayName in a React component definition passed -● Disallow missing React when using JSX passed -● Disallow negating the left operand of relational operators passed -● Disallow passing of children as props passed -● Disallow React to be incorrectly marked as unused passed -● Disallow reassigning \`const\` variables passed -● Disallow the use of \`debugger\` passed -● Disallow the use of undeclared variables unless mentioned in passed - \`/*global */\` comments -● Disallow undeclared variables in JSX passed -● Disallow unescaped HTML entities from appearing in markup passed -● Disallow usage of deprecated methods passed -● Disallow usage of findDOMNode passed -● Disallow usage of isMounted passed -● Disallow usage of the return value of ReactDOM.render passed -● Disallow usage of unknown DOM property passed -● Disallow use of optional chaining in contexts where the passed - \`undefined\` value is not allowed -● Disallow using Object.assign with an object literal as the first passed - argument and prefer the use of object spread instead -● Disallow using string references passed -● Disallow variables used in JSX to be incorrectly marked as unused passed -● Disallow when a DOM element is using both children and passed - dangerouslySetInnerHTML -● Enforce a maximum number of lines per file passed -● Enforce camelcase naming convention passed -● Enforce comparing \`typeof\` expressions against valid strings passed -● Enforce consistent brace style for all control statements passed -● Enforce ES5 or ES6 class for returning value in render function passed -● enforces the Rules of Hooks passed -● Require \`let\` or \`const\` instead of \`var\` passed -● Require calls to \`isNaN()\` when checking for \`NaN\` passed -● Require or disallow "Yoda" conditions passed -● Require using arrow functions for callbacks passed - - -Lighthouse audits - -● First Contentful Paint 1.2 s -● Largest Contentful Paint 1.5 s -● Speed Index 1.2 s -● Cumulative Layout Shift 0 -● Total Blocking Time 0 ms - - -Made with ❤ by code-pushup.dev -" -`; - exports[`logStdoutSummary > should contain all sections when using the fixture report 1`] = ` "Code PushUp Report - @code-pushup/core@0.0.1 From 45ccd9303fefeda90e205292558e8e25d1caa380 Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Sat, 9 Mar 2024 01:08:24 +0100 Subject: [PATCH 52/75] Update packages/utils/src/lib/verbose-utils.unit.test.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Katka Pilátová --- packages/utils/src/lib/verbose-utils.unit.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/lib/verbose-utils.unit.test.ts b/packages/utils/src/lib/verbose-utils.unit.test.ts index 76d6b0ba9..2326f70ec 100644 --- a/packages/utils/src/lib/verbose-utils.unit.test.ts +++ b/packages/utils/src/lib/verbose-utils.unit.test.ts @@ -32,7 +32,7 @@ describe('verbose-utils', () => { expect(getLogMessages(ui().logger)).toHaveLength(0); }); - it('log should work verbose', () => { + it('should log when verbose is on', () => { verboseUtils(true).log('42'); expect(getLogMessages(ui().logger)[0]).toContain('42'); }); From bec7758dbbed32ace33b2801fec711423ac148bd Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 9 Mar 2024 01:21:46 +0100 Subject: [PATCH 53/75] refactor(coverage-plugin): use logger instead of console --- packages/plugin-coverage/src/lib/nx/coverage-paths.ts | 7 ++++--- packages/plugin-coverage/src/lib/runner/index.ts | 9 +++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts index 171487eea..850cd5c08 100644 --- a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts +++ b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts @@ -1,6 +1,7 @@ import type { ProjectGraphProjectNode, TargetConfiguration } from '@nx/devkit'; import chalk from 'chalk'; import { join } from 'node:path'; +import { ui } from '@code-pushup/utils'; import { CoverageResult } from '../config'; /** @@ -10,7 +11,7 @@ import { CoverageResult } from '../config'; export async function getNxCoveragePaths( targets: string[] = ['test'], ): Promise { - console.info( + ui().logger.info( chalk.bold('💡 Gathering coverage from the following nx projects:'), ); const { createProjectGraphAsync } = await import('@nx/devkit'); @@ -26,7 +27,7 @@ export async function getNxCoveragePaths( const coveragePath = getCoveragePathForTarget(target, targetConfig, name); const rootToReportsDir = join(data.root, coveragePath); - console.info(`- ${name}: ${target}`); + ui().logger.info(`- ${name}: ${target}`); return { pathToProject: data.root, @@ -35,7 +36,7 @@ export async function getNxCoveragePaths( }); }); - console.info('\n'); + ui().logger.info('\n'); return coverageResults.flat(); } diff --git a/packages/plugin-coverage/src/lib/runner/index.ts b/packages/plugin-coverage/src/lib/runner/index.ts index 11fc45fa3..7d67d5322 100644 --- a/packages/plugin-coverage/src/lib/runner/index.ts +++ b/packages/plugin-coverage/src/lib/runner/index.ts @@ -7,6 +7,7 @@ import { ensureDirectoryExists, executeProcess, readJsonFile, + ui, } from '@code-pushup/utils'; import { FinalCoveragePluginConfig } from '../config'; import { applyMaxScoreAboveThreshold } from '../utils'; @@ -24,10 +25,10 @@ export async function executeRunner(): Promise { await executeProcess({ command, args }); } catch (error) { if (error instanceof ProcessError) { - console.error(chalk.bold('stdout from failed coverage tool process:')); - console.error(error.stdout); - console.error(chalk.bold('stderr from failed coverage tool process:')); - console.error(error.stderr); + ui().logger.error(chalk.bold('stdout from failed coverage tool process:')); + ui().logger.error(error.stdout); + ui().logger.error(chalk.bold('stderr from failed coverage tool process:')); + ui().logger.error(error.stderr); } throw new Error( From cf72b75ca4cea31492caafef3a3f4a86fb6e3958 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 9 Mar 2024 01:27:18 +0100 Subject: [PATCH 54/75] refactor(coverage-plugin): format --- packages/plugin-coverage/src/lib/runner/index.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/plugin-coverage/src/lib/runner/index.ts b/packages/plugin-coverage/src/lib/runner/index.ts index 7d67d5322..a88874d56 100644 --- a/packages/plugin-coverage/src/lib/runner/index.ts +++ b/packages/plugin-coverage/src/lib/runner/index.ts @@ -25,9 +25,13 @@ export async function executeRunner(): Promise { await executeProcess({ command, args }); } catch (error) { if (error instanceof ProcessError) { - ui().logger.error(chalk.bold('stdout from failed coverage tool process:')); + ui().logger.error( + chalk.bold('stdout from failed coverage tool process:'), + ); ui().logger.error(error.stdout); - ui().logger.error(chalk.bold('stderr from failed coverage tool process:')); + ui().logger.error( + chalk.bold('stderr from failed coverage tool process:'), + ); ui().logger.error(error.stderr); } From a59846feb05d084d1a23dcc8ec2c2f629e11f3ee Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 11 Mar 2024 16:00:48 +0100 Subject: [PATCH 55/75] refactor: test values --- .../core/src/lib/implementation/execute-plugin.unit.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/lib/implementation/execute-plugin.unit.test.ts b/packages/core/src/lib/implementation/execute-plugin.unit.test.ts index 06b13a31d..bc29f13d9 100644 --- a/packages/core/src/lib/implementation/execute-plugin.unit.test.ts +++ b/packages/core/src/lib/implementation/execute-plugin.unit.test.ts @@ -166,7 +166,7 @@ describe('executePlugins', () => { { slug: 'node-version', score: 1, - value: 1, + value: 18, }, ]), }, From 6d84643d7a292fad37c691db76a7aa8ab0599bb5 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 11 Mar 2024 19:43:35 +0100 Subject: [PATCH 56/75] refactor: adjust tests --- ...og-stdout-summary.integration.test.ts.snap | 13 +++++++--- .../log-stdout-summary.integration.test.ts | 26 ++++++++++++++++--- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap b/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap index 7fe027366..1dd671c32 100644 --- a/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap +++ b/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap @@ -74,10 +74,15 @@ Lighthouse audits Categories -Category|Score|Audits -Performance|92|8 -Bug prevention|68|16 -Code style|54|13 +┌─────────────────────────────────────────────────────────┬─────────┬──────────┐ +│ Category │ Score │ Audits │ +├─────────────────────────────────────────────────────────┼─────────┼──────────┤ +│ Performance │ 92 │ 8 │ +├─────────────────────────────────────────────────────────┼─────────┼──────────┤ +│ Bug prevention │ 68 │ 16 │ +├─────────────────────────────────────────────────────────┼─────────┼──────────┤ +│ Code style │ 54 │ 13 │ +└─────────────────────────────────────────────────────────┴─────────┴──────────┘ Made with ❤ by code-pushup.dev" `; diff --git a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts index 1ec0347dd..36f4f9c44 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts @@ -1,14 +1,32 @@ -import { describe } from 'vitest'; -import { getLogMessages, reportMock } from '@code-pushup/test-utils'; +import {beforeAll, describe, expect, vi} from 'vitest'; +import { reportMock } from '@code-pushup/test-utils'; import { ui } from '../logging'; import { logStdoutSummary } from './log-stdout-summary'; import { scoreReport } from './scoring'; import { sortReport } from './sorting'; + describe('logStdoutSummary', () => { + // eslint-disable-next-line vitest/require-hook + let logs: string[] = []; + beforeAll(() => { + vi.spyOn(console, 'log').mockImplementation(msg => { + logs = [...logs, msg]; + }); + // we want to see table and sticker logs in the final style ("raw" don't show borders etc so we use `console.log` here) + ui().switchMode('normal'); + }); + afterEach(() => { + logs = []; + }); + afterAll(() => { + ui().switchMode('raw'); + }); + it('should contain all sections when using the fixture report', () => { logStdoutSummary(sortReport(scoreReport(reportMock()))); - const output = getLogMessages(ui().logger).join('\n'); + + const output = logs.join('\n'); expect(output).toContain('Categories'); // removes all color codes from the output for snapshot readability @@ -20,7 +38,7 @@ describe('logStdoutSummary', () => { logStdoutSummary( sortReport(scoreReport({ ...reportMock(), categories: [] })), ); - const output = getLogMessages(ui().logger).join('\n'); + const output = logs.join('\n'); expect(output).not.toContain('Categories'); // removes all color codes from the output for snapshot readability From 8449932101c40b5d7df7c8eefd06c83ff7667584 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 11 Mar 2024 19:45:54 +0100 Subject: [PATCH 57/75] refactor: format --- .../src/lib/reports/log-stdout-summary.integration.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts index 36f4f9c44..360f39195 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts @@ -1,11 +1,10 @@ -import {beforeAll, describe, expect, vi} from 'vitest'; +import { beforeAll, describe, expect, vi } from 'vitest'; import { reportMock } from '@code-pushup/test-utils'; import { ui } from '../logging'; import { logStdoutSummary } from './log-stdout-summary'; import { scoreReport } from './scoring'; import { sortReport } from './sorting'; - describe('logStdoutSummary', () => { // eslint-disable-next-line vitest/require-hook let logs: string[] = []; From d5d4cf6864e438d2bf58ca452b58bd29af67e754 Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Tue, 12 Mar 2024 11:36:38 +0100 Subject: [PATCH 58/75] Update packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matěj Chalk <34691111+matejchalk@users.noreply.github.com> --- .../src/lib/reports/log-stdout-summary.integration.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts index 360f39195..f4f9bfa47 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts @@ -6,9 +6,9 @@ import { scoreReport } from './scoring'; import { sortReport } from './sorting'; describe('logStdoutSummary', () => { - // eslint-disable-next-line vitest/require-hook - let logs: string[] = []; + let logs: string[]; beforeAll(() => { + logs = []; vi.spyOn(console, 'log').mockImplementation(msg => { logs = [...logs, msg]; }); From f4223b26d6f358528ac2a1a7fc4f39cb26c0c11a Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 12 Mar 2024 12:10:18 +0100 Subject: [PATCH 59/75] layout --- packages/utils/src/lib/reports/log-stdout-summary.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/lib/reports/log-stdout-summary.ts b/packages/utils/src/lib/reports/log-stdout-summary.ts index 1ac737216..4ec94edae 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.ts @@ -73,7 +73,7 @@ function logCategories({ categories, plugins }: ScoredReport): void { ]); const table = ui().table(); // eslint-disable-next-line no-magic-numbers - table.columnWidths([TERMINAL_WIDTH - 7 - 8 - 8, 9, 10]); + table.columnWidths([TERMINAL_WIDTH - 9 - 10 - 5, 9, 10]); table.head( reportRawOverviewTableHeaders.map((heading, idx) => ({ content: chalk.cyan(heading), From 92ba78ad82177f49930f149aff53fcb5aab41ba0 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 12 Mar 2024 12:33:30 +0100 Subject: [PATCH 60/75] adjust table --- code-pushup.config.ts | 8 +- ...og-stdout-summary.integration.test.ts.snap | 162 ------------------ .../src/lib/reports/log-stdout-summary.ts | 3 +- 3 files changed, 6 insertions(+), 167 deletions(-) delete mode 100644 packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap diff --git a/code-pushup.config.ts b/code-pushup.config.ts index be65a271c..53c9997ba 100644 --- a/code-pushup.config.ts +++ b/code-pushup.config.ts @@ -51,7 +51,7 @@ const config: CoreConfig = { plugins: [ await eslintPlugin(await eslintConfigFromNxProjects()), - await coveragePlugin({ + /*await coveragePlugin({ coverageToolCommand: { command: 'npx', args: [ @@ -65,7 +65,7 @@ const config: CoreConfig = { ], }, reports: await getNxCoveragePaths(['unit-test', 'integration-test']), - }), + }),*/ fileSizePlugin({ directory: './dist/examples/react-todos-app', pattern: /\.js$/, @@ -98,7 +98,7 @@ const config: CoreConfig = { { type: 'group', plugin: 'eslint', slug: 'suggestions', weight: 1 }, ], }, - { + /* { slug: 'code-coverage', title: 'Code coverage', refs: [ @@ -109,7 +109,7 @@ const config: CoreConfig = { weight: 1, }, ], - }, + },*/ { slug: 'custom-checks', title: 'Custom checks', diff --git a/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap b/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap deleted file mode 100644 index 1dd671c32..000000000 --- a/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap +++ /dev/null @@ -1,162 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`logStdoutSummary > should contain all sections when using the fixture report 1`] = ` -"Code PushUp Report - @code-pushup/core@0.0.1 - - -ESLint audits - -● Disallow missing props validation in a React component definition 6 warnings -● Disallow variable declarations from shadowing variables declared 3 warnings - in the outer scope -● Require or disallow method and property shorthand syntax for 3 warnings - object literals -● verifies the list of dependencies for Hooks like useEffect and 2 warnings - similar -● Disallow missing \`key\` props in iterators/collection literals 1 warning -● Disallow unused variables 1 warning -● Enforce a maximum number of lines of code in a function 1 warning -● Require \`const\` declarations for variables that are never 1 warning - reassigned after declared -● Require braces around arrow function bodies 1 warning -● Require the use of \`===\` and \`!==\` 1 warning -● Disallow \`target="_blank"\` attribute without \`rel="noreferrer"\` passed -● Disallow assignment operators in conditional expressions passed -● Disallow comments from being inserted as text nodes passed -● Disallow direct mutation of this.state passed -● Disallow duplicate properties in JSX passed -● Disallow invalid regular expression strings in \`RegExp\` passed - constructors -● Disallow loops with a body that allows only one iteration passed -● Disallow missing displayName in a React component definition passed -● Disallow missing React when using JSX passed -● Disallow negating the left operand of relational operators passed -● Disallow passing of children as props passed -● Disallow React to be incorrectly marked as unused passed -● Disallow reassigning \`const\` variables passed -● Disallow the use of \`debugger\` passed -● Disallow the use of undeclared variables unless mentioned in passed - \`/*global */\` comments -● Disallow undeclared variables in JSX passed -● Disallow unescaped HTML entities from appearing in markup passed -● Disallow usage of deprecated methods passed -● Disallow usage of findDOMNode passed -● Disallow usage of isMounted passed -● Disallow usage of the return value of ReactDOM.render passed -● Disallow usage of unknown DOM property passed -● Disallow use of optional chaining in contexts where the passed - \`undefined\` value is not allowed -● Disallow using Object.assign with an object literal as the first passed - argument and prefer the use of object spread instead -● Disallow using string references passed -● Disallow variables used in JSX to be incorrectly marked as unused passed -● Disallow when a DOM element is using both children and passed - dangerouslySetInnerHTML -● Enforce a maximum number of lines per file passed -● Enforce camelcase naming convention passed -● Enforce comparing \`typeof\` expressions against valid strings passed -● Enforce consistent brace style for all control statements passed -● Enforce ES5 or ES6 class for returning value in render function passed -● enforces the Rules of Hooks passed -● Require \`let\` or \`const\` instead of \`var\` passed -● Require calls to \`isNaN()\` when checking for \`NaN\` passed -● Require or disallow "Yoda" conditions passed -● Require using arrow functions for callbacks passed - - -Lighthouse audits - -● First Contentful Paint 1.2 s -● Largest Contentful Paint 1.5 s -● Speed Index 1.2 s -● Cumulative Layout Shift 0 -● Total Blocking Time 0 ms - -Categories - -┌─────────────────────────────────────────────────────────┬─────────┬──────────┐ -│ Category │ Score │ Audits │ -├─────────────────────────────────────────────────────────┼─────────┼──────────┤ -│ Performance │ 92 │ 8 │ -├─────────────────────────────────────────────────────────┼─────────┼──────────┤ -│ Bug prevention │ 68 │ 16 │ -├─────────────────────────────────────────────────────────┼─────────┼──────────┤ -│ Code style │ 54 │ 13 │ -└─────────────────────────────────────────────────────────┴─────────┴──────────┘ -Made with ❤ by code-pushup.dev" -`; - -exports[`logStdoutSummary > should not contain category section when categories are empty 1`] = ` -"Code PushUp Report - @code-pushup/core@0.0.1 - - -ESLint audits - -● Disallow missing props validation in a React component definition 6 warnings -● Disallow variable declarations from shadowing variables declared 3 warnings - in the outer scope -● Require or disallow method and property shorthand syntax for 3 warnings - object literals -● verifies the list of dependencies for Hooks like useEffect and 2 warnings - similar -● Disallow missing \`key\` props in iterators/collection literals 1 warning -● Disallow unused variables 1 warning -● Enforce a maximum number of lines of code in a function 1 warning -● Require \`const\` declarations for variables that are never 1 warning - reassigned after declared -● Require braces around arrow function bodies 1 warning -● Require the use of \`===\` and \`!==\` 1 warning -● Disallow \`target="_blank"\` attribute without \`rel="noreferrer"\` passed -● Disallow assignment operators in conditional expressions passed -● Disallow comments from being inserted as text nodes passed -● Disallow direct mutation of this.state passed -● Disallow duplicate properties in JSX passed -● Disallow invalid regular expression strings in \`RegExp\` passed - constructors -● Disallow loops with a body that allows only one iteration passed -● Disallow missing displayName in a React component definition passed -● Disallow missing React when using JSX passed -● Disallow negating the left operand of relational operators passed -● Disallow passing of children as props passed -● Disallow React to be incorrectly marked as unused passed -● Disallow reassigning \`const\` variables passed -● Disallow the use of \`debugger\` passed -● Disallow the use of undeclared variables unless mentioned in passed - \`/*global */\` comments -● Disallow undeclared variables in JSX passed -● Disallow unescaped HTML entities from appearing in markup passed -● Disallow usage of deprecated methods passed -● Disallow usage of findDOMNode passed -● Disallow usage of isMounted passed -● Disallow usage of the return value of ReactDOM.render passed -● Disallow usage of unknown DOM property passed -● Disallow use of optional chaining in contexts where the passed - \`undefined\` value is not allowed -● Disallow using Object.assign with an object literal as the first passed - argument and prefer the use of object spread instead -● Disallow using string references passed -● Disallow variables used in JSX to be incorrectly marked as unused passed -● Disallow when a DOM element is using both children and passed - dangerouslySetInnerHTML -● Enforce a maximum number of lines per file passed -● Enforce camelcase naming convention passed -● Enforce comparing \`typeof\` expressions against valid strings passed -● Enforce consistent brace style for all control statements passed -● Enforce ES5 or ES6 class for returning value in render function passed -● enforces the Rules of Hooks passed -● Require \`let\` or \`const\` instead of \`var\` passed -● Require calls to \`isNaN()\` when checking for \`NaN\` passed -● Require or disallow "Yoda" conditions passed -● Require using arrow functions for callbacks passed - - -Lighthouse audits - -● First Contentful Paint 1.2 s -● Largest Contentful Paint 1.5 s -● Speed Index 1.2 s -● Cumulative Layout Shift 0 -● Total Blocking Time 0 ms - -Made with ❤ by code-pushup.dev" -`; diff --git a/packages/utils/src/lib/reports/log-stdout-summary.ts b/packages/utils/src/lib/reports/log-stdout-summary.ts index 4ec94edae..e132f6b3a 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.ts @@ -73,7 +73,7 @@ function logCategories({ categories, plugins }: ScoredReport): void { ]); const table = ui().table(); // eslint-disable-next-line no-magic-numbers - table.columnWidths([TERMINAL_WIDTH - 9 - 10 - 5, 9, 10]); + table.columnWidths([TERMINAL_WIDTH - 9 - 10 - 4, 9, 10]); table.head( reportRawOverviewTableHeaders.map((heading, idx) => ({ content: chalk.cyan(heading), @@ -92,6 +92,7 @@ function logCategories({ categories, plugins }: ScoredReport): void { log(chalk.magentaBright.bold('Categories')); log(); table.render(); + log(); } function applyScoreColor({ score, text }: { score: number; text?: string }) { From e62ae835f1cc75420f0ff78a139dacaf759e7039 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 12 Mar 2024 12:33:43 +0100 Subject: [PATCH 61/75] adjust table --- ...og-stdout-summary.integration.test.ts.snap | 163 ++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap diff --git a/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap b/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap new file mode 100644 index 000000000..3f7765313 --- /dev/null +++ b/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap @@ -0,0 +1,163 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`logStdoutSummary > should contain all sections when using the fixture report 1`] = ` +"Code PushUp Report - @code-pushup/core@0.0.1 + + +ESLint audits + +● Disallow missing props validation in a React component definition 6 warnings +● Disallow variable declarations from shadowing variables declared 3 warnings + in the outer scope +● Require or disallow method and property shorthand syntax for 3 warnings + object literals +● verifies the list of dependencies for Hooks like useEffect and 2 warnings + similar +● Disallow missing \`key\` props in iterators/collection literals 1 warning +● Disallow unused variables 1 warning +● Enforce a maximum number of lines of code in a function 1 warning +● Require \`const\` declarations for variables that are never 1 warning + reassigned after declared +● Require braces around arrow function bodies 1 warning +● Require the use of \`===\` and \`!==\` 1 warning +● Disallow \`target="_blank"\` attribute without \`rel="noreferrer"\` passed +● Disallow assignment operators in conditional expressions passed +● Disallow comments from being inserted as text nodes passed +● Disallow direct mutation of this.state passed +● Disallow duplicate properties in JSX passed +● Disallow invalid regular expression strings in \`RegExp\` passed + constructors +● Disallow loops with a body that allows only one iteration passed +● Disallow missing displayName in a React component definition passed +● Disallow missing React when using JSX passed +● Disallow negating the left operand of relational operators passed +● Disallow passing of children as props passed +● Disallow React to be incorrectly marked as unused passed +● Disallow reassigning \`const\` variables passed +● Disallow the use of \`debugger\` passed +● Disallow the use of undeclared variables unless mentioned in passed + \`/*global */\` comments +● Disallow undeclared variables in JSX passed +● Disallow unescaped HTML entities from appearing in markup passed +● Disallow usage of deprecated methods passed +● Disallow usage of findDOMNode passed +● Disallow usage of isMounted passed +● Disallow usage of the return value of ReactDOM.render passed +● Disallow usage of unknown DOM property passed +● Disallow use of optional chaining in contexts where the passed + \`undefined\` value is not allowed +● Disallow using Object.assign with an object literal as the first passed + argument and prefer the use of object spread instead +● Disallow using string references passed +● Disallow variables used in JSX to be incorrectly marked as unused passed +● Disallow when a DOM element is using both children and passed + dangerouslySetInnerHTML +● Enforce a maximum number of lines per file passed +● Enforce camelcase naming convention passed +● Enforce comparing \`typeof\` expressions against valid strings passed +● Enforce consistent brace style for all control statements passed +● Enforce ES5 or ES6 class for returning value in render function passed +● enforces the Rules of Hooks passed +● Require \`let\` or \`const\` instead of \`var\` passed +● Require calls to \`isNaN()\` when checking for \`NaN\` passed +● Require or disallow "Yoda" conditions passed +● Require using arrow functions for callbacks passed + + +Lighthouse audits + +● First Contentful Paint 1.2 s +● Largest Contentful Paint 1.5 s +● Speed Index 1.2 s +● Cumulative Layout Shift 0 +● Total Blocking Time 0 ms + +Categories + +┌─────────────────────────────────────────────────────────┬─────────┬──────────┐ +│ Category │ Score │ Audits │ +├─────────────────────────────────────────────────────────┼─────────┼──────────┤ +│ Performance │ 92 │ 8 │ +├─────────────────────────────────────────────────────────┼─────────┼──────────┤ +│ Bug prevention │ 68 │ 16 │ +├─────────────────────────────────────────────────────────┼─────────┼──────────┤ +│ Code style │ 54 │ 13 │ +└─────────────────────────────────────────────────────────┴─────────┴──────────┘ + +Made with ❤ by code-pushup.dev" +`; + +exports[`logStdoutSummary > should not contain category section when categories are empty 1`] = ` +"Code PushUp Report - @code-pushup/core@0.0.1 + + +ESLint audits + +● Disallow missing props validation in a React component definition 6 warnings +● Disallow variable declarations from shadowing variables declared 3 warnings + in the outer scope +● Require or disallow method and property shorthand syntax for 3 warnings + object literals +● verifies the list of dependencies for Hooks like useEffect and 2 warnings + similar +● Disallow missing \`key\` props in iterators/collection literals 1 warning +● Disallow unused variables 1 warning +● Enforce a maximum number of lines of code in a function 1 warning +● Require \`const\` declarations for variables that are never 1 warning + reassigned after declared +● Require braces around arrow function bodies 1 warning +● Require the use of \`===\` and \`!==\` 1 warning +● Disallow \`target="_blank"\` attribute without \`rel="noreferrer"\` passed +● Disallow assignment operators in conditional expressions passed +● Disallow comments from being inserted as text nodes passed +● Disallow direct mutation of this.state passed +● Disallow duplicate properties in JSX passed +● Disallow invalid regular expression strings in \`RegExp\` passed + constructors +● Disallow loops with a body that allows only one iteration passed +● Disallow missing displayName in a React component definition passed +● Disallow missing React when using JSX passed +● Disallow negating the left operand of relational operators passed +● Disallow passing of children as props passed +● Disallow React to be incorrectly marked as unused passed +● Disallow reassigning \`const\` variables passed +● Disallow the use of \`debugger\` passed +● Disallow the use of undeclared variables unless mentioned in passed + \`/*global */\` comments +● Disallow undeclared variables in JSX passed +● Disallow unescaped HTML entities from appearing in markup passed +● Disallow usage of deprecated methods passed +● Disallow usage of findDOMNode passed +● Disallow usage of isMounted passed +● Disallow usage of the return value of ReactDOM.render passed +● Disallow usage of unknown DOM property passed +● Disallow use of optional chaining in contexts where the passed + \`undefined\` value is not allowed +● Disallow using Object.assign with an object literal as the first passed + argument and prefer the use of object spread instead +● Disallow using string references passed +● Disallow variables used in JSX to be incorrectly marked as unused passed +● Disallow when a DOM element is using both children and passed + dangerouslySetInnerHTML +● Enforce a maximum number of lines per file passed +● Enforce camelcase naming convention passed +● Enforce comparing \`typeof\` expressions against valid strings passed +● Enforce consistent brace style for all control statements passed +● Enforce ES5 or ES6 class for returning value in render function passed +● enforces the Rules of Hooks passed +● Require \`let\` or \`const\` instead of \`var\` passed +● Require calls to \`isNaN()\` when checking for \`NaN\` passed +● Require or disallow "Yoda" conditions passed +● Require using arrow functions for callbacks passed + + +Lighthouse audits + +● First Contentful Paint 1.2 s +● Largest Contentful Paint 1.5 s +● Speed Index 1.2 s +● Cumulative Layout Shift 0 +● Total Blocking Time 0 ms + +Made with ❤ by code-pushup.dev" +`; From 4fcd62e3412a5720c6f6f6a90e5776259396576e Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 12 Mar 2024 13:16:53 +0100 Subject: [PATCH 62/75] fix --- code-pushup.config.ts | 8 ++++---- packages/utils/src/lib/reports/log-stdout-summary.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/code-pushup.config.ts b/code-pushup.config.ts index 53c9997ba..be65a271c 100644 --- a/code-pushup.config.ts +++ b/code-pushup.config.ts @@ -51,7 +51,7 @@ const config: CoreConfig = { plugins: [ await eslintPlugin(await eslintConfigFromNxProjects()), - /*await coveragePlugin({ + await coveragePlugin({ coverageToolCommand: { command: 'npx', args: [ @@ -65,7 +65,7 @@ const config: CoreConfig = { ], }, reports: await getNxCoveragePaths(['unit-test', 'integration-test']), - }),*/ + }), fileSizePlugin({ directory: './dist/examples/react-todos-app', pattern: /\.js$/, @@ -98,7 +98,7 @@ const config: CoreConfig = { { type: 'group', plugin: 'eslint', slug: 'suggestions', weight: 1 }, ], }, - /* { + { slug: 'code-coverage', title: 'Code coverage', refs: [ @@ -109,7 +109,7 @@ const config: CoreConfig = { weight: 1, }, ], - },*/ + }, { slug: 'custom-checks', title: 'Custom checks', diff --git a/packages/utils/src/lib/reports/log-stdout-summary.ts b/packages/utils/src/lib/reports/log-stdout-summary.ts index e132f6b3a..00c83853d 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.ts @@ -92,7 +92,7 @@ function logCategories({ categories, plugins }: ScoredReport): void { log(chalk.magentaBright.bold('Categories')); log(); table.render(); - log(); + log(' '); } function applyScoreColor({ score, text }: { score: number; text?: string }) { From 48c3a63def82c595a1b4987221ddc059cf41cd51 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 12 Mar 2024 13:19:24 +0100 Subject: [PATCH 63/75] fix --- packages/utils/src/lib/reports/log-stdout-summary.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/lib/reports/log-stdout-summary.ts b/packages/utils/src/lib/reports/log-stdout-summary.ts index 00c83853d..e132f6b3a 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.ts @@ -92,7 +92,7 @@ function logCategories({ categories, plugins }: ScoredReport): void { log(chalk.magentaBright.bold('Categories')); log(); table.render(); - log(' '); + log(); } function applyScoreColor({ score, text }: { score: number; text?: string }) { From 6cf446e5ebca13bc64697e6167cd62775caa9edc Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 12 Mar 2024 13:40:47 +0100 Subject: [PATCH 64/75] fix --- packages/core/src/lib/implementation/persist.unit.test.ts | 4 ++-- .../log-stdout-summary.integration.test.ts.snap | 6 ++++-- packages/utils/src/lib/reports/log-stdout-summary.ts | 1 + 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/core/src/lib/implementation/persist.unit.test.ts b/packages/core/src/lib/implementation/persist.unit.test.ts index 7cdb318f7..3ecf0989f 100644 --- a/packages/core/src/lib/implementation/persist.unit.test.ts +++ b/packages/core/src/lib/implementation/persist.unit.test.ts @@ -24,7 +24,7 @@ describe('persistReport', () => { format: [], }); const logs = getLogMessages(ui().logger); - expect(logs.at(-1)).toEqual( + expect(logs.at(-2)).toEqual( expect.stringContaining('Made with ❤ by code-pushup.dev'), ); }); @@ -36,7 +36,7 @@ describe('persistReport', () => { format: ['md', 'json'], }); const logs = getLogMessages(ui().logger); - expect(logs.at(-1)).toEqual( + expect(logs.at(-2)).toEqual( expect.stringContaining('Made with ❤ by code-pushup.dev'), ); }); diff --git a/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap b/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap index 3f7765313..0bd36aa53 100644 --- a/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap +++ b/packages/utils/src/lib/reports/__snapshots__/log-stdout-summary.integration.test.ts.snap @@ -84,7 +84,8 @@ Categories │ Code style │ 54 │ 13 │ └─────────────────────────────────────────────────────────┴─────────┴──────────┘ -Made with ❤ by code-pushup.dev" +Made with ❤ by code-pushup.dev +" `; exports[`logStdoutSummary > should not contain category section when categories are empty 1`] = ` @@ -159,5 +160,6 @@ Lighthouse audits ● Cumulative Layout Shift 0 ● Total Blocking Time 0 ms -Made with ❤ by code-pushup.dev" +Made with ❤ by code-pushup.dev +" `; diff --git a/packages/utils/src/lib/reports/log-stdout-summary.ts b/packages/utils/src/lib/reports/log-stdout-summary.ts index e132f6b3a..f016542c5 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.ts @@ -26,6 +26,7 @@ export function logStdoutSummary(report: ScoredReport): void { logCategories(report); } log(`${FOOTER_PREFIX} ${CODE_PUSHUP_DOMAIN}`); + log(); } function reportToHeaderSection(report: ScoredReport): string { From 339b7b25d5b3bd0eb225eff47aba8888fa95e929 Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Tue, 12 Mar 2024 13:47:19 +0100 Subject: [PATCH 65/75] Update packages/cli/src/lib/print-config/print-config-command.unit.test.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Katka Pilátová --- .../src/lib/print-config/print-config-command.unit.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/lib/print-config/print-config-command.unit.test.ts b/packages/cli/src/lib/print-config/print-config-command.unit.test.ts index 27a852cb0..ebaceeef8 100644 --- a/packages/cli/src/lib/print-config/print-config-command.unit.test.ts +++ b/packages/cli/src/lib/print-config/print-config-command.unit.test.ts @@ -28,8 +28,8 @@ describe('print-config-command', () => { ).parseAsync(); const log = getLogMessages(ui().logger)[0]; - expect(log).toEqual(expect.not.stringContaining('"$0":')); - expect(log).toEqual(expect.not.stringContaining('"_":')); + expect(log).not.toContain('"$0":'); + expect(log).not.toContain('"_":'); expect(log).toEqual( expect.stringContaining('"outputDir": "destinationDir"'), From 65a77e0d4efc1669c5b7348a2efbcaa3f4fd922b Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Tue, 12 Mar 2024 13:51:51 +0100 Subject: [PATCH 66/75] Update testing/test-setup/src/lib/cliui.mock.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Katka Pilátová --- testing/test-setup/src/lib/cliui.mock.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/testing/test-setup/src/lib/cliui.mock.ts b/testing/test-setup/src/lib/cliui.mock.ts index 72de45984..555734e3e 100644 --- a/testing/test-setup/src/lib/cliui.mock.ts +++ b/testing/test-setup/src/lib/cliui.mock.ts @@ -1,18 +1,17 @@ import { beforeEach, vi } from 'vitest'; import type { CliUi } from '@code-pushup/utils'; -vi.mock('@code-pushup/utils', async () => { - const module = await vi.importActual<{ ui: () => CliUi }>( +beforeAll(async () => { + const utils: typeof import('@code-pushup/utils') = await vi.importActual( '@code-pushup/utils', ); - - module.ui().switchMode('raw'); - return module; + utils.ui().switchMode('raw'); }); beforeEach(async () => { - const { ui } = await vi.importActual<{ ui: () => CliUi }>( + const { ui }: typeof import('@code-pushup/utils') = await vi.importActual( '@code-pushup/utils', ); ui().logger.flushLogs(); }); + From b585d27aa4bbae82f113ab7bbb6613281bbae2e7 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 12 Mar 2024 13:52:13 +0100 Subject: [PATCH 67/75] fix --- .../src/lib/implementation/only-plugins.utils.unit.test.ts | 7 ++----- .../src/lib/reports/log-stdout-summary.integration.test.ts | 1 + 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts index 9ecd3e9ec..88864274f 100644 --- a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts +++ b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts @@ -89,11 +89,8 @@ describe('filterCategoryByPluginSlug', () => { }, ); const logs = getLogMessages(ui().logger); - expect(logs[0]).toEqual( - expect.stringContaining('Category "category1" is ignored'), - ); - expect(logs[0]).toEqual( - expect.stringContaining('skipped plugin "plugin2"'), + expect(logs[0]).toMatch( + /Category "category1" is ignored .* skipped plugin "plugin2"/, ); }); diff --git a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts index f4f9bfa47..0e5f68278 100644 --- a/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts +++ b/packages/utils/src/lib/reports/log-stdout-summary.integration.test.ts @@ -9,6 +9,7 @@ describe('logStdoutSummary', () => { let logs: string[]; beforeAll(() => { logs = []; + // console.log is used inside the logger when in "normal" mode vi.spyOn(console, 'log').mockImplementation(msg => { logs = [...logs, msg]; }); From dfda61421232f529fc0c96bc8f9846a292f26b1f Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 12 Mar 2024 14:02:38 +0100 Subject: [PATCH 68/75] remove mock --- packages/utils/mocks/setup/cliui.mock.ts | 15 --------------- packages/utils/vite.config.integration.ts | 2 +- packages/utils/vite.config.unit.ts | 2 +- 3 files changed, 2 insertions(+), 17 deletions(-) delete mode 100644 packages/utils/mocks/setup/cliui.mock.ts diff --git a/packages/utils/mocks/setup/cliui.mock.ts b/packages/utils/mocks/setup/cliui.mock.ts deleted file mode 100644 index 3f9b73b52..000000000 --- a/packages/utils/mocks/setup/cliui.mock.ts +++ /dev/null @@ -1,15 +0,0 @@ -import {beforeEach, vi} from "vitest"; -import { type CliUi } from "../../src/lib/logging"; - -vi.mock('../../src/lib/logging', async () => { - const module = await vi.importActual<{ui: () => CliUi}>('../../src/lib/logging'); - module.ui().switchMode('raw'); - return module; -}); - -beforeEach(async () => { - const {ui} = await vi.importActual<{ ui: () => CliUi }>( - '../../src/lib/logging', - ); - ui().logger.flushLogs(); -}); diff --git a/packages/utils/vite.config.integration.ts b/packages/utils/vite.config.integration.ts index 2e728c4f4..4c991a6b1 100644 --- a/packages/utils/vite.config.integration.ts +++ b/packages/utils/vite.config.integration.ts @@ -21,7 +21,7 @@ export default defineConfig({ include: ['src/**/*.integration.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], globalSetup: ['../../global-setup.ts'], setupFiles: [ - './mocks/setup/cliui.mock.ts', + '../../testing/test-setup/src/lib/cliui.mock.ts', '../../testing/test-setup/src/lib/console.mock.ts', '../../testing/test-setup/src/lib/reset.mocks.ts', ], diff --git a/packages/utils/vite.config.unit.ts b/packages/utils/vite.config.unit.ts index 610ba8e69..febef42e1 100644 --- a/packages/utils/vite.config.unit.ts +++ b/packages/utils/vite.config.unit.ts @@ -21,7 +21,7 @@ export default defineConfig({ include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], globalSetup: ['../../global-setup.ts'], setupFiles: [ - './mocks/setup/cliui.mock.ts', + '../../testing/test-setup/src/lib/cliui.mock.ts', '../../testing/test-setup/src/lib/fs.mock.ts', '../../testing/test-setup/src/lib/console.mock.ts', '../../testing/test-setup/src/lib/reset.mocks.ts', From a1b561967afc3117472a75c332a3456c03aca336 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 12 Mar 2024 14:06:11 +0100 Subject: [PATCH 69/75] fix --- .../src/lib/implementation/execute-plugin.unit.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/core/src/lib/implementation/execute-plugin.unit.test.ts b/packages/core/src/lib/implementation/execute-plugin.unit.test.ts index bc29f13d9..f2833080c 100644 --- a/packages/core/src/lib/implementation/execute-plugin.unit.test.ts +++ b/packages/core/src/lib/implementation/execute-plugin.unit.test.ts @@ -26,7 +26,7 @@ describe('executePlugin', () => { { slug: 'node-version', score: 1, - value: 1, + value: 16, }, ]), }, @@ -51,7 +51,7 @@ describe('executePlugin', () => { { slug: 'node-version', score: 0, - value: 1, + value: 16, }, ], }); @@ -60,7 +60,7 @@ describe('executePlugin', () => { slug: 'node-version', title: 'Node version', score: 0, - value: 1, + value: 16, }), ]); }); @@ -186,7 +186,7 @@ describe('executePlugins', () => { { slug: (outputs as AuditOutputs)[0]!.slug, score: 1, - value: 1, + value: 16, displayValue: '2.0.0', }, ]), From b16201053c893740e032d060a6aa7ddc8b104c7e Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 12 Mar 2024 14:07:31 +0100 Subject: [PATCH 70/75] format --- testing/test-setup/src/lib/cliui.mock.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/testing/test-setup/src/lib/cliui.mock.ts b/testing/test-setup/src/lib/cliui.mock.ts index 555734e3e..8ceb5af5c 100644 --- a/testing/test-setup/src/lib/cliui.mock.ts +++ b/testing/test-setup/src/lib/cliui.mock.ts @@ -14,4 +14,3 @@ beforeEach(async () => { ); ui().logger.flushLogs(); }); - From 16868a24771366d7f74bafe82cd4273fb8dfdfd9 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 12 Mar 2024 14:08:59 +0100 Subject: [PATCH 71/75] fix --- .../implementation/execute-plugin.unit.test.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/core/src/lib/implementation/execute-plugin.unit.test.ts b/packages/core/src/lib/implementation/execute-plugin.unit.test.ts index f2833080c..f28aaa265 100644 --- a/packages/core/src/lib/implementation/execute-plugin.unit.test.ts +++ b/packages/core/src/lib/implementation/execute-plugin.unit.test.ts @@ -25,7 +25,7 @@ describe('executePlugin', () => { 'output.json': JSON.stringify([ { slug: 'node-version', - score: 1, + score: 0.3, value: 16, }, ]), @@ -50,7 +50,7 @@ describe('executePlugin', () => { runner: () => [ { slug: 'node-version', - score: 0, + score: 0.3, value: 16, }, ], @@ -59,7 +59,7 @@ describe('executePlugin', () => { expect.objectContaining({ slug: 'node-version', title: 'Node version', - score: 0, + score: 0.3, value: 16, }), ]); @@ -165,8 +165,8 @@ describe('executePlugins', () => { 'output.json': JSON.stringify([ { slug: 'node-version', - score: 1, - value: 18, + score: 0.3, + value: 16, }, ]), }, @@ -185,9 +185,9 @@ describe('executePlugins', () => { Promise.resolve([ { slug: (outputs as AuditOutputs)[0]!.slug, - score: 1, + score: 0.3, value: 16, - displayValue: '2.0.0', + displayValue: '16.0.0', }, ]), }, @@ -196,6 +196,6 @@ describe('executePlugins', () => { { progress: false }, ); expect(pluginResult[0]?.audits[0]?.slug).toBe('node-version'); - expect(pluginResult[0]?.audits[0]?.displayValue).toBe('2.0.0'); + expect(pluginResult[0]?.audits[0]?.displayValue).toBe('16.0.0'); }); }); From e811ed090a98261c1804b8839f3f9258e625c2a9 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 12 Mar 2024 16:41:55 +0100 Subject: [PATCH 72/75] test: adjust matcher --- .../only-plugins.utils.unit.test.ts | 6 ++--- .../print-config-command.unit.test.ts | 6 ++--- .../lib/implementation/persist.unit.test.ts | 24 +++++++------------ 3 files changed, 13 insertions(+), 23 deletions(-) diff --git a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts index 88864274f..cbf4101b0 100644 --- a/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts +++ b/packages/cli/src/lib/implementation/only-plugins.utils.unit.test.ts @@ -111,10 +111,8 @@ describe('validateOnlyPluginsOption', () => { }, ); const logs = getLogMessages(ui().logger); - expect(logs[0]).toEqual( - expect.stringContaining( - 'The --onlyPlugin argument references plugins with "plugin3", "plugin4" slugs', - ), + expect(logs[0]).toContain( + 'The --onlyPlugin argument references plugins with "plugin3", "plugin4" slugs', ); }); diff --git a/packages/cli/src/lib/print-config/print-config-command.unit.test.ts b/packages/cli/src/lib/print-config/print-config-command.unit.test.ts index ebaceeef8..403b36a92 100644 --- a/packages/cli/src/lib/print-config/print-config-command.unit.test.ts +++ b/packages/cli/src/lib/print-config/print-config-command.unit.test.ts @@ -31,9 +31,7 @@ describe('print-config-command', () => { expect(log).not.toContain('"$0":'); expect(log).not.toContain('"_":'); - expect(log).toEqual( - expect.stringContaining('"outputDir": "destinationDir"'), - ); - expect(log).toEqual(expect.not.stringContaining('"output-dir":')); + expect(log).toContain('"outputDir": "destinationDir"'); + expect(log).not.toContain('"output-dir":'); }); }); diff --git a/packages/core/src/lib/implementation/persist.unit.test.ts b/packages/core/src/lib/implementation/persist.unit.test.ts index 3ecf0989f..d749a4639 100644 --- a/packages/core/src/lib/implementation/persist.unit.test.ts +++ b/packages/core/src/lib/implementation/persist.unit.test.ts @@ -24,9 +24,7 @@ describe('persistReport', () => { format: [], }); const logs = getLogMessages(ui().logger); - expect(logs.at(-2)).toEqual( - expect.stringContaining('Made with ❤ by code-pushup.dev'), - ); + expect(logs.at(-2)).toContain('Made with ❤ by code-pushup.dev'); }); it('should print a summary to stdout when all formats are specified`', async () => { @@ -36,9 +34,7 @@ describe('persistReport', () => { format: ['md', 'json'], }); const logs = getLogMessages(ui().logger); - expect(logs.at(-2)).toEqual( - expect.stringContaining('Made with ❤ by code-pushup.dev'), - ); + expect(logs.at(-2)).toContain('Made with ❤ by code-pushup.dev'); }); it('should create a report in json format', async () => { @@ -106,15 +102,15 @@ describe('logPersistedResults', () => { logPersistedResults([{ status: 'fulfilled', value: ['out.json', 10_000] }]); const logs = getLogMessages(ui().logger); expect(logs[0]).toBe('[ green(success) ] Generated reports successfully: '); - expect(logs[1]).toEqual(expect.stringContaining('9.77 kB')); - expect(logs[1]).toEqual(expect.stringContaining('out.json')); + expect(logs[1]).toContain('9.77 kB'); + expect(logs[1]).toContain('out.json'); }); it('should log fails correctly`', () => { logPersistedResults([{ status: 'rejected', reason: 'fail' }]); const logs = getLogMessages(ui().logger); expect(logs[0]).toBe('[ yellow(warn) ] Generated reports failed: '); - expect(logs[1]).toEqual(expect.stringContaining('fail')); + expect(logs[1]).toContain('fail'); }); it('should log report sizes and fails correctly`', () => { @@ -124,12 +120,10 @@ describe('logPersistedResults', () => { ]); const logs = getLogMessages(ui().logger); expect(logs[0]).toBe('[ green(success) ] Generated reports successfully: '); - expect(logs[1]).toEqual(expect.stringContaining('out.json')); - expect(logs[1]).toEqual(expect.stringContaining('9.77 kB')); + expect(logs[1]).toContain('out.json'); + expect(logs[1]).toContain('9.77 kB'); - expect(logs[2]).toEqual( - expect.stringContaining('Generated reports failed: '), - ); - expect(logs[2]).toEqual(expect.stringContaining('fail')); + expect(logs[2]).toContain('Generated reports failed: '); + expect(logs[2]).toContain('fail'); }); }); From d2e0f1e38d9389a064c1c1e26e73acd135fd9688 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 12 Mar 2024 16:55:00 +0100 Subject: [PATCH 73/75] fix --- packages/cli/src/lib/compare/compare-command.ts | 3 ++- testing/test-setup/src/lib/cliui.mock.ts | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/cli/src/lib/compare/compare-command.ts b/packages/cli/src/lib/compare/compare-command.ts index 7f342f940..c859ca8bb 100644 --- a/packages/cli/src/lib/compare/compare-command.ts +++ b/packages/cli/src/lib/compare/compare-command.ts @@ -3,10 +3,11 @@ import { join } from 'node:path'; import { CommandModule } from 'yargs'; import { compareReportFiles } from '@code-pushup/core'; import { PersistConfig } from '@code-pushup/models'; +import { ui } from '@code-pushup/utils'; import { CLI_NAME } from '../constants'; import type { CompareOptions } from '../implementation/compare.model'; import { yargsCompareOptionsDefinition } from '../implementation/compare.options'; -import { ui } from '../implementation/logging'; + export function yargsCompareCommandObject() { const command = 'compare'; diff --git a/testing/test-setup/src/lib/cliui.mock.ts b/testing/test-setup/src/lib/cliui.mock.ts index 8ceb5af5c..3d3134dd2 100644 --- a/testing/test-setup/src/lib/cliui.mock.ts +++ b/testing/test-setup/src/lib/cliui.mock.ts @@ -1,5 +1,4 @@ -import { beforeEach, vi } from 'vitest'; -import type { CliUi } from '@code-pushup/utils'; +import { beforeAll, beforeEach, vi } from 'vitest'; beforeAll(async () => { const utils: typeof import('@code-pushup/utils') = await vi.importActual( From a8a3a62ef7ccde5356d70e4358bf1000a52249bb Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 12 Mar 2024 17:06:27 +0100 Subject: [PATCH 74/75] fix --- packages/cli/src/lib/compare/compare-command.ts | 1 - packages/core/src/lib/history.ts | 10 ++++++---- packages/plugin-lighthouse/src/lib/utils.ts | 10 +++++++--- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/cli/src/lib/compare/compare-command.ts b/packages/cli/src/lib/compare/compare-command.ts index c859ca8bb..ef48b3c85 100644 --- a/packages/cli/src/lib/compare/compare-command.ts +++ b/packages/cli/src/lib/compare/compare-command.ts @@ -8,7 +8,6 @@ import { CLI_NAME } from '../constants'; import type { CompareOptions } from '../implementation/compare.model'; import { yargsCompareOptionsDefinition } from '../implementation/compare.options'; - export function yargsCompareCommandObject() { const command = 'compare'; return { diff --git a/packages/core/src/lib/history.ts b/packages/core/src/lib/history.ts index 4e2a51904..fc4fb0202 100644 --- a/packages/core/src/lib/history.ts +++ b/packages/core/src/lib/history.ts @@ -1,6 +1,6 @@ import { LogOptions, LogResult, simpleGit } from 'simple-git'; import { CoreConfig, PersistConfig, UploadConfig } from '@code-pushup/models'; -import { getCurrentBranchOrTag, safeCheckout } from '@code-pushup/utils'; +import { getCurrentBranchOrTag, safeCheckout, ui } from '@code-pushup/utils'; import { collectAndPersistReports } from './collect-and-persist'; import { GlobalOptions } from './types'; import { upload } from './upload'; @@ -29,7 +29,7 @@ export async function history( const reports: string[] = []; // eslint-disable-next-line functional/no-loop-statements for (const commit of commits) { - console.info(`Collect ${commit}`); + ui().logger.info(`Collect ${commit}`); await safeCheckout(commit, forceCleanStatus); const currentConfig: HistoryOptions = { @@ -44,12 +44,14 @@ export async function history( await collectAndPersistReports(currentConfig); if (skipUploads) { - console.warn('Upload is skipped because skipUploads is set to true.'); + ui().logger.info('Upload is skipped because skipUploads is set to true.'); } else { if (currentConfig.upload) { await upload(currentConfig); } else { - console.warn('Upload is skipped because upload config is undefined.'); + ui().logger.info( + 'Upload is skipped because upload config is undefined.', + ); } } diff --git a/packages/plugin-lighthouse/src/lib/utils.ts b/packages/plugin-lighthouse/src/lib/utils.ts index a4cddb329..f0538c091 100644 --- a/packages/plugin-lighthouse/src/lib/utils.ts +++ b/packages/plugin-lighthouse/src/lib/utils.ts @@ -1,7 +1,12 @@ import { type CliFlags } from 'lighthouse'; import { Result } from 'lighthouse/types/lhr/audit-result'; import { Audit, AuditOutput, AuditOutputs, Group } from '@code-pushup/models'; -import { filterItemRefsBy, objectToCliArgs, toArray } from '@code-pushup/utils'; +import { + filterItemRefsBy, + objectToCliArgs, + toArray, + ui, +} from '@code-pushup/utils'; import { LIGHTHOUSE_REPORT_NAME } from './constants'; type RefinedLighthouseOption = { @@ -92,8 +97,7 @@ export function toAuditOutputs(lhrAudits: Result[]): AuditOutputs { // @TODO implement switch case for detail parsing. Related to #90 const unsupportedType = details.type; - // @TODO use cliui.logger.info Resolve TODO after PR #487 is merged. - console.info( + ui().logger.info( `Parsing details from type ${unsupportedType} is not implemented.`, ); From fba81fc7153a82c01b8bea49c18ad4ed829f6331 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 12 Mar 2024 17:30:16 +0100 Subject: [PATCH 75/75] fix --- .../utils/src/lib/git.integration.test.ts | 121 +++++++----------- 1 file changed, 45 insertions(+), 76 deletions(-) diff --git a/packages/utils/src/lib/git.integration.test.ts b/packages/utils/src/lib/git.integration.test.ts index d12dd87b3..61df82bc3 100644 --- a/packages/utils/src/lib/git.integration.test.ts +++ b/packages/utils/src/lib/git.integration.test.ts @@ -12,25 +12,23 @@ import { } from './git'; import { toUnixPath } from './transform'; -describe('git helper tests', () => { - describe('git utils in a git repo without a branch and commits', () => { - const baseDir = join( - process.cwd(), - 'tmp', - 'testing-git-repo-without-branch-and-commits', - ); - let emptyGit: SimpleGit; - - beforeAll(async () => { - await mkdir(baseDir, { recursive: true }); - emptyGit = simpleGit(baseDir); - await emptyGit.init(); - }); +describe('git utils in a git repo', () => { + const baseDir = join(process.cwd(), 'tmp', 'git-tests'); + let emptyGit: SimpleGit; + + beforeAll(async () => { + await mkdir(baseDir, { recursive: true }); + emptyGit = simpleGit(baseDir); + await emptyGit.init(); + await emptyGit.addConfig('user.name', 'John Doe'); + await emptyGit.addConfig('user.email', 'john.doe@example.com'); + }); - afterAll(async () => { - await rm(baseDir, { recursive: true, force: true }); - }); + afterAll(async () => { + await rm(baseDir, { recursive: true, force: true }); + }); + describe('without a branch and commits', () => { it('getCurrentBranchOrTag should throw if no branch or tag is given', async () => { await expect(getCurrentBranchOrTag(emptyGit)).rejects.toThrow( 'Could not get current tag or branch.', @@ -38,118 +36,88 @@ describe('git helper tests', () => { }); }); - describe('git utils in a git repo with a branch and commits clean', () => { - const baseDir = join( - process.cwd(), - 'tmp', - 'testing-git-repo-with-branch-and-commits-clean', - ); - let cleanGit: SimpleGit; - + describe('with a branch and commits clean', () => { beforeAll(async () => { - await mkdir(baseDir, { recursive: true }); - - cleanGit = simpleGit(baseDir); - await cleanGit.init(); - - await cleanGit.addConfig('user.name', 'John Doe'); - await cleanGit.addConfig('user.email', 'john.doe@example.com'); - await writeFile(join(baseDir, 'README.md'), '# hello-world\n'); - await cleanGit.add('README.md'); - await cleanGit.commit('Create README'); + await emptyGit.add('README.md'); + await emptyGit.commit('Create README'); - await cleanGit.branch(['feature-branch']); - await cleanGit.checkout(['master']); + await emptyGit.branch(['feature-branch']); + await emptyGit.checkout(['master']); }); afterAll(async () => { - await rm(baseDir, { recursive: true, force: true }); + await emptyGit.checkout(['master']); + await emptyGit.deleteLocalBranch('feature-branch'); }); it('should log latest commit', async () => { - const gitCommitDateRegex = - /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{1,2} \d{2}:\d{2}:\d{2} \d{4} [+|-]\d{4}$/; - - await expect(getLatestCommit(cleanGit)).resolves.toEqual({ + await expect(getLatestCommit(emptyGit)).resolves.toEqual({ hash: expect.stringMatching(/^[\da-f]{40}$/), message: 'Create README', author: 'John Doe', - date: expect.stringMatching(gitCommitDateRegex), + date: expect.any(Date), }); }); it('should find Git root', async () => { - await expect(getGitRoot(cleanGit)).resolves.toBe(toUnixPath(baseDir)); + await expect(getGitRoot(emptyGit)).resolves.toBe(toUnixPath(baseDir)); }); it('should convert absolute path to relative Git path', async () => { await expect( - toGitPath(join(baseDir, 'src', 'utils.ts'), cleanGit), + toGitPath(join(baseDir, 'src', 'utils.ts'), emptyGit), ).resolves.toBe('src/utils.ts'); }); it('should convert relative Windows path to relative Git path', async () => { await expect( - toGitPath('Backend\\API\\Startup.cs', cleanGit), + toGitPath('Backend\\API\\Startup.cs', emptyGit), ).resolves.toBe('../../Backend/API/Startup.cs'); }); it('should keep relative Unix path as is (already a Git path)', async () => { - await expect(toGitPath('Backend/API/Startup.cs', cleanGit)).resolves.toBe( + await expect(toGitPath('Backend/API/Startup.cs', emptyGit)).resolves.toBe( '../../Backend/API/Startup.cs', ); }); it('getCurrentBranchOrTag should log current branch', async () => { - await expect(getCurrentBranchOrTag(cleanGit)).resolves.toBe('master'); + await expect(getCurrentBranchOrTag(emptyGit)).resolves.toBe('master'); }); it('guardAgainstLocalChanges should not throw if history is clean', async () => { - await expect(guardAgainstLocalChanges(cleanGit)).resolves.toBeUndefined(); + await expect(guardAgainstLocalChanges(emptyGit)).resolves.toBeUndefined(); }); it('safeCheckout should checkout feature-branch in clean state', async () => { await expect( - safeCheckout('feature-branch', undefined, cleanGit), + safeCheckout('feature-branch', undefined, emptyGit), ).resolves.toBeUndefined(); - await expect(cleanGit.branch()).resolves.toEqual( + await expect(emptyGit.branch()).resolves.toEqual( expect.objectContaining({ current: 'feature-branch' }), ); }); it('safeCheckout should throw if a given branch does not exist', async () => { await expect( - safeCheckout('non-existing-branch', undefined, cleanGit), + safeCheckout('non-existing-branch', undefined, emptyGit), ).rejects.toThrow( "pathspec 'non-existing-branch' did not match any file(s) known to git", ); }); }); - describe('git utils in a git repo with a branch and commits dirty', () => { - const baseDir = join( - process.cwd(), - 'tmp', - 'testing-git-repo-with-branch-and-commits-dirty', - ); + describe('with a branch and commits dirty', () => { const newFilePath = join(baseDir, 'new-file.md'); - let dirtyGit: SimpleGit; beforeAll(async () => { - await mkdir(baseDir, { recursive: true }); - - dirtyGit = simpleGit(baseDir); - await dirtyGit.init(); - await dirtyGit.addConfig('user.name', 'John Doe'); - await dirtyGit.addConfig('user.email', 'john.doe@example.com'); - await writeFile(join(baseDir, 'README.md'), '# hello-world\n'); - await dirtyGit.add('README.md'); - await dirtyGit.commit('Create README'); + await emptyGit.add('README.md'); + await emptyGit.commit('Create README'); - await dirtyGit.branch(['feature-branch']); - await dirtyGit.checkout(['master']); + await emptyGit.branch(['feature-branch']); + await emptyGit.checkout(['master']); }); beforeEach(async () => { @@ -168,29 +136,30 @@ describe('git helper tests', () => { }); afterAll(async () => { - await rm(baseDir, { recursive: true, force: true }); + await emptyGit.checkout(['master']); + await emptyGit.deleteLocalBranch('feature-branch'); }); it('safeCheckout should clean local changes and check out to feature-branch', async () => { await expect( - safeCheckout('feature-branch', true, dirtyGit), + safeCheckout('feature-branch', true, emptyGit), ).resolves.toBeUndefined(); - await expect(dirtyGit.branch()).resolves.toEqual( + await expect(emptyGit.branch()).resolves.toEqual( expect.objectContaining({ current: 'feature-branch' }), ); - await expect(dirtyGit.status()).resolves.toEqual( + await expect(emptyGit.status()).resolves.toEqual( expect.objectContaining({ files: [] }), ); }); it('safeCheckout should throw if history is dirty', async () => { - await expect(safeCheckout('master', undefined, dirtyGit)).rejects.toThrow( + await expect(safeCheckout('master', undefined, emptyGit)).rejects.toThrow( 'Working directory needs to be clean before we you can proceed. Commit your local changes or stash them.', ); }); it('guardAgainstLocalChanges should throw if history is dirty', async () => { - await expect(guardAgainstLocalChanges(dirtyGit)).rejects.toThrow( + await expect(guardAgainstLocalChanges(emptyGit)).rejects.toThrow( 'Working directory needs to be clean before we you can proceed. Commit your local changes or stash them.', ); });