From eae5a2013f903c90036145a78e538ef192546cd9 Mon Sep 17 00:00:00 2001 From: "reportportal.io" Date: Thu, 21 Mar 2024 09:47:26 +0000 Subject: [PATCH 1/9] 5.2.0 -> 5.2.1-SNAPSHOT --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 91ff572..e08f178 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.2.0 +5.2.1-SNAPSHOT From 159467a259104c135ff5f059ba72154c76d79da6 Mon Sep 17 00:00:00 2001 From: Ilya Date: Thu, 28 Mar 2024 18:36:22 +0100 Subject: [PATCH 2/9] Update release.yml --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cdf5da7..c724398 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -130,6 +130,7 @@ jobs: echo "patch" > ${{ env.versionFragmentFileName }} git status git add ${{ env.versionFileName }} + git add ${{ env.versionFragmentFileName }} git commit -m "${{ needs.calculate-version.outputs.releaseVersion }} -> ${{ steps.bumpSnapshotVersion.outputs.next-version }}-SNAPSHOT" git push origin develop From a79ba431fb0cc128da160b5ee1654f2c72de104f Mon Sep 17 00:00:00 2001 From: Ilya Date: Thu, 28 Mar 2024 18:36:59 +0100 Subject: [PATCH 3/9] Update version_fragment --- version_fragment | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version_fragment b/version_fragment index acb503f..9eb7b90 100644 --- a/version_fragment +++ b/version_fragment @@ -1 +1 @@ -minor +patch From 5f0fcf1fd5ec41cb1e87217a4305c2477ac07aa4 Mon Sep 17 00:00:00 2001 From: Ilya Date: Thu, 28 Mar 2024 18:47:21 +0100 Subject: [PATCH 4/9] Update CODEOWNERS --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4d58196..2df1f2b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @AmsterGet +* @AmsterGet @AliakseiLiasnitski From 124135d1a885cc2c65d1cf5b26184cd35098c121 Mon Sep 17 00:00:00 2001 From: millerick Date: Wed, 3 Apr 2024 06:35:52 -0700 Subject: [PATCH 5/9] fix: Correct typos in README (#187) * fix: Correct typos in README * Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ca7f969..8192482 100644 --- a/README.md +++ b/README.md @@ -36,10 +36,10 @@ module.exports = defineConfig({ attributes: [ { key: 'attributeKey', - value: 'attrbiuteValue', + value: 'attributeValue', }, { - value: 'anotherAttrbiuteValue', + value: 'anotherAttributeValue', }, ], }, @@ -85,10 +85,10 @@ Add the following options to cypress.json "attributes": [ { "key": "attributeKey", - "value": "attrbiuteValue" + "value": "attributeValue" }, { - "value": "anotherAttrbiuteValue" + "value": "anotherAttributeValue" } ] } From d94e51cb20d2f6207e97525588678a6263324c2a Mon Sep 17 00:00:00 2001 From: AliakseiLiasnitski <40150869+AliakseiLiasnitski@users.noreply.github.com> Date: Fri, 3 May 2024 10:38:03 +0300 Subject: [PATCH 6/9] EPMRPP-90293 || Updated versions of vulnerable packages (#190) --- CHANGELOG.md | 2 + package-lock.json | 274 +++++++++++++++++++++++++++++++++++++++++----- package.json | 4 +- 3 files changed, 249 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a8eb64..4360153 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +### Security +- Updated versions of vulnerable packages (@reportportal/client-javascript, glob). ## [5.2.0] - 2024-03-21 ### Fixed diff --git a/package-lock.json b/package-lock.json index 77e2afd..5504685 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,11 +6,11 @@ "packages": { "": { "name": "@reportportal/agent-js-cypress", - "version": "5.1.5", + "version": "5.2.0", "license": "Apache-2.0", "dependencies": { - "@reportportal/client-javascript": "^5.1.0", - "glob": "^7.2.3", + "@reportportal/client-javascript": "^5.1.3", + "glob": "^9.3.5", "minimatch": "^3.1.2", "mocha": "^10.2.0", "node-ipc": "9.1.1" @@ -30,7 +30,7 @@ "prettier": "^2.8.8" }, "engines": { - "node": ">=10.x" + "node": ">=12.x" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -1164,6 +1164,26 @@ } } }, + "node_modules/@jest/reporters/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@jest/schemas": { "version": "29.6.0", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.0.tgz", @@ -1353,13 +1373,13 @@ } }, "node_modules/@reportportal/client-javascript": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@reportportal/client-javascript/-/client-javascript-5.1.0.tgz", - "integrity": "sha512-v1PwSNtVESOKa0xZCswQgvjaO7qCR8UD00SyI0N0pPbSQ5oMbeSGzGPFSyekyN23IN3VE3ZzQDo6TRyZXExPJA==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@reportportal/client-javascript/-/client-javascript-5.1.3.tgz", + "integrity": "sha512-1/utoKnHUgiilR6Ep8pHvuNZGv5oDeI+x1/aJNu8IADoVG1U0Q4tB2trWHDIY07T/PCzrnzp6dVcCu/wLsdVRA==", "dependencies": { - "axios": "^1.6.5", - "axios-retry": "^4.0.0", - "glob": "^7.2.3", + "axios": "^1.6.8", + "axios-retry": "^4.1.0", + "glob": "^8.1.0", "ini": "^2.0.0", "uniqid": "^5.4.0", "uuid": "^9.0.1" @@ -1368,6 +1388,43 @@ "node": ">=12.x" } }, + "node_modules/@reportportal/client-javascript/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@reportportal/client-javascript/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@reportportal/client-javascript/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -1607,6 +1664,26 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/acorn": { "version": "8.10.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", @@ -1895,19 +1972,19 @@ "dev": true }, "node_modules/axios": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz", - "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==", + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", "dependencies": { - "follow-redirects": "^1.15.4", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } }, "node_modules/axios-retry": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-4.0.0.tgz", - "integrity": "sha512-F6P4HVGITD/v4z9Lw2mIA24IabTajvpDZmKa6zq/gGwn57wN5j1P3uWrAV0+diqnW6kTM2fTqmWNfgYWGmMuiA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-4.1.0.tgz", + "integrity": "sha512-svdth4H00yhlsjBbjfLQ/sMLkXqeLxhiFC1nE1JtkN/CIssGxqk0UwTEdrVjwA2gr3yJkAulwvDSIm4z4HyPvg==", "dependencies": { "is-retry-allowed": "^2.2.0" }, @@ -3575,9 +3652,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", @@ -3781,19 +3858,17 @@ } }, "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", "dependencies": { "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -3810,6 +3885,28 @@ "node": ">= 6" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/global-dirs": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", @@ -4749,6 +4846,26 @@ } } }, + "node_modules/jest-config/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/jest-diff": { "version": "29.6.1", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.6.1.tgz", @@ -5029,6 +5146,26 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-runtime/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/jest-snapshot": { "version": "29.6.1", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.6.1.tgz", @@ -5590,6 +5727,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/mocha": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", @@ -6028,6 +6173,37 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-scurry": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -6488,6 +6664,26 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -6883,6 +7079,26 @@ "node": ">=8" } }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", diff --git a/package.json b/package.json index 930fbf0..8078081 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,8 @@ "url": "https://github.com/reportportal/agent-js-cypress" }, "dependencies": { - "@reportportal/client-javascript": "^5.1.0", - "glob": "^7.2.3", + "@reportportal/client-javascript": "^5.1.3", + "glob": "^9.3.5", "minimatch": "^3.1.2", "mocha": "^10.2.0", "node-ipc": "9.1.1" From 31badf2234e9c73beaa6b607983c08ae6a041d87 Mon Sep 17 00:00:00 2001 From: AliakseiLiasnitski <40150869+AliakseiLiasnitski@users.noreply.github.com> Date: Mon, 6 May 2024 13:46:51 +0300 Subject: [PATCH 7/9] EPMRPP-90382 || Implement reporting Gherkin scenario step as nested step (#189) --- CHANGELOG.md | 2 + README.md | 58 +++++++++++++ lib/commands/reportPortalCommands.d.ts | 5 ++ lib/commands/reportPortalCommands.js | 11 +++ lib/constants.js | 9 ++ lib/cypressReporter.js | 8 ++ lib/ipcEvents.js | 2 + lib/plugin/index.js | 8 ++ lib/reporter.js | 103 +++++++++++++++++++++- lib/worker.js | 6 ++ test/mock/mock.js | 7 +- test/reporter.test.js | 113 ++++++++++++++++++++++++- 12 files changed, 325 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4360153..c1e86ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +### Added +- `cucumberStepStart` and `cucumberStepEnd` commands for reporting `cypress-cucumber-preprocessor` scenario steps as nested steps in RP. ### Security - Updated versions of vulnerable packages (@reportportal/client-javascript, glob). diff --git a/README.md b/README.md index 8192482..c52e673 100644 --- a/README.md +++ b/README.md @@ -437,6 +437,64 @@ jobs: **Note:** The example provided for Cypress version <= 9. For Cypress version >= 10 usage of `cypress-io/github-action` may be changed. +## Cypress-cucumber-preprocessor execution + +### Configuration: +Specify the options in the cypress.config.js: + +```javascript +const { defineConfig } = require('cypress'); +const createBundler = require('@bahmutov/cypress-esbuild-preprocessor'); +const preprocessor = require('@badeball/cypress-cucumber-preprocessor'); +const createEsbuildPlugin = require('@badeball/cypress-cucumber-preprocessor/esbuild').default; +const registerReportPortalPlugin = require('@reportportal/agent-js-cypress/lib/plugin'); + +module.exports = defineConfig({ + reporter: '@reportportal/agent-js-cypress', + reporterOptions: { + endpoint: 'http://your-instance.com:8080/api/v1', + apiKey: 'reportportalApiKey', + launch: 'LAUNCH_NAME', + project: 'PROJECT_NAME', + description: 'LAUNCH_DESCRIPTION', + }, + e2e: { + async setupNodeEvents(on, config) { + await preprocessor.addCucumberPreprocessorPlugin(on, config); + on( + 'file:preprocessor', + createBundler({ + plugins: [createEsbuildPlugin(config)], + }), + ); + registerReportPortalPlugin(on, config); + + return config; + }, + specPattern: 'cypress/e2e/**/*.feature', + supportFile: 'cypress/support/e2e.js', + }, +}); +``` + +### Scenario steps +At the moment it is not possible to subscribe to start and end of scenario steps events. To solve the problem with displaying steps in the ReportPortal, the agent provides special commands: `cucumberStepStart`, `cucumberStepEnd`. +To work correctly, these commands must be called in the `BeforeStep`/`AfterStep` hooks. + +```javascript +import { BeforeStep, AfterStep } from '@badeball/cypress-cucumber-preprocessor'; + +BeforeStep((step) => { + cy.cucumberStepStart(step); +}); + +AfterStep((step) => { + cy.cucumberStepEnd(step); +}); +``` + +You can avoid duplicating this logic in each step definitions. Instead, add it to the `cypress/support/step_definitions.js` file and include the path to this file in the `stepDefinitions` array (if necessary). These hooks will be used for all step definitions. + # Copyright Notice Licensed under the [Apache License v2.0](LICENSE) diff --git a/lib/commands/reportPortalCommands.d.ts b/lib/commands/reportPortalCommands.d.ts index 77b3d0e..6e3df17 100644 --- a/lib/commands/reportPortalCommands.d.ts +++ b/lib/commands/reportPortalCommands.d.ts @@ -53,6 +53,11 @@ declare global { launchError(message: string, file?: RP_FILE): Chainable; launchFatal(message: string, file?: RP_FILE): Chainable; + // Waiting for migrate to TypeScript + // Expected step: IStepHookParameter (https://github.com/badeball/cypress-cucumber-preprocessor/blob/055d8df6a62009c94057b0d894a30e142cb87b94/lib/public-member-types.ts#L39) + cucumberStepStart(step: any): Chainable; + + cucumberStepEnd(step: any): Chainable; setStatus(status: RP_STATUS, suiteTitle?: string): Chainable; diff --git a/lib/commands/reportPortalCommands.js b/lib/commands/reportPortalCommands.js index 5a9da37..7b25c0c 100644 --- a/lib/commands/reportPortalCommands.js +++ b/lib/commands/reportPortalCommands.js @@ -131,6 +131,17 @@ Cypress.Commands.add('launchFatal', (message, file) => { }); }); +/** + * Cucumber Scenario's steps commands + */ +Cypress.Commands.add('cucumberStepStart', (step) => { + cy.task('rp_cucumberStepStart', step); +}); + +Cypress.Commands.add('cucumberStepEnd', (step) => { + cy.task('rp_cucumberStepEnd', step); +}); + /** * Attributes command */ diff --git a/lib/constants.js b/lib/constants.js index f110d24..c37d318 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -59,6 +59,14 @@ const reporterEvents = { SCREENSHOT: 'screenshot', SET_STATUS: 'setStatus', SET_LAUNCH_STATUS: 'setLaunchStatus', + CUCUMBER_STEP_START: 'cucumberStepStart', + CUCUMBER_STEP_END: 'cucumberStepEnd', +}; + +const cucumberKeywordMap = { + Outcome: 'Then', + Action: 'When', + Context: 'Given', }; module.exports = { @@ -66,5 +74,6 @@ module.exports = { logLevels, entityType, hookTypesMap, + cucumberKeywordMap, reporterEvents, }; diff --git a/lib/cypressReporter.js b/lib/cypressReporter.js index 5431ff6..796f50d 100644 --- a/lib/cypressReporter.js +++ b/lib/cypressReporter.js @@ -81,6 +81,10 @@ class CypressReporter extends Mocha.reporters.Base { this.worker.send({ event: reporterEvents.SET_STATUS, statusInfo }); const setLaunchStatusListener = (statusInfo) => this.worker.send({ event: reporterEvents.SET_LAUNCH_STATUS, statusInfo }); + const cucumberStepStartListener = (step) => + this.worker.send({ event: reporterEvents.CUCUMBER_STEP_START, step }); + const cucumberStepEndListener = (step) => + this.worker.send({ event: reporterEvents.CUCUMBER_STEP_END, step }); startIPCServer( (server) => { @@ -93,6 +97,8 @@ class CypressReporter extends Mocha.reporters.Base { server.on(IPC_EVENTS.SCREENSHOT, screenshotListener); server.on(IPC_EVENTS.SET_STATUS, setStatusListener); server.on(IPC_EVENTS.SET_LAUNCH_STATUS, setLaunchStatusListener); + server.on(IPC_EVENTS.CUCUMBER_STEP_START, cucumberStepStartListener); + server.on(IPC_EVENTS.CUCUMBER_STEP_END, cucumberStepEndListener); }, (server) => { server.off(IPC_EVENTS.CONFIG, '*'); @@ -104,6 +110,8 @@ class CypressReporter extends Mocha.reporters.Base { server.off(IPC_EVENTS.SCREENSHOT, '*'); server.off(IPC_EVENTS.SET_STATUS, '*'); server.off(IPC_EVENTS.SET_LAUNCH_STATUS, '*'); + server.off(IPC_EVENTS.CUCUMBER_STEP_START, '*'); + server.off(IPC_EVENTS.CUCUMBER_STEP_END, '*'); }, ); CypressReporter.worker = this.worker; diff --git a/lib/ipcEvents.js b/lib/ipcEvents.js index 9d56dec..f4be177 100644 --- a/lib/ipcEvents.js +++ b/lib/ipcEvents.js @@ -24,6 +24,8 @@ const IPC_EVENTS = { SCREENSHOT: 'screenshot', SET_STATUS: 'setStatus', SET_LAUNCH_STATUS: 'setLaunchStatus', + CUCUMBER_STEP_START: 'cucumberStepStart', + CUCUMBER_STEP_END: 'cucumberStepEnd', }; module.exports = { IPC_EVENTS }; diff --git a/lib/plugin/index.js b/lib/plugin/index.js index 9fc5be7..0ef1958 100644 --- a/lib/plugin/index.js +++ b/lib/plugin/index.js @@ -50,6 +50,14 @@ const registerReportPortalPlugin = (on, config, callbacks) => { ipc.of.reportportal.emit(IPC_EVENTS.SET_LAUNCH_STATUS, statusInfo); return null; }, + rp_cucumberStepStart(step) { + ipc.of.reportportal.emit(IPC_EVENTS.CUCUMBER_STEP_START, step); + return null; + }, + rp_cucumberStepEnd(step) { + ipc.of.reportportal.emit(IPC_EVENTS.CUCUMBER_STEP_END, step); + return null; + }, }); on('after:screenshot', (screenshotInfo) => { diff --git a/lib/reporter.js b/lib/reporter.js index 1e08d3a..c1cf8ee 100644 --- a/lib/reporter.js +++ b/lib/reporter.js @@ -16,13 +16,14 @@ const RPClient = require('@reportportal/client-javascript'); -const { entityType, logLevels, testItemStatuses } = require('./constants'); +const { entityType, logLevels, testItemStatuses, cucumberKeywordMap } = require('./constants'); const { getScreenshotAttachment, getTestStartObject, getTestEndObject, getHookStartObject, getAgentInfo, + getCodeRef, } = require('./utils'); const { createMergeLaunchLockFile, deleteMergeLaunchLockFile } = require('./mergeLaunchesUtils'); @@ -55,6 +56,7 @@ class Reporter { this.suiteTestCaseIds = new Map(); this.pendingTestsIds = []; this.suiteStatuses = new Map(); + this.cucumberSteps = new Map(); } resetCurrentTestFinishParams() { @@ -137,7 +139,12 @@ class Reporter { ); promiseErrorHandler(promise, 'Fail to start test'); this.testItemIds.set(test.id, tempId); - this.currentTestTempInfo = { tempId, startTime: startTestObj.startTime }; + this.currentTestTempInfo = { + tempId, + codeRef: test.codeRef, + startTime: startTestObj.startTime, + cucumberStepIds: new Set(), + }; if (this.pendingTestsIds.includes(test.id)) { this.testEnd(test); } @@ -161,6 +168,7 @@ class Reporter { testId = this.testItemIds.get(test.id); } this.sendLogOnFinishFailedItem(test, testId); + this.finishFailedStep(test); const testInfo = Object.assign({}, test, this.currentTestFinishParams); const finishTestItemPromise = this.client.finishTestItem( testId, @@ -181,6 +189,75 @@ class Reporter { } } + cucumberStepStart(data) { + const { testStepId, pickleStep } = data; + const parent = this.currentTestTempInfo; + + if (!parent) return; + + const keyword = cucumberKeywordMap[pickleStep.type]; + const stepName = pickleStep.text; + const codeRef = getCodeRef([stepName], parent.codeRef); + + const stepData = { + name: keyword ? `${keyword} ${stepName}` : stepName, + startTime: this.client.helpers.now(), + type: entityType.STEP, + codeRef, + hasStats: false, + }; + + const { tempId, promise } = this.client.startTestItem( + stepData, + this.tempLaunchId, + parent.tempId, + ); + promiseErrorHandler(promise, 'Fail to start step'); + this.cucumberSteps.set(testStepId, { tempId, tempParentId: parent.tempId, testStepId }); + parent.cucumberStepIds.add(testStepId); + } + + finishFailedStep(test) { + if (test.status === FAILED) { + const step = this.getCurrentCucumberStep(); + + if (!step) return; + + this.cucumberStepEnd({ + testStepId: step.testStepId, + testStepResult: { + status: testItemStatuses.FAILED, + message: test.err.stack, + }, + }); + } + } + + cucumberStepEnd(data) { + const { testStepId, testStepResult = { status: testItemStatuses.PASSED } } = data; + const step = this.cucumberSteps.get(testStepId); + + if (!step) return; + + if (testStepResult.status === testItemStatuses.FAILED) { + this.sendLog(step.tempId, { + time: this.client.helpers.now(), + level: logLevels.ERROR, + message: testStepResult.message, + }); + } + + this.client.finishTestItem(step.tempId, { + status: testStepResult.status, + endTime: this.client.helpers.now(), + }); + + this.cucumberSteps.delete(testStepId); + if (this.currentTestTempInfo) { + this.currentTestTempInfo.cucumberStepIds.delete(testStepId); + } + } + hookStart(hook) { const hookStartObject = getHookStartObject(hook); switch (hookStartObject.type) { @@ -227,6 +304,24 @@ class Reporter { return currentSuiteInfo && currentSuiteInfo.tempId; } + getCurrentCucumberStep() { + if (this.currentTestTempInfo && this.currentTestTempInfo.cucumberStepIds.size > 0) { + const testStepId = Array.from(this.currentTestTempInfo.cucumberStepIds.values())[ + this.currentTestTempInfo.cucumberStepIds.size - 1 + ]; + + return this.cucumberSteps.get(testStepId); + } + + return null; + } + + getCurrentCucumberStepId() { + const step = this.getCurrentCucumberStep(); + + return step && step.tempId; + } + sendLog(tempId, { level, message = '', file }) { return this.client.sendLog( tempId, @@ -241,7 +336,9 @@ class Reporter { sendLogToCurrentItem(log) { const tempItemId = - (this.currentTestTempInfo && this.currentTestTempInfo.tempId) || this.getCurrentSuiteId(); + this.getCurrentCucumberStepId() || + (this.currentTestTempInfo && this.currentTestTempInfo.tempId) || + this.getCurrentSuiteId(); if (tempItemId) { const promise = this.sendLog(tempItemId, log); promiseErrorHandler(promise, 'Fail to send log to current item'); diff --git a/lib/worker.js b/lib/worker.js index c6dce77..913a1d8 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -99,6 +99,12 @@ process.on('message', (message) => { case reporterEvents.SET_LAUNCH_STATUS: reporter.setLaunchStatus(message.statusInfo); break; + case reporterEvents.CUCUMBER_STEP_START: + reporter.cucumberStepStart(message.step); + break; + case reporterEvents.CUCUMBER_STEP_END: + reporter.cucumberStepEnd(message.step); + break; default: break; } diff --git a/test/mock/mock.js b/test/mock/mock.js index 616e907..c805f24 100644 --- a/test/mock/mock.js +++ b/test/mock/mock.js @@ -1,3 +1,5 @@ +const currentDate = new Date().valueOf(); + class RPClient { constructor(config) { this.config = config; @@ -25,6 +27,10 @@ class RPClient { this.sendLog = jest.fn().mockReturnValue({ promise: Promise.resolve('ok'), }); + + this.helpers = { + now: jest.fn().mockReturnValue(currentDate), + }; } } @@ -40,7 +46,6 @@ const getDefaultConfig = () => ({ }, }); -const currentDate = new Date().valueOf(); const RealDate = Date; const MockedDate = (...attrs) => diff --git a/test/reporter.test.js b/test/reporter.test.js index cd3e80a..848e1f8 100644 --- a/test/reporter.test.js +++ b/test/reporter.test.js @@ -5,6 +5,34 @@ const Reporter = require('./../lib/reporter'); const sep = path.sep; +const tempLaunchId = 'temp-launch-id'; +const tempTestId = 'temp-test-id'; +const tempStepId = 'temp-step-id'; +const testStepId = 'test-step-id'; + +const mockInputStep = { + testStepId, + pickleStep: { + type: 'Action', + text: 'step-name', + }, +}; +const mockStep = { + tempId: tempStepId, + parentId: tempTestId, + testStepId, +}; +const mockCurrentTestTempInfo = { + tempId: tempTestId, + codeRef: 'test-code-ref', + startTime: currentDate, + cucumberStepIds: new Set(), +}; +const mockCurrentTestTempInfoWithStep = { + ...mockCurrentTestTempInfo, + cucumberStepIds: new Set(testStepId), +}; + describe('reporter script', () => { let reporter; @@ -470,6 +498,81 @@ describe('reporter script', () => { }); }); + describe('cucumberStepStart', function () { + it('startTestItem should be called with parameters', function () { + const spyStartTestItem = jest.spyOn(reporter.client, 'startTestItem'); + + reporter.currentTestTempInfo = mockCurrentTestTempInfo; + reporter.tempLaunchId = tempLaunchId; + + reporter.cucumberStepStart(mockInputStep); + + expect(spyStartTestItem).toHaveBeenCalledTimes(1); + expect(spyStartTestItem).toHaveBeenCalledWith( + { + name: 'When step-name', + startTime: currentDate, + type: 'step', + codeRef: 'test-code-ref/step-name', + hasStats: false, + }, + tempLaunchId, + tempTestId, + ); + }); + }); + + describe('cucumberStepEnd', function () { + beforeEach(function () { + reporter.currentTestTempInfo = mockCurrentTestTempInfoWithStep; + reporter.cucumberSteps.set(testStepId, mockStep); + }); + + it('end passed step: finishTestItem should be called with parameters', function () { + const spyFinishTestItem = jest.spyOn(reporter.client, 'finishTestItem'); + + reporter.cucumberStepEnd(mockInputStep); + + expect(spyFinishTestItem).toHaveBeenCalledTimes(1); + expect(spyFinishTestItem).toHaveBeenCalledWith(tempStepId, { + status: 'passed', + endTime: currentDate, + }); + }); + + it('end failed step: finishTestItem should be called with failed status', function () { + const spyFinishTestItem = jest.spyOn(reporter.client, 'finishTestItem'); + const errorMessage = 'error-message'; + + reporter.cucumberStepEnd({ + ...mockInputStep, + testStepResult: { status: 'failed', message: errorMessage }, + }); + + expect(spyFinishTestItem).toHaveBeenCalledWith(tempStepId, { + status: 'failed', + endTime: currentDate, + }); + }); + + it('end failed step: should call sendLog on step fail', function () { + const spySendLog = jest.spyOn(reporter, 'sendLog'); + const errorMessage = 'error-message'; + + reporter.cucumberStepEnd({ + ...mockInputStep, + testStepResult: { status: 'failed', message: errorMessage }, + }); + + expect(spySendLog).toHaveBeenCalledTimes(1); + expect(spySendLog).toHaveBeenCalledWith(tempStepId, { + time: currentDate, + level: 'error', + message: errorMessage, + }); + }); + }); + describe('hookStart', function () { beforeEach(function () { reporter.tempLaunchId = 'tempLaunchId'; @@ -491,7 +594,7 @@ describe('reporter script', () => { }; const expectedHookStartObject = { name: 'hook name', - startTime: currentDate, + startTime: currentDate - 1, type: 'BEFORE_METHOD', }; @@ -598,6 +701,7 @@ describe('reporter script', () => { describe('send log', () => { beforeEach(() => { jest.clearAllMocks(); + reporter.currentTestTempInfo = mockCurrentTestTempInfo; }); it('sendLog: client.sendLog should be called with parameters', function () { const spySendLog = jest.spyOn(reporter.client, 'sendLog'); @@ -626,11 +730,14 @@ describe('reporter script', () => { message: 'error message', time: currentDate, }; - reporter.currentTestTempInfo = { tempId: 'tempTestItemId' }; reporter.sendLogToCurrentItem(logObj); - expect(spySendLog).toHaveBeenCalledWith('tempTestItemId', expectedLogObj, undefined); + expect(spySendLog).toHaveBeenCalledWith( + mockCurrentTestTempInfo.tempId, + expectedLogObj, + undefined, + ); }); it('sendLogToCurrentItem: client.sendLog rejected promise should be handled', async function () { const spyConsoleError = jest.spyOn(global.console, 'error').mockImplementation(); From 541fcf53291a86adc4de7a76586ad6c817520257 Mon Sep 17 00:00:00 2001 From: AliakseiLiasnitski <40150869+AliakseiLiasnitski@users.noreply.github.com> Date: Mon, 6 May 2024 14:15:37 +0300 Subject: [PATCH 8/9] change version_fragment from patch to minor --- version_fragment | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version_fragment b/version_fragment index 9eb7b90..acb503f 100644 --- a/version_fragment +++ b/version_fragment @@ -1 +1 @@ -patch +minor From 012936c48939fb2f8c2b62ee0df40591d5fec8b5 Mon Sep 17 00:00:00 2001 From: AliakseiLiasnitski Date: Tue, 7 May 2024 13:31:13 +0300 Subject: [PATCH 9/9] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c52e673..96ba59f 100644 --- a/README.md +++ b/README.md @@ -493,7 +493,7 @@ AfterStep((step) => { }); ``` -You can avoid duplicating this logic in each step definitions. Instead, add it to the `cypress/support/step_definitions.js` file and include the path to this file in the `stepDefinitions` array (if necessary). These hooks will be used for all step definitions. +You can avoid duplicating this logic in each step definitions. Instead, add it to the `cypress/support/step_definitions.js` file and include the path to this file in the [stepDefinitions](https://github.com/badeball/cypress-cucumber-preprocessor/blob/master/docs/step-definitions.md) array (if necessary) within cucumber-preprocessor config. These hooks will be used for all step definitions. # Copyright Notice