diff --git a/CHANGELOG.md b/CHANGELOG.md index ede556f0d..96082618a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,8 @@ Please see [CONTRIBUTING.md](https://github.com/cucumber/cucumber/blob/master/CO ### Removed ### Fixed +* When running the help command, it now shows all available formatters under the --format option. + [#1798](https://github.com/cucumber/cucumber-js/pull/1798) ## [7.3.1] (2021-07-20) diff --git a/src/cli/argv_parser.ts b/src/cli/argv_parser.ts index 0694a5f91..0519a7a1d 100644 --- a/src/cli/argv_parser.ts +++ b/src/cli/argv_parser.ts @@ -2,6 +2,7 @@ import { Command } from 'commander' import path from 'path' import { dialects } from '@cucumber/gherkin' import { SnippetInterface } from '../formatter/step_definition_snippet_builder/snippet_syntax' +import Formatters from '../formatter/helpers/formatters' // Using require instead of import so compiled typescript will have the desired folder structure const { version } = require('../../package.json') // eslint-disable-line @typescript-eslint/no-var-requires @@ -120,7 +121,8 @@ const ArgvParser = { .option('--fail-fast', 'abort the run on first failure', false) .option( '-f, --format ', - 'specify the output format, optionally supply PATH to redirect formatter output (repeatable)', + 'specify the output format, optionally supply PATH to redirect formatter output (repeatable). Available formats:\n' + + Formatters.buildFormattersDocumentationString(), ArgvParser.collect, [] ) diff --git a/src/formatter/builder.ts b/src/formatter/builder.ts index 72862b074..daf9a15e8 100644 --- a/src/formatter/builder.ts +++ b/src/formatter/builder.ts @@ -1,16 +1,7 @@ import getColorFns from './get_color_fns' import JavascriptSnippetSyntax from './step_definition_snippet_builder/javascript_snippet_syntax' -import JsonFormatter from './json_formatter' -import MessageFormatter from './message_formatter' import path from 'path' -import ProgressBarFormatter from './progress_bar_formatter' -import ProgressFormatter from './progress_formatter' -import RerunFormatter from './rerun_formatter' -import SnippetsFormatter from './snippets_formatter' import StepDefinitionSnippetBuilder from './step_definition_snippet_builder' -import SummaryFormatter from './summary_formatter' -import UsageFormatter from './usage_formatter' -import UsageJsonFormatter from './usage_json_formatter' import { ISupportCodeLibrary } from '../support_code_library_builder/types' import Formatter, { IFormatterCleanupFn, IFormatterLogFn } from '.' import { doesHaveValue, doesNotHaveValue } from '../value_checker' @@ -19,8 +10,8 @@ import EventDataCollector from './helpers/event_data_collector' import { Writable as WritableStream } from 'stream' import { IParsedArgvFormatOptions } from '../cli/argv_parser' import { SnippetInterface } from './step_definition_snippet_builder/snippet_syntax' -import HtmlFormatter from './html_formatter' import { pathToFileURL } from 'url' +import Formatters from './helpers/formatters' // eslint-disable-next-line @typescript-eslint/no-var-requires const { importer } = require('../importer') @@ -67,30 +58,12 @@ const FormatterBuilder = { type: string, cwd: string ): Promise { - switch (type) { - case 'json': - return JsonFormatter - case 'message': - return MessageFormatter - case 'html': - return HtmlFormatter - case 'progress': - return ProgressFormatter - case 'progress-bar': - return ProgressBarFormatter - case 'rerun': - return RerunFormatter - case 'snippets': - return SnippetsFormatter - case 'summary': - return SummaryFormatter - case 'usage': - return UsageFormatter - case 'usage-json': - return UsageJsonFormatter - default: - return await FormatterBuilder.loadCustomFormatter(type, cwd) - } + const formatters: Record = + Formatters.getFormatters() + + return formatters[type] + ? formatters[type] + : await FormatterBuilder.loadCustomFormatter(type, cwd) }, async getStepDefinitionSnippetBuilder({ diff --git a/src/formatter/helpers/formatters.ts b/src/formatter/helpers/formatters.ts new file mode 100644 index 000000000..d5a2698f5 --- /dev/null +++ b/src/formatter/helpers/formatters.ts @@ -0,0 +1,39 @@ +import Formatter from '../.' +import JsonFormatter from '../json_formatter' +import MessageFormatter from '../message_formatter' +import ProgressBarFormatter from '../progress_bar_formatter' +import ProgressFormatter from '../progress_formatter' +import RerunFormatter from '../rerun_formatter' +import SnippetsFormatter from '../snippets_formatter' +import SummaryFormatter from '../summary_formatter' +import UsageFormatter from '../usage_formatter' +import UsageJsonFormatter from '../usage_json_formatter' +import HtmlFormatter from '../html_formatter' + +const Formatters = { + getFormatters(): Record { + return { + json: JsonFormatter, + message: MessageFormatter, + html: HtmlFormatter, + progress: ProgressFormatter, + 'progress-bar': ProgressBarFormatter, + rerun: RerunFormatter, + snippets: SnippetsFormatter, + summary: SummaryFormatter, + usage: UsageFormatter, + 'usage-json': UsageJsonFormatter, + } + }, + buildFormattersDocumentationString(): string { + let concatanatedFormattersDocumentation: string = '' + const formatters = this.getFormatters() + for (const formatterName in formatters) { + concatanatedFormattersDocumentation += ` ${formatterName}: ${formatters[formatterName].documentation}\n` + } + + return concatanatedFormattersDocumentation + }, +} + +export default Formatters diff --git a/src/formatter/html_formatter.ts b/src/formatter/html_formatter.ts index fc43c22e2..458e76fae 100644 --- a/src/formatter/html_formatter.ts +++ b/src/formatter/html_formatter.ts @@ -8,6 +8,7 @@ import { promisify } from 'util' export default class HtmlFormatter extends Formatter { private readonly _finished: Promise + public static readonly documentation: string = 'Outputs HTML report' constructor(options: IFormatterOptions) { super(options) diff --git a/src/formatter/index.ts b/src/formatter/index.ts index 91f77a27c..16ff0ad28 100644 --- a/src/formatter/index.ts +++ b/src/formatter/index.ts @@ -39,6 +39,7 @@ export default class Formatter { protected stream: WritableStream protected supportCodeLibrary: ISupportCodeLibrary private readonly cleanup: IFormatterCleanupFn + static readonly documentation: string constructor(options: IFormatterOptions) { this.colorFns = options.colorFns diff --git a/src/formatter/json_formatter.ts b/src/formatter/json_formatter.ts index 2b2c21c33..cb1396f1a 100644 --- a/src/formatter/json_formatter.ts +++ b/src/formatter/json_formatter.ts @@ -81,6 +81,9 @@ interface UriToTestCaseAttemptsMap { } export default class JsonFormatter extends Formatter { + public static readonly documentation: string = + 'Prints the feature as JSON. The JSON format is in maintenance mode. Please consider using the message formatter with the standalone json-formatter (https://github.com/cucumber/cucumber/tree/master/json-formatter).' + constructor(options: IFormatterOptions) { super(options) options.eventBroadcaster.on('envelope', (envelope: messages.Envelope) => { diff --git a/src/formatter/message_formatter.ts b/src/formatter/message_formatter.ts index d464d1704..15f47b0e0 100644 --- a/src/formatter/message_formatter.ts +++ b/src/formatter/message_formatter.ts @@ -2,6 +2,7 @@ import Formatter, { IFormatterOptions } from '.' import * as messages from '@cucumber/messages' export default class MessageFormatter extends Formatter { + public static readonly documentation: string = 'Outputs protobuf messages' constructor(options: IFormatterOptions) { super(options) options.eventBroadcaster.on('envelope', (envelope: messages.Envelope) => diff --git a/src/formatter/progress_bar_formatter.ts b/src/formatter/progress_bar_formatter.ts index ed6fc812d..660b3994f 100644 --- a/src/formatter/progress_bar_formatter.ts +++ b/src/formatter/progress_bar_formatter.ts @@ -13,6 +13,8 @@ export default class ProgressBarFormatter extends Formatter { private testRunStarted: messages.TestRunStarted private issueCount: number public progressBar: ProgressBar + public static readonly documentation: string = + 'Similar to the Progress Formatter, but provides a real-time updating progress bar based on the total number of steps to be executed in the test run' constructor(options: IFormatterOptions) { super(options) diff --git a/src/formatter/progress_formatter.ts b/src/formatter/progress_formatter.ts index 2bd058505..cc6198c6c 100644 --- a/src/formatter/progress_formatter.ts +++ b/src/formatter/progress_formatter.ts @@ -16,6 +16,9 @@ const STATUS_CHARACTER_MAPPING: Map = ]) export default class ProgressFormatter extends SummaryFormatter { + public static readonly documentation: string = + 'Prints one character per scenario.' + constructor(options: IFormatterOptions) { options.eventBroadcaster.on('envelope', (envelope: IEnvelope) => { if (doesHaveValue(envelope.testRunFinished)) { diff --git a/src/formatter/rerun_formatter.ts b/src/formatter/rerun_formatter.ts index da5158faa..ad840e14d 100644 --- a/src/formatter/rerun_formatter.ts +++ b/src/formatter/rerun_formatter.ts @@ -15,6 +15,8 @@ interface UriToLinesMap { export default class RerunFormatter extends Formatter { private readonly separator: string + public static readonly documentation: string = + 'Prints failing files with line numbers.' constructor(options: IFormatterOptions) { super(options) diff --git a/src/formatter/snippets_formatter.ts b/src/formatter/snippets_formatter.ts index 1dd2720d4..bbc936d37 100644 --- a/src/formatter/snippets_formatter.ts +++ b/src/formatter/snippets_formatter.ts @@ -5,6 +5,9 @@ import * as messages from '@cucumber/messages' import IEnvelope = messages.Envelope export default class SnippetsFormatter extends Formatter { + public static readonly documentation: string = + "The Snippets Formatter doesn't output anything regarding the test run; it just prints snippets to implement any undefined steps" + constructor(options: IFormatterOptions) { super(options) options.eventBroadcaster.on('envelope', (envelope: IEnvelope) => { diff --git a/src/formatter/summary_formatter.ts b/src/formatter/summary_formatter.ts index e49e342a7..f91034a3d 100644 --- a/src/formatter/summary_formatter.ts +++ b/src/formatter/summary_formatter.ts @@ -12,6 +12,9 @@ interface ILogIssuesRequest { } export default class SummaryFormatter extends Formatter { + public static readonly documentation: string = + 'Summary output of feature and scenarios' + constructor(options: IFormatterOptions) { super(options) let testRunStartedTimestamp: messages.Timestamp diff --git a/src/formatter/usage_formatter.ts b/src/formatter/usage_formatter.ts index ff6afe142..0776d3656 100644 --- a/src/formatter/usage_formatter.ts +++ b/src/formatter/usage_formatter.ts @@ -6,6 +6,9 @@ import * as messages from '@cucumber/messages' import IEnvelope = messages.Envelope export default class UsageFormatter extends Formatter { + public static readonly documentation: string = + 'Prints where step definitions are used. The slowest step definitions (with duration) are listed first. If --dry-run is used the duration is not shown, and step definitions are sorted by filename instead.' + constructor(options: IFormatterOptions) { super(options) options.eventBroadcaster.on('envelope', (envelope: IEnvelope) => { diff --git a/src/formatter/usage_json_formatter.ts b/src/formatter/usage_json_formatter.ts index 863b8768c..c2b522429 100644 --- a/src/formatter/usage_json_formatter.ts +++ b/src/formatter/usage_json_formatter.ts @@ -5,6 +5,9 @@ import * as messages from '@cucumber/messages' import IEnvelope = messages.Envelope export default class UsageJsonFormatter extends Formatter { + public static readonly documentation: string = + 'Does what the Usage Formatter does, but outputs JSON, which can be output to a file and then consumed by other tools.' + constructor(options: IFormatterOptions) { super(options) options.eventBroadcaster.on('envelope', (envelope: IEnvelope) => {