@qavajs/cypress-runner-adapter 1.9.0 → 1.9.2

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
@@ -1,5 +1,9 @@
1
1
  # @qavajs/cypress-runner-adapter
2
- Adapter to run Gherkin tests via cypress test runner
2
+
3
+ Cypress preprocessor that compiles Gherkin `.feature` files into Cypress/Mocha test suites, enabling full BDD-style testing with Cucumber syntax inside Cypress.
4
+
5
+ [![npm](https://img.shields.io/npm/v/@qavajs/cypress-runner-adapter)](https://www.npmjs.com/package/@qavajs/cypress-runner-adapter)
6
+ [![license](https://img.shields.io/npm/l/@qavajs/cypress-runner-adapter)](LICENSE)
3
7
 
4
8
  ## Installation
5
9
 
@@ -7,7 +11,9 @@ Adapter to run Gherkin tests via cypress test runner
7
11
  npm install @qavajs/cypress-runner-adapter
8
12
  ```
9
13
 
10
- ## Basic Configuration
14
+ ## Configuration
15
+
16
+ Register the preprocessor in `cypress.config.js`:
11
17
 
12
18
  ```javascript
13
19
  const { defineConfig } = require('cypress');
@@ -18,39 +24,171 @@ module.exports = defineConfig({
18
24
  specPattern: 'cypress/feature/**/*.feature',
19
25
  supportFile: 'cypress/support/e2e.js',
20
26
  setupNodeEvents(on, config) {
21
- on('file:preprocessor', cucumber)
27
+ on('file:preprocessor', cucumber);
22
28
  },
23
29
  },
24
30
  });
25
31
  ```
26
32
 
27
- `support/e2e.js` is entry point with step definition;
33
+ ## Step Definitions
34
+
35
+ Define steps in your support file (e.g. `cypress/support/e2e.js`):
28
36
 
29
37
  ```javascript
30
- import { When, setWorldConstructor } from '@qavajs/cypress-runner-adapter';
38
+ import { Given, When, Then, setWorldConstructor, World } from '@qavajs/cypress-runner-adapter';
31
39
 
32
- class World {
33
- parameter = 42;
40
+ class CustomWorld extends World {
41
+ constructor(options) {
42
+ super(options);
43
+ this.myValue = null;
44
+ }
34
45
  }
35
46
 
36
- setWorldConstructor(World);
47
+ setWorldConstructor(CustomWorld);
37
48
 
38
- When('open {string} url', function (url) {
49
+ Given('I navigate to {string}', function (url) {
39
50
  cy.visit(url);
40
51
  });
52
+
53
+ When('I click {string}', function (selector) {
54
+ cy.get(selector).click();
55
+ });
56
+
57
+ Then('{string} should be visible', function (selector) {
58
+ cy.get(selector).should('be.visible');
59
+ });
60
+ ```
61
+
62
+ ## Hooks
63
+
64
+ All standard Cucumber hooks are supported. Hooks receive a `params` object with context about the current test.
65
+
66
+ ```javascript
67
+ import { Before, After, BeforeStep, AfterStep, BeforeAll, AfterAll } from '@qavajs/cypress-runner-adapter';
68
+
69
+ BeforeAll(function () {
70
+ // runs once before all tests
71
+ });
72
+
73
+ Before(function ({ gherkinDocument, pickle, testCaseStartedId }) {
74
+ // runs before each scenario
75
+ });
76
+
77
+ Before({ tags: '@login' }, function () {
78
+ // runs before scenarios tagged with @login
79
+ });
80
+
81
+ Before({ name: 'setup' }, function () {
82
+ // named hook
83
+ });
84
+
85
+ BeforeStep(function ({ testStepId }) {
86
+ // runs before each step
87
+ });
88
+
89
+ AfterStep(function ({ result }) {
90
+ // runs after each step
91
+ });
92
+
93
+ After(function ({ result, error }) {
94
+ // runs after each scenario
95
+ });
96
+
97
+ AfterAll(function () {
98
+ // runs once after all tests
99
+ });
100
+ ```
101
+
102
+ ## Parameter Types
103
+
104
+ Define custom parameter types using `defineParameterType`:
105
+
106
+ ```javascript
107
+ import { defineParameterType } from '@qavajs/cypress-runner-adapter';
108
+
109
+ defineParameterType({
110
+ name: 'color',
111
+ regexp: /(red|blue|green)/,
112
+ transformer: color => color.toUpperCase()
113
+ });
114
+
115
+ // usage in step definition:
116
+ // When('I select {color} theme', function (color) { ... });
117
+ ```
118
+
119
+ ## World
120
+
121
+ The `World` class is instantiated for each scenario and is available as `this` inside step definitions and hooks. Extend it to share state across steps within a scenario.
122
+
123
+ | Property / Method | Description |
124
+ |---|---|
125
+ | `this.log(message)` | Log a message to the Cypress command log |
126
+ | `this.attach(data)` | Attach data to the test report |
127
+ | `this.link(url)` | Attach a link to the test report |
128
+ | `this.executeStep(text)` | Programmatically execute a step by its text |
129
+
130
+ ```javascript
131
+ import { When, World, setWorldConstructor } from '@qavajs/cypress-runner-adapter';
132
+
133
+ class AppWorld extends World {
134
+ constructor(options) {
135
+ super(options);
136
+ this.userId = null;
137
+ }
138
+ }
139
+
140
+ setWorldConstructor(AppWorld);
141
+
142
+ When('I store user {string}', function (id) {
143
+ this.userId = id;
144
+ });
145
+
146
+ When('I use stored user', function () {
147
+ cy.log(this.userId);
148
+ });
149
+
150
+ When('I execute another step', function () {
151
+ this.executeStep('I navigate to "https://example.com"');
152
+ });
41
153
  ```
42
154
 
43
- ## Tags
44
- Test can be filtered using Cucumber tag expressions provided via environment variable `TAGS`
155
+ ## Template Steps
156
+
157
+ `Template` composes a step from other steps using a multiline string. The function receives the same arguments as the step and returns the steps to execute:
158
+
159
+ ```javascript
160
+ import { When, Template } from '@qavajs/cypress-runner-adapter';
161
+
162
+ When('I search for {string} on Wikipedia', Template(term => `
163
+ I navigate to 'https://en.wikipedia.org/'
164
+ I search '${term}'
165
+ `));
45
166
  ```
46
- TAGS='@first and @second' npx cypress run
167
+
168
+ ## Tag Filtering
169
+
170
+ Filter scenarios using Cucumber tag expressions via the `TAGS` environment variable:
171
+
172
+ ```bash
173
+ TAGS='@smoke' npx cypress run
174
+ TAGS='@smoke and not @slow' npx cypress run
175
+ TAGS='@login or @auth' npx cypress run
47
176
  ```
48
177
 
49
- ## Translation Mode
50
- Gherkin tests can be translated in different modes
51
- - `describe` - default mode. Scenario will be translated as `describe`, each step will be translated as `it`
52
- - `it` - Scenario will be translated as `it`
178
+ ## Translation Modes
179
+
180
+ Controls how Gherkin scenarios are mapped to Mocha constructs. Set via the `MODE` environment variable.
181
+
182
+ | Mode | Scenario maps to | Steps map to |
183
+ |---|---|---|
184
+ | `describe` (default) | `describe` | `it` |
185
+ | `it` | `it` | _(inline)_ |
53
186
 
54
187
  ```bash
188
+ # default (describe) mode
189
+ npx cypress run
190
+
191
+ # it mode
192
+ MODE=it npx cypress run
55
193
  MODE=it npx cypress open
56
- ```
194
+ ```
package/adapter/index.js CHANGED
@@ -1,4 +1,5 @@
1
- const { ensureFileSync, writeFileSync, readFileSync } = require('fs-extra');
1
+ const { mkdirSync, writeFileSync, readFileSync } = require('node:fs');
2
+ const { dirname } = require('node:path');
2
3
  const { randomUUID } = require('node:crypto');
3
4
  const { AstBuilder, compile, GherkinClassicTokenMatcher, Parser } = require('@cucumber/gherkin');
4
5
  const webpackPreprocessor = require('@cypress/webpack-preprocessor')();
@@ -18,7 +19,7 @@ function adapter(testCases) {
18
19
  }
19
20
 
20
21
  module.exports = async function cucumber(file) {
21
- const { filePath, outputPath, shouldWatch } = file;
22
+ const { filePath, outputPath } = file;
22
23
  if (!filePath.endsWith('.feature')) {
23
24
  return webpackPreprocessor(file);
24
25
  }
@@ -26,7 +27,7 @@ module.exports = async function cucumber(file) {
26
27
  const tagExpression = tagExpressionParser(process.env.TAGS || '');
27
28
  const testCases = compile(gherkinDocument, filePath, uuidFn)
28
29
  .filter(test => tagExpression.evaluate(test.tags.map(tag => tag.name)));
29
- ensureFileSync(outputPath);
30
+ mkdirSync(dirname(outputPath), { recursive: true });
30
31
  writeFileSync(outputPath, adapter(testCases), 'utf-8');
31
32
  return outputPath;
32
33
  }
@@ -155,7 +155,7 @@ module.exports = function makeMochaTest(tests) {
155
155
  it('Scenario: ' + test.name, function () {
156
156
  const world = this.world;
157
157
  for (const step of test.steps) {
158
- runStep({ keyword: keyword(step), name: stepNameText(step) }, function () {
158
+ runStep({ keyword: keyword(step), name: stepNameText(step) }, () => {
159
159
  this.step = step;
160
160
  const result = { status: 'passed', duration: 0 };
161
161
  for (const beforeStep of supportCodeLibrary.beforeTestStepHookDefinitions) {
package/adapter.d.ts CHANGED
@@ -1 +1 @@
1
- export default function (file: any): void;
1
+ export default function (file: any): Promise<any>;
package/index.d.ts CHANGED
@@ -13,7 +13,6 @@ declare type ParameterTypeOption = {
13
13
  transformer?: Function,
14
14
  useForSnippets?: boolean
15
15
  }
16
- declare interface IWorld {}
17
16
  export function Given(expression: Expression, fn: Function): void;
18
17
  export function When(expression: Expression, fn: Function): void;
19
18
  export function Then(expression: Expression, fn: Function): void;
@@ -31,6 +30,10 @@ export function setWorldConstructor(world: IWorld): void;
31
30
  export function defineParameterType(option: ParameterTypeOption): void;
32
31
  export function Template(template: (...args: any[]) => string): () => void;
33
32
  export class World {
33
+ log: (...args: any) => void;
34
+ attach: (...args: any) => void;
35
+ link: (...args: any) => void;
36
+ executeStep(text: string, argument?: any): void;
34
37
  constructor(options: {
35
38
  log: (...args: any) => void;
36
39
  attach: (...args: any) => void;
package/package.json CHANGED
@@ -1,7 +1,17 @@
1
1
  {
2
2
  "name": "@qavajs/cypress-runner-adapter",
3
- "version": "1.9.0",
4
- "main": "index.js",
3
+ "version": "1.9.2",
4
+ "main": "supportCodeLibrary/index.js",
5
+ "exports": {
6
+ ".": "./supportCodeLibrary/index.js",
7
+ "./adapter": "./adapter/index.js"
8
+ },
9
+ "files": [
10
+ "adapter",
11
+ "supportCodeLibrary",
12
+ "index.d.ts",
13
+ "adapter.d.ts"
14
+ ],
5
15
  "scripts": {
6
16
  "debug": "cypress open --config-file test/cypress.config.js",
7
17
  "test": "cypress run --config-file test/cypress.config.js",
@@ -25,12 +35,10 @@
25
35
  "@cucumber/cucumber-expressions": "^19.0.0",
26
36
  "@cucumber/gherkin": "^39.0.0",
27
37
  "@cucumber/tag-expressions": "^9.1.0",
28
- "@cypress/webpack-preprocessor": "^7.0.2",
29
- "fs-extra": "^11.3.4"
38
+ "@cypress/webpack-preprocessor": "^7.1.0"
30
39
  },
31
40
  "devDependencies": {
32
- "cypress": "^15.11.0",
33
- "mochawesome": "^7.1.4"
41
+ "cypress": "^15.13.0"
34
42
  },
35
43
  "keywords": [
36
44
  "cypress",
@@ -42,4 +50,4 @@
42
50
  "test",
43
51
  "test-automation"
44
52
  ]
45
- }
53
+ }
@@ -47,6 +47,6 @@ export default class DataTable {
47
47
  const transposed = this.rawTable[0].map((x, i) =>
48
48
  this.rawTable.map((y) => y[i])
49
49
  )
50
- return new Data_table(transposed)
50
+ return new DataTable(transposed)
51
51
  }
52
52
  }
@@ -52,8 +52,7 @@ export function Given(pattern, code) {
52
52
  }
53
53
 
54
54
  export function Before(optionsOrCode, code) {
55
- const defaultOptions = { name: 'Before' };
56
- const options = code ? Object.assign(defaultOptions, optionsOrCode) : defaultOptions;
55
+ const options = code ? Object.assign({ name: 'Before' }, optionsOrCode) : { name: 'Before' };
57
56
  const handler = code ?? optionsOrCode;
58
57
  supportCodeLibrary.beforeTestCaseHookDefinitions.push(new TestCaseHookDefinition({
59
58
  code: handler,
@@ -62,8 +61,7 @@ export function Before(optionsOrCode, code) {
62
61
  }
63
62
 
64
63
  export function After(optionsOrCode, code) {
65
- const defaultOptions = { name: 'After' };
66
- const options = code ? Object.assign(defaultOptions, optionsOrCode) : defaultOptions;
64
+ const options = code ? Object.assign({ name: 'After' }, optionsOrCode) : { name: 'After' };
67
65
  const handler = code ?? optionsOrCode;
68
66
  supportCodeLibrary.afterTestCaseHookDefinitions.push(new TestCaseHookDefinition({
69
67
  code: handler,
@@ -13,8 +13,4 @@ export class SourcedParameterTypeRegistry extends ParameterTypeRegistry {
13
13
  this.defineParameterType(parameterType)
14
14
  this.parameterTypeToSource.set(parameterType, source)
15
15
  }
16
-
17
- lookupSource(parameterType) {
18
- return this.parameterTypeToSource.get(parameterType)
19
- }
20
16
  }
@@ -21,8 +21,6 @@ export default class StepDefinition extends Definition {
21
21
  parameters.push(argumentParameter)
22
22
  }
23
23
  return {
24
- getInvalidCodeLengthMessage: () =>
25
- this.baseGetInvalidCodeLengthMessage(parameters),
26
24
  parameters,
27
25
  validCodeLengths: [parameters.length, parameters.length + 1],
28
26
  }
@@ -5,7 +5,7 @@ export default class TestCaseHookDefinition extends Definition {
5
5
 
6
6
  constructor(data) {
7
7
  super(data)
8
- this.name = data.options.name
8
+ this.name = data.options.name ?? 'Hook'
9
9
  this.tagExpression = data.options.tags
10
10
  this.pickleTagFilter = new PickleTagFilter(data.options.tags)
11
11
  }
@@ -13,13 +13,4 @@ export default class TestCaseHookDefinition extends Definition {
13
13
  appliesToTestCase(pickle) {
14
14
  return this.pickleTagFilter.matchesAllTagExpressions(pickle)
15
15
  }
16
-
17
- async getInvocationParameters({ hookParameter }) {
18
- return {
19
- getInvalidCodeLengthMessage: () =>
20
- this.buildInvalidCodeLengthMessage('0 or 1', '2'),
21
- parameters: [hookParameter],
22
- validCodeLengths: [0, 1, 2],
23
- }
24
- }
25
16
  }
@@ -11,13 +11,4 @@ export default class TestStepHookDefinition extends Definition {
11
11
  appliesToTestCase(pickle) {
12
12
  return this.pickleTagFilter.matchesAllTagExpressions(pickle)
13
13
  }
14
-
15
- async getInvocationParameters({ hookParameter }) {
16
- return {
17
- getInvalidCodeLengthMessage: () =>
18
- this.buildInvalidCodeLengthMessage('0 or 1', '2'),
19
- parameters: [hookParameter],
20
- validCodeLengths: [0, 1, 2],
21
- }
22
- }
23
14
  }
package/CHANGELOG.md DELETED
@@ -1,82 +0,0 @@
1
- # Change Log
2
-
3
- All notable changes to the "@qavajs/cypress-runner-adapter" will be documented in this file.
4
-
5
- Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
6
-
7
- :rocket: - new feature
8
-
9
- :beetle: - bugfix
10
-
11
- :x: - deprecation/removal
12
-
13
- :pencil: - chore
14
-
15
- :microscope: - experimental
16
-
17
- ## [1.9.0]
18
- - :rocket: added step log groups for `it` mode
19
-
20
- ## [1.8.0]
21
- - :rocket: added `testCaseStartedId` and `testStepId` as hooks parameters to comply cucumber spec
22
-
23
- ## [1.7.0]
24
- - :rocket: updated @cucumber/cucumber-expressions, @cucumber/gherkin, @cucumber/tag-expressions
25
-
26
- ## [1.6.0]
27
- - :rocket: updated logs for Gherkin steps
28
- - :rocket: improved multi line and data table step logging
29
-
30
- ## [1.5.0]
31
- - :rocket: added `world.log` method
32
- - :rocket: updated test.body to render corresponding step code
33
-
34
- ## [1.4.2]
35
- - :pencil: updated to cypress 15.7.0
36
- - :pencil: updated to gherkin to 37.0.0
37
-
38
- ## [1.4.1]
39
- - :beetle: fixed `result` property in `After` and `AfterStep` hooks
40
- - :rocket: added workaround to complete `AfterStep` hook in case of step fail
41
-
42
- ## [1.4.0]
43
- - :rocket: added `Template` utility function
44
- ```typescript
45
- import { When, Template } from '@qavajs/playwright-runner-adapter';
46
-
47
- When('I click {string} and verify {string}', Template((locator, expected) => `
48
- I click '${locator}'
49
- I expect '${locator} > Value' to equal '${expected}'
50
- `));
51
- ```
52
-
53
- ## [1.3.0]
54
- - :rocket: added tags support
55
- - :rocket: added alternative 'it mode' to translate gherkin tests to mocha `it` instead of `describe`
56
- ```bash
57
- MODE=it npx cypress open
58
- ```
59
-
60
- ## [1.2.1]
61
- - :pencil: updated to cypress 15.3
62
-
63
- ## [1.2.0]
64
- - :pencil: updated to cypress 15
65
-
66
- ## [1.1.0]
67
- - :pencil: updated to cypress 14
68
-
69
- ## [1.0.1]
70
- - :pencil: updated dependencies
71
-
72
- ## [1.0.0]
73
- - :rocket: added `this.executeStep` world method
74
-
75
- ## [0.2.0]
76
- - :rocket: added _BeforeAll_ and _AfterAll_ hooks support
77
-
78
- ## [0.1.1]
79
- - :beetle: changed browserify to webpack
80
-
81
- ## [0.1.0]
82
- - :rocket: initial implementation
package/adapter.js DELETED
@@ -1 +0,0 @@
1
- module.exports = require('./adapter/index');
package/index.js DELETED
@@ -1 +0,0 @@
1
- module.exports = require('./supportCodeLibrary');