dceky 1.0.5-beta.ky-declarations.12 ā 1.0.5
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 +45 -29
- package/lib/commands/assertDoesNotHaveClass.d.ts +18 -0
- package/lib/commands/assertDoesNotHaveClass.js +17 -0
- package/lib/commands/assertDoesNotHaveClass.js.map +1 -0
- package/lib/commands/assertHasClass.d.ts +18 -0
- package/lib/commands/assertHasClass.js +17 -0
- package/lib/commands/assertHasClass.js.map +1 -0
- package/lib/commands/assertNumElements.d.ts +18 -0
- package/lib/commands/assertNumElements.js +17 -0
- package/lib/commands/assertNumElements.js.map +1 -0
- package/lib/commands/clickWithRetry.d.ts +19 -0
- package/lib/commands/clickWithRetry.js +29 -0
- package/lib/commands/clickWithRetry.js.map +1 -0
- package/lib/commands/genTextOfLength.d.ts +20 -0
- package/lib/commands/genTextOfLength.js +20 -0
- package/lib/commands/genTextOfLength.js.map +1 -0
- package/lib/commands/getAttribute.d.ts +20 -0
- package/lib/commands/getAttribute.js +22 -0
- package/lib/commands/getAttribute.js.map +1 -0
- package/lib/commands/getClassName.d.ts +15 -0
- package/lib/commands/getClassName.js +21 -0
- package/lib/commands/getClassName.js.map +1 -0
- package/lib/commands/getCurrentDateInfo.d.ts +21 -0
- package/lib/commands/getCurrentDateInfo.js +25 -0
- package/lib/commands/getCurrentDateInfo.js.map +1 -0
- package/lib/commands/getId.d.ts +15 -0
- package/lib/commands/getId.js +21 -0
- package/lib/commands/getId.js.map +1 -0
- package/lib/commands/getNumElements.d.ts +14 -0
- package/lib/commands/getNumElements.js +19 -0
- package/lib/commands/getNumElements.js.map +1 -0
- package/lib/commands/getSpecialChars.d.ts +14 -0
- package/lib/commands/getSpecialChars.js +16 -0
- package/lib/commands/getSpecialChars.js.map +1 -0
- package/lib/commands/getTitle.d.ts +13 -0
- package/lib/commands/getTitle.js +20 -0
- package/lib/commands/getTitle.js.map +1 -0
- package/lib/commands/handleHarvardKey.d.ts +18 -0
- package/lib/commands/handleHarvardKey.js +56 -0
- package/lib/commands/handleHarvardKey.js.map +1 -0
- package/lib/commands/handleHarvardKey2.d.ts +14 -0
- package/lib/commands/handleHarvardKey2.js +88 -0
- package/lib/commands/handleHarvardKey2.js.map +1 -0
- package/lib/commands/launchAs.d.ts +20 -0
- package/lib/commands/launchAs.js +60 -0
- package/lib/commands/launchAs.js.map +1 -0
- package/lib/commands/launchLTIUsingToken.d.ts +19 -0
- package/lib/commands/launchLTIUsingToken.js +74 -0
- package/lib/commands/launchLTIUsingToken.js.map +1 -0
- package/lib/commands/listSelectLabels.d.ts +15 -0
- package/lib/commands/listSelectLabels.js +24 -0
- package/lib/commands/listSelectLabels.js.map +1 -0
- package/lib/commands/listSelectValues.d.ts +15 -0
- package/lib/commands/listSelectValues.js +26 -0
- package/lib/commands/listSelectValues.js.map +1 -0
- package/lib/commands/navigateToHref.d.ts +19 -0
- package/lib/commands/navigateToHref.js +23 -0
- package/lib/commands/navigateToHref.js.map +1 -0
- package/lib/commands/padWithZeros.d.ts +20 -0
- package/lib/commands/padWithZeros.js +24 -0
- package/lib/commands/padWithZeros.js.map +1 -0
- package/lib/commands/runScript.d.ts +16 -0
- package/lib/commands/runScript.js +25 -0
- package/lib/commands/runScript.js.map +1 -0
- package/lib/commands/typeInto.d.ts +20 -0
- package/lib/commands/typeInto.js +28 -0
- package/lib/commands/typeInto.js.map +1 -0
- package/lib/commands/uniquify.d.ts +15 -0
- package/lib/commands/uniquify.js +25 -0
- package/lib/commands/uniquify.js.map +1 -0
- package/lib/commands/visitCanvasEndpoint.d.ts +27 -0
- package/lib/commands/visitCanvasEndpoint.js +35 -0
- package/lib/commands/visitCanvasEndpoint.js.map +1 -0
- package/lib/commands/visitCanvasGETEndpoint.d.ts +20 -0
- package/lib/commands/visitCanvasGETEndpoint.js +26 -0
- package/lib/commands/visitCanvasGETEndpoint.js.map +1 -0
- package/lib/commands/waitForAtLeastOneElementPresent.d.ts +23 -0
- package/lib/commands/waitForAtLeastOneElementPresent.js +27 -0
- package/lib/commands/waitForAtLeastOneElementPresent.js.map +1 -0
- package/lib/commands/waitForElementVisible.d.ts +14 -0
- package/lib/commands/waitForElementVisible.js +20 -0
- package/lib/commands/waitForElementVisible.js.map +1 -0
- package/lib/index.js.map +1 -0
- package/lib/init.d.ts +6 -0
- package/lib/init.js +69 -0
- package/lib/init.js.map +1 -0
- package/lib/setup/genCommandImportFile.js +5 -0
- package/lib/setup/genCommandImportFile.js.map +1 -1
- package/lib/setup/genE2ELaunchFile.js +5 -0
- package/lib/setup/genE2ELaunchFile.js.map +1 -1
- package/lib/src/commands/extractDataFromClass.d.ts +7 -4
- package/lib/src/commands/extractDataFromClass.js +2 -1
- package/lib/src/commands/extractDataFromClass.js.map +1 -1
- package/lib/src/commands/extractDataFromClassByContents.d.ts +9 -5
- package/lib/src/commands/extractDataFromClassByContents.js +2 -1
- package/lib/src/commands/extractDataFromClassByContents.js.map +1 -1
- package/lib/src/commands/genTextOfLength.d.ts +20 -0
- package/lib/src/commands/genTextOfLength.js +20 -0
- package/lib/src/commands/genTextOfLength.js.map +1 -0
- package/lib/src/commands/getAttribute.d.ts +20 -0
- package/lib/src/commands/getAttribute.js +22 -0
- package/lib/src/commands/getAttribute.js.map +1 -0
- package/lib/src/commands/getClassName.d.ts +15 -0
- package/lib/src/commands/getClassName.js +21 -0
- package/lib/src/commands/getClassName.js.map +1 -0
- package/lib/src/commands/getCurrentDateInfo.d.ts +21 -0
- package/lib/src/commands/getCurrentDateInfo.js +25 -0
- package/lib/src/commands/getCurrentDateInfo.js.map +1 -0
- package/lib/src/commands/getId.d.ts +15 -0
- package/lib/src/commands/getId.js +21 -0
- package/lib/src/commands/getId.js.map +1 -0
- package/lib/src/commands/getJSON.d.ts +0 -1
- package/lib/src/commands/getJSON.js +1 -4
- package/lib/src/commands/getJSON.js.map +1 -1
- package/lib/src/commands/getSpecialChars.d.ts +14 -0
- package/lib/src/commands/getSpecialChars.js +16 -0
- package/lib/src/commands/getSpecialChars.js.map +1 -0
- package/lib/src/commands/getTitle.d.ts +13 -0
- package/lib/src/commands/getTitle.js +20 -0
- package/lib/src/commands/getTitle.js.map +1 -0
- package/lib/src/commands/index.js +29 -5
- package/lib/src/commands/index.js.map +1 -1
- package/lib/src/commands/launchLTIUsingToken.js +12 -4
- package/lib/src/commands/launchLTIUsingToken.js.map +1 -1
- package/lib/src/commands/listSelectLabels.d.ts +15 -0
- package/lib/src/commands/listSelectLabels.js +24 -0
- package/lib/src/commands/listSelectLabels.js.map +1 -0
- package/lib/src/commands/listSelectValues.d.ts +15 -0
- package/lib/src/commands/listSelectValues.js +27 -0
- package/lib/src/commands/listSelectValues.js.map +1 -0
- package/lib/src/commands/padWithZeros.d.ts +20 -0
- package/lib/src/commands/padWithZeros.js +24 -0
- package/lib/src/commands/padWithZeros.js.map +1 -0
- package/lib/src/commands/uniquify.d.ts +15 -0
- package/lib/src/commands/uniquify.js +26 -0
- package/lib/src/commands/uniquify.js.map +1 -0
- package/lib/src/commands/visitCanvasEndpoint.d.ts +26 -0
- package/lib/src/commands/visitCanvasEndpoint.js +36 -0
- package/lib/src/commands/visitCanvasEndpoint.js.map +1 -0
- package/lib/src/commands/waitForAtLeastOneElementPresent.d.ts +23 -0
- package/lib/src/commands/waitForAtLeastOneElementPresent.js +28 -0
- package/lib/src/commands/waitForAtLeastOneElementPresent.js.map +1 -0
- package/lib/src/init.js +28 -2
- package/lib/src/init.js.map +1 -1
- package/lib/start/constants/DEFAULT_THREADS_PER_COMBO.d.ts +6 -0
- package/lib/start/constants/DEFAULT_THREADS_PER_COMBO.js +9 -0
- package/lib/start/constants/DEFAULT_THREADS_PER_COMBO.js.map +1 -0
- package/lib/start/helpers/collectPngFiles.d.ts +9 -0
- package/lib/start/helpers/collectPngFiles.js +31 -0
- package/lib/start/helpers/collectPngFiles.js.map +1 -0
- package/lib/start/helpers/executeAllHeadlessCombinations.d.ts +15 -0
- package/lib/start/helpers/executeAllHeadlessCombinations.js +116 -0
- package/lib/start/helpers/executeAllHeadlessCombinations.js.map +1 -0
- package/lib/start/helpers/executeCypress.d.ts +17 -0
- package/lib/start/helpers/executeCypress.js +103 -0
- package/lib/start/helpers/executeCypress.js.map +1 -0
- package/lib/start/helpers/generateHtmlReport.d.ts +14 -0
- package/lib/start/helpers/generateHtmlReport.js +54 -0
- package/lib/start/helpers/generateHtmlReport.js.map +1 -0
- package/lib/start/helpers/generateReportHomepage.d.ts +9 -0
- package/lib/start/helpers/generateReportHomepage.js +142 -0
- package/lib/start/helpers/generateReportHomepage.js.map +1 -0
- package/lib/start/helpers/generateReporterConfig.d.ts +17 -0
- package/lib/start/helpers/generateReporterConfig.js +32 -0
- package/lib/start/helpers/generateReporterConfig.js.map +1 -0
- package/lib/start/helpers/getDateLabeledDir.d.ts +7 -0
- package/lib/start/helpers/getDateLabeledDir.js +38 -0
- package/lib/start/helpers/getDateLabeledDir.js.map +1 -0
- package/lib/start/helpers/mergeAllReportsAndGenerateHtml.d.ts +11 -0
- package/lib/start/helpers/mergeAllReportsAndGenerateHtml.js +121 -0
- package/lib/start/helpers/mergeAllReportsAndGenerateHtml.js.map +1 -0
- package/lib/start/helpers/mergeReports.d.ts +14 -0
- package/lib/start/helpers/mergeReports.js +63 -0
- package/lib/start/helpers/mergeReports.js.map +1 -0
- package/lib/start/helpers/reportHomepage.ejs +272 -0
- package/lib/start/helpers/runCypressHeadless.d.ts +18 -0
- package/lib/start/helpers/runCypressHeadless.js +138 -0
- package/lib/start/helpers/runCypressHeadless.js.map +1 -0
- package/lib/start/helpers/runCypressVisible.d.ts +8 -0
- package/lib/start/helpers/runCypressVisible.js +53 -0
- package/lib/start/helpers/runCypressVisible.js.map +1 -0
- package/lib/start/index.js +23 -5
- package/lib/start/index.js.map +1 -1
- package/lib/start/types/MochawesomeReporterConfig.d.ts +15 -0
- package/lib/start/types/MochawesomeReporterConfig.js +3 -0
- package/lib/start/types/MochawesomeReporterConfig.js.map +1 -0
- package/lib/start/types/Profile.d.ts +9 -0
- package/lib/start/types/Profile.js +3 -0
- package/lib/start/types/Profile.js.map +1 -0
- package/lib/start/types/ReportInfo.d.ts +14 -0
- package/lib/start/types/ReportInfo.js +3 -0
- package/lib/start/types/ReportInfo.js.map +1 -0
- package/lib/start/types/RunResult.d.ts +12 -0
- package/lib/start/types/RunResult.js +3 -0
- package/lib/start/types/RunResult.js.map +1 -0
- package/lib/start/types/ScreenshotInfo.d.ts +10 -0
- package/lib/start/types/ScreenshotInfo.js +3 -0
- package/lib/start/types/ScreenshotInfo.js.map +1 -0
- package/lib/start/types/TemplateReportInfo.d.ts +12 -0
- package/lib/start/types/TemplateReportInfo.js +3 -0
- package/lib/start/types/TemplateReportInfo.js.map +1 -0
- package/package.json +10 -8
- package/setup/genCommandImportFile.ts +6 -0
- package/setup/genE2ELaunchFile.ts +6 -0
- package/src/commands/extractDataFromClass.ts +17 -6
- package/src/commands/extractDataFromClassByContents.ts +21 -8
- package/src/commands/genTextOfLength.ts +54 -0
- package/src/commands/getAttribute.ts +58 -0
- package/src/commands/getClassName.ts +44 -0
- package/src/commands/getCurrentDateInfo.ts +57 -0
- package/src/commands/getId.ts +44 -0
- package/src/commands/getJSON.ts +0 -4
- package/src/commands/getSpecialChars.ts +34 -0
- package/src/commands/getTitle.ts +39 -0
- package/src/commands/index.ts +29 -5
- package/src/commands/launchLTIUsingToken.ts +12 -4
- package/src/commands/listSelectLabels.ts +47 -0
- package/src/commands/listSelectValues.ts +50 -0
- package/src/commands/padWithZeros.ts +53 -0
- package/src/commands/uniquify.ts +49 -0
- package/src/commands/visitCanvasEndpoint.ts +75 -0
- package/src/commands/waitForAtLeastOneElementPresent.ts +64 -0
- package/start/constants/DEFAULT_THREADS_PER_COMBO.ts +7 -0
- package/start/helpers/collectPngFiles.ts +25 -0
- package/start/helpers/executeAllHeadlessCombinations.ts +92 -0
- package/start/helpers/executeCypress.ts +66 -0
- package/start/helpers/generateHtmlReport.ts +71 -0
- package/start/helpers/generateReportHomepage.ts +148 -0
- package/start/helpers/generateReporterConfig.ts +39 -0
- package/start/helpers/getDateLabeledDir.ts +43 -0
- package/start/helpers/mergeAllReportsAndGenerateHtml.ts +150 -0
- package/start/helpers/mergeReports.ts +82 -0
- package/start/helpers/reportHomepage.ejs +272 -0
- package/start/helpers/runCypressHeadless.ts +164 -0
- package/start/helpers/runCypressVisible.ts +45 -0
- package/start/index.ts +23 -5
- package/start/types/MochawesomeReporterConfig.ts +23 -0
- package/start/types/Profile.ts +12 -0
- package/start/types/ReportInfo.ts +22 -0
- package/start/types/RunResult.ts +18 -0
- package/start/types/ScreenshotInfo.ts +13 -0
- package/start/types/TemplateReportInfo.ts +16 -0
- package/src/commands/visitCanvasGETEndpoint.ts +0 -61
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import ejs from 'ejs';
|
|
5
|
+
|
|
6
|
+
// Import helpers
|
|
7
|
+
import collectPngFiles from './collectPngFiles';
|
|
8
|
+
|
|
9
|
+
// Import types
|
|
10
|
+
import ReportInfo from '../types/ReportInfo';
|
|
11
|
+
import ScreenshotInfo from '../types/ScreenshotInfo';
|
|
12
|
+
import TemplateReportInfo from '../types/TemplateReportInfo';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Generate an HTML homepage that links to all reports
|
|
16
|
+
* @author Yuen Ler Chow
|
|
17
|
+
* @param reports - Array of report information
|
|
18
|
+
* @param outputDir - The directory where the homepage should be created
|
|
19
|
+
*/
|
|
20
|
+
const generateReportHomepage = (
|
|
21
|
+
reports: ReportInfo[],
|
|
22
|
+
outputDir: string,
|
|
23
|
+
): void => {
|
|
24
|
+
const homepagePath = path.join(outputDir, 'index.html');
|
|
25
|
+
const combinedReportPath = path.join(outputDir, 'all-runs.html');
|
|
26
|
+
const combinedJsonPath = path.join(outputDir, 'all-report-data.json');
|
|
27
|
+
|
|
28
|
+
const hasCombinedReport = fs.existsSync(combinedReportPath);
|
|
29
|
+
|
|
30
|
+
// Try to read combined stats from all-report-data.json
|
|
31
|
+
let combinedTotalTests: number | null = null;
|
|
32
|
+
let combinedPassedTests: number | null = null;
|
|
33
|
+
if (fs.existsSync(combinedJsonPath)) {
|
|
34
|
+
try {
|
|
35
|
+
const raw = fs.readFileSync(combinedJsonPath, 'utf-8');
|
|
36
|
+
const data = JSON.parse(raw);
|
|
37
|
+
const stats = (data && data.stats) || null;
|
|
38
|
+
if (stats && typeof stats.tests === 'number' && typeof stats.passes === 'number') {
|
|
39
|
+
combinedTotalTests = stats.tests;
|
|
40
|
+
combinedPassedTests = stats.passes;
|
|
41
|
+
}
|
|
42
|
+
} catch (err) {
|
|
43
|
+
// File exists but couldn't be read/parsed - log warning
|
|
44
|
+
console.warn('ā ļø Could not read combined stats:', err);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Try to read per-combination stats from each combo's report-data.json
|
|
49
|
+
reports.forEach((report) => {
|
|
50
|
+
const comboJsonPath = path.join(
|
|
51
|
+
outputDir,
|
|
52
|
+
`${report.profileName}-${report.browser}`,
|
|
53
|
+
'report-data.json',
|
|
54
|
+
);
|
|
55
|
+
if (!fs.existsSync(comboJsonPath)) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const raw = fs.readFileSync(comboJsonPath, 'utf-8');
|
|
60
|
+
const data = JSON.parse(raw);
|
|
61
|
+
const stats = (data && data.stats) || null;
|
|
62
|
+
if (stats && typeof stats.tests === 'number' && typeof stats.passes === 'number') {
|
|
63
|
+
// eslint-disable-next-line no-param-reassign
|
|
64
|
+
report.totalTests = stats.tests;
|
|
65
|
+
// eslint-disable-next-line no-param-reassign
|
|
66
|
+
report.passedTests = stats.passes;
|
|
67
|
+
}
|
|
68
|
+
} catch (err) {
|
|
69
|
+
// File exists but couldn't be read/parsed - log warning
|
|
70
|
+
console.warn(`ā ļø Could not read stats for ${report.profileName}-${report.browser}:`, err);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Sort reports by profile name, then browser
|
|
75
|
+
const sortedReports = [...reports].sort((a, b) => {
|
|
76
|
+
if (a.profileName !== b.profileName) {
|
|
77
|
+
return a.profileName.localeCompare(b.profileName);
|
|
78
|
+
}
|
|
79
|
+
return a.browser.localeCompare(b.browser);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Prepare reports with computed fields for the template
|
|
83
|
+
const templateReports: TemplateReportInfo[] = sortedReports.map((report) => {
|
|
84
|
+
// Compute relative report path
|
|
85
|
+
let relativeReportPath: string | null = null;
|
|
86
|
+
if (report.reportPath && fs.existsSync(report.reportPath)) {
|
|
87
|
+
relativeReportPath = path.relative(outputDir, report.reportPath).replace(/\\/g, '/');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Collect screenshots
|
|
91
|
+
const screenshots: ScreenshotInfo[] = [];
|
|
92
|
+
const comboScreenshotsDir = path.join(
|
|
93
|
+
outputDir,
|
|
94
|
+
`${report.profileName}-${report.browser}`,
|
|
95
|
+
'screenshots',
|
|
96
|
+
);
|
|
97
|
+
if (fs.existsSync(comboScreenshotsDir)) {
|
|
98
|
+
const pngFiles = collectPngFiles(comboScreenshotsDir);
|
|
99
|
+
pngFiles.forEach((rel) => {
|
|
100
|
+
const href = path
|
|
101
|
+
.relative(outputDir, path.join(comboScreenshotsDir, rel))
|
|
102
|
+
.replace(/\\/g, '/');
|
|
103
|
+
screenshots.push({ href, name: rel });
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
...report,
|
|
109
|
+
relativeReportPath,
|
|
110
|
+
screenshots,
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Group by profile
|
|
115
|
+
const reportsByProfile: { [key: string]: TemplateReportInfo[] } = {};
|
|
116
|
+
templateReports.forEach((report) => {
|
|
117
|
+
if (!reportsByProfile[report.profileName]) {
|
|
118
|
+
reportsByProfile[report.profileName] = [];
|
|
119
|
+
}
|
|
120
|
+
reportsByProfile[report.profileName].push(report);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Calculate summary stats
|
|
124
|
+
const totalRuns = reports.length;
|
|
125
|
+
const passedRuns = reports.filter((r) => { return r.success; }).length;
|
|
126
|
+
const failedRuns = reports.filter((r) => { return !r.success; }).length;
|
|
127
|
+
const profileCount = Object.keys(reportsByProfile).length;
|
|
128
|
+
|
|
129
|
+
// Load and render EJS template
|
|
130
|
+
const templatePath = path.join(__dirname, 'reportHomepage.ejs');
|
|
131
|
+
const templateFile = fs.readFileSync(templatePath, 'utf-8');
|
|
132
|
+
const html = ejs.render(templateFile, {
|
|
133
|
+
hasCombinedReport,
|
|
134
|
+
combinedTotalTests,
|
|
135
|
+
combinedPassedTests,
|
|
136
|
+
totalRuns,
|
|
137
|
+
passedRuns,
|
|
138
|
+
failedRuns,
|
|
139
|
+
profileCount,
|
|
140
|
+
reportsByProfile,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// Write the HTML file
|
|
144
|
+
fs.writeFileSync(homepagePath, html, 'utf-8');
|
|
145
|
+
console.log(`\nš Report homepage generated: ${homepagePath}`);
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export default generateReportHomepage;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import MochawesomeReporterConfig from '../types/MochawesomeReporterConfig';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Generate inline reporter configuration for cypress-multi-reporters
|
|
6
|
+
* that produces granular mochawesome JSON per spec
|
|
7
|
+
* @author Yuen Ler Chow
|
|
8
|
+
* @param opts - object of arguments
|
|
9
|
+
* @param opts.resultsDir - Base directory for results
|
|
10
|
+
* @param opts.profileName - Profile name
|
|
11
|
+
* @param opts.browserName - Browser name
|
|
12
|
+
* @returns Reporter config object
|
|
13
|
+
*/
|
|
14
|
+
const generateReporterConfig = (opts: {
|
|
15
|
+
resultsDir: string;
|
|
16
|
+
profileName: string;
|
|
17
|
+
browserName: string;
|
|
18
|
+
}): MochawesomeReporterConfig => {
|
|
19
|
+
const { resultsDir, profileName, browserName } = opts;
|
|
20
|
+
|
|
21
|
+
const granularResultsDir = path.join(
|
|
22
|
+
resultsDir,
|
|
23
|
+
`${profileName}-${browserName}`,
|
|
24
|
+
'granular-results',
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
reporterEnabled: 'mochawesome',
|
|
29
|
+
mochawesomeReporterOptions: {
|
|
30
|
+
reportDir: granularResultsDir,
|
|
31
|
+
reportFilename: 'test-[name]',
|
|
32
|
+
overwrite: false,
|
|
33
|
+
html: false,
|
|
34
|
+
json: true,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default generateReporterConfig;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import getRootPath from './getRootPath';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Get a date-labeled directory path for results using Eastern Time
|
|
6
|
+
* @author Yuen Ler Chow
|
|
7
|
+
* @returns path to date-labeled directory (e.g., cypress-results/2024-1-15_3-05pm)
|
|
8
|
+
*/
|
|
9
|
+
const getDateLabeledDir = (): string => {
|
|
10
|
+
const root = getRootPath();
|
|
11
|
+
const now = new Date();
|
|
12
|
+
|
|
13
|
+
// Format date in Eastern Time
|
|
14
|
+
const str = now.toLocaleString(
|
|
15
|
+
'en-US', // Using US encoding (it's the only one installed on containers)
|
|
16
|
+
{ timeZone: 'America/New_York' }, // Force EST timezone
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
// Parse the string for the date/time info
|
|
20
|
+
const [dateStr, timeStr] = str.split(', '); // Format: MM/DD/YYYY, HH:MM:SS AM
|
|
21
|
+
const [monthStr, dayStr, yearStr] = dateStr.split('/'); // Format: MM/DD/YYYY
|
|
22
|
+
const [hourStr, minStr, ending] = timeStr.split(':'); // Format: HH:MM:SS AM
|
|
23
|
+
|
|
24
|
+
// Create all time numbers
|
|
25
|
+
const year = Number.parseInt(yearStr, 10);
|
|
26
|
+
const month = Number.parseInt(monthStr, 10);
|
|
27
|
+
const day = Number.parseInt(dayStr, 10);
|
|
28
|
+
const minute = Number.parseInt(minStr, 10);
|
|
29
|
+
const hour12 = Number.parseInt(hourStr, 10);
|
|
30
|
+
|
|
31
|
+
// Determine AM/PM
|
|
32
|
+
const isAM = ending.toLowerCase().includes('am');
|
|
33
|
+
|
|
34
|
+
// Pad minute with leading zero if needed
|
|
35
|
+
const minutePadded = minute.toString().padStart(2, '0');
|
|
36
|
+
|
|
37
|
+
// Build formatted date string: YYYY-M-D_H-MMam/pm (no spaces for shell compatibility)
|
|
38
|
+
const formattedDate = `${year}-${month}-${day}_${hour12}-${minutePadded}${isAM ? 'am' : 'pm'}`;
|
|
39
|
+
|
|
40
|
+
return path.join(root, 'cypress-results', formattedDate);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export default getDateLabeledDir;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
|
|
3
|
+
// Import libs
|
|
4
|
+
import { execSync } from 'child_process';
|
|
5
|
+
import fs from 'fs';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
|
|
8
|
+
// Import helpers
|
|
9
|
+
import getRootPath from './getRootPath';
|
|
10
|
+
import RunResult from '../types/RunResult';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Recursively annotate mochawesome suites (not individual tests) with a label
|
|
14
|
+
* so the combined report shows profile+browser for each suite
|
|
15
|
+
* @author Yuen Ler Chow
|
|
16
|
+
* @param node - The mochawesome node to annotate
|
|
17
|
+
* @param label - The label to prepend to suite titles
|
|
18
|
+
*/
|
|
19
|
+
const annotateMochawesomeSuites = (node: any, label: string): void => {
|
|
20
|
+
if (!node || typeof node !== 'object') {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// If this is an array of nodes, annotate each element
|
|
25
|
+
if (Array.isArray(node)) {
|
|
26
|
+
node.forEach((child: any) => {
|
|
27
|
+
annotateMochawesomeSuites(child, label);
|
|
28
|
+
});
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Only annotate if this is a suite (has suites or tests arrays)
|
|
33
|
+
const isSuite = Array.isArray(node.suites) || Array.isArray(node.tests);
|
|
34
|
+
if (isSuite) {
|
|
35
|
+
if (typeof node.title === 'string') {
|
|
36
|
+
// eslint-disable-next-line no-param-reassign
|
|
37
|
+
node.title = `${label}${node.title}`;
|
|
38
|
+
}
|
|
39
|
+
if (typeof node.fullTitle === 'string') {
|
|
40
|
+
// eslint-disable-next-line no-param-reassign
|
|
41
|
+
node.fullTitle = `${label}${node.fullTitle}`;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Recurse into child suites (but not tests)
|
|
46
|
+
if (Array.isArray(node.suites)) {
|
|
47
|
+
node.suites.forEach((suite: any) => {
|
|
48
|
+
annotateMochawesomeSuites(suite, label);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Merge all per-combination mochawesome JSON reports into a single JSON
|
|
55
|
+
* and generate one combined HTML report for all runs.
|
|
56
|
+
* Each suite/test is annotated with [profile][browser] in its title.
|
|
57
|
+
* @author Yuen Ler Chow
|
|
58
|
+
* @param outputDir - Date-labeled results directory
|
|
59
|
+
* @param results - Array of run results
|
|
60
|
+
*/
|
|
61
|
+
const mergeAllReportsAndGenerateHtml = (
|
|
62
|
+
outputDir: string,
|
|
63
|
+
results: RunResult[],
|
|
64
|
+
): void => {
|
|
65
|
+
// Collect annotated copies of report-data.json files from successful runs
|
|
66
|
+
const annotatedJsonPaths: string[] = [];
|
|
67
|
+
|
|
68
|
+
results.forEach((result) => {
|
|
69
|
+
const jsonPath = path.join(
|
|
70
|
+
outputDir,
|
|
71
|
+
`${result.profileName}-${result.browser}`,
|
|
72
|
+
'report-data.json',
|
|
73
|
+
);
|
|
74
|
+
if (!fs.existsSync(jsonPath)) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
// Import the json report
|
|
80
|
+
const raw = fs.readFileSync(jsonPath, 'utf-8');
|
|
81
|
+
const data = JSON.parse(raw);
|
|
82
|
+
const label = `[${result.profileName}][${result.browser}] `;
|
|
83
|
+
|
|
84
|
+
if (Array.isArray(data.results)) {
|
|
85
|
+
data.results.forEach((res: any) => {
|
|
86
|
+
if (res && res.suites) {
|
|
87
|
+
annotateMochawesomeSuites(res.suites, label);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Annotate tests with their profile+browser
|
|
93
|
+
const annotatedPath = path.join(
|
|
94
|
+
outputDir,
|
|
95
|
+
`${result.profileName}-${result.browser}-labeled.json`,
|
|
96
|
+
);
|
|
97
|
+
fs.writeFileSync(annotatedPath, JSON.stringify(data, null, 2), 'utf-8');
|
|
98
|
+
annotatedJsonPaths.push(annotatedPath);
|
|
99
|
+
} catch (e) {
|
|
100
|
+
console.error(`Error annotating report for ${result.profileName} + ${result.browser}:`, e);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
if (annotatedJsonPaths.length === 0) {
|
|
105
|
+
console.warn('No annotated report-data.json files found. Skipping global merge.');
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const allReportDataPath = path.join(outputDir, 'all-report-data.json');
|
|
110
|
+
const allReportHtmlDir = outputDir;
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
// Build mochawesome-merge command with all annotated JSON paths
|
|
114
|
+
const mergedArgs = (
|
|
115
|
+
annotatedJsonPaths
|
|
116
|
+
.map((p) => {
|
|
117
|
+
return `"${p}"`;
|
|
118
|
+
})
|
|
119
|
+
.join(' ')
|
|
120
|
+
);
|
|
121
|
+
const mergeCommand = `npx mochawesome-merge ${mergedArgs} > "${allReportDataPath}"`;
|
|
122
|
+
|
|
123
|
+
console.log('Merging all annotated report-data.json files into a single JSON for all runs...');
|
|
124
|
+
|
|
125
|
+
execSync(mergeCommand, {
|
|
126
|
+
stdio: 'inherit',
|
|
127
|
+
cwd: getRootPath(),
|
|
128
|
+
shell: '/bin/bash',
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Generate combined HTML using marge
|
|
132
|
+
const margeCommand = `npx marge "${allReportDataPath}" --reportDir "${allReportHtmlDir}" --reportFilename "all-runs"`;
|
|
133
|
+
|
|
134
|
+
console.log('Generating combined HTML report for all runs...');
|
|
135
|
+
|
|
136
|
+
execSync(
|
|
137
|
+
margeCommand,
|
|
138
|
+
{
|
|
139
|
+
stdio: 'inherit',
|
|
140
|
+
cwd: getRootPath(),
|
|
141
|
+
},
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
console.log(`Combined HTML report generated at: ${path.join(allReportHtmlDir, 'all-runs.html')}`);
|
|
145
|
+
} catch (e) {
|
|
146
|
+
console.error('Error generating combined HTML report for all runs:', e);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
export default mergeAllReportsAndGenerateHtml;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { execSync } from 'child_process';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { existsSync, readdirSync } from 'fs';
|
|
5
|
+
import getRootPath from './getRootPath';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Merge mochawesome JSON reports into a single JSON file using mochawesome-merge
|
|
9
|
+
* @author Yuen Ler Chow
|
|
10
|
+
* @param opts - object of arguments
|
|
11
|
+
* @param opts.resultsDir - Results directory containing the reports
|
|
12
|
+
* @param opts.profileName - Profile name
|
|
13
|
+
* @param opts.browserName - Browser name
|
|
14
|
+
*/
|
|
15
|
+
const mergeReports = (
|
|
16
|
+
opts: {
|
|
17
|
+
resultsDir: string;
|
|
18
|
+
profileName: string;
|
|
19
|
+
browserName: string;
|
|
20
|
+
},
|
|
21
|
+
): void => {
|
|
22
|
+
const { resultsDir, profileName, browserName } = opts;
|
|
23
|
+
|
|
24
|
+
const granularResultsDir = path.join(
|
|
25
|
+
resultsDir,
|
|
26
|
+
`${profileName}-${browserName}`,
|
|
27
|
+
'granular-results',
|
|
28
|
+
);
|
|
29
|
+
const reportDataPath = path.join(
|
|
30
|
+
resultsDir,
|
|
31
|
+
`${profileName}-${browserName}`,
|
|
32
|
+
'report-data.json',
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
console.log(`\nš Merge Reports Debug for ${profileName} + ${browserName}:`);
|
|
36
|
+
console.log(` Granular results dir: ${granularResultsDir}`);
|
|
37
|
+
console.log(` Report data path: ${reportDataPath}`);
|
|
38
|
+
|
|
39
|
+
if (!existsSync(granularResultsDir)) {
|
|
40
|
+
const errorMsg = `ā ERROR: Granular results directory does not exist: ${granularResultsDir}`;
|
|
41
|
+
console.error(errorMsg);
|
|
42
|
+
throw new Error(errorMsg);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// List files in granular results directory
|
|
46
|
+
const files = readdirSync(granularResultsDir);
|
|
47
|
+
const jsonFiles = files.filter((f) => { return f.endsWith('.json'); });
|
|
48
|
+
console.log(` Found ${jsonFiles.length} JSON files: ${jsonFiles.join(', ') || '(none)'}`);
|
|
49
|
+
|
|
50
|
+
if (jsonFiles.length === 0) {
|
|
51
|
+
const errorMsg = `ā ERROR: No JSON files found in granular results directory: ${granularResultsDir}`;
|
|
52
|
+
console.error(errorMsg);
|
|
53
|
+
throw new Error(errorMsg);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
const command = `npx mochawesome-merge "${path.join(granularResultsDir, '*.json')}" > "${reportDataPath}"`;
|
|
58
|
+
|
|
59
|
+
console.log(` Running: ${command}`);
|
|
60
|
+
console.log(`Merging reports for ${profileName} + ${browserName}...`);
|
|
61
|
+
|
|
62
|
+
execSync(command, {
|
|
63
|
+
stdio: 'inherit',
|
|
64
|
+
cwd: getRootPath(),
|
|
65
|
+
shell: '/bin/bash',
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Verify the report was created
|
|
69
|
+
if (!existsSync(reportDataPath)) {
|
|
70
|
+
const errorMsg = `ā ERROR: Report data was not created at: ${reportDataPath}`;
|
|
71
|
+
console.error(errorMsg);
|
|
72
|
+
throw new Error(errorMsg);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
console.log(` ā
Report data created successfully at: ${reportDataPath}`);
|
|
76
|
+
} catch (e) {
|
|
77
|
+
console.error(`Error merging reports for ${profileName} + ${browserName}:`, e);
|
|
78
|
+
throw e;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export default mergeReports;
|