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.
Files changed (243) hide show
  1. package/README.md +45 -29
  2. package/lib/commands/assertDoesNotHaveClass.d.ts +18 -0
  3. package/lib/commands/assertDoesNotHaveClass.js +17 -0
  4. package/lib/commands/assertDoesNotHaveClass.js.map +1 -0
  5. package/lib/commands/assertHasClass.d.ts +18 -0
  6. package/lib/commands/assertHasClass.js +17 -0
  7. package/lib/commands/assertHasClass.js.map +1 -0
  8. package/lib/commands/assertNumElements.d.ts +18 -0
  9. package/lib/commands/assertNumElements.js +17 -0
  10. package/lib/commands/assertNumElements.js.map +1 -0
  11. package/lib/commands/clickWithRetry.d.ts +19 -0
  12. package/lib/commands/clickWithRetry.js +29 -0
  13. package/lib/commands/clickWithRetry.js.map +1 -0
  14. package/lib/commands/genTextOfLength.d.ts +20 -0
  15. package/lib/commands/genTextOfLength.js +20 -0
  16. package/lib/commands/genTextOfLength.js.map +1 -0
  17. package/lib/commands/getAttribute.d.ts +20 -0
  18. package/lib/commands/getAttribute.js +22 -0
  19. package/lib/commands/getAttribute.js.map +1 -0
  20. package/lib/commands/getClassName.d.ts +15 -0
  21. package/lib/commands/getClassName.js +21 -0
  22. package/lib/commands/getClassName.js.map +1 -0
  23. package/lib/commands/getCurrentDateInfo.d.ts +21 -0
  24. package/lib/commands/getCurrentDateInfo.js +25 -0
  25. package/lib/commands/getCurrentDateInfo.js.map +1 -0
  26. package/lib/commands/getId.d.ts +15 -0
  27. package/lib/commands/getId.js +21 -0
  28. package/lib/commands/getId.js.map +1 -0
  29. package/lib/commands/getNumElements.d.ts +14 -0
  30. package/lib/commands/getNumElements.js +19 -0
  31. package/lib/commands/getNumElements.js.map +1 -0
  32. package/lib/commands/getSpecialChars.d.ts +14 -0
  33. package/lib/commands/getSpecialChars.js +16 -0
  34. package/lib/commands/getSpecialChars.js.map +1 -0
  35. package/lib/commands/getTitle.d.ts +13 -0
  36. package/lib/commands/getTitle.js +20 -0
  37. package/lib/commands/getTitle.js.map +1 -0
  38. package/lib/commands/handleHarvardKey.d.ts +18 -0
  39. package/lib/commands/handleHarvardKey.js +56 -0
  40. package/lib/commands/handleHarvardKey.js.map +1 -0
  41. package/lib/commands/handleHarvardKey2.d.ts +14 -0
  42. package/lib/commands/handleHarvardKey2.js +88 -0
  43. package/lib/commands/handleHarvardKey2.js.map +1 -0
  44. package/lib/commands/launchAs.d.ts +20 -0
  45. package/lib/commands/launchAs.js +60 -0
  46. package/lib/commands/launchAs.js.map +1 -0
  47. package/lib/commands/launchLTIUsingToken.d.ts +19 -0
  48. package/lib/commands/launchLTIUsingToken.js +74 -0
  49. package/lib/commands/launchLTIUsingToken.js.map +1 -0
  50. package/lib/commands/listSelectLabels.d.ts +15 -0
  51. package/lib/commands/listSelectLabels.js +24 -0
  52. package/lib/commands/listSelectLabels.js.map +1 -0
  53. package/lib/commands/listSelectValues.d.ts +15 -0
  54. package/lib/commands/listSelectValues.js +26 -0
  55. package/lib/commands/listSelectValues.js.map +1 -0
  56. package/lib/commands/navigateToHref.d.ts +19 -0
  57. package/lib/commands/navigateToHref.js +23 -0
  58. package/lib/commands/navigateToHref.js.map +1 -0
  59. package/lib/commands/padWithZeros.d.ts +20 -0
  60. package/lib/commands/padWithZeros.js +24 -0
  61. package/lib/commands/padWithZeros.js.map +1 -0
  62. package/lib/commands/runScript.d.ts +16 -0
  63. package/lib/commands/runScript.js +25 -0
  64. package/lib/commands/runScript.js.map +1 -0
  65. package/lib/commands/typeInto.d.ts +20 -0
  66. package/lib/commands/typeInto.js +28 -0
  67. package/lib/commands/typeInto.js.map +1 -0
  68. package/lib/commands/uniquify.d.ts +15 -0
  69. package/lib/commands/uniquify.js +25 -0
  70. package/lib/commands/uniquify.js.map +1 -0
  71. package/lib/commands/visitCanvasEndpoint.d.ts +27 -0
  72. package/lib/commands/visitCanvasEndpoint.js +35 -0
  73. package/lib/commands/visitCanvasEndpoint.js.map +1 -0
  74. package/lib/commands/visitCanvasGETEndpoint.d.ts +20 -0
  75. package/lib/commands/visitCanvasGETEndpoint.js +26 -0
  76. package/lib/commands/visitCanvasGETEndpoint.js.map +1 -0
  77. package/lib/commands/waitForAtLeastOneElementPresent.d.ts +23 -0
  78. package/lib/commands/waitForAtLeastOneElementPresent.js +27 -0
  79. package/lib/commands/waitForAtLeastOneElementPresent.js.map +1 -0
  80. package/lib/commands/waitForElementVisible.d.ts +14 -0
  81. package/lib/commands/waitForElementVisible.js +20 -0
  82. package/lib/commands/waitForElementVisible.js.map +1 -0
  83. package/lib/index.js.map +1 -0
  84. package/lib/init.d.ts +6 -0
  85. package/lib/init.js +69 -0
  86. package/lib/init.js.map +1 -0
  87. package/lib/setup/genCommandImportFile.js +5 -0
  88. package/lib/setup/genCommandImportFile.js.map +1 -1
  89. package/lib/setup/genE2ELaunchFile.js +5 -0
  90. package/lib/setup/genE2ELaunchFile.js.map +1 -1
  91. package/lib/src/commands/extractDataFromClass.d.ts +7 -4
  92. package/lib/src/commands/extractDataFromClass.js +2 -1
  93. package/lib/src/commands/extractDataFromClass.js.map +1 -1
  94. package/lib/src/commands/extractDataFromClassByContents.d.ts +9 -5
  95. package/lib/src/commands/extractDataFromClassByContents.js +2 -1
  96. package/lib/src/commands/extractDataFromClassByContents.js.map +1 -1
  97. package/lib/src/commands/genTextOfLength.d.ts +20 -0
  98. package/lib/src/commands/genTextOfLength.js +20 -0
  99. package/lib/src/commands/genTextOfLength.js.map +1 -0
  100. package/lib/src/commands/getAttribute.d.ts +20 -0
  101. package/lib/src/commands/getAttribute.js +22 -0
  102. package/lib/src/commands/getAttribute.js.map +1 -0
  103. package/lib/src/commands/getClassName.d.ts +15 -0
  104. package/lib/src/commands/getClassName.js +21 -0
  105. package/lib/src/commands/getClassName.js.map +1 -0
  106. package/lib/src/commands/getCurrentDateInfo.d.ts +21 -0
  107. package/lib/src/commands/getCurrentDateInfo.js +25 -0
  108. package/lib/src/commands/getCurrentDateInfo.js.map +1 -0
  109. package/lib/src/commands/getId.d.ts +15 -0
  110. package/lib/src/commands/getId.js +21 -0
  111. package/lib/src/commands/getId.js.map +1 -0
  112. package/lib/src/commands/getJSON.d.ts +0 -1
  113. package/lib/src/commands/getJSON.js +1 -4
  114. package/lib/src/commands/getJSON.js.map +1 -1
  115. package/lib/src/commands/getSpecialChars.d.ts +14 -0
  116. package/lib/src/commands/getSpecialChars.js +16 -0
  117. package/lib/src/commands/getSpecialChars.js.map +1 -0
  118. package/lib/src/commands/getTitle.d.ts +13 -0
  119. package/lib/src/commands/getTitle.js +20 -0
  120. package/lib/src/commands/getTitle.js.map +1 -0
  121. package/lib/src/commands/index.js +29 -5
  122. package/lib/src/commands/index.js.map +1 -1
  123. package/lib/src/commands/launchLTIUsingToken.js +12 -4
  124. package/lib/src/commands/launchLTIUsingToken.js.map +1 -1
  125. package/lib/src/commands/listSelectLabels.d.ts +15 -0
  126. package/lib/src/commands/listSelectLabels.js +24 -0
  127. package/lib/src/commands/listSelectLabels.js.map +1 -0
  128. package/lib/src/commands/listSelectValues.d.ts +15 -0
  129. package/lib/src/commands/listSelectValues.js +27 -0
  130. package/lib/src/commands/listSelectValues.js.map +1 -0
  131. package/lib/src/commands/padWithZeros.d.ts +20 -0
  132. package/lib/src/commands/padWithZeros.js +24 -0
  133. package/lib/src/commands/padWithZeros.js.map +1 -0
  134. package/lib/src/commands/uniquify.d.ts +15 -0
  135. package/lib/src/commands/uniquify.js +26 -0
  136. package/lib/src/commands/uniquify.js.map +1 -0
  137. package/lib/src/commands/visitCanvasEndpoint.d.ts +26 -0
  138. package/lib/src/commands/visitCanvasEndpoint.js +36 -0
  139. package/lib/src/commands/visitCanvasEndpoint.js.map +1 -0
  140. package/lib/src/commands/waitForAtLeastOneElementPresent.d.ts +23 -0
  141. package/lib/src/commands/waitForAtLeastOneElementPresent.js +28 -0
  142. package/lib/src/commands/waitForAtLeastOneElementPresent.js.map +1 -0
  143. package/lib/src/init.js +28 -2
  144. package/lib/src/init.js.map +1 -1
  145. package/lib/start/constants/DEFAULT_THREADS_PER_COMBO.d.ts +6 -0
  146. package/lib/start/constants/DEFAULT_THREADS_PER_COMBO.js +9 -0
  147. package/lib/start/constants/DEFAULT_THREADS_PER_COMBO.js.map +1 -0
  148. package/lib/start/helpers/collectPngFiles.d.ts +9 -0
  149. package/lib/start/helpers/collectPngFiles.js +31 -0
  150. package/lib/start/helpers/collectPngFiles.js.map +1 -0
  151. package/lib/start/helpers/executeAllHeadlessCombinations.d.ts +15 -0
  152. package/lib/start/helpers/executeAllHeadlessCombinations.js +116 -0
  153. package/lib/start/helpers/executeAllHeadlessCombinations.js.map +1 -0
  154. package/lib/start/helpers/executeCypress.d.ts +17 -0
  155. package/lib/start/helpers/executeCypress.js +103 -0
  156. package/lib/start/helpers/executeCypress.js.map +1 -0
  157. package/lib/start/helpers/generateHtmlReport.d.ts +14 -0
  158. package/lib/start/helpers/generateHtmlReport.js +54 -0
  159. package/lib/start/helpers/generateHtmlReport.js.map +1 -0
  160. package/lib/start/helpers/generateReportHomepage.d.ts +9 -0
  161. package/lib/start/helpers/generateReportHomepage.js +142 -0
  162. package/lib/start/helpers/generateReportHomepage.js.map +1 -0
  163. package/lib/start/helpers/generateReporterConfig.d.ts +17 -0
  164. package/lib/start/helpers/generateReporterConfig.js +32 -0
  165. package/lib/start/helpers/generateReporterConfig.js.map +1 -0
  166. package/lib/start/helpers/getDateLabeledDir.d.ts +7 -0
  167. package/lib/start/helpers/getDateLabeledDir.js +38 -0
  168. package/lib/start/helpers/getDateLabeledDir.js.map +1 -0
  169. package/lib/start/helpers/mergeAllReportsAndGenerateHtml.d.ts +11 -0
  170. package/lib/start/helpers/mergeAllReportsAndGenerateHtml.js +121 -0
  171. package/lib/start/helpers/mergeAllReportsAndGenerateHtml.js.map +1 -0
  172. package/lib/start/helpers/mergeReports.d.ts +14 -0
  173. package/lib/start/helpers/mergeReports.js +63 -0
  174. package/lib/start/helpers/mergeReports.js.map +1 -0
  175. package/lib/start/helpers/reportHomepage.ejs +272 -0
  176. package/lib/start/helpers/runCypressHeadless.d.ts +18 -0
  177. package/lib/start/helpers/runCypressHeadless.js +138 -0
  178. package/lib/start/helpers/runCypressHeadless.js.map +1 -0
  179. package/lib/start/helpers/runCypressVisible.d.ts +8 -0
  180. package/lib/start/helpers/runCypressVisible.js +53 -0
  181. package/lib/start/helpers/runCypressVisible.js.map +1 -0
  182. package/lib/start/index.js +23 -5
  183. package/lib/start/index.js.map +1 -1
  184. package/lib/start/types/MochawesomeReporterConfig.d.ts +15 -0
  185. package/lib/start/types/MochawesomeReporterConfig.js +3 -0
  186. package/lib/start/types/MochawesomeReporterConfig.js.map +1 -0
  187. package/lib/start/types/Profile.d.ts +9 -0
  188. package/lib/start/types/Profile.js +3 -0
  189. package/lib/start/types/Profile.js.map +1 -0
  190. package/lib/start/types/ReportInfo.d.ts +14 -0
  191. package/lib/start/types/ReportInfo.js +3 -0
  192. package/lib/start/types/ReportInfo.js.map +1 -0
  193. package/lib/start/types/RunResult.d.ts +12 -0
  194. package/lib/start/types/RunResult.js +3 -0
  195. package/lib/start/types/RunResult.js.map +1 -0
  196. package/lib/start/types/ScreenshotInfo.d.ts +10 -0
  197. package/lib/start/types/ScreenshotInfo.js +3 -0
  198. package/lib/start/types/ScreenshotInfo.js.map +1 -0
  199. package/lib/start/types/TemplateReportInfo.d.ts +12 -0
  200. package/lib/start/types/TemplateReportInfo.js +3 -0
  201. package/lib/start/types/TemplateReportInfo.js.map +1 -0
  202. package/package.json +10 -8
  203. package/setup/genCommandImportFile.ts +6 -0
  204. package/setup/genE2ELaunchFile.ts +6 -0
  205. package/src/commands/extractDataFromClass.ts +17 -6
  206. package/src/commands/extractDataFromClassByContents.ts +21 -8
  207. package/src/commands/genTextOfLength.ts +54 -0
  208. package/src/commands/getAttribute.ts +58 -0
  209. package/src/commands/getClassName.ts +44 -0
  210. package/src/commands/getCurrentDateInfo.ts +57 -0
  211. package/src/commands/getId.ts +44 -0
  212. package/src/commands/getJSON.ts +0 -4
  213. package/src/commands/getSpecialChars.ts +34 -0
  214. package/src/commands/getTitle.ts +39 -0
  215. package/src/commands/index.ts +29 -5
  216. package/src/commands/launchLTIUsingToken.ts +12 -4
  217. package/src/commands/listSelectLabels.ts +47 -0
  218. package/src/commands/listSelectValues.ts +50 -0
  219. package/src/commands/padWithZeros.ts +53 -0
  220. package/src/commands/uniquify.ts +49 -0
  221. package/src/commands/visitCanvasEndpoint.ts +75 -0
  222. package/src/commands/waitForAtLeastOneElementPresent.ts +64 -0
  223. package/start/constants/DEFAULT_THREADS_PER_COMBO.ts +7 -0
  224. package/start/helpers/collectPngFiles.ts +25 -0
  225. package/start/helpers/executeAllHeadlessCombinations.ts +92 -0
  226. package/start/helpers/executeCypress.ts +66 -0
  227. package/start/helpers/generateHtmlReport.ts +71 -0
  228. package/start/helpers/generateReportHomepage.ts +148 -0
  229. package/start/helpers/generateReporterConfig.ts +39 -0
  230. package/start/helpers/getDateLabeledDir.ts +43 -0
  231. package/start/helpers/mergeAllReportsAndGenerateHtml.ts +150 -0
  232. package/start/helpers/mergeReports.ts +82 -0
  233. package/start/helpers/reportHomepage.ejs +272 -0
  234. package/start/helpers/runCypressHeadless.ts +164 -0
  235. package/start/helpers/runCypressVisible.ts +45 -0
  236. package/start/index.ts +23 -5
  237. package/start/types/MochawesomeReporterConfig.ts +23 -0
  238. package/start/types/Profile.ts +12 -0
  239. package/start/types/ReportInfo.ts +22 -0
  240. package/start/types/RunResult.ts +18 -0
  241. package/start/types/ScreenshotInfo.ts +13 -0
  242. package/start/types/TemplateReportInfo.ts +16 -0
  243. 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;