@qavajs/playwright-runner-adapter 2.4.0 → 2.5.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/CHANGELOG.md +28 -0
- package/README.md +160 -11
- package/adapter/PlaywrightWorld.d.ts +8 -6
- package/adapter/PlaywrightWorld.js +21 -8
- package/adapter/PlaywrightWorld.js.map +1 -1
- package/adapter/Template.d.ts +13 -2
- package/adapter/Template.js +57 -8
- package/adapter/Template.js.map +1 -1
- package/adapter/cucumberAdapter.d.ts +7 -0
- package/adapter/cucumberAdapter.js +253 -98
- package/adapter/cucumberAdapter.js.map +1 -1
- package/adapter/filter.d.ts +8 -0
- package/adapter/filter.js +27 -1
- package/adapter/filter.js.map +1 -1
- package/adapter/gherkin.d.ts +45 -0
- package/adapter/gherkin.js +155 -0
- package/adapter/gherkin.js.map +1 -0
- package/adapter/index.d.ts +1 -0
- package/adapter/index.js +1 -0
- package/adapter/index.js.map +1 -1
- package/adapter/js/PlaywrightWorld.d.ts +8 -6
- package/adapter/js/PlaywrightWorld.js +21 -8
- package/adapter/js/Template.d.ts +13 -2
- package/adapter/js/Template.js +57 -8
- package/adapter/js/cucumberAdapter.d.ts +7 -0
- package/adapter/js/cucumberAdapter.js +253 -98
- package/adapter/js/filter.d.ts +8 -0
- package/adapter/js/filter.js +27 -1
- package/adapter/js/gherkin.d.ts +45 -0
- package/adapter/js/gherkin.js +154 -0
- package/adapter/js/index.d.ts +1 -0
- package/adapter/js/index.js +1 -0
- package/adapter/js/loader.d.ts +9 -1
- package/adapter/js/loader.js +35 -15
- package/adapter/js/testDetails.d.ts +10 -0
- package/adapter/js/testDetails.js +27 -1
- package/adapter/js/timeout.d.ts +17 -0
- package/adapter/js/timeout.js +24 -0
- package/adapter/js/types.d.ts +35 -6
- package/adapter/js/withWorld.d.ts +43 -0
- package/adapter/js/withWorld.js +16 -0
- package/adapter/loader.d.ts +9 -1
- package/adapter/loader.js +35 -15
- package/adapter/loader.js.map +1 -1
- package/adapter/testDetails.d.ts +10 -0
- package/adapter/testDetails.js +27 -1
- package/adapter/testDetails.js.map +1 -1
- package/adapter/timeout.d.ts +17 -0
- package/adapter/timeout.js +25 -0
- package/adapter/timeout.js.map +1 -0
- package/adapter/types.d.ts +35 -6
- package/adapter/withWorld.d.ts +43 -0
- package/adapter/withWorld.js +17 -0
- package/adapter/withWorld.js.map +1 -0
- package/package.json +6 -4
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,34 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how
|
|
|
14
14
|
|
|
15
15
|
:microscope: - experimental
|
|
16
16
|
|
|
17
|
+
## [2.5.0]
|
|
18
|
+
- :beetle: `requireModules` are now required as modules (e.g. `ts-node/register`) resolved from the current working directory instead of being treated as globs
|
|
19
|
+
- :beetle: `worldParameters` config option is passed to the world as `this.parameters`
|
|
20
|
+
- :beetle: `this.attach` accepts media type as a string (`attach(data, 'image/png')`), decodes `;base64` media types and supports readable streams
|
|
21
|
+
- :beetle: `this.log` attaches text to the report (attachment `log` on the current step) instead of printing to stdout
|
|
22
|
+
- :beetle: steps returning `'pending'` fail the scenario (or mark it as fixme with `strict: false`); steps and `Before` hooks returning `'skipped'` skip the scenario
|
|
23
|
+
- :beetle: `After` hooks receive `FAILED` status when a `Before` hook fails; soft assertion failures, undefined, ambiguous and pending steps are reported with their own status
|
|
24
|
+
- :beetle: features with the same name in different files no longer produce duplicate test titles; unnamed features use the file path as title
|
|
25
|
+
- :rocket: undefined step error includes the feature file location and a step definition snippet
|
|
26
|
+
- :rocket: added `tags` config option and `CUCUMBER_TAGS` env variable to select scenarios by tag expression evaluated on Gherkin tags
|
|
27
|
+
- :rocket: added `CUCUMBER_PATHS` env variable to override feature paths
|
|
28
|
+
- :rocket: `executeStep` accepts a doc string (`string`) or data table (`string[][]` / `DataTable`) argument
|
|
29
|
+
- :rocket: `Template` supports data tables and doc strings
|
|
30
|
+
- :rocket: tests and describe blocks are reported at their location in the `.feature` file
|
|
31
|
+
- :rocket: step titles include a preview of their doc string or data table argument
|
|
32
|
+
- :rocket: added `@timeout(ms)` tag to set test timeout and `@retries(n)` feature tag to set retries
|
|
33
|
+
- :rocket: added `withWorld<World>()` helper returning step and hook functions with typed `this`
|
|
34
|
+
- :rocket: added `stepLocation` config option to point steps to the feature file instead of step definitions
|
|
35
|
+
- :rocket: step and hook `{ timeout }` option and `setDefaultTimeout` are applied (no implicit 5s default)
|
|
36
|
+
- :rocket: steps run by `executeStep` and `Template` are shown as nested steps in the report
|
|
37
|
+
- :rocket: invalid tag expressions report their source (`tags()`, `tags` option, `CUCUMBER_TAGS`); tags without `@` are rejected
|
|
38
|
+
- :pencil: replaced `glob` dependency with built-in `fs.globSync`; matched files are loaded in sorted order
|
|
39
|
+
- :pencil: tests no longer depend on external websites
|
|
40
|
+
- :pencil: CI: tests cover all test projects (TS, CommonJS, ESM configs), `CUCUMBER_PATHS` / `CUCUMBER_TAGS`, type checks and a smoke test of the packed package in fresh CommonJS, ESM and TypeScript projects
|
|
41
|
+
- :pencil: CI: publish no longer runs e2e tests
|
|
42
|
+
- :pencil: README: clarified the difference between the main and `./js` entrypoints
|
|
43
|
+
- :pencil: documented and tested supported Cucumber APIs: `defineParameterType`, `setDefinitionFunctionWrapper`, localized Gherkin, Rule tags
|
|
44
|
+
|
|
17
45
|
## [2.4.0]
|
|
18
46
|
- :rocket: added `@lock(name)` tag mapped to playwright test locks (`@lock(-exclusive-)` for the built-in exclusive lock)
|
|
19
47
|
- :rocket: added `@skip(reason)`, `@fixme(reason)`, `@fail(reason)`, `@slow(reason)` tags mapped to playwright test modifiers (reason is optional: `@skip()`)
|
package/README.md
CHANGED
|
@@ -13,15 +13,20 @@ Adapter to run [Cucumber](https://cucumber.io/) BDD tests via the [Playwright](h
|
|
|
13
13
|
- [TestWorld](#testworld)
|
|
14
14
|
- [PlaywrightWorld](#playwrightworld)
|
|
15
15
|
- [Custom World](#custom-world)
|
|
16
|
+
- [Typed Steps](#typed-steps)
|
|
16
17
|
- [Hooks](#hooks)
|
|
17
18
|
- [Step Arguments](#step-arguments)
|
|
18
19
|
- [Template Steps](#template-steps)
|
|
20
|
+
- [Step Results](#step-results)
|
|
19
21
|
- [Filtering Tests](#filtering-tests)
|
|
20
22
|
- [Tag Expressions](#tag-expressions)
|
|
21
23
|
- [Predicate Filter](#predicate-filter)
|
|
22
24
|
- [Annotations, Modifiers and Locks](#annotations-modifiers-and-locks)
|
|
23
25
|
- [Parallelism](#parallelism)
|
|
24
|
-
- [
|
|
26
|
+
- [Reports](#reports)
|
|
27
|
+
- [Entrypoints and JavaScript Support](#entrypoints-and-javascript-support)
|
|
28
|
+
- [Timeouts](#timeouts)
|
|
29
|
+
- [Supported Cucumber APIs](#supported-cucumber-apis)
|
|
25
30
|
- [Limitations](#limitations)
|
|
26
31
|
|
|
27
32
|
---
|
|
@@ -55,10 +60,13 @@ export default defineConfig({
|
|
|
55
60
|
import { defineConfig } from '@playwright/test';
|
|
56
61
|
|
|
57
62
|
export default defineConfig({
|
|
58
|
-
testMatch: 'cucumber.config.ts'
|
|
63
|
+
testMatch: 'cucumber.config.ts',
|
|
64
|
+
fullyParallel: true
|
|
59
65
|
});
|
|
60
66
|
```
|
|
61
67
|
|
|
68
|
+
> All scenarios are defined in a single test file (`cucumber.config.ts`), so without `fullyParallel: true` Playwright runs the whole suite in one worker.
|
|
69
|
+
|
|
62
70
|
**3. Run tests**
|
|
63
71
|
|
|
64
72
|
```bash
|
|
@@ -76,7 +84,11 @@ npx playwright test
|
|
|
76
84
|
| `paths` | `string[]` | Glob patterns for `.feature` files |
|
|
77
85
|
| `require` | `string[]` | Glob patterns for step definition files (CommonJS `require`) |
|
|
78
86
|
| `import` | `string[]` | Glob patterns for step definition files (ESM `import`) |
|
|
79
|
-
| `requireModules` | `string[]` |
|
|
87
|
+
| `requireModules` | `string[]` | Module names or paths (resolved from the current working directory) to require before step definitions (e.g. `ts-node/register`) |
|
|
88
|
+
| `worldParameters` | `unknown` | Value available in steps and hooks as `this.parameters` |
|
|
89
|
+
| `tags` | `string` | Cucumber tag expression selecting scenarios to run |
|
|
90
|
+
| `strict` | `boolean` | Fail scenarios with pending steps (default `true`). When `false` they are marked as `fixme` |
|
|
91
|
+
| `stepLocation` | `'definition' \| 'feature'` | Location reported for steps: step definition code (default) or the step line in the `.feature` file |
|
|
80
92
|
|
|
81
93
|
```typescript
|
|
82
94
|
// cucumber.config.ts
|
|
@@ -85,10 +97,19 @@ import { defineConfig } from '@qavajs/playwright-runner-adapter';
|
|
|
85
97
|
export default defineConfig({
|
|
86
98
|
paths: ['test/features/**/*.feature'],
|
|
87
99
|
require: ['test/step_definitions/**/*.ts'],
|
|
88
|
-
requireModules: [],
|
|
100
|
+
requireModules: ['./test/support/setup.ts'],
|
|
101
|
+
worldParameters: { baseUrl: 'https://example.com' },
|
|
102
|
+
tags: 'not @wip',
|
|
89
103
|
});
|
|
90
104
|
```
|
|
91
105
|
|
|
106
|
+
Environment variables:
|
|
107
|
+
|
|
108
|
+
| Variable | Description |
|
|
109
|
+
|---|---|
|
|
110
|
+
| `CUCUMBER_TAGS` | Tag expression combined with the `tags` option using `and`: `CUCUMBER_TAGS='@smoke' npx playwright test` |
|
|
111
|
+
| `CUCUMBER_PATHS` | Comma-separated feature globs replacing `paths`: `CUCUMBER_PATHS=features/login.feature npx playwright test` |
|
|
112
|
+
|
|
92
113
|
---
|
|
93
114
|
|
|
94
115
|
## World Classes
|
|
@@ -106,17 +127,29 @@ import { TestWorld } from '@qavajs/playwright-runner-adapter';
|
|
|
106
127
|
| `test` | `TestType` | Playwright `test` instance (default or custom) |
|
|
107
128
|
| `expect` | `ExpectType` | Playwright `expect` instance (default or custom) |
|
|
108
129
|
| `attach` | `function` | Attach files/data to the test report |
|
|
109
|
-
| `log` | `function` | Log
|
|
110
|
-
| `parameters` | `
|
|
130
|
+
| `log` | `function` | Log text to the test report (attachment named `log` on the current step) |
|
|
131
|
+
| `parameters` | `unknown` | Value of the `worldParameters` config option |
|
|
111
132
|
| `config` | `any` | Cucumber config object |
|
|
112
133
|
| `supportCodeLibrary` | `any` | Access to the loaded support code library |
|
|
113
134
|
|
|
114
|
-
**`
|
|
135
|
+
**`attach(data, mediaTypeOrOptions?)`** — same signature as in Cucumber:
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
await this.attach('plain text'); // text/plain
|
|
139
|
+
await this.attach(JSON.stringify(data), 'application/json');
|
|
140
|
+
await this.attach(screenshot, { mediaType: 'image/png', fileName: 'screenshot.png' });
|
|
141
|
+
await this.attach(base64Png, 'image/png;base64'); // base64 string is decoded
|
|
142
|
+
await this.attach(fs.createReadStream('report.pdf'), 'application/pdf'); // streams are supported
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**`executeStep(text, argument?)`** — programmatically invoke a step by its text. `argument` is passed as a doc string (`string`) or data table (`string[][]` or `DataTable`); any other value is passed as an extra parameter. Each executed step is shown in the report as a nested step of the calling step, and its `{ timeout }` option applies:
|
|
115
146
|
|
|
116
147
|
```typescript
|
|
117
148
|
When('composite step', async function (this: PlaywrightWorld) {
|
|
118
149
|
await this.executeStep('I open the home page');
|
|
119
150
|
await this.executeStep('I click "Login"');
|
|
151
|
+
await this.executeStep('I fill the form', [['username', 'alice'], ['password', 'secret']]);
|
|
152
|
+
await this.executeStep('I set the body', '{"key": "value"}');
|
|
120
153
|
});
|
|
121
154
|
```
|
|
122
155
|
|
|
@@ -198,6 +231,24 @@ The `init` function receives Playwright fixtures as its argument. Its signature
|
|
|
198
231
|
|
|
199
232
|
---
|
|
200
233
|
|
|
234
|
+
### Typed Steps
|
|
235
|
+
|
|
236
|
+
`withWorld<World>()` returns step and hook functions with `this` typed as your world, so you don't need a `this: MyWorld` annotation in every step:
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
import { withWorld } from '@qavajs/playwright-runner-adapter';
|
|
240
|
+
|
|
241
|
+
const { Given, When, Then, Before, After } = withWorld<MyWorld>();
|
|
242
|
+
|
|
243
|
+
When('I open {string}', async function (url: string) {
|
|
244
|
+
await this.page.goto(url); // `this` is MyWorld
|
|
245
|
+
});
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Cucumber's generic form works too: `When<MyWorld>('I open {string}', async function (url) { ... })`.
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
201
252
|
## Hooks
|
|
202
253
|
|
|
203
254
|
All standard Cucumber hooks are supported. Hooks run as named Playwright steps and appear in the trace viewer and HTML report.
|
|
@@ -310,7 +361,45 @@ When('I log in as {string}', Template((username: string) => `
|
|
|
310
361
|
`));
|
|
311
362
|
```
|
|
312
363
|
|
|
313
|
-
Each non-empty line in the returned string is executed as an individual step against the current world. Steps run sequentially; a failure stops the sequence.
|
|
364
|
+
Each non-empty line in the returned string is executed as an individual step against the current world and shown as a nested step in the report. Steps run sequentially; a failure stops the sequence.
|
|
365
|
+
|
|
366
|
+
Steps in a template can have data tables and doc strings, written the same way as in feature files:
|
|
367
|
+
|
|
368
|
+
```typescript
|
|
369
|
+
When('I register as {string}', Template((username: string) => `
|
|
370
|
+
I fill the form
|
|
371
|
+
| username | ${username} |
|
|
372
|
+
| password | secret |
|
|
373
|
+
I set the body
|
|
374
|
+
"""
|
|
375
|
+
{"user": "${username}"}
|
|
376
|
+
"""
|
|
377
|
+
`));
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
## Step Results
|
|
383
|
+
|
|
384
|
+
Steps and hooks follow Cucumber semantics:
|
|
385
|
+
|
|
386
|
+
- a step returning `'pending'` fails the scenario (or marks it as `fixme` with `strict: false`)
|
|
387
|
+
- a step or `Before` hook returning `'skipped'` skips the rest of the scenario and marks it as skipped
|
|
388
|
+
- an undefined step fails the scenario with its location in the feature file and a ready-to-paste snippet:
|
|
389
|
+
|
|
390
|
+
```
|
|
391
|
+
Step 'I have 5 "apples"' is not defined
|
|
392
|
+
at /project/features/cart.feature:12
|
|
393
|
+
|
|
394
|
+
Implement it with the following snippet:
|
|
395
|
+
|
|
396
|
+
When('I have {int} {string}', async function (int, string) {
|
|
397
|
+
// Write code here that turns the phrase above into concrete actions
|
|
398
|
+
return 'pending';
|
|
399
|
+
});
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
`After` and `AfterStep` hooks receive the actual status (`PASSED`, `FAILED`, `SKIPPED`, `PENDING`, `UNDEFINED`, `AMBIGUOUS`), including failures in `Before` hooks and soft assertions.
|
|
314
403
|
|
|
315
404
|
---
|
|
316
405
|
|
|
@@ -318,7 +407,9 @@ Each non-empty line in the returned string is executed as an individual step aga
|
|
|
318
407
|
|
|
319
408
|
### Tag Expressions
|
|
320
409
|
|
|
321
|
-
|
|
410
|
+
The simplest way to select scenarios is the `tags` [config option](#configuration-reference) and the `CUCUMBER_TAGS` environment variable. They are evaluated against the scenario's Gherkin tags, and scenarios that don't match are not created at all.
|
|
411
|
+
|
|
412
|
+
Use `tags()` to translate a Cucumber tag expression into a Playwright `grep` pattern:
|
|
322
413
|
|
|
323
414
|
```typescript
|
|
324
415
|
// playwright.config.ts
|
|
@@ -332,6 +423,10 @@ export default defineConfig({
|
|
|
332
423
|
|
|
333
424
|
Supports the full [Cucumber tag expression syntax](https://github.com/cucumber/tag-expressions): `and`, `or`, `not`, parentheses.
|
|
334
425
|
|
|
426
|
+
Invalid expressions fail fast with an error naming their source (`tags()`, the `tags` option or `CUCUMBER_TAGS`). Tags written without `@` (e.g. `smoke and not @wip`) are rejected too, because they would silently match nothing.
|
|
427
|
+
|
|
428
|
+
`tags()` is evaluated against Playwright's grep string (titles + tags), so, like Playwright itself, it treats `@words` in feature and scenario titles as tags. Use the `tags` config option when that matters.
|
|
429
|
+
|
|
335
430
|
### Predicate Filter
|
|
336
431
|
|
|
337
432
|
Use `filter` when you need arbitrary logic to select scenarios:
|
|
@@ -362,6 +457,8 @@ Gherkin tags are translated into Playwright [test details](https://playwright.de
|
|
|
362
457
|
| `@lock(name)` | `lock: 'name'` — scenarios sharing a lock never run concurrently |
|
|
363
458
|
| `@lock(-exclusive-)` | built-in exclusive lock — runs only when no other test is running |
|
|
364
459
|
| `@annotation(type,description)` | `annotation: { type, description }` — description is optional: `@annotation(flaky)` |
|
|
460
|
+
| `@timeout(ms)` | sets the test timeout, e.g. `@timeout(60000)`; overrides `@slow()`, the last tag wins (scenario over feature) |
|
|
461
|
+
| `@retries(n)` | number of retries for all scenarios of the feature — **Feature only**, using it on a Rule or Scenario is an error |
|
|
365
462
|
|
|
366
463
|
Modifiers are passed as annotations of type `skip`, `fixme`, `fail`, `slow`, which Playwright applies like `test.skip()` and the other modifiers, and the optional reason is shown in the report. Plain tags such as `@skip` or `@slow` are ordinary tags and do nothing. Tags set on a `Feature` or `Rule` apply to all its scenarios.
|
|
367
464
|
|
|
@@ -416,13 +513,31 @@ export default defineConfig({
|
|
|
416
513
|
|
|
417
514
|
Tag scenarios that must run serially with `@serial` (or any tag of your choice) and keep everything else fully parallel.
|
|
418
515
|
|
|
516
|
+
To run a single feature or scenario use `CUCUMBER_PATHS=features/login.feature npx playwright test` or `npx playwright test -g "Feature name"`. Passing a `.feature` path as a Playwright CLI argument does not work, because all scenarios are defined in `cucumber.config.ts`.
|
|
517
|
+
|
|
419
518
|
> To get the current worker index inside a step, use `this.test.info().parallelIndex`.
|
|
420
519
|
|
|
421
520
|
---
|
|
422
521
|
|
|
423
|
-
##
|
|
522
|
+
## Reports
|
|
523
|
+
|
|
524
|
+
- Scenarios are reported at their location in the `.feature` file (Scenario Outline examples point to their example row), so reporters and `--list` show `features/login.feature:12:3`.
|
|
525
|
+
- Steps point to their step definition; set `stepLocation: 'feature'` to point them to the step line in the `.feature` file instead.
|
|
526
|
+
- Steps are reported with a short preview of their argument: `I submit the form [DataTable: | field | value | | username | alice |]`.
|
|
527
|
+
- Features with the same name in different files get the file path appended to their title to keep test titles unique.
|
|
528
|
+
|
|
529
|
+
---
|
|
530
|
+
|
|
531
|
+
## Entrypoints and JavaScript Support
|
|
532
|
+
|
|
533
|
+
The package is compiled to CommonJS JavaScript with type declarations, so it works from TypeScript and plain JavaScript, with `require` and `import`. It has two entrypoints with the same API:
|
|
424
534
|
|
|
425
|
-
|
|
535
|
+
| Entrypoint | Difference |
|
|
536
|
+
|---|---|
|
|
537
|
+
| `@qavajs/playwright-runner-adapter` | ships source maps |
|
|
538
|
+
| `@qavajs/playwright-runner-adapter/js` | the same build without source maps — stack traces show the compiled `.js` files |
|
|
539
|
+
|
|
540
|
+
Plain JavaScript projects don't need any TypeScript setup with either entrypoint:
|
|
426
541
|
|
|
427
542
|
```javascript
|
|
428
543
|
// cucumber.config.js
|
|
@@ -441,6 +556,40 @@ const { Given, When, Then, PlaywrightWorld } = require('@qavajs/playwright-runne
|
|
|
441
556
|
|
|
442
557
|
---
|
|
443
558
|
|
|
559
|
+
## Timeouts
|
|
560
|
+
|
|
561
|
+
- The Playwright test timeout (`timeout` in `playwright.config.ts`, `@timeout(ms)` or `@slow()` tags) limits the whole scenario.
|
|
562
|
+
- A step or hook `{ timeout }` option limits that single step or hook, as in Cucumber:
|
|
563
|
+
|
|
564
|
+
```typescript
|
|
565
|
+
When('I upload a big file', { timeout: 60_000 }, async function () { /* ... */ });
|
|
566
|
+
Before({ tags: '@db', timeout: 10_000 }, async function () { /* ... */ });
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
- `setDefaultTimeout(ms)` sets the timeout for all steps and hooks without their own `{ timeout }`. Unlike Cucumber, there is no 5 second default: without `setDefaultTimeout` only the Playwright test timeout applies. `-1` disables the timeout for a definition.
|
|
570
|
+
|
|
571
|
+
---
|
|
572
|
+
|
|
573
|
+
## Supported Cucumber APIs
|
|
574
|
+
|
|
575
|
+
| API | Supported |
|
|
576
|
+
|---|---|
|
|
577
|
+
| `Given` / `When` / `Then` / `defineStep` (Cucumber expressions and RegExp) | ✅ |
|
|
578
|
+
| `Before` / `After` / `BeforeStep` / `AfterStep` (named, tagged) | ✅ |
|
|
579
|
+
| `BeforeAll` / `AfterAll` | ✅ once per worker |
|
|
580
|
+
| `setWorldConstructor` | ✅ |
|
|
581
|
+
| `defineParameterType` | ✅ |
|
|
582
|
+
| `setDefinitionFunctionWrapper` (incl. `wrapperOptions`) | ✅ |
|
|
583
|
+
| Data tables, doc strings | ✅ |
|
|
584
|
+
| Scenario Outline, Background, Rule (incl. Rule tags) | ✅ |
|
|
585
|
+
| Localized Gherkin (`# language: de`) | ✅ |
|
|
586
|
+
| `worldParameters`, `tags`, `strict` | ✅ |
|
|
587
|
+
| `setDefaultTimeout`, step and hook `{ timeout }` option | ✅ see [Timeouts](#timeouts) |
|
|
588
|
+
| `setParallelCanAssign` | ❌ see [Limitations](#limitations) |
|
|
589
|
+
| Cucumber formatters (`format`) | ❌ use Playwright [reporters](https://playwright.dev/docs/test-reporters) |
|
|
590
|
+
|
|
591
|
+
---
|
|
592
|
+
|
|
444
593
|
## Limitations
|
|
445
594
|
|
|
446
595
|
- **ES modules** — not supported for Node.js < 22 (where experimental ESM `require` is available). Use CommonJS or TypeScript with `ts-node`.
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import { APIRequestContext, Browser, BrowserContext, Page } from '@playwright/test';
|
|
2
|
-
import type { CucumberAdapterConfig, SupportCodeLibrary, WorldOptions } from './types';
|
|
2
|
+
import type { AttachFn, CucumberAdapterConfig, SupportCodeLibrary, WorldOptions } from './types';
|
|
3
3
|
export declare class TestWorld {
|
|
4
4
|
log: (data: unknown) => void;
|
|
5
|
-
attach:
|
|
6
|
-
fileName?: string;
|
|
7
|
-
mediaType?: string;
|
|
8
|
-
}) => Promise<void>;
|
|
5
|
+
attach: AttachFn;
|
|
9
6
|
parameters: unknown;
|
|
10
7
|
config: CucumberAdapterConfig;
|
|
11
8
|
supportCodeLibrary: SupportCodeLibrary;
|
|
12
9
|
test: import("@playwright/test").TestType<import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions, import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions>;
|
|
13
10
|
expect: import("@playwright/test").Expect<{}>;
|
|
14
11
|
constructor(options: WorldOptions);
|
|
15
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Execute step by its text
|
|
14
|
+
* @param text - step text
|
|
15
|
+
* @param argument - doc string (`string`), data table (`string[][]` or `DataTable`) or any extra parameter
|
|
16
|
+
*/
|
|
17
|
+
executeStep(this: TestWorld, text: string, argument?: unknown): Promise<void>;
|
|
16
18
|
}
|
|
17
19
|
export declare class PlaywrightWorld extends TestWorld {
|
|
18
20
|
page: Page;
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PlaywrightWorld = exports.TestWorld = void 0;
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
|
+
const gherkin_1 = require("./gherkin");
|
|
6
|
+
const timeout_1 = require("./timeout");
|
|
5
7
|
class TestWorld {
|
|
6
8
|
log;
|
|
7
9
|
attach;
|
|
@@ -17,7 +19,12 @@ class TestWorld {
|
|
|
17
19
|
this.supportCodeLibrary = options.supportCodeLibrary;
|
|
18
20
|
this.config = options.config;
|
|
19
21
|
}
|
|
20
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Execute step by its text
|
|
24
|
+
* @param text - step text
|
|
25
|
+
* @param argument - doc string (`string`), data table (`string[][]` or `DataTable`) or any extra parameter
|
|
26
|
+
*/
|
|
27
|
+
async executeStep(text, argument) {
|
|
21
28
|
const steps = this.supportCodeLibrary.stepDefinitions
|
|
22
29
|
.filter(s => s.matchesStepName(text));
|
|
23
30
|
if (steps.length === 0)
|
|
@@ -27,13 +34,19 @@ class TestWorld {
|
|
|
27
34
|
throw new Error(`Step "${text}" matches multiple step definitions:\n${locations}`);
|
|
28
35
|
}
|
|
29
36
|
const step = steps[0];
|
|
30
|
-
const {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
const { argument: pickleArgument, extra } = (0, gherkin_1.toPickleArgument)(argument);
|
|
38
|
+
const location = step.uri ? { file: step.uri, line: step.line, column: 1 } : undefined;
|
|
39
|
+
// reported as a nested step, so failures inside composite steps point to the exact inner step
|
|
40
|
+
await this.test.step((0, gherkin_1.stepTitle)({ text, argument: pickleArgument }), async () => {
|
|
41
|
+
const { parameters } = await step.getInvocationParameters({ step: { text, argument: pickleArgument }, world: this });
|
|
42
|
+
const args = extra === undefined ? parameters : [...parameters, extra];
|
|
43
|
+
try {
|
|
44
|
+
await (0, timeout_1.runWithTimeout)(() => step.code.apply(this, args), (0, timeout_1.resolveTimeout)(step, this.supportCodeLibrary.defaultTimeout), `Step '${text}' timed out after {timeout} ms\n at ${step.uri}:${step.line}`);
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
throw new Error(`Step failed: ${text}`, { cause: err });
|
|
48
|
+
}
|
|
49
|
+
}, { location });
|
|
37
50
|
}
|
|
38
51
|
}
|
|
39
52
|
exports.TestWorld = TestWorld;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlaywrightWorld.js","sourceRoot":"","sources":["../src/PlaywrightWorld.ts"],"names":[],"mappings":";;;AAAA,2CAAkG;
|
|
1
|
+
{"version":3,"file":"PlaywrightWorld.js","sourceRoot":"","sources":["../src/PlaywrightWorld.ts"],"names":[],"mappings":"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"}
|
package/adapter/Template.d.ts
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
|
+
export interface TemplateStep {
|
|
2
|
+
text: string;
|
|
3
|
+
argument?: string | string[][];
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Parse template text into steps. Supports data tables (`| a | b |` lines)
|
|
7
|
+
* and doc strings (`"""` or ``` blocks) placed after a step.
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseTemplate(scenario: string): TemplateStep[];
|
|
1
10
|
/**
|
|
2
11
|
* Define template step
|
|
3
|
-
* @param {string} scenario - multiline string with steps
|
|
12
|
+
* @param {string} scenario - multiline string with steps; steps can have data tables and doc strings
|
|
4
13
|
* @example
|
|
5
14
|
* When('I click {string} and verify {string}', Template((locator, expected) => `
|
|
6
15
|
* I click '${locator}'
|
|
7
16
|
* I expect '${locator} > Value' to equal '${expected}'
|
|
17
|
+
* I fill form
|
|
18
|
+
* | name | John |
|
|
8
19
|
* `));
|
|
9
20
|
*/
|
|
10
|
-
export declare function Template(scenario: (...args:
|
|
21
|
+
export declare function Template(scenario: (...args: any[]) => string): (...args: unknown[]) => string;
|
package/adapter/Template.js
CHANGED
|
@@ -1,25 +1,74 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseTemplate = parseTemplate;
|
|
3
4
|
exports.Template = Template;
|
|
5
|
+
const DOC_STRING_DELIMITERS = ['"""', '```'];
|
|
6
|
+
function parseRow(line) {
|
|
7
|
+
const content = line.replace(/^\|/, '').replace(/(?<!\\)\|$/, '');
|
|
8
|
+
return content
|
|
9
|
+
.split(/(?<!\\)\|/)
|
|
10
|
+
.map(cell => cell.trim().replace(/\\\|/g, '|'));
|
|
11
|
+
}
|
|
12
|
+
function stripIndent(line, indent) {
|
|
13
|
+
const leading = line.length - line.trimStart().length;
|
|
14
|
+
return line.slice(Math.min(indent, leading));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Parse template text into steps. Supports data tables (`| a | b |` lines)
|
|
18
|
+
* and doc strings (`"""` or ``` blocks) placed after a step.
|
|
19
|
+
*/
|
|
20
|
+
function parseTemplate(scenario) {
|
|
21
|
+
const lines = scenario.split('\n');
|
|
22
|
+
const steps = [];
|
|
23
|
+
const previousStep = (line) => {
|
|
24
|
+
const step = steps.at(-1);
|
|
25
|
+
if (!step)
|
|
26
|
+
throw new Error(`Template argument "${line.trim()}" must follow a step`);
|
|
27
|
+
return step;
|
|
28
|
+
};
|
|
29
|
+
for (let i = 0; i < lines.length; i++) {
|
|
30
|
+
const line = lines[i];
|
|
31
|
+
const trimmed = line.trim();
|
|
32
|
+
if (!trimmed)
|
|
33
|
+
continue;
|
|
34
|
+
const delimiter = DOC_STRING_DELIMITERS.find(d => trimmed.startsWith(d));
|
|
35
|
+
if (delimiter) {
|
|
36
|
+
const step = previousStep(line);
|
|
37
|
+
const indent = line.indexOf(delimiter);
|
|
38
|
+
const content = [];
|
|
39
|
+
for (i++; i < lines.length && lines[i].trim() !== delimiter; i++) {
|
|
40
|
+
content.push(stripIndent(lines[i], indent));
|
|
41
|
+
}
|
|
42
|
+
step.argument = content.join('\n');
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (trimmed.startsWith('|')) {
|
|
46
|
+
const step = previousStep(line);
|
|
47
|
+
if (!Array.isArray(step.argument))
|
|
48
|
+
step.argument = [];
|
|
49
|
+
step.argument.push(parseRow(trimmed));
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
steps.push({ text: trimmed });
|
|
53
|
+
}
|
|
54
|
+
return steps;
|
|
55
|
+
}
|
|
4
56
|
/**
|
|
5
57
|
* Define template step
|
|
6
|
-
* @param {string} scenario - multiline string with steps
|
|
58
|
+
* @param {string} scenario - multiline string with steps; steps can have data tables and doc strings
|
|
7
59
|
* @example
|
|
8
60
|
* When('I click {string} and verify {string}', Template((locator, expected) => `
|
|
9
61
|
* I click '${locator}'
|
|
10
62
|
* I expect '${locator} > Value' to equal '${expected}'
|
|
63
|
+
* I fill form
|
|
64
|
+
* | name | John |
|
|
11
65
|
* `));
|
|
12
66
|
*/
|
|
13
67
|
function Template(scenario) {
|
|
14
68
|
return new Proxy(scenario, {
|
|
15
69
|
apply: async function (template, world, args) {
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
.split('\n')
|
|
19
|
-
.map(step => step.trim())
|
|
20
|
-
.filter(Boolean);
|
|
21
|
-
for (const step of steps) {
|
|
22
|
-
await world.executeStep(step);
|
|
70
|
+
for (const step of parseTemplate(template(...args))) {
|
|
71
|
+
await world.executeStep(step.text, step.argument);
|
|
23
72
|
}
|
|
24
73
|
},
|
|
25
74
|
});
|
package/adapter/Template.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Template.js","sourceRoot":"","sources":["../src/Template.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Template.js","sourceRoot":"","sources":["../src/Template.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,9 @@
|
|
|
1
|
+
import type { Pickle } from '@cucumber/messages';
|
|
1
2
|
import type { CucumberAdapterConfig } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Create scenario filter from tag expressions keyed by their source (used in error messages),
|
|
5
|
+
* e.g. `{ 'tags option': config.tags, 'CUCUMBER_TAGS env variable': process.env.CUCUMBER_TAGS }`.
|
|
6
|
+
* All expressions must match.
|
|
7
|
+
*/
|
|
8
|
+
export declare function createTagFilter(sources: Record<string, string | undefined>): (pickle: Pickle) => boolean;
|
|
2
9
|
export declare function defineConfig(config: CucumberAdapterConfig): void;
|