diff --git a/README.md b/README.md index 603eea3ed..a3d988003 100644 --- a/README.md +++ b/README.md @@ -211,7 +211,8 @@ This command executes a set of user-flow definitions against the target URL and | **`-a`**, **`--awaitServeStdout`** | `string` | `.user-flowrc` setting | Waits for stdout from the serve command to start collecting user-flows | | **`-f`**, **`--format`** | `string` | `html`, `json` setting | Format of the creates reports | | **`-e`**, **`--openReport`** | `boolean` | `true` | Opens browser automatically after the user-flow is captured | -| **`-b`**, **`--budget-path`** | `string` | `./budget.json` | Path to the lighthouse `budget.json` file | +| **`-b`**, **`--budget-path`** | `string` | n/a | Path to the lighthouse `budget.json` file | +| **`-b`**, **`--config-path`** | `string` | n/a | Path to the lighthouse `config.json` file | | **`-d`**, **`--dryRun`** | `boolean` | `false` | When true the user-flow test will get executed without measures (for fast development) | > **💡 Pro Tip:** @@ -224,6 +225,21 @@ This command executes a set of user-flow definitions against the target URL and The CLI supports the official [user-flow/lighthouse configuration](https://github.com/GoogleChrome/lighthouse/blob/master/docs/configuration.md). +This configuration options can be used globally with the `configPath` option of the [`collect` command](#collect-command), +or per user flow in the [`UserFlowProvider#UserFlowOptions#config`](https://github.com/push-based/user-flow/blob/main/packages/cli/src/lib/commands/collect/utils/user-flow/types.ts#L39) option. + +### Overwrites + +As configuration can be placed on multiple levels at the same time we the overwrite order is defined as follows: + +There are 2 levels: +- **global** - can be configured in the `.user-flowrc.json` or as CLI parameter +- **local** - per file configuration located in `.uf.ts` + +- **local** `configPath` settings overwrite **global** settings + - **local** `budgets` or `budgetsPath` overwrite **global** settings form `configPath` + + ### Executing user-flows (`ufPath`) To execute a single user-flow pass the user set the ufPath to user-flow file. You and set this ether in the config json file: diff --git a/package-lock.json b/package-lock.json index 9606a29e5..39eab2bbe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,6 +55,9 @@ "rimraf": "^3.0.2", "ts-jest": "^29.0.3", "typescript": "^4.9.3" + }, + "engines": { + "node": "16.14.3" } }, "node_modules/@ampproject/remapping": { diff --git a/package.json b/package.json index 4b261ef1a..d4f6dd6a7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,9 @@ { "name": "push-based-user-flow-workspace", "version": "0.0.0", + "engines": { + "node": "16.14.3" + }, "license": "MIT", "scripts": { "nx": "nx", diff --git a/packages/cli/src/lib/commands/collect/options/types.ts b/packages/cli/src/lib/commands/collect/options/types.ts index f003041b7..f0bce1aa3 100644 --- a/packages/cli/src/lib/commands/collect/options/types.ts +++ b/packages/cli/src/lib/commands/collect/options/types.ts @@ -16,6 +16,7 @@ export type CollectRcOptions = { // @TODO get better typing for if serveCommand is given await is required serveCommand?: string, awaitServeStdout?: string; + configPath?: string; } export type CollectCliOnlyOptions = { dryRun?: boolean; diff --git a/packages/cli/src/lib/commands/collect/processes/collect-reports.ts b/packages/cli/src/lib/commands/collect/processes/collect-reports.ts index 92519b4d9..3eba165c2 100644 --- a/packages/cli/src/lib/commands/collect/processes/collect-reports.ts +++ b/packages/cli/src/lib/commands/collect/processes/collect-reports.ts @@ -5,6 +5,9 @@ import { get as dryRun } from '../../../commands/collect/options/dryRun'; import { collectFlow, loadFlow, openFlowReport, persistFlow } from '../utils/user-flow'; import { AssertRcOptions } from '../../assert/options/types'; import { RcJson } from '../../../types'; +import { CollectArgvOptions } from '../options/types'; +import { readFile } from '../../../core/file'; +import { readConfig } from '../utils/config'; export async function collectReports(cfg: RcJson): Promise { @@ -18,6 +21,7 @@ export async function collectReports(cfg: RcJson): Promise { (_: any) => { provider = normalizeProviderObject(provider); + provider = addConfigIfGiven(provider, collect); provider = addBudgetsIfGiven(provider, assert); return collectFlow({ ...collect, dryRun: dryRun() }, { ...provider, path }) @@ -41,6 +45,19 @@ function normalizeProviderObject(provider: UserFlowProvider): UserFlowProvider { return provider; } +function addConfigIfGiven(provider: UserFlowProvider, collectOptions: CollectArgvOptions = {} as CollectArgvOptions): UserFlowProvider { + const { configPath } = collectOptions; + + if (configPath) { + logVerbose(`Configuration ${configPath} is used instead of a potential configuration in the user-flow.uf.ts`); + + // @ts-ignore + provider.flowOptions.config = readConfig(configPath); + } + + return provider; +} + function addBudgetsIfGiven(provider: UserFlowProvider, assertOptions: AssertRcOptions = {} as AssertRcOptions): UserFlowProvider { const { budgetPath, budgets } = assertOptions; diff --git a/packages/cli/src/lib/commands/collect/utils/config/index.ts b/packages/cli/src/lib/commands/collect/utils/config/index.ts new file mode 100644 index 000000000..57903c041 --- /dev/null +++ b/packages/cli/src/lib/commands/collect/utils/config/index.ts @@ -0,0 +1,21 @@ +import { readFile, writeFile } from '../../../../core/file'; +import { logVerbose } from '../../../../core/loggin'; +import { DEFAULT_COLLECT_CONFIG_PATH } from '../../options/configPath.constant'; +import { LhConfigJson } from '../../../../hacky-things/lighthouse'; + + +export function readConfig(configPath: string = DEFAULT_COLLECT_CONFIG_PATH): LhConfigJson { + const configJson = JSON.parse(readFile(configPath) || '{}'); + return configJson; +} + +export function writeConfig(config: LhConfigJson, configPath: string = DEFAULT_COLLECT_CONFIG_PATH): void { + logVerbose(`Update config under ${configPath}`); + + if (JSON.stringify(readConfig()) !== JSON.stringify(config)) { + writeFile(configPath, JSON.stringify(config)); + logVerbose(`New config ${JSON.stringify(config)}`); + } else { + logVerbose(`No updates for ${configPath} to save.`); + } +} diff --git a/packages/cli/src/lib/commands/collect/utils/params.ts b/packages/cli/src/lib/commands/collect/utils/params.ts index 1aeea5f1a..ec3c7d762 100644 --- a/packages/cli/src/lib/commands/collect/utils/params.ts +++ b/packages/cli/src/lib/commands/collect/utils/params.ts @@ -17,7 +17,7 @@ export function getCollectCommandOptionsFromArgv(argv: RcJsonAsArgv): CollectCom const { url, ufPath, serveCommand, awaitServeStdout, dryRun, openReport, - outPath, format, budgetPath, budgets + outPath, format, budgetPath, budgets, configPath } = (argv || {}) as any as (keyof CollectRcOptions & keyof PersistRcOptions); let collect = {} as CollectArgvOptions; @@ -26,6 +26,7 @@ export function getCollectCommandOptionsFromArgv(argv: RcJsonAsArgv): CollectCom // optional serveCommand && (collect.serveCommand = serveCommand); awaitServeStdout && (collect.awaitServeStdout = awaitServeStdout); + configPath && (collect.configPath = configPath); // cli only dryRun !== undefined && (collect.dryRun = Boolean(dryRun)); diff --git a/packages/cli/src/lib/commands/collect/utils/user-flow/collect-flow.ts b/packages/cli/src/lib/commands/collect/utils/user-flow/collect-flow.ts index 7b7dcbab3..4ff020f75 100644 --- a/packages/cli/src/lib/commands/collect/utils/user-flow/collect-flow.ts +++ b/packages/cli/src/lib/commands/collect/utils/user-flow/collect-flow.ts @@ -3,7 +3,7 @@ import { logVerbose } from '../../../../core/loggin'; import * as puppeteer from 'puppeteer'; import { Browser, Page } from 'puppeteer'; import { normalize } from 'path'; -import { startFlow, UserFlow } from '../../../../hacky-things/lighthouse'; +import { LhConfigJson, startFlow, UserFlow } from '../../../../hacky-things/lighthouse'; import { get as dryRun } from '../../../../commands/collect/options/dryRun'; import { UserFlowMock } from './user-flow.mock'; import * as Config from 'lighthouse/types/config'; @@ -11,6 +11,7 @@ import Budget from 'lighthouse/types/lhr/budget'; import { readBudgets } from '../../../assert/utils/budgets'; import { detectCliMode } from '../../../../global/cli-mode/cli-mode'; import { CollectArgvOptions } from '../../options/types'; +import { readConfig } from '../config'; export async function collectFlow( cliOption: CollectArgvOptions, @@ -24,8 +25,13 @@ export async function collectFlow( launchOptions } = userFlowProvider; - const { config, ...rest } = providerFlowOptions; - const flowOptions = { ...rest, config: parseUserFlowOptionsConfig(providerFlowOptions.config) }; + let { config, ...rest } = providerFlowOptions; + let mergedLhConfig = { ...config } + if(cliOption?.configPath) { + mergedLhConfig = {...mergedLhConfig, ...readConfig(cliOption.configPath)}; + } + + const flowOptions = { ...rest, config: parseUserFlowOptionsConfig(mergedLhConfig) }; // object containing the options for puppeteer/chromium launchOptions = launchOptions || { @@ -59,14 +65,14 @@ export async function collectFlow( } -function parseUserFlowOptionsConfig(flowOptionsConfig?: UserFlowProvider['flowOptions']['config']): Config.default.Json { +function parseUserFlowOptionsConfig(flowOptionsConfig?: LhConfigJson): Config.default.Json { flowOptionsConfig = flowOptionsConfig || {} as any; // @ts-ignore flowOptionsConfig?.extends || (flowOptionsConfig.extends = 'lighthouse:default'); // if budgets are given if (flowOptionsConfig?.settings?.budgets) { - logVerbose('format given budgets') + logVerbose('Use budgets from UserFlowProvider objects under the flowOptions.settings.budgets property'); let budgets: Budget[] = flowOptionsConfig?.settings?.budgets; budgets && (budgets = Array.isArray(budgets) ? budgets : readBudgets(budgets)); flowOptionsConfig.settings.budgets = budgets; diff --git a/packages/cli/src/lib/commands/collect/utils/user-flow/user-flow.mock.ts b/packages/cli/src/lib/commands/collect/utils/user-flow/user-flow.mock.ts index 8a4eea106..69424c64f 100644 --- a/packages/cli/src/lib/commands/collect/utils/user-flow/user-flow.mock.ts +++ b/packages/cli/src/lib/commands/collect/utils/user-flow/user-flow.mock.ts @@ -4,7 +4,8 @@ import FlowResult from 'lighthouse/types/lhr/flow'; import { StepOptions, UserFlowOptions } from './types'; const dummyFlowResult: (cfg: UserFlowOptions) => FlowResult = (cfg: UserFlowOptions): FlowResult => { - const budgets = cfg?.config?.settings?.budgets; + const config = cfg?.config || { }; + logVerbose('dummy config used:', config) const report = { name: cfg.name, steps: [ @@ -12,9 +13,7 @@ const dummyFlowResult: (cfg: UserFlowOptions) => FlowResult = (cfg: UserFlowOpti name: 'Navigation report (127.0.0.1/)', lhr: { fetchTime: new Date().toISOString(), - configSettings: { - // "budgets": [] // budgets from configurations - }, + configSettings: config, audits: { // "performance-budget": {}, // "timing-budget": {} @@ -23,6 +22,11 @@ const dummyFlowResult: (cfg: UserFlowOptions) => FlowResult = (cfg: UserFlowOpti } ] }; + if (config) { + report.steps[0].lhr.configSettings = config; + } + + const budgets = config?.settings?.budgets; if (budgets) { report.steps[0].lhr.configSettings.budgets = budgets; report.steps[0].lhr.audits['performance-budget'] = {}; @@ -67,6 +71,7 @@ export class UserFlowMock { logVerbose(`flow#navigate: ${stepName || requestor}`); return this.page.goto(requestor); } + constructor(page: Page, cfg: UserFlowOptions) { this.page = page; this.cfg = cfg; diff --git a/packages/cli/src/lib/global/rc-json/index.ts b/packages/cli/src/lib/global/rc-json/index.ts index 5d1aabf7c..b325404e8 100644 --- a/packages/cli/src/lib/global/rc-json/index.ts +++ b/packages/cli/src/lib/global/rc-json/index.ts @@ -4,18 +4,18 @@ import { RcJson } from '../../types'; import { globalOptions } from '../options'; export function readRcConfig(rcPath: string = ''): RcJson { - const configPath = rcPath || globalOptions.getRcPath(); - const repoConfigJson = readFile(configPath, { ext: 'json' }) || {}; + rcPath = rcPath || globalOptions.getRcPath(); + const repoConfigJson = readFile(rcPath, { ext: 'json' }) || {}; return repoConfigJson; } export function updateRcConfig(config: RcJson, rcPath: string = ''): void { - const configPath = rcPath || globalOptions.getRcPath(); + rcPath = rcPath || globalOptions.getRcPath(); // NOTICE: this is needed for better git flow. // Touch a file only if needed if (JSON.stringify(readRcConfig()) !== JSON.stringify(config)) { - writeFile(configPath, JSON.stringify(config)); - logVerbose(`Update config under ${configPath} to`, config); + writeFile(rcPath, JSON.stringify(config)); + logVerbose(`Update config under ${rcPath} to`, config); } } diff --git a/packages/cli/src/lib/hacky-things/lighthouse.ts b/packages/cli/src/lib/hacky-things/lighthouse.ts index f8bafb34a..3dc1a3290 100644 --- a/packages/cli/src/lib/hacky-things/lighthouse.ts +++ b/packages/cli/src/lib/hacky-things/lighthouse.ts @@ -5,6 +5,10 @@ * * */ +// @ts-ignore +import { default as LhConfig } from 'lighthouse/types/config'; +export type LhConfigJson = LhConfig.Json; + // @ts-ignore export {Util} from 'lighthouse/lighthouse-core/util-commonjs'; // @ts-ignore diff --git a/packages/cli/tests/commands/collect/collect.budgets.test.ts b/packages/cli/tests/commands/collect/collect.budgets.test.ts index 48e87ec79..05f762cd7 100644 --- a/packages/cli/tests/commands/collect/collect.budgets.test.ts +++ b/packages/cli/tests/commands/collect/collect.budgets.test.ts @@ -25,7 +25,7 @@ describe('$collect() sandbox+NO-assets with RC()', () => { afterEach(async () => await staticPrj.teardown()); it('should NOT log budgets info', async () => { - const { exitCode, stdout, stderr } = await staticPrj.$collect({}); + const { exitCode, stdout, stderr } = await staticPrj.$collect(); expect(stderr).toBe(''); expectNoBudgetsFileExistLog(stdout); @@ -85,7 +85,8 @@ let staticWBudgetPathPrjCfg: UserFlowProjectConfig = { create: { ...STATIC_PRJ_CFG.create, [LH_NAVIGATION_BUDGETS_NAME]: LH_NAVIGATION_BUDGETS - } + }, + delete: (STATIC_PRJ_CFG?.delete || []).concat([LH_NAVIGATION_BUDGETS_NAME]) }; describe('$collect() sandbox+assets with RC({budgetPath}))', () => { diff --git a/packages/cli/tests/commands/collect/collect.configPath.test.ts b/packages/cli/tests/commands/collect/collect.configPath.test.ts new file mode 100644 index 000000000..f99aea943 --- /dev/null +++ b/packages/cli/tests/commands/collect/collect.configPath.test.ts @@ -0,0 +1,78 @@ +import { UserFlowCliProject, UserFlowCliProjectFactory } from '../../user-flow-cli-project/user-flow-cli'; +import { STATIC_PRJ_CFG } from '../../fixtures/sandbox/static'; +import { UserFlowProjectConfig } from '../../user-flow-cli-project/types'; +import { STATIC_JSON_REPORT_NAME, STATIC_RC_JSON } from '../../fixtures/rc-files/static'; +import { DEFAULT_RC_NAME } from '../../../src/lib/constants'; +import { + expectConfigPathUsageLog, + expectNoConfigFileExistLog, + expectResultsToIncludeConfig +} from '../../user-flow-cli-project/expect'; +import { LH_CONFIG, LH_CONFIG_NAME } from '../../fixtures/config/lh-config'; +import { expectCollectCfgToContain } from '../../utils/cli-expectations'; + +let staticPrj: UserFlowCliProject; + +describe('$collect() sandbox+NO-assets with RC()', () => { + beforeEach(async () => { + if (!staticPrj) { + staticPrj = await UserFlowCliProjectFactory.create(STATIC_PRJ_CFG); + } + await staticPrj.setup(); + }); + afterEach(async () => await staticPrj.teardown()); + + it('should NOT log configPath info', async () => { + const { exitCode, stdout, stderr } = await staticPrj.$collect(); + + expect(stderr).toBe(''); + expectNoConfigFileExistLog(stdout); + expect(exitCode).toBe(0); + + }); + +}); + +let staticWConfigAssetsPrj: UserFlowCliProject; +let staticWConfigPathPrjCfg: UserFlowProjectConfig = { + ...STATIC_PRJ_CFG, + rcFile: { + [DEFAULT_RC_NAME]: { + ...STATIC_RC_JSON, + collect: { + ...STATIC_RC_JSON.collect, + configPath: LH_CONFIG_NAME + } + } + }, + create: { + ...STATIC_PRJ_CFG.create, + [LH_CONFIG_NAME]: LH_CONFIG + }, + delete: [LH_CONFIG_NAME].concat(STATIC_PRJ_CFG?.delete || []) +}; + +describe('$collect() sandbox+assets with RC({configPath}))', () => { + beforeEach(async () => { + if (!staticWConfigAssetsPrj) { + staticWConfigAssetsPrj = await UserFlowCliProjectFactory.create(staticWConfigPathPrjCfg); + } + await staticWConfigAssetsPrj.setup(); + }); + afterEach(async () => await staticWConfigAssetsPrj.teardown()); + + it('should load configPath from RC file', async () => { + const { exitCode, stdout, stderr } = await staticWConfigAssetsPrj.$collect({ + configPath: LH_CONFIG_NAME + }); + + + expect(stderr).toBe(''); + expectCollectCfgToContain(stdout, {configPath: LH_CONFIG_NAME}) + expectConfigPathUsageLog(stdout, LH_CONFIG_NAME); + expectResultsToIncludeConfig(staticWConfigAssetsPrj, STATIC_JSON_REPORT_NAME.split('.json').pop()+''); + expect(exitCode).toBe(0); + + }, 60_000); + +}); diff --git a/packages/cli/tests/fixtures/config/lh-config.ts b/packages/cli/tests/fixtures/config/lh-config.ts new file mode 100644 index 000000000..cae018e33 --- /dev/null +++ b/packages/cli/tests/fixtures/config/lh-config.ts @@ -0,0 +1,12 @@ +import { LhConfigJson } from '../../../src/lib/hacky-things/lighthouse'; + +export const LH_CONFIG_NAME = 'config.json'; +export const LH_CONFIG: LhConfigJson = { + extends: 'lighthouse:default', + settings: { + /** If present, the run should only conduct this list of audits. */ + onlyAudits: ['lcp-lazy-loaded'] + /** If present, the run should only conduct this list of categories. */ + //'only-categories': ['performance'] + } +}; diff --git a/packages/cli/tests/user-flow-cli-project/expect.ts b/packages/cli/tests/user-flow-cli-project/expect.ts index 7682ca749..6ac8ac27f 100644 --- a/packages/cli/tests/user-flow-cli-project/expect.ts +++ b/packages/cli/tests/user-flow-cli-project/expect.ts @@ -8,6 +8,8 @@ import { PROMPT_PERSIST_OUT_PATH } from '../../src/lib/commands/collect/options/ import { PROMPT_PERSIST_FORMAT } from '../../src/lib/commands/collect/options/format.constant'; import { LH_NAVIGATION_BUDGETS_NAME } from '../fixtures/budget/lh-navigation-budget'; import { DEFAULT_RC_NAME } from '../../src/lib/constants'; +import { ConfigSettings } from 'lighthouse/types/lhr/settings'; +import { LH_CONFIG, LH_CONFIG_NAME } from '../fixtures/config/lh-config'; export function expectCollectCommandNotToCreateLogsFromMockInStdout( prj: UserFlowCliProject, @@ -95,6 +97,24 @@ export function expectResultsToIncludeBudgets(prj: UserFlowCliProject, reportNam expect(report.steps[0].lhr.audits['timing-budget']).toBeDefined(); } +export function expectResultsToIncludeConfig(prj: UserFlowCliProject, reportName: string, config: string = LH_CONFIG_NAME) { + const report = prj.readOutput(reportName) as any; + const resolvedConfig = prj.readConfig(config); + + expect(report.steps[0].lhr.configSettings).toEqual(resolvedConfig); + +} + +export function expectConfigPathUsageLog(stdout: string, configPath: string = '') { + expect(stdout).toContain(`Configuration ${configPath} is used instead of a potential configuration in the user-flow.uf.ts`); +} + +export function expectNoConfigFileExistLog(stdout: string) { + expect(stdout).not.toContain(`CLI options --configPath or .user-flowrc.json configuration`); + expect(stdout).not.toContain('.user-flowrc.json configuration is used instead of a potential configuration in the user flow'); + expect(stdout).not.toContain('Use config from UserFlowProvider objects under the flowOptions property'); +} + export function expectCliToCreateRc( prj: UserFlowCliProject, json: RcJson, diff --git a/packages/cli/tests/user-flow-cli-project/user-flow-cli.ts b/packages/cli/tests/user-flow-cli-project/user-flow-cli.ts index d24262a84..46df1a935 100644 --- a/packages/cli/tests/user-flow-cli-project/user-flow-cli.ts +++ b/packages/cli/tests/user-flow-cli-project/user-flow-cli.ts @@ -20,6 +20,8 @@ import { LH_NAVIGATION_BUDGETS_NAME } from '../fixtures/budget/lh-navigation-bud import Budget from 'lighthouse/types/lhr/budget'; import { TestResult } from '../cli-testing/process'; import { DEFAULT_PERSIST_OUT_PATH } from '../../src/lib/commands/collect/options/outPath.constant'; +import { LH_CONFIG_NAME } from '../fixtures/config/lh-config'; +import { LhConfigJson } from '../../src/lib/hacky-things/lighthouse'; export class UserFlowCliProjectFactory { static async create(cfg: UserFlowProjectConfig): Promise { @@ -90,12 +92,20 @@ export class UserFlowCliProject extends CliProject { } readBudget(budgetName:string = LH_NAVIGATION_BUDGETS_NAME): Budget[] { - return JSON.parse(fs.readFileSync(path.join(this.root, budgetName)) as any); + return JSON.parse(fs.readFileSync(this.budgetPath(budgetName)) as any); } budgetPath(budgetName:string = LH_NAVIGATION_BUDGETS_NAME): string { return path.join(this.root, budgetName); } + readConfig(configName:string = LH_CONFIG_NAME): LhConfigJson { + return JSON.parse(fs.readFileSync(this.configPath(configName)) as any); + } + configPath(configName:string = LH_CONFIG_NAME): string { + return path.join(this.root, configName); + } + + readOutput(userFlowName: string, rcFileName: string = DEFAULT_RC_NAME): string | {} { const outputFiles = fs.readdirSync(this.outputPath()); const reportName = outputFiles.find((name) => name.includes(name)) || userFlowName; diff --git a/packages/cli/tests/utils/cli-expectations.ts b/packages/cli/tests/utils/cli-expectations.ts index 83458ba4a..732382511 100644 --- a/packages/cli/tests/utils/cli-expectations.ts +++ b/packages/cli/tests/utils/cli-expectations.ts @@ -60,6 +60,7 @@ export function expectCollectCfgToContain(stdout: string, cliParams: {}) { case 'serveCommand': case 'awaitServeStdout': case 'budgetPath': + case 'configPath': expect(stdout).toContain(`${k}: '${v}'`); break; case 'format': @@ -106,18 +107,18 @@ export function expectOutputRcInStdout(stdout: string, cfg: RcJson) { export function expectBudgetsPathUsageLog(stdout: string, budgetPath: string = '') { expect(stdout).toContain(`Collect options budgetPath is used over CLI param or .user-flowrc.json. Configuration ${budgetPath} is used instead of a potential configuration in the user-flow.uf.ts`); - expect(stdout).toContain('format given budgets'); + expect(stdout).toContain('Use budgets from UserFlowProvider objects under the flowOptions.settings.budgets property'); } export function expectBudgetsUsageLog(stdout: string, budgets: Budget[] = []) { expect(stdout).toContain('Collect options budgets is used over CLI param or .user-flowrc.json. Configuration ${budgets} is used instead of a potential configuration in the user-flow.uf.ts'); - expect(stdout).toContain('format given budgets'); + expect(stdout).toContain('Use budgets from UserFlowProvider objects under the flowOptions.settings.budgets property'); } export function expectNoBudgetsFileExistLog(stdout: string) { expect(stdout).not.toContain(`CLI options --budgetPath or .user-flowrc.json configuration`); expect(stdout).not.toContain('.user-flowrc.json configuration is used instead of a potential configuration in the user flow'); - expect(stdout).not.toContain('format given budgets'); + expect(stdout).not.toContain('Use budgets from UserFlowProvider objects under the flowOptions.settings.budgets property'); } export function old_expectResultsToIncludeBudgets(resultPath: string, budgets: Budget[] | string) {