@qanalyzer/forge-cypress 1.1.1
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/LICENSE +202 -0
- package/README.md +105 -0
- package/dist/__fixtures__/saucedemo-13.json +131 -0
- package/dist/enrich-screenshots.d.ts +6 -0
- package/dist/enrich-screenshots.js +71 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/metadata-manager.d.ts +13 -0
- package/dist/metadata-manager.js +19 -0
- package/dist/metadata.d.ts +10 -0
- package/dist/metadata.js +35 -0
- package/dist/mocha.d.ts +24 -0
- package/dist/mocha.js +100 -0
- package/dist/plugin.d.ts +17 -0
- package/dist/plugin.js +89 -0
- package/dist/report-builder.d.ts +23 -0
- package/dist/report-builder.js +72 -0
- package/dist/reporter.d.ts +24 -0
- package/dist/reporter.js +141 -0
- package/dist/resolve-options.d.ts +8 -0
- package/dist/resolve-options.js +18 -0
- package/dist/results-manager.d.ts +11 -0
- package/dist/results-manager.js +66 -0
- package/dist/screenshots-manager.d.ts +25 -0
- package/dist/screenshots-manager.js +110 -0
- package/package.json +64 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ScreenshotsManager = void 0;
|
|
4
|
+
exports.isStillImagePath = isStillImagePath;
|
|
5
|
+
exports.matchScreenshotToAssertion = matchScreenshotToAssertion;
|
|
6
|
+
exports.nextUnusedSpecScreenshot = nextUnusedSpecScreenshot;
|
|
7
|
+
/**
|
|
8
|
+
* Bridge for Cypress `after:screenshot` details → plugin `after:run` upload (FR71).
|
|
9
|
+
*/
|
|
10
|
+
const node_fs_1 = require("node:fs");
|
|
11
|
+
const node_path_1 = require("node:path");
|
|
12
|
+
const node_os_1 = require("node:os");
|
|
13
|
+
const DEFAULT_BASENAME = 'qa-cypress-screenshots.json';
|
|
14
|
+
function defaultPath() {
|
|
15
|
+
if (process.env.QANALYZER_CYPRESS_SCREENSHOTS_PATH) {
|
|
16
|
+
return process.env.QANALYZER_CYPRESS_SCREENSHOTS_PATH;
|
|
17
|
+
}
|
|
18
|
+
const results = process.env.QANALYZER_CYPRESS_RESULTS_PATH;
|
|
19
|
+
if (results) {
|
|
20
|
+
return results.replace(/\.json$/i, '') + '-screenshots.json';
|
|
21
|
+
}
|
|
22
|
+
return (0, node_path_1.join)((0, node_os_1.tmpdir)(), DEFAULT_BASENAME);
|
|
23
|
+
}
|
|
24
|
+
class ScreenshotsManager {
|
|
25
|
+
static resolvePath(explicit) {
|
|
26
|
+
return explicit ?? defaultPath();
|
|
27
|
+
}
|
|
28
|
+
static clear(path = ScreenshotsManager.resolvePath()) {
|
|
29
|
+
if ((0, node_fs_1.existsSync)(path)) {
|
|
30
|
+
try {
|
|
31
|
+
(0, node_fs_1.unlinkSync)(path);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// ignore
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
static getAll(path = ScreenshotsManager.resolvePath()) {
|
|
39
|
+
if (!(0, node_fs_1.existsSync)(path))
|
|
40
|
+
return [];
|
|
41
|
+
try {
|
|
42
|
+
const raw = JSON.parse((0, node_fs_1.readFileSync)(path, 'utf8'));
|
|
43
|
+
return Array.isArray(raw.screenshots) ? raw.screenshots : [];
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
static append(record, path = ScreenshotsManager.resolvePath()) {
|
|
50
|
+
if (!record.path)
|
|
51
|
+
return;
|
|
52
|
+
const screenshots = ScreenshotsManager.getAll(path);
|
|
53
|
+
screenshots.push(record);
|
|
54
|
+
try {
|
|
55
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(path), { recursive: true });
|
|
56
|
+
(0, node_fs_1.writeFileSync)(path, JSON.stringify({ screenshots }, null, 0), 'utf8');
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Never fail the Cypress run
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.ScreenshotsManager = ScreenshotsManager;
|
|
64
|
+
/** True for still images; videos are skipped (Phase 3 still-image only). */
|
|
65
|
+
function isStillImagePath(filePath) {
|
|
66
|
+
return /\.(png|jpe?g|webp|bmp)$/i.test(filePath);
|
|
67
|
+
}
|
|
68
|
+
function belongsToSpec(shot, specName) {
|
|
69
|
+
if (!shot.specName) {
|
|
70
|
+
// Path often contains the relative spec path
|
|
71
|
+
const hay = shot.path.replace(/\\/g, '/').toLowerCase();
|
|
72
|
+
const want = specName.replace(/\\/g, '/').toLowerCase();
|
|
73
|
+
const base = want.split('/').pop() ?? want;
|
|
74
|
+
return Boolean(base && hay.includes(base));
|
|
75
|
+
}
|
|
76
|
+
const normSpec = shot.specName.replace(/\\/g, '/').toLowerCase();
|
|
77
|
+
const normName = specName.replace(/\\/g, '/').toLowerCase();
|
|
78
|
+
return (normName.endsWith(normSpec) ||
|
|
79
|
+
normSpec.endsWith(normName) ||
|
|
80
|
+
normName.includes(normSpec) ||
|
|
81
|
+
normSpec.includes(normName.split('/').pop() ?? ''));
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Match a failure screenshot to a failed assertion by title / fullName.
|
|
85
|
+
*/
|
|
86
|
+
function matchScreenshotToAssertion(shot, assertion, specName) {
|
|
87
|
+
if (assertion.status !== 'failed')
|
|
88
|
+
return false;
|
|
89
|
+
if (shot.testFailure === false)
|
|
90
|
+
return false;
|
|
91
|
+
if (!isStillImagePath(shot.path))
|
|
92
|
+
return false;
|
|
93
|
+
if (!belongsToSpec(shot, specName))
|
|
94
|
+
return false;
|
|
95
|
+
const haystack = `${shot.path} ${shot.name ?? ''}`.toLowerCase();
|
|
96
|
+
const title = assertion.title.toLowerCase();
|
|
97
|
+
if (title && haystack.includes(title))
|
|
98
|
+
return true;
|
|
99
|
+
const full = (assertion.fullName ?? '').toLowerCase();
|
|
100
|
+
if (full && haystack.includes(full))
|
|
101
|
+
return true;
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
/** Next unused failure still-image for this spec (ordered fallback). */
|
|
105
|
+
function nextUnusedSpecScreenshot(shots, used, specName) {
|
|
106
|
+
return shots.findIndex((s, i) => !used.has(i) &&
|
|
107
|
+
s.testFailure !== false &&
|
|
108
|
+
isStillImagePath(s.path) &&
|
|
109
|
+
belongsToSpec(s, specName));
|
|
110
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@qanalyzer/forge-cypress",
|
|
3
|
+
"version": "1.1.1",
|
|
4
|
+
"description": "QAnalyzer Cypress reporter + plugin \u2014 ingest or file modes via @qanalyzer/forge-commons",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"qanalyzer",
|
|
7
|
+
"cypress",
|
|
8
|
+
"reporter",
|
|
9
|
+
"testing",
|
|
10
|
+
"jira"
|
|
11
|
+
],
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./mocha": {
|
|
20
|
+
"types": "./dist/mocha.d.ts",
|
|
21
|
+
"default": "./dist/mocha.js"
|
|
22
|
+
},
|
|
23
|
+
"./plugin": {
|
|
24
|
+
"types": "./dist/plugin.d.ts",
|
|
25
|
+
"default": "./dist/plugin.js"
|
|
26
|
+
},
|
|
27
|
+
"./metadata": {
|
|
28
|
+
"types": "./dist/metadata.d.ts",
|
|
29
|
+
"default": "./dist/metadata.js"
|
|
30
|
+
},
|
|
31
|
+
"./package.json": "./package.json"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"!dist/__tests__",
|
|
36
|
+
"README.md"
|
|
37
|
+
],
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "npm run clean && npx tsc --project tsconfig.build.json && cp -R src/__fixtures__ dist/__fixtures__",
|
|
43
|
+
"clean": "rm -rf dist",
|
|
44
|
+
"test": "npm run build && node --test dist/__tests__/**/*.test.js",
|
|
45
|
+
"prepublishOnly": "npm test"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@qanalyzer/forge-commons": "^1.1.1"
|
|
49
|
+
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"cypress": ">=12.0.0",
|
|
52
|
+
"mocha": ">=10.0.0"
|
|
53
|
+
},
|
|
54
|
+
"peerDependenciesMeta": {
|
|
55
|
+
"mocha": {
|
|
56
|
+
"optional": false
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@types/mocha": "^10.0.10",
|
|
61
|
+
"mocha": "^11.3.0"
|
|
62
|
+
},
|
|
63
|
+
"license": "Apache-2.0"
|
|
64
|
+
}
|