@flakiness/cucumberjs 1.0.0-alpha.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/.github/workflows/flakiness-upload-fork-prs.yml +30 -0
- package/.github/workflows/publish-npm.yml +41 -0
- package/.github/workflows/tests.yml +45 -0
- package/CONTRIBUTING.md +58 -0
- package/LICENSE +21 -0
- package/agenda.md +2 -0
- package/build.mts +34 -0
- package/cucumber.mjs +6 -0
- package/features/attachments.feature +32 -0
- package/features/basic.feature +27 -0
- package/features/data_tables.feature +45 -0
- package/features/description.feature +49 -0
- package/features/errors.feature +28 -0
- package/features/hooks_named.feature +32 -0
- package/features/hooks_unnamed.feature +33 -0
- package/features/locations.feature +37 -0
- package/features/retries.feature +30 -0
- package/features/rules.feature +25 -0
- package/features/scenario_outlines.feature +57 -0
- package/features/scenario_outlines_multiple.feature +44 -0
- package/features/statuses.feature +70 -0
- package/features/stdio.feature +29 -0
- package/features/steps.feature +24 -0
- package/features/support/attachments_steps.ts +32 -0
- package/features/support/basic_steps.ts +235 -0
- package/features/support/description_steps.ts +37 -0
- package/features/support/errors_steps.ts +48 -0
- package/features/support/harness.ts +196 -0
- package/features/support/project_steps.ts +24 -0
- package/features/support/stdio_steps.ts +21 -0
- package/features/support/tags_steps.ts +10 -0
- package/features/tags.feature +19 -0
- package/features/tags_hierarchy.feature +37 -0
- package/package.json +37 -0
- package/plan.md +59 -0
- package/pnpm-workspace.yaml +2 -0
- package/src/formatter.ts +635 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Upload Flakiness.io report (fork PRs)
|
|
2
|
+
on:
|
|
3
|
+
workflow_run:
|
|
4
|
+
# Must match the name(s) of workflows that produce flakiness-report artifacts
|
|
5
|
+
workflows: ["Tests"]
|
|
6
|
+
types: [completed]
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
upload-flakiness-report:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
if: >-
|
|
12
|
+
(github.event.workflow_run.conclusion == 'success' || github.event.workflow_run.conclusion == 'failure')
|
|
13
|
+
&& github.event.workflow_run.event == 'pull_request'
|
|
14
|
+
&& github.event.workflow_run.head_repository.full_name != github.event.workflow_run.repository.full_name
|
|
15
|
+
permissions:
|
|
16
|
+
actions: read
|
|
17
|
+
contents: read
|
|
18
|
+
id-token: write
|
|
19
|
+
steps:
|
|
20
|
+
- name: Install Flakiness CLI
|
|
21
|
+
run: curl -LsSf https://cli.flakiness.io/install.sh | sh
|
|
22
|
+
|
|
23
|
+
- name: Download flakiness-report artifacts
|
|
24
|
+
env:
|
|
25
|
+
GH_TOKEN: ${{ github.token }}
|
|
26
|
+
RUN_ID: ${{ github.event.workflow_run.id }}
|
|
27
|
+
run: gh run download "$RUN_ID" --repo "$GITHUB_REPOSITORY" --pattern 'flakiness-report-*' --dir .
|
|
28
|
+
|
|
29
|
+
- name: Upload to Flakiness.io
|
|
30
|
+
run: find . -path '*/flakiness-report-*/report.json' -exec flakiness upload {} \;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: Publish to NPM
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
id-token: write # Required for OIDC
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
publish-to-npm:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Setup Node.js
|
|
19
|
+
uses: actions/setup-node@v4
|
|
20
|
+
with:
|
|
21
|
+
node-version: 24
|
|
22
|
+
|
|
23
|
+
- name: Setup PNPM
|
|
24
|
+
uses: pnpm/action-setup@v4
|
|
25
|
+
with:
|
|
26
|
+
version: 10
|
|
27
|
+
|
|
28
|
+
- name: Build & Publish
|
|
29
|
+
run: |
|
|
30
|
+
pnpm i --frozen-lockfile
|
|
31
|
+
pnpm build
|
|
32
|
+
|
|
33
|
+
VERSION=${GITHUB_REF_NAME#v}
|
|
34
|
+
|
|
35
|
+
if [[ "$VERSION" == *"-"* ]]; then
|
|
36
|
+
echo "Publishing prerelease to @next"
|
|
37
|
+
pnpm publish --access=public --no-git-checks --tag next
|
|
38
|
+
else
|
|
39
|
+
echo "Publishing stable to @latest"
|
|
40
|
+
pnpm publish --access=public --no-git-checks
|
|
41
|
+
fi
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
id-token: write
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
test:
|
|
15
|
+
strategy:
|
|
16
|
+
fail-fast: false
|
|
17
|
+
matrix:
|
|
18
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
19
|
+
runs-on: ${{ matrix.os }}
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- name: Setup pnpm
|
|
24
|
+
uses: pnpm/action-setup@v4
|
|
25
|
+
with:
|
|
26
|
+
version: 10
|
|
27
|
+
|
|
28
|
+
- uses: actions/setup-node@v4
|
|
29
|
+
with:
|
|
30
|
+
node-version: lts/*
|
|
31
|
+
cache: pnpm
|
|
32
|
+
|
|
33
|
+
# Since tests initialize git repositories, we have
|
|
34
|
+
# to configure git to avoid warnings.
|
|
35
|
+
- run: git config --global init.defaultBranch main
|
|
36
|
+
- run: pnpm install --frozen-lockfile
|
|
37
|
+
- run: pnpm build
|
|
38
|
+
- run: pnpm test
|
|
39
|
+
- name: Upload Flakiness report artifact (for Pull Requests from forks)
|
|
40
|
+
if: always() && github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork
|
|
41
|
+
uses: actions/upload-artifact@v4
|
|
42
|
+
with:
|
|
43
|
+
name: flakiness-report-${{ github.job }}-${{ strategy.job-index }}
|
|
44
|
+
path: flakiness-report/
|
|
45
|
+
retention-days: 1
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Prerequisites
|
|
4
|
+
|
|
5
|
+
- Node.js 22+
|
|
6
|
+
- [pnpm](https://pnpm.io/)
|
|
7
|
+
|
|
8
|
+
## Getting Started
|
|
9
|
+
|
|
10
|
+
Clone the repo and install dependencies:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
git clone https://github.com/flakiness/cucumberjs.git fk-cucumber
|
|
14
|
+
cd fk-cucumber
|
|
15
|
+
pnpm install
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Building
|
|
19
|
+
|
|
20
|
+
This project uses [Kubik](https://github.com/flakiness/kubik) as its build system. The build script is defined in `build.mts`.
|
|
21
|
+
|
|
22
|
+
To build:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pnpm build
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
To watch:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pnpm build -w
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
This will bundle the source with esbuild and generate TypeScript declarations.
|
|
35
|
+
|
|
36
|
+
## Releasing
|
|
37
|
+
|
|
38
|
+
To release a new version:
|
|
39
|
+
|
|
40
|
+
1. Bump the version:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# For a stable minor release
|
|
44
|
+
pnpm version minor
|
|
45
|
+
|
|
46
|
+
# For an alpha pre-release
|
|
47
|
+
pnpm version preminor --preid=alpha
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
2. Push the commit and tag:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
git push --follow-tags
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
3. [Create a GitHub Release](https://github.com/flakiness/cucumberjs/releases/new) for the new tag and publish it.
|
|
57
|
+
|
|
58
|
+
CI will handle publishing to npm. Pre-releases are published under @next tag.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023-2026 Degu Labs, Inc
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/agenda.md
ADDED
package/build.mts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env pnpm kubik
|
|
2
|
+
|
|
3
|
+
import esbuild from 'esbuild';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import { Task } from 'kubik';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
|
|
8
|
+
const { __dirname, $ } = Task.init(import.meta, {
|
|
9
|
+
name: 'cucubmer',
|
|
10
|
+
watch: [ './src' ],
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const outDir = path.join(__dirname, 'lib');
|
|
14
|
+
const typesDir = path.join(__dirname, 'types');
|
|
15
|
+
const srcDir = path.join(__dirname, 'src');
|
|
16
|
+
await fs.promises.rm(outDir, { recursive: true, force: true });
|
|
17
|
+
await fs.promises.rm(typesDir, { recursive: true, force: true });
|
|
18
|
+
|
|
19
|
+
const { errors } = await esbuild.build({
|
|
20
|
+
color: true,
|
|
21
|
+
entryPoints: [
|
|
22
|
+
path.join(srcDir, 'formatter.ts'),
|
|
23
|
+
],
|
|
24
|
+
outdir: outDir,
|
|
25
|
+
format: 'esm',
|
|
26
|
+
platform: 'node',
|
|
27
|
+
target: ['node22'],
|
|
28
|
+
sourcemap: true,
|
|
29
|
+
bundle: false,
|
|
30
|
+
minify: false,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
if (!errors.length)
|
|
34
|
+
await $`tsc --pretty -p .`;
|
package/cucumber.mjs
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
Feature: Attachments
|
|
2
|
+
Scenario: captures Cucumber attachments
|
|
3
|
+
Given the project file "features/attachments.feature":
|
|
4
|
+
"""
|
|
5
|
+
Feature: Attachments
|
|
6
|
+
Scenario: it attaches data
|
|
7
|
+
Given a step with attachments
|
|
8
|
+
"""
|
|
9
|
+
And the project file "features/support/steps.js":
|
|
10
|
+
"""
|
|
11
|
+
const { Given } = require('@cucumber/cucumber');
|
|
12
|
+
Given('a step with attachments', function() {
|
|
13
|
+
this.attach('hello attachment', { mediaType: 'text/plain', fileName: 'note.txt' });
|
|
14
|
+
this.attach(Buffer.from('{"ok":true}', 'utf8'), { mediaType: 'application/json', fileName: 'data.json' });
|
|
15
|
+
});
|
|
16
|
+
"""
|
|
17
|
+
When I generate the Flakiness report for "scenario with attachments"
|
|
18
|
+
When I look at the test named "it attaches data"
|
|
19
|
+
Then the test contains 1 attempt
|
|
20
|
+
When I look at the attempt #1
|
|
21
|
+
Then the attempt contains 2 attachments
|
|
22
|
+
And the report contains 0 missing attachments
|
|
23
|
+
|
|
24
|
+
When I look at the attachment #1
|
|
25
|
+
Then the attachment is called "note.txt"
|
|
26
|
+
And the attachment has content type "text/plain"
|
|
27
|
+
And the stored attachment has text "hello attachment"
|
|
28
|
+
|
|
29
|
+
When I look at the attachment #2
|
|
30
|
+
Then the attachment is called "data.json"
|
|
31
|
+
And the attachment has content type "application/json"
|
|
32
|
+
And the stored attachment has text "{\"ok\":true}"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Feature: Basic Functionality
|
|
2
|
+
Scenario: generates a basic report
|
|
3
|
+
Given the project file "features/passing.feature":
|
|
4
|
+
"""
|
|
5
|
+
Feature: Passing Test Suite
|
|
6
|
+
Scenario: it passes
|
|
7
|
+
Given a passing step
|
|
8
|
+
"""
|
|
9
|
+
And the project file "features/support/steps.js":
|
|
10
|
+
"""
|
|
11
|
+
const { Given } = require('@cucumber/cucumber');
|
|
12
|
+
Given('a passing step', function() {});
|
|
13
|
+
"""
|
|
14
|
+
And the environment variable "BUILD_URL" is "https://ci.example.test/build/123"
|
|
15
|
+
When I generate the Flakiness report for "passing scenario"
|
|
16
|
+
Then the report should contain the basic metadata
|
|
17
|
+
And the report hierarchy is:
|
|
18
|
+
"""
|
|
19
|
+
`- file passing.feature
|
|
20
|
+
`- suite Passing Test Suite
|
|
21
|
+
`- test it passes
|
|
22
|
+
`- attempt #1 passed
|
|
23
|
+
`- step Given a passing step
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
When I look at the test named "it passes"
|
|
27
|
+
Then the test is in file "features/passing.feature" at line 2
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
Feature: Data Tables
|
|
2
|
+
Scenario: keeps step titles single-line for data tables
|
|
3
|
+
Given the project file "features/data-table.feature":
|
|
4
|
+
"""
|
|
5
|
+
Feature: Data table
|
|
6
|
+
|
|
7
|
+
Scenario: addition
|
|
8
|
+
Given a table
|
|
9
|
+
| a | b | result |
|
|
10
|
+
| 2 | 2 | 4 |
|
|
11
|
+
| 1 | 7 | 8 |
|
|
12
|
+
When I add the values
|
|
13
|
+
Then I get the expected results
|
|
14
|
+
"""
|
|
15
|
+
And the project file "features/support/steps.js":
|
|
16
|
+
"""
|
|
17
|
+
const assert = require('node:assert/strict');
|
|
18
|
+
const { Given, When, Then } = require('@cucumber/cucumber');
|
|
19
|
+
|
|
20
|
+
Given('a table', function(dataTable) {
|
|
21
|
+
this.rows = dataTable.hashes().map(row => ({
|
|
22
|
+
a: Number(row.a),
|
|
23
|
+
b: Number(row.b),
|
|
24
|
+
result: Number(row.result),
|
|
25
|
+
}));
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
When('I add the values', function() {
|
|
29
|
+
this.results = this.rows.map(row => row.a + row.b);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
Then('I get the expected results', function() {
|
|
33
|
+
assert.deepEqual(this.results, this.rows.map(row => row.result));
|
|
34
|
+
});
|
|
35
|
+
"""
|
|
36
|
+
When I generate the Flakiness report for "scenario with a data table"
|
|
37
|
+
When I look at the test named "addition"
|
|
38
|
+
Then the test contains 1 attempt
|
|
39
|
+
When I look at the attempt #1
|
|
40
|
+
Then the attempt contains 3 steps:
|
|
41
|
+
"""
|
|
42
|
+
Given a table
|
|
43
|
+
When I add the values
|
|
44
|
+
Then I get the expected results
|
|
45
|
+
"""
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
Feature: Descriptions
|
|
2
|
+
|
|
3
|
+
Scenario: captures native Gherkin descriptions as annotations
|
|
4
|
+
Given the project file "features/help-center.feature":
|
|
5
|
+
"""
|
|
6
|
+
Feature: Help center
|
|
7
|
+
These scenarios describe what support agents can read.
|
|
8
|
+
They should stay visible in the report.
|
|
9
|
+
|
|
10
|
+
Scenario: opens a pinned article
|
|
11
|
+
Support agents can inspect a pinned article before replying.
|
|
12
|
+
Given a pinned article exists
|
|
13
|
+
|
|
14
|
+
Scenario: lists pinned articles
|
|
15
|
+
Given several pinned articles exist
|
|
16
|
+
"""
|
|
17
|
+
And the project file "features/support/steps.js":
|
|
18
|
+
"""
|
|
19
|
+
const { Given } = require('@cucumber/cucumber');
|
|
20
|
+
|
|
21
|
+
Given('a pinned article exists', function() {});
|
|
22
|
+
Given('several pinned articles exist', function() {});
|
|
23
|
+
"""
|
|
24
|
+
When I generate the Flakiness report for "descriptions"
|
|
25
|
+
|
|
26
|
+
When I look at the test named "opens a pinned article"
|
|
27
|
+
Then the test contains 1 attempt
|
|
28
|
+
When I look at the attempt #1
|
|
29
|
+
Then the attempt contains 2 annotations
|
|
30
|
+
And the attempt has an annotation "feature" with description:
|
|
31
|
+
"""
|
|
32
|
+
These scenarios describe what support agents can read.
|
|
33
|
+
They should stay visible in the report.
|
|
34
|
+
"""
|
|
35
|
+
And the attempt has an annotation "scenario" with description:
|
|
36
|
+
"""
|
|
37
|
+
Support agents can inspect a pinned article before replying.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
When I look at the test named "lists pinned articles"
|
|
41
|
+
Then the test contains 1 attempt
|
|
42
|
+
When I look at the attempt #1
|
|
43
|
+
Then the attempt contains 1 annotation
|
|
44
|
+
And the attempt has an annotation "feature" with description:
|
|
45
|
+
"""
|
|
46
|
+
These scenarios describe what support agents can read.
|
|
47
|
+
They should stay visible in the report.
|
|
48
|
+
"""
|
|
49
|
+
And the attempt has no annotation "scenario"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
Feature: Errors
|
|
2
|
+
Scenario: captures thrown errors
|
|
3
|
+
Given the project file "features/failing.feature":
|
|
4
|
+
"""
|
|
5
|
+
Feature: Failing
|
|
6
|
+
Scenario: it fails
|
|
7
|
+
Given a step that throws an error
|
|
8
|
+
"""
|
|
9
|
+
And the project file "features/support/steps.js":
|
|
10
|
+
"""
|
|
11
|
+
const { Given } = require('@cucumber/cucumber');
|
|
12
|
+
Given('a step that throws an error', function() {
|
|
13
|
+
throw new Error('intentional failure');
|
|
14
|
+
});
|
|
15
|
+
"""
|
|
16
|
+
When I generate the Flakiness report for "failing scenario"
|
|
17
|
+
When I look at the test named "it fails"
|
|
18
|
+
Then the test contains 1 attempt
|
|
19
|
+
When I look at the "failed" attempt
|
|
20
|
+
# Make sure the attempt has error
|
|
21
|
+
Then the attempt contains 1 error
|
|
22
|
+
And the attempt error #1 has message "intentional failure"
|
|
23
|
+
And the attempt error #1 has a stack trace
|
|
24
|
+
|
|
25
|
+
# Make sure the same error exists in step too
|
|
26
|
+
Then the attempt contains 1 step
|
|
27
|
+
When I look at the step named "Given a step that throws an error"
|
|
28
|
+
And the step has an error with message "intentional failure"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
Feature: Named Hooks
|
|
2
|
+
Scenario: captures named hooks
|
|
3
|
+
Given the project file "features/passing.feature":
|
|
4
|
+
"""
|
|
5
|
+
Feature: Hooks
|
|
6
|
+
Scenario: it runs named hooks
|
|
7
|
+
Given a passing step
|
|
8
|
+
"""
|
|
9
|
+
And the project file "features/support/steps.js":
|
|
10
|
+
"""
|
|
11
|
+
const { Before, After, Given } = require('@cucumber/cucumber');
|
|
12
|
+
Before({ name: 'database setup' }, function() {});
|
|
13
|
+
After({ name: 'database cleanup' }, function() {});
|
|
14
|
+
Given('a passing step', function() {});
|
|
15
|
+
"""
|
|
16
|
+
When I generate the Flakiness report for "scenario with named hooks"
|
|
17
|
+
When I look at the test named "it runs named hooks"
|
|
18
|
+
And the test contains 1 attempt
|
|
19
|
+
When I look at the attempt #1
|
|
20
|
+
And the attempt contains 3 steps
|
|
21
|
+
|
|
22
|
+
When I look at the step #1
|
|
23
|
+
Then the step is called "Before (database setup)"
|
|
24
|
+
And the step is in file "features/support/steps.js" at line 2
|
|
25
|
+
|
|
26
|
+
When I look at the step #2
|
|
27
|
+
Then the step is called "Given a passing step"
|
|
28
|
+
And the step is in file "features/passing.feature" at line 3
|
|
29
|
+
|
|
30
|
+
When I look at the step #3
|
|
31
|
+
Then the step is called "After (database cleanup)"
|
|
32
|
+
And the step is in file "features/support/steps.js" at line 3
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Feature: Unnamed Hooks
|
|
2
|
+
Scenario: captures before and after hooks
|
|
3
|
+
Given the project file "features/passing.feature":
|
|
4
|
+
"""
|
|
5
|
+
Feature: Hooks
|
|
6
|
+
Scenario: it runs hooks
|
|
7
|
+
Given a passing step
|
|
8
|
+
"""
|
|
9
|
+
And the project file "features/support/steps.js":
|
|
10
|
+
"""
|
|
11
|
+
const { Before, After, Given } = require('@cucumber/cucumber');
|
|
12
|
+
Before(function() {});
|
|
13
|
+
After(function() {});
|
|
14
|
+
Given('a passing step', function() {});
|
|
15
|
+
"""
|
|
16
|
+
And the environment variable "BUILD_URL" is "https://ci.example.test/build/123"
|
|
17
|
+
When I generate the Flakiness report for "scenario with hooks"
|
|
18
|
+
When I look at the test named "it runs hooks"
|
|
19
|
+
And the test contains 1 attempt
|
|
20
|
+
When I look at the attempt #1
|
|
21
|
+
And the attempt contains 3 steps
|
|
22
|
+
|
|
23
|
+
When I look at the step #1
|
|
24
|
+
Then the step is called "Before"
|
|
25
|
+
And the step is in file "features/support/steps.js" at line 2
|
|
26
|
+
|
|
27
|
+
When I look at the step #2
|
|
28
|
+
Then the step is called "Given a passing step"
|
|
29
|
+
And the step is in file "features/passing.feature" at line 3
|
|
30
|
+
|
|
31
|
+
When I look at the step #3
|
|
32
|
+
Then the step is called "After"
|
|
33
|
+
And the step is in file "features/support/steps.js" at line 3
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
Feature: Locations
|
|
2
|
+
Scenario: computes locations relative to the git root
|
|
3
|
+
Given the project file "features/orders/nested/checkout.feature":
|
|
4
|
+
"""
|
|
5
|
+
Feature: Nested checkout
|
|
6
|
+
|
|
7
|
+
Scenario: computes locations from git root
|
|
8
|
+
Given a passing step
|
|
9
|
+
"""
|
|
10
|
+
And the project file "features/support/nested/steps.js":
|
|
11
|
+
"""
|
|
12
|
+
const { Before, Given } = require('@cucumber/cucumber');
|
|
13
|
+
|
|
14
|
+
Before(function() {});
|
|
15
|
+
Given('a passing step', function() {});
|
|
16
|
+
"""
|
|
17
|
+
When I generate the Flakiness report for "nested locations"
|
|
18
|
+
When I look at the suite named "checkout.feature"
|
|
19
|
+
Then the suite is in file "features/orders/nested/checkout.feature" at line 0
|
|
20
|
+
When I look at the suite named "Nested checkout"
|
|
21
|
+
Then the suite is in file "features/orders/nested/checkout.feature" at line 1
|
|
22
|
+
When I look at the test named "computes locations from git root"
|
|
23
|
+
Then the test is in file "features/orders/nested/checkout.feature" at line 3
|
|
24
|
+
And the test contains 1 attempt
|
|
25
|
+
|
|
26
|
+
When I look at the attempt #1
|
|
27
|
+
Then the attempt contains 2 steps:
|
|
28
|
+
"""
|
|
29
|
+
Before
|
|
30
|
+
Given a passing step
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
When I look at the step #1
|
|
34
|
+
Then the step is in file "features/support/nested/steps.js" at line 3
|
|
35
|
+
|
|
36
|
+
When I look at the step #2
|
|
37
|
+
Then the step is in file "features/orders/nested/checkout.feature" at line 4
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
Feature: Retries
|
|
2
|
+
Scenario: captures a scenario that succeeds on retry
|
|
3
|
+
Given the project file "features/eventually-passing.feature":
|
|
4
|
+
"""
|
|
5
|
+
Feature: Eventually passing
|
|
6
|
+
Scenario: it succeeds on retry
|
|
7
|
+
Given a step that succeeds on retry
|
|
8
|
+
"""
|
|
9
|
+
And the project file "features/support/steps.js":
|
|
10
|
+
"""
|
|
11
|
+
const { Given } = require('@cucumber/cucumber');
|
|
12
|
+
let hasFailedOnce = false;
|
|
13
|
+
|
|
14
|
+
Given('a step that succeeds on retry', function() {
|
|
15
|
+
if (hasFailedOnce)
|
|
16
|
+
return;
|
|
17
|
+
hasFailedOnce = true;
|
|
18
|
+
throw new Error('intentional first-attempt failure');
|
|
19
|
+
});
|
|
20
|
+
"""
|
|
21
|
+
And the Cucumber arguments are:
|
|
22
|
+
| --retry |
|
|
23
|
+
| 1 |
|
|
24
|
+
When I generate the Flakiness report for "flaky scenario"
|
|
25
|
+
When I look at the test named "it succeeds on retry"
|
|
26
|
+
Then the test contains 2 attempts
|
|
27
|
+
When I look at the "failed" attempt
|
|
28
|
+
Then the attempt contains 1 step
|
|
29
|
+
When I look at the "passed" attempt
|
|
30
|
+
Then the attempt contains 1 step
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
Feature: Rules
|
|
2
|
+
Scenario: captures rules as suites
|
|
3
|
+
Given the project file "features/rules.feature":
|
|
4
|
+
"""
|
|
5
|
+
Feature: Wallet
|
|
6
|
+
|
|
7
|
+
Rule: Balance cannot go negative
|
|
8
|
+
Scenario: rejects overspending
|
|
9
|
+
Given an account with a balance
|
|
10
|
+
"""
|
|
11
|
+
And the project file "features/support/steps.js":
|
|
12
|
+
"""
|
|
13
|
+
const { Given } = require('@cucumber/cucumber');
|
|
14
|
+
Given('an account with a balance', function() {});
|
|
15
|
+
"""
|
|
16
|
+
When I generate the Flakiness report for "rules"
|
|
17
|
+
Then the report hierarchy is:
|
|
18
|
+
"""
|
|
19
|
+
`- file rules.feature
|
|
20
|
+
`- suite Wallet
|
|
21
|
+
`- suite Balance cannot go negative
|
|
22
|
+
`- test rejects overspending
|
|
23
|
+
`- attempt #1 passed
|
|
24
|
+
`- step Given an account with a balance
|
|
25
|
+
"""
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
Feature: Scenario Outlines
|
|
2
|
+
Scenario: captures one reported test per example row
|
|
3
|
+
Given the project file "features/addition.feature":
|
|
4
|
+
"""
|
|
5
|
+
Feature: Addition
|
|
6
|
+
|
|
7
|
+
Scenario Outline: addition
|
|
8
|
+
Given a calculator
|
|
9
|
+
When I add <a> to <b>
|
|
10
|
+
Then I get <result>
|
|
11
|
+
|
|
12
|
+
Examples:
|
|
13
|
+
| a | b | result |
|
|
14
|
+
| 2 | 2 | 4 |
|
|
15
|
+
| 1 | 7 | 8 |
|
|
16
|
+
"""
|
|
17
|
+
And the project file "features/support/steps.js":
|
|
18
|
+
"""
|
|
19
|
+
const assert = require('node:assert/strict');
|
|
20
|
+
const { Given, When, Then } = require('@cucumber/cucumber');
|
|
21
|
+
|
|
22
|
+
Given('a calculator', function() {});
|
|
23
|
+
|
|
24
|
+
When('I add {int} to {int}', function(a, b) {
|
|
25
|
+
this.result = a + b;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
Then('I get {int}', function(expected) {
|
|
29
|
+
assert.equal(this.result, expected);
|
|
30
|
+
});
|
|
31
|
+
"""
|
|
32
|
+
When I generate the Flakiness report for "scenario outline"
|
|
33
|
+
Then the report contains 2 tests
|
|
34
|
+
|
|
35
|
+
When I look at the test named "addition [a=2, b=2, result=4]"
|
|
36
|
+
And the test is in file "features/addition.feature" at line 10
|
|
37
|
+
And the test contains 1 attempt
|
|
38
|
+
|
|
39
|
+
When I look at the attempt #1
|
|
40
|
+
Then the attempt contains 3 steps:
|
|
41
|
+
"""
|
|
42
|
+
Given a calculator
|
|
43
|
+
When I add 2 to 2
|
|
44
|
+
Then I get 4
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
When I look at the test named "addition [a=1, b=7, result=8]"
|
|
48
|
+
And the test is in file "features/addition.feature" at line 11
|
|
49
|
+
And the test contains 1 attempt
|
|
50
|
+
|
|
51
|
+
When I look at the attempt #1
|
|
52
|
+
Then the attempt contains 3 steps:
|
|
53
|
+
"""
|
|
54
|
+
Given a calculator
|
|
55
|
+
When I add 1 to 7
|
|
56
|
+
Then I get 8
|
|
57
|
+
"""
|