@gnuechtel/nx-cucumber 24.1.0 → 24.2.0

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 CHANGED
@@ -7,8 +7,8 @@ Plugin to use Cucumber within Nx workspaces
7
7
  - [Introduction](#introduction)
8
8
  - [Release 24.1.0 and versioning](#release-2410-and-versioning)
9
9
  - [Playwright-BDD and UI Mode](#playwright-bdd-and-ui-mode)
10
+ - [API-only Playwright-BDD tests](#api-only-playwright-bdd-tests)
10
11
  - [Dependency security notice](#dependency-security-notice)
11
- - [What changed in 2.x](#what-changed-in-2x)
12
12
  - [Prerequisites](#prerequisites)
13
13
  - [Quick start](#quick-start)
14
14
  - [Install Nx](#install-nx)
@@ -36,7 +36,6 @@ Plugin to use Cucumber within Nx workspaces
36
36
  - [Code coverage](#code-coverage)
37
37
  - [Example projects](#example-projects)
38
38
  - [Main examples](#main-examples)
39
- - [More examples](#more-examples)
40
39
  - [End-to-end tests of this project](#end-to-end-tests-of-this-project)
41
40
  - [Continuous delivery pipeline](#continuous-delivery-pipeline)
42
41
  - [Debugging and watching scenarios](#debugging-and-watching-scenarios)
@@ -68,7 +67,7 @@ own changes. For example, a plugin-only fix can be released as 23.0.1 while the
68
67
  supported Nx baseline stays the same. The exact compatibility ranges are defined
69
68
  in the package's dependencies and peer dependencies.
70
69
 
71
- This release updates the existing integration for Nx 24, Cucumber 13 and Playwright 1.64. It uses the canonical `createNodes` entrypoint, generates flat ESLint configuration, and updates dependency versions. Existing worlds, hooks and test metadata remain part of the integration. See the [24.1.0 release notes](../../docs/release-24.1.md), including the reviewed upstream security exception, before upgrading.
70
+ The Cucumber integration targets Nx 24, Cucumber 13 and Playwright 1.64+. Existing worlds, hooks and test metadata remain supported. Version 24.1.0 also adds Playwright-BDD generation and conversion through the normal Nx Playwright plugin. See the [24.1.0 release notes](../../docs/release-notes/24.1.0.md), including the reviewed upstream security exception, before upgrading.
72
71
 
73
72
  ## Playwright-BDD and UI Mode
74
73
 
@@ -103,6 +102,16 @@ Playwright Test installed. The converter deliberately leaves original projects
103
102
  and dependency cleanup to us. Follow the
104
103
  [cleanup and uninstall steps](https://gitlab.com/gnuechtel/open-source/-/blob/main/docs/playwright-bdd-migration.md#remove-nx-cucumber-after-migration).
105
104
 
105
+ ## API-only Playwright-BDD tests
106
+
107
+ Version 24.2.0 adds API-only generation with Playwright's native request fixtures
108
+ and requires no browser installation. See the
109
+ [API guide](../../docs/playwright-bdd-api.md) for generation, backend startup,
110
+ authentication, reports and execution without our runtime packages.
111
+ Our [local API example](../../apps/example/api-app-bdd-e2e/README.md) demonstrates
112
+ health checks, authenticated requests and rejection without a token.
113
+ The [24.2.0 release notes](../../docs/release-notes/24.2.0.md) summarize the changes.
114
+
106
115
  ## Dependency security notice
107
116
 
108
117
  **Known upstream dependency risk: accepted release exception.** As checked on October
@@ -135,20 +144,6 @@ findings and scan errors still block release. The dependency itself remains
135
144
  affected until a repaired Nx patch is adopted. See
136
145
  [the security explanation and verification](../../docs/dependency-security-fix.md).
137
146
 
138
- ## What changed in 2.x
139
-
140
- Version 2.x is a deliberate breaking release that simplifies the plugin architecture:
141
-
142
- - **Inferred tasks replace explicit executors.** The `@gnuechtel/nx-cucumber:cucumber-api` executor has been removed. Projects are discovered via `cucumber.js` config files and targets are inferred automatically using [Nx Project Crystal](https://nx.dev/concepts/inferred-tasks).
143
- - **Framework-native execution.** Tests run via `npx cucumber-js` directly instead of an in-process Cucumber API. This unlocks full Cucumber CLI capabilities without plugin-specific wrappers.
144
- - **Less configuration.** Generated projects include a `cucumber.js` config file and a minimal `project.json`. All Cucumber and Playwright options are configured through standard Cucumber and Playwright mechanisms.
145
- - **Nx 22.** The 2.x line targets Nx `>=22 <23`.
146
- - **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.
147
- - **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.
148
- - **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.
149
- - **Legacy HTML post-processing removed.** The previously exported `createBeautifulHtmlReport` helper and `cucumber-html-reporter` integration are no longer part of 2.x.
150
- - **All cucumber-js config formats.** Plugin discovery, generation, and migration support every cucumber-js configuration file format (`cucumber.js`, `.cjs`, `.mjs`, `.ts`, `.mts`, `.cts`, `.json`, `.yaml`, `.yml`). See [Config file formats](#config-file-formats).
151
-
152
147
  ## Prerequisites
153
148
 
154
149
  This plugin requires [Node.js](https://nodejs.org/), [Nx](https://nx.dev/) and [Cucumber](https://github.com/cucumber/cucumber-js). Version 24.1.0 targets Nx `>=24 <25` and Node.js 24; published 2.x packages remain the Nx-22 path. Plugin 23.x remains available for Nx 23. Browser automation uses the [Playwright library](https://playwright.dev/docs/library) when selected by the generator. Consult `package.json` for all dependency requirements and `.gitlab-ci.yml` for the pinned CI versions. Minor and patch versions follow this plugin's changes independently of Nx.
@@ -192,9 +187,6 @@ There are two feasible options to [install Nx](https://nx.dev/getting-started/in
192
187
  - either via `npx create-nx-workspace@24.0.1` to setup a fresh Nx repo or
193
188
  - via `npx nx@24.0.1 init` to convert an existing Node.js project into an Nx workspace.
194
189
 
195
- It is never recommended to install all those Nx [dependencies](https://www.npmjs.com/org/nx) manually.
196
- It would just cause too much unnecessary work.
197
-
198
190
  Before installing this plugin, verify the installed Nx version with `npx nx --version`: it must be `>=24 <25`. The workspace CLI can download a template with a newer Nx version independently of its own version. In that case, start from a template pinned to Nx 24 or use an existing Nx-24 workspace; do not bypass the peer requirements.
199
191
 
200
192
  ## Install dependencies
@@ -272,7 +264,7 @@ All possible project generator options may be passed as command-line parameters
272
264
 
273
265
  ### Inferred tasks
274
266
 
275
- In 2.x, no executor configuration is needed. For core projects, the `e2e` target is inferred automatically when the plugin detects a `cucumber.js` config file in a project directory:
267
+ For core projects, the `e2e` target is inferred automatically when the plugin detects a supported cucumber-js config file in a project directory:
276
268
 
277
269
  ```bash
278
270
  npx nx e2e my-project-e2e
@@ -315,7 +307,7 @@ The generator scaffolds a cucumber-js configuration file for each project. It is
315
307
 
316
308
  #### Default configuration
317
309
 
318
- By default the generator creates a `cucumber.js`. Because the code formats are evaluated when loaded, options can be computed at runtime — for example, deriving the tag filter from an environment variable:
310
+ By default the generator creates a `cucumber.js`. Because the code formats are evaluated when loaded, options can be computed at runtime - for example, deriving the tag filter from an environment variable:
319
311
 
320
312
  ```javascript
321
313
  const tagsFilter = process.env['CI_STAGE'] !== 'qa' ? 'and not @qa-stage-only' : 'and (@qa-stage or @qa-stage-only)';
@@ -345,54 +337,8 @@ Nx-cucumber supports every cucumber-js configuration file format for inferred-ta
345
337
 
346
338
  The **code formats** (`js`, `cjs`, `mjs`, `ts`, `mts`, `cts`) are evaluated as modules, so they can contain logic like the default configuration above. The **data formats** (`json`, `yaml`, `yml`) are static and hold plain values only.
347
339
 
348
- The same configuration expressed in the remaining formats:
349
-
350
- **ES module** — `cucumber.mjs`
351
-
352
- ```javascript
353
- const tagsFilter = process.env['CI_STAGE'] !== 'qa' ? 'and not @qa-stage-only' : 'and (@qa-stage or @qa-stage-only)';
354
-
355
- export default {
356
- default: {
357
- tags: `not @ignore ${tagsFilter}`,
358
- },
359
- };
360
- ```
361
-
362
- **TypeScript** — `cucumber.ts`, `cucumber.mts`, `cucumber.cts`
363
-
364
- ```typescript
365
- import type { IConfiguration } from '@cucumber/cucumber';
366
-
367
- const tagsFilter = process.env['CI_STAGE'] !== 'qa' ? 'and not @qa-stage-only' : 'and (@qa-stage or @qa-stage-only)';
368
-
369
- const config: { default: Partial<IConfiguration> } = {
370
- default: {
371
- tags: `not @ignore ${tagsFilter}`,
372
- },
373
- };
374
-
375
- export default config;
376
- ```
377
-
378
- **JSON** — `cucumber.json`
379
-
380
- JSON is static and cannot run the environment check above, so the tags are set directly:
381
-
382
- ```json
383
- {
384
- "default": {
385
- "tags": "not @ignore"
386
- }
387
- }
388
- ```
389
-
390
- **YAML** — `cucumber.yaml`, `cucumber.yml`
391
-
392
- ```yaml
393
- default:
394
- tags: 'not @ignore'
395
- ```
340
+ ES modules use `export default`; CommonJS uses `module.exports`. JSON and YAML
341
+ contain the same profile/options structure without executable expressions.
396
342
 
397
343
  ### World parameters
398
344
 
@@ -434,7 +380,7 @@ module.exports = {
434
380
 
435
381
  ### Change screenshot options
436
382
 
437
- By default, screenshots are attached to every Playwright scenario. Screenshot _files_ are created only on error. To change this:
383
+ By default, screenshots are attached after each Playwright step. Screenshot _files_ are created for unsuccessful steps. To change this:
438
384
 
439
385
  ```javascript
440
386
  module.exports = {
@@ -543,13 +489,10 @@ This repository contains [example projects](https://gitlab.com/gnuechtel/open-so
543
489
  | **Execute cucumber project** | `npx nx e2e example-react-app-e2e` | `npx nx e2e example-node-app-e2e` |
544
490
  | **Source cucumber project** | [apps/example/react-app-e2e](https://gitlab.com/gnuechtel/open-source/-/tree/main/apps/example/react-app-e2e) | [apps/example/node-app-e2e](https://gitlab.com/gnuechtel/open-source/-/tree/main/apps/example/node-app-e2e) |
545
491
 
546
- ### More examples
547
-
548
- If we have executed our nx-cucumber [end-to-end tests](#end-to-end-tests-of-this-project), we got a lot of more example projects and their Cucumber output for free.
549
-
550
492
  ## End-to-end tests of this project
551
493
 
552
- 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)!
494
+ The [Cucumber scenarios](https://gitlab.com/gnuechtel/open-source/-/blob/main/apps/nx-cucumber-e2e/features/nx-cucumber.feature)
495
+ exercise generation, migration and installed-package behavior.
553
496
 
554
497
  Generation coverage includes validation for unknown `--project` ids and execution against real Nx project ids detected in the test workspace.
555
498
 
@@ -578,9 +521,9 @@ are retained under `dist/e2e/apps/nx-cucumber-e2e/playwright-bdd`.
578
521
 
579
522
  ## Continuous delivery pipeline
580
523
 
581
- Our [continuous delivery pipeline](https://gitlab.com/gnuechtel/open-source/-/pipelines/latest) runs builds and tests for Linux, macOS and Windows on the latest Node.js [LTS](https://en.wikipedia.org/wiki/Long-term_support) version.
524
+ Our [continuous delivery pipeline](https://gitlab.com/gnuechtel/open-source/-/pipelines/latest) runs builds and tests for Linux, macOS and Windows on Node.js 24.
582
525
 
583
- The end-to-end tests use pinned versions in [`.gitlab-ci.yml`](../../.gitlab-ci.yml), including a Cucumber compatibility matrix and a separate migration matrix for historical 1.x releases. These are recorded checks for the existing implementation, not a commitment to validate future upstream releases.
526
+ The end-to-end tests use the pinned Nx/framework versions in [`.gitlab-ci.yml`](../../.gitlab-ci.yml). Current CI jobs exclude the historical `@migration` scenario. These checks validate the existing implementation; they do not establish compatibility with future upstream releases.
584
527
 
585
528
  Linux runs the full test suite. macOS and Windows run `@core` tagged scenarios for faster feedback.
586
529
 
@@ -592,9 +535,9 @@ Watching means, that scenarios will be executed automatically after file changes
592
535
 
593
536
  ### Debugging
594
537
 
595
- Debugging is available for the Playwright test runner only.
596
- It enables the Playwright inspector with paused execution in a headed browser.
597
- Set the `PWDEBUG` environment variable:
538
+ For cucumber-js browser projects, set `PWDEBUG` to pause execution in the
539
+ Playwright inspector with a headed browser. Playwright-BDD projects provide
540
+ [native UI/debug targets](../../docs/playwright-bdd-migration.md#ui-mode-regeneration-and-debugging).
598
541
 
599
542
  ```bash
600
543
  PWDEBUG=1 npx nx e2e my-project-e2e
@@ -723,7 +666,7 @@ The correct usage is: `npx nx e2e example-react-app-e2e -- --tags "@mytag"`.
723
666
 
724
667
  ### Some Cucumber product feature does not work with nx-cucumber
725
668
 
726
- Since 2.x uses framework-native execution via `npx cucumber-js`, all Cucumber CLI features are available directly. Configure them in the `cucumber.js` file.
669
+ Cucumber tasks run the native `cucumber-js` CLI. Configure Cucumber options and formatters in the project's Cucumber configuration.
727
670
 
728
671
  If a feature is missing, please open an issue with a minimal reproducible setup.
729
672
 
@@ -802,23 +745,17 @@ If it reports changes are required, run `npx nx sync` and commit the resulting f
802
745
 
803
746
  ### `TS_NODE_PROJECT` and formatter file extensions
804
747
 
805
- 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.
748
+ Inferred Cucumber tasks set `TS_NODE_PROJECT` to the project's `tsconfig.json`.
749
+ For generated Cucumber/Playwright projects, `run-e2e.js` sets it for the Cucumber
750
+ child process. New config templates do not set it as a module side effect.
751
+ When invoking `cucumber-js` directly, supply the same environment variable so
752
+ `ts-node/register` resolves the project's TypeScript configuration.
806
753
 
807
754
  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.
808
755
 
809
- ### Windows Playwright teardown noise
810
-
811
- On Windows, after all scenarios finish, the following message may appear in the output:
812
-
813
- ```
814
- ERROR: The process "XXXX" not found.
815
- ```
816
-
817
- 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.
818
-
819
756
  ## Migration from 1.x
820
757
 
821
- The following is the historical migration to **2.x on Nx 22**. Use that intermediate release before assessing the separate [Nx-23 upgrade](../../docs/release-23.md). The historical multi-version migration matrix is not part of the 23.0.0 validation.
758
+ The following is the historical migration to **2.x on Nx 22**. Use that intermediate release before assessing the separate [Nx 23 upgrade](../../docs/release-notes/23.0.0.md). The historical migration scenario is separate from current compatibility validation.
822
759
 
823
760
  ### Prerequisites
824
761
 
@@ -873,14 +810,12 @@ Dry-run mode:
873
810
 
874
811
  - Set `NX_CUCUMBER_MIGRATION_DRY_RUN=true` before running migrations to print planned changes without modifying files.
875
812
 
876
- ### CI migration tests
877
-
878
- The repository includes an automated migration matrix test (`@migration` scenarios) for all stable 1.x versions (`1.0.0` to `1.4.1`).
879
-
880
- - For `1.0.0 - 1.0.2`, the test uses a compatible Nx 17 workspace first, removes the legacy plugin package, upgrades Nx to 22, then runs the 2.x migration.
881
- - For `1.1.0+`, the test runs directly on Nx 22.
813
+ ### Historical migration tests
882
814
 
883
- `npm install` failures from legacy generator internals are not treated as acceptable in these migration tests.
815
+ The repository retains an `@migration` scenario for a configured legacy version,
816
+ but current CI jobs exclude it. It is not an active all-1.x compatibility matrix.
817
+ The migration helper handles the Nx 17 to 22 upgrade path for `1.0.0` through `1.0.2`;
818
+ `1.1.0+` can start on Nx 22.
884
819
 
885
820
  ### Step 1: Register the plugin
886
821
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gnuechtel/nx-cucumber",
3
- "version": "24.1.0",
3
+ "version": "24.2.0",
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": ">=24 <25",
13
13
  "minimatch": "^10.0.0",
14
14
  "tslib": "^2.8.1",
15
- "@gnuechtel/shared-coverage": "24.1.0",
16
- "@gnuechtel/shared-util": "24.1.0"
15
+ "@gnuechtel/shared-coverage": "24.2.0",
16
+ "@gnuechtel/shared-util": "24.2.0"
17
17
  },
18
18
  "peerDependencies": {
19
19
  "@cucumber/cucumber": ">=13 <14",
@@ -6,10 +6,12 @@ the normal `@nx/playwright` plugin executes them. No nx-cucumber runtime is used
6
6
  Run these commands from the Nx workspace root:
7
7
 
8
8
  ```sh
9
- npx playwright install chromium
9
+ <% if (!isApi) { %>npx playwright install chromium
10
+ <% } %>
10
11
  npx nx run "<%= name %>:<%= e2eTarget %>"
11
12
  npx nx run "<%= name %>:<%= ciTarget %>"
12
- npx nx run "<%= name %>:<%= e2eTarget %>-headed"
13
+ <% if (!isApi) { %>npx nx run "<%= name %>:<%= e2eTarget %>-headed"
14
+ <% } %>
13
15
  npx nx run "<%= name %>:<%= e2eTarget %>-ui"
14
16
  npx nx run "<%= name %>:<%= e2eTarget %>-debug"
15
17
  ```
@@ -30,6 +32,40 @@ npx bddgen --config <%= projectRoot %>/playwright.config.mts
30
32
  npx playwright test --config <%= projectRoot %>/playwright.config.mts
31
33
  ```
32
34
 
35
+ <% if (isApi) { %>
36
+ This API-only project uses Playwright's native `request` fixture and needs no
37
+ browser installation. The example expects `GET /health` to return HTTP 200 and
38
+ JSON containing `{ "status": "ok" }`. Adapt the endpoint and assertions to our
39
+ backend contract; the generator does not change the backend.
40
+
41
+ `API_BASE_URL` overrides the default in `playwright.config.mts`. An optional
42
+ `API_TOKEN` sets the `Authorization: Bearer ...` header on requests. Supply values
43
+ through our shell or CI secret store; no `.env` loader is installed. Never commit
44
+ credentials. Change `extraHTTPHeaders` for a different authentication scheme.
45
+
46
+ ```sh
47
+ API_BASE_URL=http://localhost:3000 npx nx run "<%= name %>:<%= ciTarget %>" --skip-nx-cache
48
+ ```
49
+
50
+ <% if (apiServeCommandJson) { %>
51
+ Playwright starts the configured Nx target and waits for the base URL. Keep that
52
+ URL consistent with the target's host/port; no frontend port flags are added.
53
+ Existing servers are reused locally, while CI starts its own server. Readiness
54
+ uses Playwright's HTTP URL check; configure a public health URL if the root needs
55
+ authentication. Playwright owns server shutdown.
56
+ <% } else { %>
57
+ No server is started. Start our backend separately or point `API_BASE_URL` at an
58
+ already reachable API. The implicit project dependency does not start a server.
59
+ <% } %>
60
+
61
+ API execution targets are uncached because server data can change independently
62
+ of source files. BDD generation remains cached. HTML and JUnit reports go below
63
+ `dist/e2e/<%= projectRoot %>`. Traces are disabled by default because they can
64
+ capture request/response data and authentication. No screenshot/video hooks or
65
+ BrowserWorld are generated. UI Mode is optional and requires a desktop; normal
66
+ and CI execution need no browsers. This is new-project generation, not API-test
67
+ conversion. Features, configuration and steps belong to this project.
68
+ <% } else { %>
33
69
  Features and steps belong to this project. `src/fixtures.ts` supplies a local
34
70
  world so Cucumber-style `function (this: BrowserWorld)` definitions can remain.
35
71
  Extend the local fixtures for application behavior. Cucumber hook argument
@@ -46,6 +82,7 @@ The original project is preserved. Missing steps must be implemented before
46
82
  claiming the migration is complete. Review tags, timeouts, world parameters,
47
83
  coverage and custom metadata; these are not automatically reproduced.
48
84
 
85
+ <% } %>
49
86
  After switching CI and retiring old Cucumber projects, nx-cucumber can be
50
87
  uninstalled if no other project needs it. Remove its unused `nx.json` plugin
51
88
  registration first, preserve `@nx/playwright/plugin`, and verify a fresh run with
@@ -1,4 +1,4 @@
1
- import { defineConfig, devices } from '@playwright/test';
1
+ import { defineConfig<% if (!isApi) { %>, devices<% } %> } from '@playwright/test';
2
2
  import { defineBddConfig } from 'playwright-bdd';
3
3
  import { nxE2EPreset } from '@nx/playwright/preset';
4
4
  import { join } from 'node:path';
@@ -25,22 +25,35 @@ export default defineConfig({
25
25
  ['junit', { outputFile: join(reports, 'reports/test-results/junit.xml') }],
26
26
  ],
27
27
  use: {
28
+ <% if (isApi) { %>
29
+ baseURL: process.env['API_BASE_URL'] || <%- baseUrlJson %>,
30
+ extraHTTPHeaders: process.env['API_TOKEN']
31
+ ? { Authorization: `Bearer ${process.env['API_TOKEN']}` }
32
+ : {},
33
+ // Request/response data and credentials can be captured in traces. Enable explicitly if needed.
34
+ trace: 'off',
35
+ <% } else { %>
28
36
  baseURL: 'http://localhost:4200',
29
37
  // The local AfterStep hook attaches screenshots with the world's mask options.
30
38
  // Avoid an additional, automatically captured screenshot without those masks.
31
39
  screenshot: 'off',
32
40
  video: 'retain-on-failure',
33
41
  trace: 'retain-on-failure',
42
+ <% } %>
34
43
  },
44
+ <% if (!isApi || apiServeCommandJson) { %>
35
45
  webServer: {
36
- command: <%- serveCommandJson %>,
46
+ command: <%- isApi ? apiServeCommandJson : serveCommandJson %>,
37
47
  cwd: workspaceRoot,
38
48
  // Prevent inherited cucumber-js ts-node settings from configuring the app server.
39
49
  env: { TS_NODE_PROJECT: '' },
40
- url: 'http://localhost:4200',
50
+ url: <% if (isApi) { %>process.env['API_BASE_URL'] || <%- baseUrlJson %><% } else { %>'http://localhost:4200'<% } %>,
41
51
  reuseExistingServer: !process.env['CI'],
42
52
  timeout: 60_000,
43
53
  gracefulShutdown: { signal: 'SIGTERM', timeout: 5_000 },
44
54
  },
55
+ <% } %>
56
+ <% if (!isApi) { %>
45
57
  projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }],
58
+ <% } %>
46
59
  });
@@ -0,0 +1,4 @@
1
+ Feature: API health
2
+
3
+ Scenario: The backend is healthy
4
+ Then GET "/health" returns a healthy response
@@ -0,0 +1,3 @@
1
+ import { createBdd } from 'playwright-bdd';
2
+
3
+ export const { Given, When, Then } = createBdd();
@@ -0,0 +1,8 @@
1
+ import { expect } from '@playwright/test';
2
+ import { Then } from '../fixtures';
3
+
4
+ Then('GET {string} returns a healthy response', async ({ request }, endpoint: string) => {
5
+ const response = await request.get(endpoint);
6
+ expect(response.status()).toBe(200);
7
+ expect(await response.json()).toMatchObject({ status: 'ok' });
8
+ });
@@ -7,6 +7,28 @@ const path = tslib_1.__importStar(require("node:path"));
7
7
  const names_1 = require("./names");
8
8
  async function playwrightBddProjectGenerator(tree, options) {
9
9
  (0, devkit_1.readProjectConfiguration)(tree, options.project);
10
+ const isApi = options.testType === 'api';
11
+ if (!isApi && (options.baseUrl !== undefined || options.webServerTarget !== undefined)) {
12
+ throw new Error('baseUrl and webServerTarget require --test-type=api.');
13
+ }
14
+ const baseUrl = options.baseUrl ?? 'http://localhost:3000';
15
+ if (isApi) {
16
+ const url = new URL(baseUrl);
17
+ if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password) {
18
+ throw new Error('baseUrl must be an HTTP(S) URL without credentials. Use API_TOKEN for authentication.');
19
+ }
20
+ }
21
+ let serverProject;
22
+ if (options.webServerTarget !== undefined) {
23
+ const [project, target, configuration, ...rest] = options.webServerTarget.split(':');
24
+ if (!project || !target || configuration === '' || rest.length || !/^[\w@./:-]+$/.test(options.webServerTarget)) {
25
+ throw new Error('webServerTarget must be project:target[:configuration].');
26
+ }
27
+ // Devkit's Tree configuration omits plugin-inferred targets. Let Nx resolve the
28
+ // target/configuration at execution time, so inferred backend targets work too.
29
+ (0, devkit_1.readProjectConfiguration)(tree, project);
30
+ serverProject = project;
31
+ }
10
32
  const name = (0, names_1.normalizeGeneratedProjectName)(options.project, options.name);
11
33
  const layout = (0, devkit_1.getWorkspaceLayout)(tree);
12
34
  const directory = (0, devkit_1.normalizePath)(options.directory || (0, names_1.defaultProjectDirectory)(name));
@@ -40,6 +62,7 @@ async function playwrightBddProjectGenerator(tree, options) {
40
62
  { externalDependencies: ['@playwright/test', 'playwright-bdd', '@nx/playwright'] },
41
63
  { env: 'CI' },
42
64
  ];
65
+ const testInputs = isApi ? [...inputs, { env: 'API_BASE_URL' }, { env: 'API_TOKEN' }] : inputs;
43
66
  const config = `${root}/playwright.config.mts`;
44
67
  const bddgen = `npx bddgen --config ${config}`;
45
68
  const run = `npx playwright test --config ${config}`;
@@ -48,7 +71,7 @@ async function playwrightBddProjectGenerator(tree, options) {
48
71
  root,
49
72
  sourceRoot: `${root}/src`,
50
73
  projectType: 'application',
51
- implicitDependencies: [options.project],
74
+ implicitDependencies: [...new Set([options.project, ...(serverProject ? [serverProject] : [])])],
52
75
  targets: {
53
76
  bddgen: {
54
77
  command: bddgen,
@@ -57,10 +80,10 @@ async function playwrightBddProjectGenerator(tree, options) {
57
80
  outputs: [`{projectRoot}/.features-gen`],
58
81
  },
59
82
  // @nx/playwright/plugin infers the actual e2e task from the generated config.
60
- [e2eTarget]: { dependsOn: ['bddgen'], inputs, outputs: [output] },
83
+ [e2eTarget]: { dependsOn: ['bddgen'], inputs: testInputs, outputs: [output], ...(isApi ? { cache: false } : {}) },
61
84
  // A native command replaces an inferred atomized aggregator, including its Cloud-only metadata.
62
85
  // Generated specs do not exist when Nx first discovers individual test files.
63
- [ciTarget]: { command: run, dependsOn: ['bddgen'], cache: true, inputs, outputs: [output] },
86
+ [ciTarget]: { command: run, dependsOn: ['bddgen'], cache: !isApi, inputs: testInputs, outputs: [output] },
64
87
  [`${e2eTarget}-ui`]: { command: `${run} --ui`, dependsOn: ['bddgen'], cache: false, continuous: true },
65
88
  [`${e2eTarget}-headed`]: { command: `${run} --headed`, dependsOn: ['bddgen'], cache: false, outputs: [output] },
66
89
  [`${e2eTarget}-debug`]: { command: `${run} --debug`, dependsOn: ['bddgen'], cache: false, continuous: true },
@@ -69,15 +92,24 @@ async function playwrightBddProjectGenerator(tree, options) {
69
92
  });
70
93
  (0, devkit_1.generateFiles)(tree, path.join(__dirname, 'files', 'playwright-bdd'), root, {
71
94
  ...options,
95
+ isApi,
96
+ baseUrlJson: JSON.stringify(baseUrl),
97
+ apiServeCommandJson: options.webServerTarget ? JSON.stringify(`npx nx run ${options.webServerTarget}`) : undefined,
72
98
  name,
73
99
  e2eTarget,
74
100
  ciTarget,
75
101
  projectRoot: root,
76
102
  workspaceRootRelative,
77
- serveCommandJson: JSON.stringify((0, names_1.buildServeCommand)(tree, options.project, `${options.project}:serve`, 'http://localhost:4200')),
103
+ serveCommandJson: JSON.stringify(isApi ? '' : (0, names_1.buildServeCommand)(tree, options.project, `${options.project}:serve`, 'http://localhost:4200')),
78
104
  rootEslintConfig: ['eslint.config.mjs', 'eslint.config.js', 'eslint.config.cjs'].find((file) => tree.exists(file)) ??
79
105
  'eslint.config.mjs',
80
106
  });
107
+ if (isApi) {
108
+ for (const file of ['src/world.ts', 'src/steps/homepage.steps.ts', 'features/homepage.feature']) {
109
+ tree.delete(`${root}/${file}`);
110
+ }
111
+ (0, devkit_1.generateFiles)(tree, path.join(__dirname, 'files', 'playwright-bdd-api'), root, {});
112
+ }
81
113
  (0, devkit_1.updateJson)(tree, 'nx.json', (json) => {
82
114
  json.plugins ??= [];
83
115
  if (!json.plugins.some((entry) => (typeof entry === 'string' ? entry : entry.plugin) === '@nx/playwright/plugin')) {
@@ -1 +1 @@
1
- {"version":3,"file":"playwright-bdd.js","sourceRoot":"","sources":["../../../../../../libs/nx-cucumber/src/generators/project/playwright-bdd.ts"],"names":[],"mappings":";;AAmBA,sEAsGC;;AAzHD,uCAcoB;AACpB,wDAAkC;AAClC,mCAAoG;AAG7F,KAAK,UAAU,6BAA6B,CAAC,IAAU,EAAE,OAAkC;IAChG,IAAA,iCAAwB,EAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,IAAA,qCAA6B,EAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E,MAAM,MAAM,GAAG,IAAA,2BAAkB,EAAC,IAAI,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,IAAA,sBAAa,EAAC,OAAO,CAAC,SAAS,IAAI,IAAA,+BAAuB,EAAC,IAAI,CAAC,CAAC,CAAC;IACpF,MAAM,IAAI,GACR,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,qBAAqB;QACxE,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,IAAI,SAAS,EAAE;QAClC,CAAC,CAAC,SAAS,CAAC;IAChB,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;QACzD,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,IAAI,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,YAAY,IAAI,8CAA8C,CAAC,CAAC;IACjH,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;QACrD,MAAM,IAAI,KAAK,CAAC,gBAAgB,IAAI,mDAAmD,CAAC,CAAC;IAC3F,MAAM,qBAAqB,GAAG,IAAA,uBAAc,EAAC,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,IAAA,iBAAQ,EAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IAChD,kFAAkF;IAClF,MAAM,SAAS,GAAW,IAAA,qBAAY,EAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,OAAO,CAAC;IACnF,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC5G,MAAM,cAAc,GAAG,CAAC,IAAA,iBAAQ,EAAC,IAAI,EAAE,SAAS,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,CACnE,CAAC,KAAkC,EAAE,EAAE,CACrC,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,uBAAuB,CACjF,CAAC;IACF,MAAM,SAAS,GAAW,OAAO,cAAc,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,OAAO,EAAE,UAAU,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACrH,MAAM,cAAc,GAClB,OAAO,cAAc,KAAK,QAAQ;QAChC,CAAC,CAAC,CAAC,cAAc,CAAC,OAAO,EAAE,YAAY,IAAI,QAAQ,CAAC;QACpD,CAAC,CAAC,cAAc;YACd,CAAC,CAAC,QAAQ;YACV,CAAC,CAAC,EAAE,CAAC;IACX,MAAM,QAAQ,GAAW,cAAc,IAAI,GAAG,SAAS,KAAK,CAAC;IAC7D,MAAM,MAAM,GAAG;QACb,SAAS;QACT,aAAa;QACb,gCAAgC;QAChC,EAAE,oBAAoB,EAAE,CAAC,kBAAkB,EAAE,gBAAgB,EAAE,gBAAgB,CAAC,EAAE;QAClF,EAAE,GAAG,EAAE,IAAI,EAAE;KACd,CAAC;IACF,MAAM,MAAM,GAAG,GAAG,IAAI,wBAAwB,CAAC;IAC/C,MAAM,MAAM,GAAG,uBAAuB,MAAM,EAAE,CAAC;IAC/C,MAAM,GAAG,GAAG,gCAAgC,MAAM,EAAE,CAAC;IACrD,MAAM,MAAM,GAAG,4BAA4B,IAAI,EAAE,CAAC;IAClD,IAAA,gCAAuB,EAAC,IAAI,EAAE,IAAI,EAAE;QAClC,IAAI;QACJ,UAAU,EAAE,GAAG,IAAI,MAAM;QACzB,WAAW,EAAE,aAAa;QAC1B,oBAAoB,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;QACvC,OAAO,EAAE;YACP,MAAM,EAAE;gBACN,OAAO,EAAE,MAAM;gBACf,KAAK,EAAE,IAAI;gBACX,MAAM;gBACN,OAAO,EAAE,CAAC,6BAA6B,CAAC;aACzC;YACD,8EAA8E;YAC9E,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE;YACjE,gGAAgG;YAChG,8EAA8E;YAC9E,CAAC,QAAQ,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE;YAC3F,CAAC,GAAG,SAAS,KAAK,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,GAAG,OAAO,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE;YACtG,CAAC,GAAG,SAAS,SAAS,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,GAAG,WAAW,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE;YAC/G,CAAC,GAAG,SAAS,QAAQ,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,GAAG,UAAU,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE;YAC5G,IAAI,EAAE,EAAE,OAAO,EAAE,cAAc,IAAI,aAAa,IAAI,oBAAoB,EAAE;SAC3E;KACF,CAAC,CAAC;IACH,IAAA,sBAAa,EAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,gBAAgB,CAAC,EAAE,IAAI,EAAE;QACzE,GAAG,OAAO;QACV,IAAI;QACJ,SAAS;QACT,QAAQ;QACR,WAAW,EAAE,IAAI;QACjB,qBAAqB;QACrB,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAC9B,IAAA,yBAAiB,EAAC,IAAI,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,QAAQ,EAAE,uBAAuB,CAAC,CAC9F;QACD,gBAAgB,EACd,CAAC,mBAAmB,EAAE,kBAAkB,EAAE,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAChG,mBAAmB;KACtB,CAAC,CAAC;IACH,IAAA,mBAAU,EAAC,IAAI,EAAE,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE;QACnC,IAAI,CAAC,OAAO,KAAK,EAAE,CAAC;QACpB,IACE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAChB,CAAC,KAAkC,EAAE,EAAE,CACrC,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,uBAAuB,CACjF,EACD,CAAC;YACD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,uBAAuB,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QAC3G,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,IAAA,qCAA4B,EAC1C,IAAI,EACJ,EAAE,EACF;QACE,gBAAgB,EAAE,SAAS;QAC3B,kBAAkB,EAAE,QAAQ,CAAC,eAAe,EAAE,CAAC,kBAAkB,CAAC,IAAI,QAAQ;QAC9E,gBAAgB,EAAE,OAAO;KAC1B,CACF,CAAC;IACF,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;IACxB,OAAO,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;AACzD,CAAC","sourcesContent":["import {\n addDependenciesToPackageJson,\n addProjectConfiguration,\n formatFiles,\n generateFiles,\n getWorkspaceLayout,\n getProjects,\n normalizePath,\n offsetFromRoot,\n readJson,\n readJsonFile,\n readProjectConfiguration,\n Tree,\n updateJson,\n} from '@nx/devkit';\nimport * as path from 'node:path';\nimport { buildServeCommand, defaultProjectDirectory, normalizeGeneratedProjectName } from './names';\nimport { CucumberJsGeneratorSchema } from './schema';\n\nexport async function playwrightBddProjectGenerator(tree: Tree, options: CucumberJsGeneratorSchema) {\n readProjectConfiguration(tree, options.project);\n const name = normalizeGeneratedProjectName(options.project, options.name);\n const layout = getWorkspaceLayout(tree);\n const directory = normalizePath(options.directory || defaultProjectDirectory(name));\n const root =\n layout.appsDir && layout.appsDir !== '.' && !options.ignoreWorkspaceLayout\n ? `${layout.appsDir}/${directory}`\n : directory;\n if (path.isAbsolute(root) || root.split('/').includes('..'))\n throw new Error('Destination must be inside the workspace.');\n if (getProjects(tree).has(name)) throw new Error(`Project \"${name}\" already exists; choose a new project name.`);\n if (tree.exists(root) || tree.children(root).length > 0)\n throw new Error(`Destination \"${root}\" already exists; choose a new project directory.`);\n const workspaceRootRelative = offsetFromRoot(root).replace(/\\/$/, '');\n const manifest = readJson(tree, 'package.json');\n // Match the installed Nx runtime, rather than pinning consumers to our own patch.\n const nxVersion: string = readJsonFile(require.resolve('nx/package.json')).version;\n if (!nxVersion.startsWith('24.')) throw new Error('Playwright-BDD generation requires an Nx 24 workspace.');\n const existingPlugin = (readJson(tree, 'nx.json').plugins ?? []).find(\n (entry: string | { plugin: string }) =>\n (typeof entry === 'string' ? entry : entry.plugin) === '@nx/playwright/plugin',\n );\n const e2eTarget: string = typeof existingPlugin === 'object' ? (existingPlugin.options?.targetName ?? 'e2e') : 'e2e';\n const nativeCiTarget =\n typeof existingPlugin === 'object'\n ? (existingPlugin.options?.ciTargetName ?? 'e2e-ci')\n : existingPlugin\n ? 'e2e-ci'\n : '';\n const ciTarget: string = nativeCiTarget || `${e2eTarget}-ci`;\n const inputs = [\n 'default',\n '^production',\n '{workspaceRoot}/tsconfig*.json',\n { externalDependencies: ['@playwright/test', 'playwright-bdd', '@nx/playwright'] },\n { env: 'CI' },\n ];\n const config = `${root}/playwright.config.mts`;\n const bddgen = `npx bddgen --config ${config}`;\n const run = `npx playwright test --config ${config}`;\n const output = `{workspaceRoot}/dist/e2e/${root}`;\n addProjectConfiguration(tree, name, {\n root,\n sourceRoot: `${root}/src`,\n projectType: 'application',\n implicitDependencies: [options.project],\n targets: {\n bddgen: {\n command: bddgen,\n cache: true,\n inputs,\n outputs: [`{projectRoot}/.features-gen`],\n },\n // @nx/playwright/plugin infers the actual e2e task from the generated config.\n [e2eTarget]: { dependsOn: ['bddgen'], inputs, outputs: [output] },\n // A native command replaces an inferred atomized aggregator, including its Cloud-only metadata.\n // Generated specs do not exist when Nx first discovers individual test files.\n [ciTarget]: { command: run, dependsOn: ['bddgen'], cache: true, inputs, outputs: [output] },\n [`${e2eTarget}-ui`]: { command: `${run} --ui`, dependsOn: ['bddgen'], cache: false, continuous: true },\n [`${e2eTarget}-headed`]: { command: `${run} --headed`, dependsOn: ['bddgen'], cache: false, outputs: [output] },\n [`${e2eTarget}-debug`]: { command: `${run} --debug`, dependsOn: ['bddgen'], cache: false, continuous: true },\n lint: { command: `npx eslint ${root} --config ${root}/eslint.config.mjs` },\n },\n });\n generateFiles(tree, path.join(__dirname, 'files', 'playwright-bdd'), root, {\n ...options,\n name,\n e2eTarget,\n ciTarget,\n projectRoot: root,\n workspaceRootRelative,\n serveCommandJson: JSON.stringify(\n buildServeCommand(tree, options.project, `${options.project}:serve`, 'http://localhost:4200'),\n ),\n rootEslintConfig:\n ['eslint.config.mjs', 'eslint.config.js', 'eslint.config.cjs'].find((file) => tree.exists(file)) ??\n 'eslint.config.mjs',\n });\n updateJson(tree, 'nx.json', (json) => {\n json.plugins ??= [];\n if (\n !json.plugins.some(\n (entry: string | { plugin: string }) =>\n (typeof entry === 'string' ? entry : entry.plugin) === '@nx/playwright/plugin',\n )\n ) {\n json.plugins.push({ plugin: '@nx/playwright/plugin', options: { targetName: 'e2e', ciTargetName: '' } });\n }\n return json;\n });\n const install = addDependenciesToPackageJson(\n tree,\n {},\n {\n '@nx/playwright': nxVersion,\n '@playwright/test': manifest.devDependencies?.['@playwright/test'] || '1.64.1',\n 'playwright-bdd': '9.2.1',\n },\n );\n await formatFiles(tree);\n return options.skipInstall ? () => undefined : install;\n}\n"]}
1
+ {"version":3,"file":"playwright-bdd.js","sourceRoot":"","sources":["../../../../../../libs/nx-cucumber/src/generators/project/playwright-bdd.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n addDependenciesToPackageJson,\n addProjectConfiguration,\n formatFiles,\n generateFiles,\n getWorkspaceLayout,\n getProjects,\n normalizePath,\n offsetFromRoot,\n readJson,\n readJsonFile,\n readProjectConfiguration,\n Tree,\n updateJson,\n} from '@nx/devkit';\nimport * as path from 'node:path';\nimport { buildServeCommand, defaultProjectDirectory, normalizeGeneratedProjectName } from './names';\nimport { CucumberJsGeneratorSchema } from './schema';\n\nexport async function playwrightBddProjectGenerator(tree: Tree, options: CucumberJsGeneratorSchema) {\n readProjectConfiguration(tree, options.project);\n const isApi = options.testType === 'api';\n if (!isApi && (options.baseUrl !== undefined || options.webServerTarget !== undefined)) {\n throw new Error('baseUrl and webServerTarget require --test-type=api.');\n }\n const baseUrl = options.baseUrl ?? 'http://localhost:3000';\n if (isApi) {\n const url = new URL(baseUrl);\n if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password) {\n throw new Error('baseUrl must be an HTTP(S) URL without credentials. Use API_TOKEN for authentication.');\n }\n }\n let serverProject: string | undefined;\n if (options.webServerTarget !== undefined) {\n const [project, target, configuration, ...rest] = options.webServerTarget.split(':');\n if (!project || !target || configuration === '' || rest.length || !/^[\\w@./:-]+$/.test(options.webServerTarget)) {\n throw new Error('webServerTarget must be project:target[:configuration].');\n }\n // Devkit's Tree configuration omits plugin-inferred targets. Let Nx resolve the\n // target/configuration at execution time, so inferred backend targets work too.\n readProjectConfiguration(tree, project);\n serverProject = project;\n }\n const name = normalizeGeneratedProjectName(options.project, options.name);\n const layout = getWorkspaceLayout(tree);\n const directory = normalizePath(options.directory || defaultProjectDirectory(name));\n const root =\n layout.appsDir && layout.appsDir !== '.' && !options.ignoreWorkspaceLayout\n ? `${layout.appsDir}/${directory}`\n : directory;\n if (path.isAbsolute(root) || root.split('/').includes('..'))\n throw new Error('Destination must be inside the workspace.');\n if (getProjects(tree).has(name)) throw new Error(`Project \"${name}\" already exists; choose a new project name.`);\n if (tree.exists(root) || tree.children(root).length > 0)\n throw new Error(`Destination \"${root}\" already exists; choose a new project directory.`);\n const workspaceRootRelative = offsetFromRoot(root).replace(/\\/$/, '');\n const manifest = readJson(tree, 'package.json');\n // Match the installed Nx runtime, rather than pinning consumers to our own patch.\n const nxVersion: string = readJsonFile(require.resolve('nx/package.json')).version;\n if (!nxVersion.startsWith('24.')) throw new Error('Playwright-BDD generation requires an Nx 24 workspace.');\n const existingPlugin = (readJson(tree, 'nx.json').plugins ?? []).find(\n (entry: string | { plugin: string }) =>\n (typeof entry === 'string' ? entry : entry.plugin) === '@nx/playwright/plugin',\n );\n const e2eTarget: string = typeof existingPlugin === 'object' ? (existingPlugin.options?.targetName ?? 'e2e') : 'e2e';\n const nativeCiTarget =\n typeof existingPlugin === 'object'\n ? (existingPlugin.options?.ciTargetName ?? 'e2e-ci')\n : existingPlugin\n ? 'e2e-ci'\n : '';\n const ciTarget: string = nativeCiTarget || `${e2eTarget}-ci`;\n const inputs = [\n 'default',\n '^production',\n '{workspaceRoot}/tsconfig*.json',\n { externalDependencies: ['@playwright/test', 'playwright-bdd', '@nx/playwright'] },\n { env: 'CI' },\n ];\n const testInputs = isApi ? [...inputs, { env: 'API_BASE_URL' }, { env: 'API_TOKEN' }] : inputs;\n const config = `${root}/playwright.config.mts`;\n const bddgen = `npx bddgen --config ${config}`;\n const run = `npx playwright test --config ${config}`;\n const output = `{workspaceRoot}/dist/e2e/${root}`;\n addProjectConfiguration(tree, name, {\n root,\n sourceRoot: `${root}/src`,\n projectType: 'application',\n implicitDependencies: [...new Set([options.project, ...(serverProject ? [serverProject] : [])])],\n targets: {\n bddgen: {\n command: bddgen,\n cache: true,\n inputs,\n outputs: [`{projectRoot}/.features-gen`],\n },\n // @nx/playwright/plugin infers the actual e2e task from the generated config.\n [e2eTarget]: { dependsOn: ['bddgen'], inputs: testInputs, outputs: [output], ...(isApi ? { cache: false } : {}) },\n // A native command replaces an inferred atomized aggregator, including its Cloud-only metadata.\n // Generated specs do not exist when Nx first discovers individual test files.\n [ciTarget]: { command: run, dependsOn: ['bddgen'], cache: !isApi, inputs: testInputs, outputs: [output] },\n [`${e2eTarget}-ui`]: { command: `${run} --ui`, dependsOn: ['bddgen'], cache: false, continuous: true },\n [`${e2eTarget}-headed`]: { command: `${run} --headed`, dependsOn: ['bddgen'], cache: false, outputs: [output] },\n [`${e2eTarget}-debug`]: { command: `${run} --debug`, dependsOn: ['bddgen'], cache: false, continuous: true },\n lint: { command: `npx eslint ${root} --config ${root}/eslint.config.mjs` },\n },\n });\n generateFiles(tree, path.join(__dirname, 'files', 'playwright-bdd'), root, {\n ...options,\n isApi,\n baseUrlJson: JSON.stringify(baseUrl),\n apiServeCommandJson: options.webServerTarget ? JSON.stringify(`npx nx run ${options.webServerTarget}`) : undefined,\n name,\n e2eTarget,\n ciTarget,\n projectRoot: root,\n workspaceRootRelative,\n serveCommandJson: JSON.stringify(\n isApi ? '' : buildServeCommand(tree, options.project, `${options.project}:serve`, 'http://localhost:4200'),\n ),\n rootEslintConfig:\n ['eslint.config.mjs', 'eslint.config.js', 'eslint.config.cjs'].find((file) => tree.exists(file)) ??\n 'eslint.config.mjs',\n });\n if (isApi) {\n for (const file of ['src/world.ts', 'src/steps/homepage.steps.ts', 'features/homepage.feature']) {\n tree.delete(`${root}/${file}`);\n }\n generateFiles(tree, path.join(__dirname, 'files', 'playwright-bdd-api'), root, {});\n }\n updateJson(tree, 'nx.json', (json) => {\n json.plugins ??= [];\n if (\n !json.plugins.some(\n (entry: string | { plugin: string }) =>\n (typeof entry === 'string' ? entry : entry.plugin) === '@nx/playwright/plugin',\n )\n ) {\n json.plugins.push({ plugin: '@nx/playwright/plugin', options: { targetName: 'e2e', ciTargetName: '' } });\n }\n return json;\n });\n const install = addDependenciesToPackageJson(\n tree,\n {},\n {\n '@nx/playwright': nxVersion,\n '@playwright/test': manifest.devDependencies?.['@playwright/test'] || '1.64.1',\n 'playwright-bdd': '9.2.1',\n },\n );\n await formatFiles(tree);\n return options.skipInstall ? () => undefined : install;\n}\n"]}
@@ -11,6 +11,9 @@ const test_run_options_1 = require("../../core/test-run-options");
11
11
  async function cucumberJsGenerator(tree, options) {
12
12
  if (options.testRunner === 'playwright-bdd')
13
13
  return (0, playwright_bdd_1.playwrightBddProjectGenerator)(tree, options);
14
+ if (options.testType || options.baseUrl || options.webServerTarget) {
15
+ throw new Error('testType, baseUrl and webServerTarget require --test-runner=playwright-bdd.');
16
+ }
14
17
  if (!options.testRunner)
15
18
  options.testRunner = test_run_options_1.defaultTestRunner;
16
19
  if (!options.configFormat)
@@ -1 +1 @@
1
- {"version":3,"file":"project.js","sourceRoot":"","sources":["../../../../../../libs/nx-cucumber/src/generators/project/project.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n buildServeCommand,\n defaultProjectDirectory,\n normalizeGeneratedProjectName,\n parseScopedProjectName,\n readPortFromUrl,\n} from './names';\nimport { playwrightBddProjectGenerator } from './playwright-bdd';\nimport {\n addProjectConfiguration,\n formatFiles,\n generateFiles,\n Tree,\n addDependenciesToPackageJson,\n normalizePath,\n offsetFromRoot,\n getWorkspaceLayout,\n readProjectConfiguration,\n updateJson,\n} from '@nx/devkit';\nimport * as path from 'path';\nimport { ConfigFormat, CucumberJsGeneratorSchema } from './schema';\nimport { existsSync } from 'fs';\nimport { defaultTestRunner } from '../../core/test-run-options';\n\nexport async function cucumberJsGenerator(tree: Tree, options: CucumberJsGeneratorSchema) {\n if (options.testRunner === 'playwright-bdd') return playwrightBddProjectGenerator(tree, options);\n if (!options.testRunner) options.testRunner = defaultTestRunner;\n if (!options.configFormat) options.configFormat = 'js';\n assertConfigFormatSupported(tree, options.configFormat);\n ensureProjectExists(tree, options.project);\n options.name = normalizeGeneratedProjectName(options.project, options.name);\n if (!options.directory) options.directory = defaultProjectDirectory(options.name);\n const isPlaywright = options.testRunner === 'playwright';\n const baseUrl = isPlaywright ? 'http://localhost:4200' : undefined;\n const serveTarget = isPlaywright ? `${options.project}:serve` : undefined;\n\n const normalizedDirectory = normalizePath(options.directory);\n const workspaceLayout = getWorkspaceLayout(tree);\n const skipAppsDir = workspaceLayout.appsDir === '.' || options.ignoreWorkspaceLayout;\n const parentDir = workspaceLayout.appsDir && !skipAppsDir ? workspaceLayout.appsDir + '/' : '';\n const projectRoot = `${parentDir}${normalizedDirectory}`;\n const workspaceRootRelative = offsetFromRoot(projectRoot).replace(/\\/$/, '');\n const playwrightTargets =\n isPlaywright && baseUrl && serveTarget ? buildPlaywrightTargets(options.name, projectRoot) : {};\n\n addProjectConfiguration(tree, options.name, {\n root: projectRoot,\n sourceRoot: `${projectRoot}/src`,\n projectType: 'application',\n targets: {\n lint: {\n command: `npx eslint ${projectRoot}`,\n },\n ...playwrightTargets,\n },\n implicitDependencies: [options.project],\n });\n\n const playwrightRequires =\n options.testRunner === 'playwright'\n ? [\n 'node_modules/@gnuechtel/nx-cucumber/src/playwright/playwright-world-default.js',\n 'node_modules/@gnuechtel/nx-cucumber/src/playwright/playwright-hooks.js',\n ]\n : [];\n\n const configFormat = options.configFormat!;\n const configFileName = `cucumber.${configFormat}`;\n const configShapeDir = resolveConfigShapeDir(configFormat);\n const isTypeScript = ['ts', 'mts', 'cts'].includes(configFormat);\n const isEsmModule = ['mjs', 'mts'].includes(configFormat);\n\n const serveCommand =\n isPlaywright && baseUrl && serveTarget ? buildServeCommand(tree, options.project, serveTarget, baseUrl) : '';\n const testCommand = `npx cucumber-js --config ${projectRoot}/${configFileName}`;\n const templateProjectName = parseScopedProjectName(options.project).name;\n\n const substitutions = {\n ...options,\n project: templateProjectName,\n testedProject: options.project,\n workspaceRootRelative,\n rootEslintConfig:\n ['eslint.config.mjs', 'eslint.config.js', 'eslint.config.cjs'].find((file) => tree.exists(file)) ??\n 'eslint.config.mjs',\n projectRoot,\n playwrightRequires: JSON.stringify(playwrightRequires),\n playwrightRequiresArray: playwrightRequires,\n isPlaywright,\n isTypeScript,\n isEsmModule,\n baseUrl: baseUrl || '',\n serveTarget: serveTarget || '',\n port: baseUrl ? readPortFromUrl(baseUrl) : 0,\n serveCommandJson: JSON.stringify(serveCommand),\n testCommandJson: JSON.stringify(testCommand),\n };\n\n generateFiles(tree, path.join(__dirname, 'files', 'all'), projectRoot, substitutions);\n generateFiles(tree, path.join(__dirname, 'files', 'config', configShapeDir), projectRoot, substitutions);\n generateFiles(tree, path.join(__dirname, 'files', options.testRunner), projectRoot, substitutions);\n\n const customWorldFiles = path.join(__dirname, 'files', `${options.testRunner}.custom-world`);\n if (options.customWorld && existsSync(customWorldFiles)) {\n generateFiles(tree, customWorldFiles, projectRoot, substitutions);\n }\n\n registerPlugin(tree);\n\n await formatFiles(tree);\n\n const additionalDevDependencies: Record<string, string> = {\n 'ts-node': '10.9.2',\n 'tsconfig-paths': '4.2.0',\n };\n\n const installTask = addDependenciesToPackageJson(tree, {}, additionalDevDependencies);\n return options.skipInstall ? () => undefined : installTask;\n}\n\nfunction buildPlaywrightTargets(e2eProjectName: string, projectRoot: string) {\n return {\n 'e2e-prepare': {\n cache: false,\n command: buildPlaywrightPrepareCommand(),\n },\n e2e: {\n command: `node ${projectRoot}/run-e2e.js`,\n },\n 'e2e-ci': {\n command: `npx nx run ${e2eProjectName}:e2e-prepare && npx nx run ${e2eProjectName}:e2e`,\n },\n };\n}\n\nfunction buildPlaywrightPrepareCommand() {\n return `node -e \"const { execSync } = require('node:child_process'); const installCommand = process.platform === 'linux' ? 'npx playwright install --with-deps chromium' : 'npx playwright install chromium'; execSync(installCommand, { stdio: 'inherit' });\"`;\n}\n\nfunction ensureProjectExists(tree: Tree, projectName: string) {\n try {\n readProjectConfiguration(tree, projectName);\n } catch {\n throw new Error(`Project \"${projectName}\" does not exist in this workspace.`);\n }\n}\n\nconst TYPESCRIPT_CONFIG_FORMATS: ConfigFormat[] = ['ts', 'mts', 'cts'];\nconst MINIMUM_CUCUMBER_VERSION_FOR_TS_CONFIG = '12.4.0';\n\n// cucumber-js only loads TypeScript config files (.ts/.mts/.cts) from 12.4.0 onwards\n// (versions 10.0-12.3 reject them with \"Unsupported configuration file extension\").\n// Fail fast with an actionable error instead of letting the user hit that at run time.\nfunction assertConfigFormatSupported(tree: Tree, configFormat: ConfigFormat) {\n if (!TYPESCRIPT_CONFIG_FORMATS.includes(configFormat)) return;\n const cucumberVersion = readInstalledCucumberVersion(tree);\n if (cucumberVersion && isBelowVersion(cucumberVersion, MINIMUM_CUCUMBER_VERSION_FOR_TS_CONFIG)) {\n throw new Error(\n `Cucumber configuration format \"${configFormat}\" requires @cucumber/cucumber >=${MINIMUM_CUCUMBER_VERSION_FOR_TS_CONFIG}, ` +\n `but found ${cucumberVersion}. Choose a different --config-format (js, cjs, mjs, json, yaml) ` +\n `or upgrade @cucumber/cucumber.`,\n );\n }\n}\n\nfunction readInstalledCucumberVersion(tree: Tree): string | undefined {\n const packageJsonPath = 'node_modules/@cucumber/cucumber/package.json';\n if (!tree.exists(packageJsonPath)) return undefined;\n try {\n const content = tree.read(packageJsonPath, 'utf-8');\n const version = content ? JSON.parse(content).version : undefined;\n return typeof version === 'string' ? version : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction isBelowVersion(version: string, minimum: string): boolean {\n const toParts = (value: string) =>\n value\n .split('-')[0]\n .split('.')\n .map((part) => parseInt(part, 10) || 0);\n const [vMajor, vMinor, vPatch] = toParts(version);\n const [mMajor, mMinor, mPatch] = toParts(minimum);\n if (vMajor !== mMajor) return vMajor < mMajor;\n if (vMinor !== mMinor) return vMinor < mMinor;\n return vPatch < mPatch;\n}\n\nfunction resolveConfigShapeDir(configFormat: ConfigFormat): string {\n if (configFormat === 'json') return 'json';\n if (configFormat === 'yaml' || configFormat === 'yml') return 'yaml';\n // cucumber-js loads .mjs/.mts/.ts via dynamic import (ESM), so they need the\n // import.meta-based shape; .cjs/.cts/.js are require-loaded and stay CommonJS.\n if (configFormat === 'mjs' || configFormat === 'mts' || configFormat === 'ts') return 'esm';\n return 'cjs';\n}\n\nfunction registerPlugin(tree: Tree) {\n if (!tree.exists('nx.json')) return;\n updateJson(tree, 'nx.json', (json) => {\n if (!Array.isArray(json.plugins)) json.plugins = [];\n if (!json.plugins.includes('@gnuechtel/nx-cucumber')) {\n json.plugins.push('@gnuechtel/nx-cucumber');\n }\n return json;\n });\n}\n\nexport default cucumberJsGenerator;\n"]}
1
+ {"version":3,"file":"project.js","sourceRoot":"","sources":["../../../../../../libs/nx-cucumber/src/generators/project/project.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n buildServeCommand,\n defaultProjectDirectory,\n normalizeGeneratedProjectName,\n parseScopedProjectName,\n readPortFromUrl,\n} from './names';\nimport { playwrightBddProjectGenerator } from './playwright-bdd';\nimport {\n addProjectConfiguration,\n formatFiles,\n generateFiles,\n Tree,\n addDependenciesToPackageJson,\n normalizePath,\n offsetFromRoot,\n getWorkspaceLayout,\n readProjectConfiguration,\n updateJson,\n} from '@nx/devkit';\nimport * as path from 'path';\nimport { ConfigFormat, CucumberJsGeneratorSchema } from './schema';\nimport { existsSync } from 'fs';\nimport { defaultTestRunner } from '../../core/test-run-options';\n\nexport async function cucumberJsGenerator(tree: Tree, options: CucumberJsGeneratorSchema) {\n if (options.testRunner === 'playwright-bdd') return playwrightBddProjectGenerator(tree, options);\n if (options.testType || options.baseUrl || options.webServerTarget) {\n throw new Error('testType, baseUrl and webServerTarget require --test-runner=playwright-bdd.');\n }\n if (!options.testRunner) options.testRunner = defaultTestRunner;\n if (!options.configFormat) options.configFormat = 'js';\n assertConfigFormatSupported(tree, options.configFormat);\n ensureProjectExists(tree, options.project);\n options.name = normalizeGeneratedProjectName(options.project, options.name);\n if (!options.directory) options.directory = defaultProjectDirectory(options.name);\n const isPlaywright = options.testRunner === 'playwright';\n const baseUrl = isPlaywright ? 'http://localhost:4200' : undefined;\n const serveTarget = isPlaywright ? `${options.project}:serve` : undefined;\n\n const normalizedDirectory = normalizePath(options.directory);\n const workspaceLayout = getWorkspaceLayout(tree);\n const skipAppsDir = workspaceLayout.appsDir === '.' || options.ignoreWorkspaceLayout;\n const parentDir = workspaceLayout.appsDir && !skipAppsDir ? workspaceLayout.appsDir + '/' : '';\n const projectRoot = `${parentDir}${normalizedDirectory}`;\n const workspaceRootRelative = offsetFromRoot(projectRoot).replace(/\\/$/, '');\n const playwrightTargets =\n isPlaywright && baseUrl && serveTarget ? buildPlaywrightTargets(options.name, projectRoot) : {};\n\n addProjectConfiguration(tree, options.name, {\n root: projectRoot,\n sourceRoot: `${projectRoot}/src`,\n projectType: 'application',\n targets: {\n lint: {\n command: `npx eslint ${projectRoot}`,\n },\n ...playwrightTargets,\n },\n implicitDependencies: [options.project],\n });\n\n const playwrightRequires =\n options.testRunner === 'playwright'\n ? [\n 'node_modules/@gnuechtel/nx-cucumber/src/playwright/playwright-world-default.js',\n 'node_modules/@gnuechtel/nx-cucumber/src/playwright/playwright-hooks.js',\n ]\n : [];\n\n const configFormat = options.configFormat!;\n const configFileName = `cucumber.${configFormat}`;\n const configShapeDir = resolveConfigShapeDir(configFormat);\n const isTypeScript = ['ts', 'mts', 'cts'].includes(configFormat);\n const isEsmModule = ['mjs', 'mts'].includes(configFormat);\n\n const serveCommand =\n isPlaywright && baseUrl && serveTarget ? buildServeCommand(tree, options.project, serveTarget, baseUrl) : '';\n const testCommand = `npx cucumber-js --config ${projectRoot}/${configFileName}`;\n const templateProjectName = parseScopedProjectName(options.project).name;\n\n const substitutions = {\n ...options,\n project: templateProjectName,\n testedProject: options.project,\n workspaceRootRelative,\n rootEslintConfig:\n ['eslint.config.mjs', 'eslint.config.js', 'eslint.config.cjs'].find((file) => tree.exists(file)) ??\n 'eslint.config.mjs',\n projectRoot,\n playwrightRequires: JSON.stringify(playwrightRequires),\n playwrightRequiresArray: playwrightRequires,\n isPlaywright,\n isTypeScript,\n isEsmModule,\n baseUrl: baseUrl || '',\n serveTarget: serveTarget || '',\n port: baseUrl ? readPortFromUrl(baseUrl) : 0,\n serveCommandJson: JSON.stringify(serveCommand),\n testCommandJson: JSON.stringify(testCommand),\n };\n\n generateFiles(tree, path.join(__dirname, 'files', 'all'), projectRoot, substitutions);\n generateFiles(tree, path.join(__dirname, 'files', 'config', configShapeDir), projectRoot, substitutions);\n generateFiles(tree, path.join(__dirname, 'files', options.testRunner), projectRoot, substitutions);\n\n const customWorldFiles = path.join(__dirname, 'files', `${options.testRunner}.custom-world`);\n if (options.customWorld && existsSync(customWorldFiles)) {\n generateFiles(tree, customWorldFiles, projectRoot, substitutions);\n }\n\n registerPlugin(tree);\n\n await formatFiles(tree);\n\n const additionalDevDependencies: Record<string, string> = {\n 'ts-node': '10.9.2',\n 'tsconfig-paths': '4.2.0',\n };\n\n const installTask = addDependenciesToPackageJson(tree, {}, additionalDevDependencies);\n return options.skipInstall ? () => undefined : installTask;\n}\n\nfunction buildPlaywrightTargets(e2eProjectName: string, projectRoot: string) {\n return {\n 'e2e-prepare': {\n cache: false,\n command: buildPlaywrightPrepareCommand(),\n },\n e2e: {\n command: `node ${projectRoot}/run-e2e.js`,\n },\n 'e2e-ci': {\n command: `npx nx run ${e2eProjectName}:e2e-prepare && npx nx run ${e2eProjectName}:e2e`,\n },\n };\n}\n\nfunction buildPlaywrightPrepareCommand() {\n return `node -e \"const { execSync } = require('node:child_process'); const installCommand = process.platform === 'linux' ? 'npx playwright install --with-deps chromium' : 'npx playwright install chromium'; execSync(installCommand, { stdio: 'inherit' });\"`;\n}\n\nfunction ensureProjectExists(tree: Tree, projectName: string) {\n try {\n readProjectConfiguration(tree, projectName);\n } catch {\n throw new Error(`Project \"${projectName}\" does not exist in this workspace.`);\n }\n}\n\nconst TYPESCRIPT_CONFIG_FORMATS: ConfigFormat[] = ['ts', 'mts', 'cts'];\nconst MINIMUM_CUCUMBER_VERSION_FOR_TS_CONFIG = '12.4.0';\n\n// cucumber-js only loads TypeScript config files (.ts/.mts/.cts) from 12.4.0 onwards\n// (versions 10.0-12.3 reject them with \"Unsupported configuration file extension\").\n// Fail fast with an actionable error instead of letting the user hit that at run time.\nfunction assertConfigFormatSupported(tree: Tree, configFormat: ConfigFormat) {\n if (!TYPESCRIPT_CONFIG_FORMATS.includes(configFormat)) return;\n const cucumberVersion = readInstalledCucumberVersion(tree);\n if (cucumberVersion && isBelowVersion(cucumberVersion, MINIMUM_CUCUMBER_VERSION_FOR_TS_CONFIG)) {\n throw new Error(\n `Cucumber configuration format \"${configFormat}\" requires @cucumber/cucumber >=${MINIMUM_CUCUMBER_VERSION_FOR_TS_CONFIG}, ` +\n `but found ${cucumberVersion}. Choose a different --config-format (js, cjs, mjs, json, yaml) ` +\n `or upgrade @cucumber/cucumber.`,\n );\n }\n}\n\nfunction readInstalledCucumberVersion(tree: Tree): string | undefined {\n const packageJsonPath = 'node_modules/@cucumber/cucumber/package.json';\n if (!tree.exists(packageJsonPath)) return undefined;\n try {\n const content = tree.read(packageJsonPath, 'utf-8');\n const version = content ? JSON.parse(content).version : undefined;\n return typeof version === 'string' ? version : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction isBelowVersion(version: string, minimum: string): boolean {\n const toParts = (value: string) =>\n value\n .split('-')[0]\n .split('.')\n .map((part) => parseInt(part, 10) || 0);\n const [vMajor, vMinor, vPatch] = toParts(version);\n const [mMajor, mMinor, mPatch] = toParts(minimum);\n if (vMajor !== mMajor) return vMajor < mMajor;\n if (vMinor !== mMinor) return vMinor < mMinor;\n return vPatch < mPatch;\n}\n\nfunction resolveConfigShapeDir(configFormat: ConfigFormat): string {\n if (configFormat === 'json') return 'json';\n if (configFormat === 'yaml' || configFormat === 'yml') return 'yaml';\n // cucumber-js loads .mjs/.mts/.ts via dynamic import (ESM), so they need the\n // import.meta-based shape; .cjs/.cts/.js are require-loaded and stay CommonJS.\n if (configFormat === 'mjs' || configFormat === 'mts' || configFormat === 'ts') return 'esm';\n return 'cjs';\n}\n\nfunction registerPlugin(tree: Tree) {\n if (!tree.exists('nx.json')) return;\n updateJson(tree, 'nx.json', (json) => {\n if (!Array.isArray(json.plugins)) json.plugins = [];\n if (!json.plugins.includes('@gnuechtel/nx-cucumber')) {\n json.plugins.push('@gnuechtel/nx-cucumber');\n }\n return json;\n });\n}\n\nexport default cucumberJsGenerator;\n"]}
@@ -7,6 +7,9 @@ export type CucumberJsGeneratorSchema = {
7
7
  name?: string;
8
8
  directory?: string;
9
9
  testRunner?: TestRunner | 'playwright-bdd';
10
+ testType?: 'browser' | 'api';
11
+ baseUrl?: string;
12
+ webServerTarget?: string;
10
13
  configFormat?: ConfigFormat;
11
14
  customWorld?: boolean;
12
15
  ignoreWorkspaceLayout?: boolean;
@@ -49,6 +49,19 @@
49
49
  "type": "boolean",
50
50
  "description": "Skip package installation",
51
51
  "default": false
52
+ },
53
+ "testType": {
54
+ "type": "string",
55
+ "enum": ["browser", "api"],
56
+ "description": "Playwright-BDD test type; defaults to browser. API uses native request fixtures without browsers"
57
+ },
58
+ "baseUrl": {
59
+ "type": "string",
60
+ "description": "API-only default base URL, overridden at runtime by API_BASE_URL; defaults to http://localhost:3000"
61
+ },
62
+ "webServerTarget": {
63
+ "type": "string",
64
+ "description": "API-only optional Nx project:target[:configuration] to start locally; omitted for an already reachable API"
52
65
  }
53
66
  },
54
67
  "required": ["project"]