diff --git a/CHANGELOG.md b/CHANGELOG.md index aebb8fcfe..2aed165a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,17 @@ Please see [CONTRIBUTING.md](./CONTRIBUTING.md) on how to contribute to Cucumber ## [Unreleased] +## [9.5.1] - 2023-09-06 +### Fixed +- Allow single-item arrays as a format ([#2324](https://github.com/cucumber/cucumber-js/pull/2324)) + +## [9.5.0] - 2023-09-03 +### Added +- Support array notation of formats with path in configuration files ([#2318](https://github.com/cucumber/cucumber-js/pull/2318)) + +### Fixed +- Wait for stream to finish at end of publish plugin ([#2322](https://github.com/cucumber/cucumber-js/pull/2322)) + ## [9.4.0] - 2023-08-12 ### Fixed - Fix type import from cucumber-expressions ([#2310](https://github.com/cucumber/cucumber-js/pull/2310)) @@ -1521,7 +1532,9 @@ this.Given(), this.When(), this.Then() and this.defineStep() ([#2](https://githu ## 0.0.1 -[Unreleased]: https://github.com/cucumber/cucumber-js/compare/v9.4.0...HEAD +[Unreleased]: https://github.com/cucumber/cucumber-js/compare/v9.5.1...HEAD +[9.5.1]: https://github.com/cucumber/cucumber-js/compare/v9.5.0...v9.5.1 +[9.5.0]: https://github.com/cucumber/cucumber-js/compare/v9.4.0...v9.5.0 [9.4.0]: https://github.com/cucumber/cucumber-js/compare/v9.3.0...v9.4.0 [9.3.0]: https://github.com/cucumber/cucumber-js/compare/v9.2.0...v9.3.0 [9.2.0]: https://github.com/cucumber/cucumber-js/compare/v9.1.2...v9.2.0 diff --git a/cucumber.json b/cucumber.json index 401715dd1..a8cd30254 100644 --- a/cucumber.json +++ b/cucumber.json @@ -4,11 +4,11 @@ "require": ["features/**/*.ts"], "format": [ "progress-bar", - "rerun:@rerun.txt", - "usage:reports/usage.txt", - "message:reports/messages.ndjson", - "junit:reports/junit.xml", - "html:reports/html-formatter.html" + ["rerun", "@rerun.txt"], + ["usage", "reports/usage.txt"], + ["message", "reports/messages.ndjson"], + ["junit", "reports/junit.xml"], + ["html", "reports/html-formatter.html"] ], "retry": 2, "retryTagFilter": "@flaky" diff --git a/docs/formatters.md b/docs/formatters.md index 213952c70..be559c77d 100644 --- a/docs/formatters.md +++ b/docs/formatters.md @@ -6,22 +6,19 @@ cucumber-js provides many built-in Formatters, plus building blocks with which y You can specify one or more formats via the `format` configuration option: -- In a configuration file `{ format: [''] }` -- On the CLI `$ cucumber-js --format ` +- In a configuration file `{ format: ['progress-bar', ['html', 'cucumber-report.html']] }` +- On the CLI `$ cucumber-js --format progress-bar --format html:cucumber-report.html` -For each value you provide, `TYPE` should be one of: +For each format you specify, you have to provide one or two values. The first (required) is to identify the formatter. It can take a few forms: -* The name of one of the built-in formatters (below) e.g. `progress` +* The name of one of the built-in formatters (below) e.g. `progress-bar` * A module/package name e.g. `@cucumber/pretty-formatter` * A relative path to a local formatter implementation e.g. `./my-customer-formatter.js` * An absolute path to a local formatter implementation in the form of a `file://` URL -If `PATH` is supplied, the formatter prints to the given file, otherwise it prints to `stdout`. If the path includes directories that do not yet exist they will be created. +Without a second value, the formatter will print to `stdout`. The second value, if present, is a path to where the formatter output should be written. If the path includes directories that do not yet exist, they will be created. -For example, this configuration would give you a progress bar as you run, plus JSON and HTML report files: - -- In a configuration file `{ format: ['progress-bar', 'json:cucumber-report.json', 'html:cucumber-report.html'] }` -- On the CLI `$ cucumber-js --format progress-bar --format json:cucumber-report.json --format html:cucumber-report.html` +On the CLI, when specifying both a name and path, you'll need to use `:` as a delimiter. In a configuration file you can do this too, but you can also provide an array with the two values as separate strings, which is recommended. Some notes on specifying Formatters: diff --git a/package-lock.json b/package-lock.json index 814397884..df0e63b99 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cucumber/cucumber", - "version": "9.4.0", + "version": "9.5.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@cucumber/cucumber", - "version": "9.4.0", + "version": "9.5.1", "license": "MIT", "dependencies": { "@cucumber/ci-environment": "9.2.0", @@ -48,7 +48,7 @@ "verror": "^1.10.0", "xmlbuilder": "^15.1.1", "yaml": "^2.2.2", - "yup": "^0.32.11" + "yup": "1.2.0" }, "bin": { "cucumber-js": "bin/cucumber.js" @@ -180,9 +180,9 @@ } }, "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -223,9 +223,9 @@ } }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -458,17 +458,6 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", - "dependencies": { - "regenerator-runtime": "^0.13.11" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/template": { "version": "7.20.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", @@ -1454,7 +1443,8 @@ "node_modules/@types/lodash": { "version": "4.14.194", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.194.tgz", - "integrity": "sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g==" + "integrity": "sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g==", + "dev": true }, "node_modules/@types/lodash.merge": { "version": "4.6.7", @@ -2823,9 +2813,9 @@ } }, "node_modules/dependency-lint/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -3371,9 +3361,9 @@ } }, "node_modules/eslint-plugin-node/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -4059,9 +4049,9 @@ } }, "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true, "engines": { "node": "*" @@ -4909,9 +4899,9 @@ } }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -5145,12 +5135,8 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true }, "node_modules/lodash.flattendeep": { "version": "4.4.0", @@ -5246,9 +5232,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -5596,11 +5582,6 @@ "thenify-all": "^1.0.0" } }, - "node_modules/nanoclone": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/nanoclone/-/nanoclone-0.2.1.tgz", - "integrity": "sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==" - }, "node_modules/nanoid": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", @@ -6538,9 +6519,9 @@ } }, "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "bin": { "semver": "bin/semver" @@ -6597,11 +6578,6 @@ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" }, - "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" - }, "node_modules/regexp-match-indices": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regexp-match-indices/-/regexp-match-indices-1.0.2.tgz", @@ -7384,6 +7360,11 @@ "node": ">=0.8" } }, + "node_modules/tiny-case": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", + "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==" + }, "node_modules/tmp": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", @@ -7877,9 +7858,9 @@ } }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -8084,20 +8065,25 @@ } }, "node_modules/yup": { - "version": "0.32.11", - "resolved": "https://registry.npmjs.org/yup/-/yup-0.32.11.tgz", - "integrity": "sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/yup/-/yup-1.2.0.tgz", + "integrity": "sha512-PPqYKSAXjpRCgLgLKVGPA33v5c/WgEx3wi6NFjIiegz90zSwyMpvTFp/uGcVnnbx6to28pgnzp/q8ih3QRjLMQ==", "dependencies": { - "@babel/runtime": "^7.15.4", - "@types/lodash": "^4.14.175", - "lodash": "^4.17.21", - "lodash-es": "^4.17.21", - "nanoclone": "^0.2.1", - "property-expr": "^2.0.4", - "toposort": "^2.0.2" - }, + "property-expr": "^2.0.5", + "tiny-case": "^1.0.3", + "toposort": "^2.0.2", + "type-fest": "^2.19.0" + } + }, + "node_modules/yup/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", "engines": { - "node": ">=10" + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/z-schema": { diff --git a/package.json b/package.json index 6905ab3bd..f0b34277b 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "gherkin", "tests" ], - "version": "9.4.0", + "version": "9.5.1", "homepage": "https://github.com/cucumber/cucumber-js", "author": "Julien Biezemans ", "contributors": [ @@ -246,7 +246,7 @@ "verror": "^1.10.0", "xmlbuilder": "^15.1.1", "yaml": "^2.2.2", - "yup": "^0.32.11" + "yup": "1.2.0" }, "devDependencies": { "@cucumber/compatibility-kit": "^12.0.0", diff --git a/src/api/convert_configuration.ts b/src/api/convert_configuration.ts index ddc7c3cae..588f40204 100644 --- a/src/api/convert_configuration.ts +++ b/src/api/convert_configuration.ts @@ -42,7 +42,7 @@ function convertFormats( env: NodeJS.ProcessEnv ) { const splitFormats: string[][] = flatConfiguration.format.map((item) => - OptionSplitter.split(item) + Array.isArray(item) ? item : OptionSplitter.split(item) ) return { stdout: diff --git a/src/api/convert_configuration_spec.ts b/src/api/convert_configuration_spec.ts index a864291f1..4ca25d26b 100644 --- a/src/api/convert_configuration_spec.ts +++ b/src/api/convert_configuration_spec.ts @@ -39,7 +39,7 @@ describe('convertConfiguration', () => { }) }) - it('should map multiple formatters', async () => { + it('should map multiple formatters with string notation', async () => { const result = await convertConfiguration( { ...DEFAULT_CONFIGURATION, @@ -64,6 +64,31 @@ describe('convertConfiguration', () => { }) }) + it('should map multiple formatters with array notation', async () => { + const result = await convertConfiguration( + { + ...DEFAULT_CONFIGURATION, + format: [ + ['summary'], + ['message'], + ['json', './report.json'], + ['html', './report.html'], + ], + }, + {} + ) + + expect(result.formats).to.eql({ + stdout: 'message', + files: { + './report.html': 'html', + './report.json': 'json', + }, + publish: false, + options: {}, + }) + }) + it('should map formatters correctly when file:// urls are involved', async () => { const result = await convertConfiguration( { diff --git a/src/configuration/check_schema.ts b/src/configuration/check_schema.ts index 758704eba..9538d7b18 100644 --- a/src/configuration/check_schema.ts +++ b/src/configuration/check_schema.ts @@ -7,7 +7,15 @@ const schema = yup.object().shape({ dryRun: yup.boolean(), exit: yup.boolean(), failFast: yup.boolean(), - format: yup.array().of(yup.string()), + format: yup + .array() + .of( + yup.lazy((val) => + Array.isArray(val) + ? yup.array().of(yup.string()).min(2).max(2) + : yup.string() + ) + ), formatOptions: yup.object(), import: yup.array().of(yup.string()), language: yup.string().oneOf(Object.keys(dialects)), diff --git a/src/configuration/types.ts b/src/configuration/types.ts index cdc75b1d7..8310ec75c 100644 --- a/src/configuration/types.ts +++ b/src/configuration/types.ts @@ -1,12 +1,14 @@ import { FormatOptions } from '../formatter' import { PickleOrder } from '../models/pickle_order' +type FormatsConfiguration = Array + export interface IConfiguration { backtrace: boolean dryRun: boolean forceExit: boolean failFast: boolean - format: string[] + format: FormatsConfiguration formatOptions: FormatOptions import: string[] language: string diff --git a/src/publish/publish_plugin.ts b/src/publish/publish_plugin.ts index 4d785f28c..fd1fe29e8 100644 --- a/src/publish/publish_plugin.ts +++ b/src/publish/publish_plugin.ts @@ -35,8 +35,13 @@ export const publishPlugin: Plugin = async ({ stream.pipe(readerStream) stream.on('error', (error: Error) => logger.error(error.message)) on('message', (value) => stream.write(JSON.stringify(value) + '\n')) - return () => stream.end() + return () => + new Promise((resolve) => { + stream.on('finish', () => resolve()) + stream.end() + }) } + /* This is because the Cucumber Reports service returns a pre-formatted console message including ANSI escapes, so if our stderr stream doesn't support those we need to