@gnuechtel/nx-cucumber 2.0.0-beta.4 → 2.1.0-14848049561
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -49
- package/migrations.json +1 -1
- package/package.json +3 -9
- package/src/adapters/registry.js +1 -1
- package/src/adapters/registry.js.map +1 -1
- package/src/core/cucumber-run-metadata-formatter.js +111 -0
- package/src/generators/project/files/config/cjs/cucumber.__configFormat__.template +72 -0
- package/src/generators/project/files/config/esm/cucumber.__configFormat__.template +47 -0
- package/src/generators/project/files/config/json/cucumber.__configFormat__.template +37 -0
- package/src/generators/project/files/config/yaml/cucumber.__configFormat__.template +32 -0
- package/src/generators/project/files/playwright/run-e2e.js.template +112 -0
- package/src/generators/project/project.js +136 -29
- package/src/generators/project/project.js.map +1 -1
- package/src/generators/project/schema.d.ts +3 -0
- package/src/generators/project/schema.json +6 -0
- package/src/index.d.ts +0 -4
- package/src/index.js +1 -6
- package/src/index.js.map +1 -1
- package/src/migrations/update-2-0-0/migrate-cucumber-api-to-inferred-tasks.js +24 -8
- package/src/migrations/update-2-0-0/migrate-cucumber-api-to-inferred-tasks.js.map +1 -1
- package/src/plugin/create-nodes.d.ts +14 -0
- package/src/plugin/create-nodes.js +8 -0
- package/src/plugin/create-nodes.js.map +1 -1
- package/src/core/cucumber-report-html.d.ts +0 -11
- package/src/core/cucumber-report-html.js +0 -58
- package/src/core/cucumber-report-html.js.map +0 -1
- package/src/core/web-server.d.ts +0 -29
- package/src/core/web-server.js +0 -139
- package/src/core/web-server.js.map +0 -1
- package/src/generators/project/files/all/cucumber.js.template +0 -27
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ Plugin to use Cucumber within Nx workspaces
|
|
|
11
11
|
- [Install Nx](#install-nx)
|
|
12
12
|
- [Install dependencies](#install-dependencies)
|
|
13
13
|
- [Generate Cucumber projects](#generate-cucumber-projects)
|
|
14
|
+
- [Choosing the --project value](#choosing-the---project-value)
|
|
14
15
|
- [Basic project generator usage](#basic-project-generator-usage)
|
|
15
16
|
- [Additional project generator options](#additional-project-generator-options)
|
|
16
17
|
- [Execute Cucumber projects](#execute-cucumber-projects)
|
|
@@ -24,9 +25,9 @@ Plugin to use Cucumber within Nx workspaces
|
|
|
24
25
|
- [Playwright world](#playwright-world)
|
|
25
26
|
- [Core world](#core-world)
|
|
26
27
|
- [Reports](#reports)
|
|
27
|
-
- [Built-in
|
|
28
|
-
- [
|
|
29
|
-
- [
|
|
28
|
+
- [Built-in formatter outputs](#built-in-formatter-outputs)
|
|
29
|
+
- [Run metadata report](#run-metadata-report)
|
|
30
|
+
- [Custom formatter configuration](#custom-formatter-configuration)
|
|
30
31
|
- [Code coverage](#code-coverage)
|
|
31
32
|
- [Example projects](#example-projects)
|
|
32
33
|
- [Main examples](#main-examples)
|
|
@@ -64,6 +65,9 @@ Version 2.x is a deliberate breaking release that simplifies the plugin architec
|
|
|
64
65
|
- **Nx >=22 only.** The 2.x line requires Nx 22 or later.
|
|
65
66
|
- **Adapter-oriented architecture.** The plugin uses an adapter contract to support multiple executable-spec frameworks. See [docs/adapters/contract.md](https://gitlab.com/gnuechtel/open-source/-/blob/main/docs/adapters/contract.md) for details.
|
|
66
67
|
- **Faster execution.** Removing the executor bootstrap, in-process Cucumber API, plugin-managed dev server lifecycle, and report post-processing from the execution path results in faster test runs.
|
|
68
|
+
- **Reporting is formatter-first.** Generated projects now rely on Cucumber-native formatters (`html`, `json`, `message`, `junit`) plus a dedicated run-metadata formatter artifact. No HTML mutation layer is used.
|
|
69
|
+
- **Legacy HTML post-processing removed.** The previously exported `createBeautifulHtmlReport` helper and `cucumber-html-reporter` integration are no longer part of 2.x.
|
|
70
|
+
- **Configuration filename scope.** In 2.x, plugin discovery/generation/migration is centered on `cucumber.js`.
|
|
67
71
|
|
|
68
72
|
## Prerequisites
|
|
69
73
|
|
|
@@ -91,11 +95,14 @@ npm i -D @gnuechtel/nx-cucumber
|
|
|
91
95
|
# register the plugin in nx.json (enables inferred tasks)
|
|
92
96
|
# add "@gnuechtel/nx-cucumber" to the "plugins" array in nx.json
|
|
93
97
|
|
|
94
|
-
#
|
|
95
|
-
npx nx
|
|
98
|
+
# inspect available Nx project ids (quick-start app id is @gnu-repo/gnu-app)
|
|
99
|
+
npx nx show projects
|
|
96
100
|
|
|
97
|
-
#
|
|
98
|
-
npx nx
|
|
101
|
+
# create a cucumber project for the quick-start app project id
|
|
102
|
+
npx nx g @gnuechtel/nx-cucumber:project --project="@gnu-repo/gnu-app" --test-runner=playwright
|
|
103
|
+
|
|
104
|
+
# run cucumber scenarios with the generated e2e project id
|
|
105
|
+
npx nx e2e "@gnu-repo/gnu-app-e2e"
|
|
99
106
|
```
|
|
100
107
|
|
|
101
108
|
## Install Nx
|
|
@@ -122,27 +129,43 @@ If we want to use the Playwright test runner, we should also install one of the
|
|
|
122
129
|
|
|
123
130
|
We recommend using `@playwright/test`, which also includes the `playwright` dependency and provides very useful [expect](https://playwright.dev/docs/test-assertions) extensions.
|
|
124
131
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
- [cucumber-html-reporter](https://www.npmjs.com/package/cucumber-html-reporter) is required for the [beautiful HTML report](#beautiful-html-report).
|
|
132
|
+
No additional reporting dependency is required for the default outputs.
|
|
128
133
|
|
|
129
134
|
## Generate Cucumber projects
|
|
130
135
|
|
|
136
|
+
### Choosing the `--project` value
|
|
137
|
+
|
|
138
|
+
`--project` must be an existing Nx project id, not the workspace folder name.
|
|
139
|
+
|
|
140
|
+
Use `npx nx show projects` to list valid project ids in your workspace. For Nx 22 monorepo presets (including this quick-start), app project ids are scoped by default (for example `@gnu-repo/gnu-app`).
|
|
141
|
+
|
|
142
|
+
Some existing/legacy workspaces can still use unscoped ids, so always copy the exact id from `npx nx show projects`.
|
|
143
|
+
|
|
144
|
+
If the id is scoped, quote it in shell commands:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
npx nx g @gnuechtel/nx-cucumber:project --project="@smoke-test/smoke-test"
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
If `--project` does not exist, generation fails fast with an explicit error.
|
|
151
|
+
|
|
152
|
+
When `--name` is unscoped and the tested project id is scoped, the generated e2e project id inherits the same scope.
|
|
153
|
+
|
|
131
154
|
### Basic project generator usage
|
|
132
155
|
|
|
133
156
|
After the installation of the dependencies, we can create a project with Cucumber, for any kind of node application:
|
|
134
157
|
|
|
135
158
|
```bash
|
|
136
|
-
# Prerequisite: create application
|
|
159
|
+
# Prerequisite: create an application and identify its Nx project id via "npx nx show projects"
|
|
137
160
|
|
|
138
161
|
# default core test runner (generates an e2e app 'my-project-e2e')
|
|
139
|
-
npx nx g @gnuechtel/nx-cucumber:project --project=
|
|
162
|
+
npx nx g @gnuechtel/nx-cucumber:project --project="<app-project-id>"
|
|
140
163
|
|
|
141
164
|
# playwright test runner (also generates an e2e app 'my-project-e2e')
|
|
142
|
-
npx nx g @gnuechtel/nx-cucumber:project --project=
|
|
165
|
+
npx nx g @gnuechtel/nx-cucumber:project --project="<app-project-id>" --test-runner=playwright
|
|
143
166
|
|
|
144
167
|
# playwright test runner with custom e2e project name (generates an app 'my-project-foo-e2e')
|
|
145
|
-
npx nx g @gnuechtel/nx-cucumber:project --project=
|
|
168
|
+
npx nx g @gnuechtel/nx-cucumber:project --project="<app-project-id>" --name my-project-foo-e2e --test-runner=playwright
|
|
146
169
|
```
|
|
147
170
|
|
|
148
171
|
The generator creates:
|
|
@@ -155,8 +178,8 @@ The `e2e` target behavior depends on the selected test runner:
|
|
|
155
178
|
|
|
156
179
|
- **Core runner:** no explicit `e2e` target is generated. The `e2e` task is inferred by the plugin from `cucumber.js`.
|
|
157
180
|
- **Playwright runner:** explicit command targets are generated:
|
|
158
|
-
- `e2e-prepare` installs Playwright Chromium (Linux uses `--with-deps`)
|
|
159
|
-
- `e2e` runs `
|
|
181
|
+
- `e2e-prepare` installs Playwright Chromium (Linux uses `--with-deps`) and is configured with `cache: false`.
|
|
182
|
+
- `e2e` runs a generated `run-e2e.js` lifecycle script that manages the full dev server lifecycle (clear port, start server, wait for readiness, run Cucumber, stop server) using only Node.js built-ins.
|
|
160
183
|
- `e2e-ci` runs `e2e-prepare` and then `e2e`.
|
|
161
184
|
|
|
162
185
|
### Additional project generator options
|
|
@@ -223,6 +246,8 @@ module.exports = {
|
|
|
223
246
|
|
|
224
247
|
All advanced Cucumber [options](https://github.com/cucumber/cucumber-js/blob/main/docs/configuration.md#options) can be set in the `cucumber.js` file.
|
|
225
248
|
|
|
249
|
+
> **2.x limitation:** `@gnuechtel/nx-cucumber` currently supports `cucumber.js` as the plugin configuration file for inferred-task discovery, generator output, and migration output. Other Cucumber config filenames (for example `cucumber.mjs`) are not supported by the plugin in this major version.
|
|
250
|
+
|
|
226
251
|
### World parameters
|
|
227
252
|
|
|
228
253
|
Playwright-related options that were previously set in `project.json` executor options are now configured via `worldParameters` in `cucumber.js`:
|
|
@@ -330,36 +355,26 @@ export class CustomWorld extends World {
|
|
|
330
355
|
|
|
331
356
|
## Reports
|
|
332
357
|
|
|
333
|
-
### Built-in
|
|
334
|
-
|
|
335
|
-
The generator configures the Cucumber built-in `html` formatter by default. The report is generated at `dist/e2e/<project-root>/reports/html/cucumber-test-report-builtin.html`.
|
|
336
|
-
|
|
337
|
-
### Beautiful HTML report
|
|
358
|
+
### Built-in formatter outputs
|
|
338
359
|
|
|
339
|
-
|
|
360
|
+
Generated projects configure Cucumber-native formatter outputs by default:
|
|
340
361
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
362
|
+
- HTML: `dist/e2e/<project-root>/reports/html/cucumber-test-report-builtin.html`
|
|
363
|
+
- JSON: `dist/e2e/<project-root>/reports/cucumber-json/cucumber-test-report.json`
|
|
364
|
+
- NDJSON messages: `dist/e2e/<project-root>/reports/cucumber-messages/cucumber-messages.ndjson`
|
|
365
|
+
- XML (JUnit): `dist/e2e/<project-root>/reports/test-results/cucumber-test-report.xml`
|
|
344
366
|
|
|
345
|
-
|
|
367
|
+
### Run metadata report
|
|
346
368
|
|
|
347
|
-
|
|
348
|
-
import { createBeautifulHtmlReport } from '@gnuechtel/nx-cucumber';
|
|
369
|
+
Generated projects also include an additional metadata artifact:
|
|
349
370
|
|
|
350
|
-
|
|
351
|
-
jsonDir: 'dist/e2e/apps/my-project-e2e/reports/cucumber-json',
|
|
352
|
-
outputDir: 'dist/e2e/apps/my-project-e2e/reports/html',
|
|
353
|
-
reportTitle: 'My Project E2E Tests',
|
|
354
|
-
});
|
|
355
|
-
```
|
|
371
|
+
- Metadata JSON: `dist/e2e/<project-root>/reports/metadata/cucumber-run-metadata.json`
|
|
356
372
|
|
|
357
|
-
|
|
373
|
+
This file is written by `@gnuechtel/nx-cucumber/src/core/cucumber-run-metadata-formatter.js` and is intentionally separate from Cucumber's standard JSON/NDJSON schema. It contains run context (for example Cucumber meta info, run timestamps, selected world parameters, and environment hints like browser/baseUrl/mode).
|
|
358
374
|
|
|
359
|
-
|
|
375
|
+
### Custom formatter configuration
|
|
360
376
|
|
|
361
|
-
|
|
362
|
-
- XML (JUnit): `dist/e2e/<project-root>/reports/test-results/cucumber-test-report.xml`
|
|
377
|
+
The plugin does not lock formatter choices. You can freely add, remove, or replace formatters in your `cucumber.js` file. The generated metadata formatter receives values via `formatOptions.nxCucumberRunMetadata.worldParameters`, while normal runtime behavior still uses `worldParameters`.
|
|
363
378
|
|
|
364
379
|
## Code coverage
|
|
365
380
|
|
|
@@ -390,6 +405,8 @@ If we have executed our nx-cucumber [end-to-end tests](#end-to-end-tests-of-this
|
|
|
390
405
|
|
|
391
406
|
We support Cucumber with this plugin, and it would be a shame if we used anything other than Cucumber for our own end to end tests. So, we [just do it](https://gitlab.com/gnuechtel/open-source/-/blob/main/apps/nx-cucumber-e2e/features/nx-cucumber.feature)!
|
|
392
407
|
|
|
408
|
+
Generation coverage includes validation for unknown `--project` ids and execution against real Nx project ids detected in the test workspace.
|
|
409
|
+
|
|
393
410
|
To run our own end-to-end tests we simply execute them by:
|
|
394
411
|
|
|
395
412
|
```bash
|
|
@@ -549,32 +566,95 @@ Since 2.x uses framework-native execution via `npx cucumber-js`, all Cucumber CL
|
|
|
549
566
|
|
|
550
567
|
If a feature is missing, please open an issue with a minimal reproducible setup.
|
|
551
568
|
|
|
552
|
-
###
|
|
569
|
+
### Garbled terminal output with verbose Playwright logs (`pw:api`)
|
|
570
|
+
|
|
571
|
+
If log lines look overwritten or scattered (for example on macOS, Linux, or Windows terminals), there are usually two independent redraw layers:
|
|
572
|
+
|
|
573
|
+
1. Cucumber formatter output:
|
|
574
|
+
- `progress-bar` is a real-time updating bar (redraws terminal line).
|
|
575
|
+
- `progress` is step-by-step progress output without a live bar redraw.
|
|
576
|
+
2. Nx task output lifecycle:
|
|
577
|
+
- dynamic/TUI modes may also rewrite terminal output while tasks run.
|
|
578
|
+
- `static` prints append-only output.
|
|
579
|
+
|
|
580
|
+
References:
|
|
581
|
+
|
|
582
|
+
- Cucumber formatters (`progress` vs `progress-bar`): https://github.com/cucumber/cucumber-js/blob/main/docs/formatters.md
|
|
583
|
+
- Nx `outputStyle` modes: https://nx.dev/reference/core-api/nx/documents/show#outputstyle
|
|
584
|
+
|
|
585
|
+
nx-cucumber templates currently use `progress-bar`. If redraw artifacts are distracting with verbose `pw:api` logs, switch to `progress` (or keep only `summary`) in your local `cucumber.js`.
|
|
553
586
|
|
|
554
|
-
If
|
|
587
|
+
If you still want fully append-only Nx logs, run:
|
|
555
588
|
|
|
556
589
|
```bash
|
|
557
|
-
npx
|
|
590
|
+
npx nx e2e "<project-id>" --outputStyle=static
|
|
558
591
|
```
|
|
559
592
|
|
|
560
|
-
|
|
593
|
+
or set this in a **workspace-root** `.env`:
|
|
594
|
+
|
|
595
|
+
```env
|
|
596
|
+
NX_DEFAULT_OUTPUT_STYLE=static
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
Note: nx-cucumber intentionally does not generate or modify a workspace-root `.env`, because that would change logging behavior globally for unrelated projects in the same workspace.
|
|
600
|
+
|
|
601
|
+
### Workspace sync after generating projects
|
|
602
|
+
|
|
603
|
+
On Nx 20+, running `e2e` immediately after generating a new nx-cucumber project (core or Playwright) may fail with:
|
|
604
|
+
|
|
605
|
+
```
|
|
606
|
+
The workspace is out of sync
|
|
607
|
+
[@nx/js:typescript-sync]: Some TypeScript configuration files are missing project references...
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
This is standard Nx behaviour and is not Windows-specific. It can happen on macOS, Linux, and Windows when sync generators detect pending workspace updates.
|
|
611
|
+
|
|
612
|
+
For deterministic smoke-test runs, execute:
|
|
561
613
|
|
|
562
614
|
```bash
|
|
563
|
-
npx nx
|
|
615
|
+
npx nx sync
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
and then rerun your `npx nx e2e "<project-id>"` command.
|
|
619
|
+
|
|
620
|
+
To avoid this manual step in interactive environments, configure `nx.json`:
|
|
621
|
+
|
|
622
|
+
```json
|
|
623
|
+
{
|
|
624
|
+
"sync": { "applyChanges": true }
|
|
625
|
+
}
|
|
564
626
|
```
|
|
565
627
|
|
|
566
|
-
|
|
628
|
+
With this setting Nx automatically applies sync changes before running tasks in interactive terminals.
|
|
567
629
|
|
|
568
|
-
|
|
569
|
-
- `start-server-and-test` owns start/wait/test/stop lifecycle in one process chain.
|
|
570
|
-
- `--strictPort` prevents fallback port switches by Vite that can break URL expectations.
|
|
630
|
+
In non-interactive local runs (no TTY), Nx cannot prompt; if sync changes are needed, task execution stops with a workspace-out-of-sync error.
|
|
571
631
|
|
|
572
|
-
|
|
632
|
+
In CI on Nx 22, task-time sync prompting is skipped, so add an explicit preflight:
|
|
573
633
|
|
|
574
634
|
```bash
|
|
575
|
-
|
|
635
|
+
npx nx sync:check
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
If it reports changes are required, run `npx nx sync` and commit the resulting files.
|
|
639
|
+
|
|
640
|
+
`npx nx reset` is a recovery step for stale daemon/project-graph state (for example `Cannot find project "..."` right after generation, or a newly generated project missing from `npx nx show projects` even after `npx nx sync`). It is not the primary sync fix.
|
|
641
|
+
|
|
642
|
+
### `TS_NODE_PROJECT` and formatter file extensions
|
|
643
|
+
|
|
644
|
+
Generated `cucumber.js` files set `process.env.TS_NODE_PROJECT` explicitly. Keep this setting so `ts-node/register` resolves the correct `tsconfig.json` in monorepos.
|
|
645
|
+
|
|
646
|
+
If you add custom formatters, prefer `.js` (or precompiled output) for formatter modules referenced in `format`. Cucumber loads formatter modules via dynamic import, and pointing directly to a `.ts` formatter can fail with `ERR_UNKNOWN_FILE_EXTENSION` before TypeScript transpilation hooks are applied.
|
|
647
|
+
|
|
648
|
+
### Windows Playwright teardown noise
|
|
649
|
+
|
|
650
|
+
On Windows, after all scenarios finish, the following message may appear in the output:
|
|
651
|
+
|
|
652
|
+
```
|
|
653
|
+
ERROR: The process "XXXX" not found.
|
|
576
654
|
```
|
|
577
655
|
|
|
656
|
+
This is harmless. The generated `run-e2e.js` lifecycle script attempts to stop the dev server after testing. If the server has already exited on its own, `taskkill` reports this message. It does not indicate a test failure.
|
|
657
|
+
|
|
578
658
|
## Migration from 1.x
|
|
579
659
|
|
|
580
660
|
### Prerequisites
|
|
@@ -670,6 +750,7 @@ module.exports = {
|
|
|
670
750
|
'summary',
|
|
671
751
|
'progress-bar',
|
|
672
752
|
`json:${outputDir}/reports/cucumber-json/cucumber-test-report.json`,
|
|
753
|
+
`message:${outputDir}/reports/cucumber-messages/cucumber-messages.ndjson`,
|
|
673
754
|
`html:${outputDir}/reports/html/cucumber-test-report-builtin.html`,
|
|
674
755
|
`junit:${outputDir}/reports/test-results/cucumber-test-report.xml`,
|
|
675
756
|
],
|
package/migrations.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"generators": {
|
|
3
3
|
"migrate-cucumber-api-to-inferred-tasks": {
|
|
4
|
-
"version": "2.0.0
|
|
4
|
+
"version": "2.0.0",
|
|
5
5
|
"description": "Migrate legacy cucumber-api executor projects to adapter-based inferred tasks",
|
|
6
6
|
"implementation": "./src/migrations/update-2-0-0/migrate-cucumber-api-to-inferred-tasks",
|
|
7
7
|
"cli": "nx"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gnuechtel/nx-cucumber",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0-14848049561",
|
|
4
4
|
"description": "Plugin to use Cucumber within Nx workspaces",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"@nx/devkit": ">=22 <23",
|
|
13
13
|
"minimatch": "^10.0.0",
|
|
14
14
|
"tslib": "^2.3.0",
|
|
15
|
-
"@gnuechtel/shared-coverage": "2.
|
|
16
|
-
"@gnuechtel/shared-util": "2.
|
|
15
|
+
"@gnuechtel/shared-coverage": "2.1.0-14848049561",
|
|
16
|
+
"@gnuechtel/shared-util": "2.1.0-14848049561"
|
|
17
17
|
},
|
|
18
18
|
"peerDependencies": {
|
|
19
19
|
"@cucumber/cucumber": ">=9 <13",
|
|
@@ -22,14 +22,8 @@
|
|
|
22
22
|
"playwright-core": ">=1.38.0-0 <2",
|
|
23
23
|
"playwright": ">=1.38.0-0 <2",
|
|
24
24
|
"@playwright/test": ">=1.38.0-0 <2",
|
|
25
|
-
"cucumber-html-reporter": "^7.1.0",
|
|
26
25
|
"nx": ">=22 <23"
|
|
27
26
|
},
|
|
28
|
-
"peerDependenciesMeta": {
|
|
29
|
-
"cucumber-html-reporter": {
|
|
30
|
-
"optional": true
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
27
|
"type": "commonjs",
|
|
34
28
|
"main": "./src/index.js",
|
|
35
29
|
"generators": "./generators.json",
|
package/src/adapters/registry.js
CHANGED
|
@@ -7,7 +7,7 @@ const minimatch_1 = require("minimatch");
|
|
|
7
7
|
const path_1 = require("path");
|
|
8
8
|
const cucumberJsAdapter = {
|
|
9
9
|
name: 'cucumber-js',
|
|
10
|
-
configFilePattern: 'cucumber.{js,cjs,mjs,yaml,yml}',
|
|
10
|
+
configFilePattern: 'cucumber.{js,cjs,mjs,ts,mts,cts,json,yaml,yml}',
|
|
11
11
|
technologies: ['@cucumber/cucumber'],
|
|
12
12
|
targets: {
|
|
13
13
|
e2e: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../../../libs/nx-cucumber/src/adapters/registry.ts"],"names":[],"mappings":";;AAmBA,gDAEC;AAMD,4DAMC;AAOD,gDAKC;AA7CD,yCAAsC;AACtC,+BAAgC;AAGhC,MAAM,iBAAiB,GAAsB;IAC3C,IAAI,EAAE,aAAa;IACnB,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../../../libs/nx-cucumber/src/adapters/registry.ts"],"names":[],"mappings":";;AAmBA,gDAEC;AAMD,4DAMC;AAOD,gDAKC;AA7CD,yCAAsC;AACtC,+BAAgC;AAGhC,MAAM,iBAAiB,GAAsB;IAC3C,IAAI,EAAE,aAAa;IACnB,iBAAiB,EAAE,gDAAgD;IACnE,YAAY,EAAE,CAAC,oBAAoB,CAAC;IACpC,OAAO,EAAE;QACP,GAAG,EAAE;YACH,OAAO,EAAE,iBAAiB;YAC1B,SAAS,EAAE,CAAC,QAAQ,CAAC;SACtB;KACF;CACF,CAAC;AAEF;;GAEG;AACH,SAAgB,kBAAkB;IAChC,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAC7B,CAAC;AAED;;;GAGG;AACH,SAAgB,wBAAwB,CACtC,UAAkB,EAClB,QAA6B;IAE7B,MAAM,QAAQ,GAAG,IAAA,eAAQ,EAAC,UAAU,CAAC,CAAC;IACtC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAA,qBAAS,EAAC,QAAQ,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC;AACpF,CAAC;AAED;;;;GAIG;AACH,SAAgB,kBAAkB,CAAC,QAA6B;IAC9D,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC5C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,QAAQ,CAAC,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC;IACxE,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACpE,OAAO,OAAO,QAAQ,GAAG,CAAC;AAC5B,CAAC","sourcesContent":["import { minimatch } from 'minimatch';\nimport { basename } from 'path';\nimport { AdapterDefinition } from './contract';\n\nconst cucumberJsAdapter: AdapterDefinition = {\n name: 'cucumber-js',\n configFilePattern: 'cucumber.{js,cjs,mjs,ts,mts,cts,json,yaml,yml}',\n technologies: ['@cucumber/cucumber'],\n targets: {\n e2e: {\n command: 'npx cucumber-js',\n dependsOn: ['^build'],\n },\n },\n};\n\n/**\n * Returns all built-in adapter definitions.\n */\nexport function getBuiltinAdapters(): AdapterDefinition[] {\n return [cucumberJsAdapter];\n}\n\n/**\n * Finds the adapter whose configFilePattern matches the given config file path.\n * Returns undefined if no adapter matches.\n */\nexport function findAdapterForConfigFile(\n configFile: string,\n adapters: AdapterDefinition[]\n): AdapterDefinition | undefined {\n const fileName = basename(configFile);\n return adapters.find((adapter) => minimatch(fileName, adapter.configFilePattern));\n}\n\n/**\n * Builds a combined glob pattern from all registered adapter config file patterns.\n * Used by createNodesV2 to discover adapter-managed projects in one pass.\n * Returns undefined if no adapters are registered.\n */\nexport function buildDiscoveryGlob(adapters: AdapterDefinition[]): string | undefined {\n if (adapters.length === 0) return undefined;\n if (adapters.length === 1) return `**/${adapters[0].configFilePattern}`;\n const patterns = adapters.map((a) => a.configFilePattern).join(',');\n return `**/{${patterns}}`;\n}\n"]}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Formatter } = require('@cucumber/cucumber');
|
|
4
|
+
|
|
5
|
+
class CucumberRunMetadataFormatter extends Formatter {
|
|
6
|
+
constructor(options) {
|
|
7
|
+
super(options);
|
|
8
|
+
const parsedArgvOptions = options.parsedArgvOptions || {};
|
|
9
|
+
const metadataOptions = readObject(parsedArgvOptions.nxCucumberRunMetadata);
|
|
10
|
+
this.worldParameters =
|
|
11
|
+
readWorldParameters(metadataOptions?.worldParameters) ?? readWorldParameters(parsedArgvOptions.worldParameters);
|
|
12
|
+
this.meta = undefined;
|
|
13
|
+
this.startedAt = undefined;
|
|
14
|
+
this.finishedAt = undefined;
|
|
15
|
+
this.emitted = false;
|
|
16
|
+
|
|
17
|
+
options.eventBroadcaster.on('envelope', (envelope) => {
|
|
18
|
+
if (envelope.meta && !this.meta) {
|
|
19
|
+
this.meta = envelope.meta;
|
|
20
|
+
}
|
|
21
|
+
if (envelope.testRunStarted && envelope.testRunStarted.timestamp) {
|
|
22
|
+
this.startedAt = timestampToIso(envelope.testRunStarted.timestamp);
|
|
23
|
+
}
|
|
24
|
+
if (envelope.testRunFinished) {
|
|
25
|
+
this.finishedAt = timestampToIso(envelope.testRunFinished.timestamp);
|
|
26
|
+
this.emitMetadata();
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async finished() {
|
|
32
|
+
this.emitMetadata();
|
|
33
|
+
await super.finished();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
emitMetadata() {
|
|
37
|
+
if (this.emitted) return;
|
|
38
|
+
this.log(
|
|
39
|
+
`${JSON.stringify(buildRunMetadata(this.meta, this.startedAt, this.finishedAt, this.worldParameters), null, 2)}\n`
|
|
40
|
+
);
|
|
41
|
+
this.emitted = true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function buildRunMetadata(meta, startedAt, finishedAt, worldParameters) {
|
|
46
|
+
const environment = resolveEnvironmentMetadata(worldParameters);
|
|
47
|
+
const metadata = {
|
|
48
|
+
schemaVersion: 1,
|
|
49
|
+
generatedAt: new Date().toISOString(),
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
if (meta) metadata.meta = meta;
|
|
53
|
+
if (startedAt || finishedAt) metadata.testRun = { startedAt, finishedAt };
|
|
54
|
+
if (worldParameters && Object.keys(worldParameters).length > 0) metadata.worldParameters = worldParameters;
|
|
55
|
+
if (environment && Object.keys(environment).length > 0) metadata.environment = environment;
|
|
56
|
+
return metadata;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function resolveEnvironmentMetadata(worldParameters) {
|
|
60
|
+
if (!worldParameters) return undefined;
|
|
61
|
+
const browser = stringValue(worldParameters.browser);
|
|
62
|
+
const baseUrl = stringValue(worldParameters.baseUrl);
|
|
63
|
+
const headed = worldParameters.headed;
|
|
64
|
+
const mode = typeof headed === 'boolean' ? (headed ? 'headed' : 'headless') : undefined;
|
|
65
|
+
const environment = {};
|
|
66
|
+
if (browser) environment.browser = browser;
|
|
67
|
+
if (baseUrl) environment.baseUrl = baseUrl;
|
|
68
|
+
if (mode) environment.mode = mode;
|
|
69
|
+
return Object.keys(environment).length > 0 ? environment : undefined;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function readWorldParameters(value) {
|
|
73
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined;
|
|
74
|
+
return value;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function readObject(value) {
|
|
78
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined;
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function stringValue(value) {
|
|
83
|
+
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function timestampToIso(timestamp) {
|
|
87
|
+
if (!timestamp) return undefined;
|
|
88
|
+
const seconds = numberValue(timestamp.seconds);
|
|
89
|
+
if (seconds === undefined) return undefined;
|
|
90
|
+
const nanos = numberValue(timestamp.nanos) || 0;
|
|
91
|
+
return new Date(seconds * 1000 + nanos / 1000000).toISOString();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function numberValue(value) {
|
|
95
|
+
if (typeof value === 'number') return Number.isFinite(value) ? value : undefined;
|
|
96
|
+
if (typeof value === 'bigint') return Number(value);
|
|
97
|
+
if (typeof value === 'string') {
|
|
98
|
+
const parsed = Number(value);
|
|
99
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
100
|
+
}
|
|
101
|
+
if (!value || typeof value !== 'object') return undefined;
|
|
102
|
+
if (typeof value.toNumber === 'function') {
|
|
103
|
+
const result = value.toNumber();
|
|
104
|
+
return Number.isFinite(result) ? result : undefined;
|
|
105
|
+
}
|
|
106
|
+
if (typeof value.low === 'number') return Number.isFinite(value.low) ? value.low : undefined;
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
module.exports = CucumberRunMetadataFormatter;
|
|
111
|
+
module.exports.buildRunMetadata = buildRunMetadata;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<% if (isTypeScript) { %>import type { IConfiguration } from '@cucumber/cucumber';
|
|
2
|
+
import { pathToFileURL } from 'url';
|
|
3
|
+
<% } else { %>const { pathToFileURL } = require('url');
|
|
4
|
+
<% } %>const outputDir = 'dist/e2e/<%= projectRoot %>';
|
|
5
|
+
const runMetadataFormatter = pathToFileURL(
|
|
6
|
+
require.resolve('@gnuechtel/nx-cucumber/src/core/cucumber-run-metadata-formatter.js')
|
|
7
|
+
).href;
|
|
8
|
+
const worldParameters = {
|
|
9
|
+
outputDirectory: outputDir,<% if (isPlaywright) { %>
|
|
10
|
+
baseUrl: '<%= baseUrl %>',
|
|
11
|
+
disableVideoFiles: true,
|
|
12
|
+
disableVideoAttachments: true,<% } %>
|
|
13
|
+
};
|
|
14
|
+
<% if (isTypeScript) { %>
|
|
15
|
+
const config: { [profile: string]: Partial<IConfiguration> } = {
|
|
16
|
+
default: {
|
|
17
|
+
paths: ['<%= projectRoot %>/features/**/*.feature'],
|
|
18
|
+
requireModule: ['ts-node/register', 'tsconfig-paths/register'],
|
|
19
|
+
require: [
|
|
20
|
+
'<%= projectRoot %>/src/**/!(*.d|*.spec|*.test).ts',<% if (playwrightRequires !== '[]') { %>
|
|
21
|
+
...<%- playwrightRequires %>,<% } %>
|
|
22
|
+
],
|
|
23
|
+
tags: 'not @ignore',
|
|
24
|
+
format: [
|
|
25
|
+
'summary',
|
|
26
|
+
'progress-bar',
|
|
27
|
+
`json:${outputDir}/reports/cucumber-json/cucumber-test-report.json`,
|
|
28
|
+
`message:${outputDir}/reports/cucumber-messages/cucumber-messages.ndjson`,
|
|
29
|
+
`html:${outputDir}/reports/html/cucumber-test-report-builtin.html`,
|
|
30
|
+
[runMetadataFormatter, `${outputDir}/reports/metadata/cucumber-run-metadata.json`],
|
|
31
|
+
`junit:${outputDir}/reports/test-results/cucumber-test-report.xml`,
|
|
32
|
+
],
|
|
33
|
+
formatOptions: {
|
|
34
|
+
nxCucumberRunMetadata: {
|
|
35
|
+
worldParameters,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
worldParameters,
|
|
39
|
+
publishQuiet: true,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export default config;
|
|
44
|
+
<% } else { %>
|
|
45
|
+
module.exports = {
|
|
46
|
+
default: {
|
|
47
|
+
paths: ['<%= projectRoot %>/features/**/*.feature'],
|
|
48
|
+
requireModule: ['ts-node/register', 'tsconfig-paths/register'],
|
|
49
|
+
require: [
|
|
50
|
+
'<%= projectRoot %>/src/**/!(*.d|*.spec|*.test).ts',<% if (playwrightRequires !== '[]') { %>
|
|
51
|
+
...<%- playwrightRequires %>,<% } %>
|
|
52
|
+
],
|
|
53
|
+
tags: 'not @ignore',
|
|
54
|
+
format: [
|
|
55
|
+
'summary',
|
|
56
|
+
'progress-bar',
|
|
57
|
+
`json:${outputDir}/reports/cucumber-json/cucumber-test-report.json`,
|
|
58
|
+
`message:${outputDir}/reports/cucumber-messages/cucumber-messages.ndjson`,
|
|
59
|
+
`html:${outputDir}/reports/html/cucumber-test-report-builtin.html`,
|
|
60
|
+
[runMetadataFormatter, `${outputDir}/reports/metadata/cucumber-run-metadata.json`],
|
|
61
|
+
`junit:${outputDir}/reports/test-results/cucumber-test-report.xml`,
|
|
62
|
+
],
|
|
63
|
+
formatOptions: {
|
|
64
|
+
nxCucumberRunMetadata: {
|
|
65
|
+
worldParameters,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
worldParameters,
|
|
69
|
+
publishQuiet: true,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
<% } %>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<% if (isTypeScript) { %>import type { IConfiguration } from '@cucumber/cucumber';
|
|
2
|
+
<% } %>import { pathToFileURL } from 'url';
|
|
3
|
+
import { createRequire } from 'module';
|
|
4
|
+
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
const outputDir = 'dist/e2e/<%= projectRoot %>';
|
|
7
|
+
const runMetadataFormatter = pathToFileURL(
|
|
8
|
+
require.resolve('@gnuechtel/nx-cucumber/src/core/cucumber-run-metadata-formatter.js')
|
|
9
|
+
).href;
|
|
10
|
+
const worldParameters = {
|
|
11
|
+
outputDirectory: outputDir,<% if (isPlaywright) { %>
|
|
12
|
+
baseUrl: '<%= baseUrl %>',
|
|
13
|
+
disableVideoFiles: true,
|
|
14
|
+
disableVideoAttachments: true,<% } %>
|
|
15
|
+
};
|
|
16
|
+
<% if (isTypeScript) { %>
|
|
17
|
+
const config: { [profile: string]: Partial<IConfiguration> } = {
|
|
18
|
+
<% } else { %>
|
|
19
|
+
const config = {
|
|
20
|
+
<% } %> default: {
|
|
21
|
+
paths: ['<%= projectRoot %>/features/**/*.feature'],
|
|
22
|
+
requireModule: ['ts-node/register', 'tsconfig-paths/register'],
|
|
23
|
+
require: [
|
|
24
|
+
'<%= projectRoot %>/src/**/!(*.d|*.spec|*.test).ts',<% if (playwrightRequires !== '[]') { %>
|
|
25
|
+
...<%- playwrightRequires %>,<% } %>
|
|
26
|
+
],
|
|
27
|
+
tags: 'not @ignore',
|
|
28
|
+
format: [
|
|
29
|
+
'summary',
|
|
30
|
+
'progress-bar',
|
|
31
|
+
`json:${outputDir}/reports/cucumber-json/cucumber-test-report.json`,
|
|
32
|
+
`message:${outputDir}/reports/cucumber-messages/cucumber-messages.ndjson`,
|
|
33
|
+
`html:${outputDir}/reports/html/cucumber-test-report-builtin.html`,
|
|
34
|
+
[runMetadataFormatter, `${outputDir}/reports/metadata/cucumber-run-metadata.json`],
|
|
35
|
+
`junit:${outputDir}/reports/test-results/cucumber-test-report.xml`,
|
|
36
|
+
],
|
|
37
|
+
formatOptions: {
|
|
38
|
+
nxCucumberRunMetadata: {
|
|
39
|
+
worldParameters,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
worldParameters,
|
|
43
|
+
publishQuiet: true,
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export default config;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"default": {
|
|
3
|
+
"paths": ["<%= projectRoot %>/features/**/*.feature"],
|
|
4
|
+
"requireModule": ["ts-node/register", "tsconfig-paths/register"],
|
|
5
|
+
"require": [
|
|
6
|
+
"<%= projectRoot %>/src/**/!(*.d|*.spec|*.test).ts"<% for (const req of playwrightRequiresArray) { %>,
|
|
7
|
+
"<%= req %>"<% } %>
|
|
8
|
+
],
|
|
9
|
+
"tags": "not @ignore",
|
|
10
|
+
"format": [
|
|
11
|
+
"summary",
|
|
12
|
+
"progress-bar",
|
|
13
|
+
"json:dist/e2e/<%= projectRoot %>/reports/cucumber-json/cucumber-test-report.json",
|
|
14
|
+
"message:dist/e2e/<%= projectRoot %>/reports/cucumber-messages/cucumber-messages.ndjson",
|
|
15
|
+
"html:dist/e2e/<%= projectRoot %>/reports/html/cucumber-test-report-builtin.html",
|
|
16
|
+
["@gnuechtel/nx-cucumber/src/core/cucumber-run-metadata-formatter.js", "dist/e2e/<%= projectRoot %>/reports/metadata/cucumber-run-metadata.json"],
|
|
17
|
+
"junit:dist/e2e/<%= projectRoot %>/reports/test-results/cucumber-test-report.xml"
|
|
18
|
+
],
|
|
19
|
+
"formatOptions": {
|
|
20
|
+
"nxCucumberRunMetadata": {
|
|
21
|
+
"worldParameters": {
|
|
22
|
+
"outputDirectory": "dist/e2e/<%= projectRoot %>"<% if (isPlaywright) { %>,
|
|
23
|
+
"baseUrl": "<%= baseUrl %>",
|
|
24
|
+
"disableVideoFiles": true,
|
|
25
|
+
"disableVideoAttachments": true<% } %>
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"worldParameters": {
|
|
30
|
+
"outputDirectory": "dist/e2e/<%= projectRoot %>"<% if (isPlaywright) { %>,
|
|
31
|
+
"baseUrl": "<%= baseUrl %>",
|
|
32
|
+
"disableVideoFiles": true,
|
|
33
|
+
"disableVideoAttachments": true<% } %>
|
|
34
|
+
},
|
|
35
|
+
"publishQuiet": true
|
|
36
|
+
}
|
|
37
|
+
}
|