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,272 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Cypress Test Reports</title>
|
|
7
|
+
<style>
|
|
8
|
+
* {
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0;
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
}
|
|
13
|
+
body {
|
|
14
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
15
|
+
background: #f5f5f5;
|
|
16
|
+
padding: 2rem 1rem;
|
|
17
|
+
color: #222;
|
|
18
|
+
}
|
|
19
|
+
.container {
|
|
20
|
+
max-width: 75rem;
|
|
21
|
+
margin: 0 auto;
|
|
22
|
+
background: #ffffff;
|
|
23
|
+
border-radius: 0.5rem;
|
|
24
|
+
border: 0.0625rem solid #e0e0e0;
|
|
25
|
+
box-shadow: 0 0.25rem 1rem rgba(0, 0, 0, 0.04);
|
|
26
|
+
}
|
|
27
|
+
header {
|
|
28
|
+
border-bottom: 0.0625rem solid #e0e0e0;
|
|
29
|
+
padding: 1.25rem 1.5rem;
|
|
30
|
+
text-align: center;
|
|
31
|
+
}
|
|
32
|
+
h1 {
|
|
33
|
+
font-size: 1.75rem;
|
|
34
|
+
margin-bottom: 0.625rem;
|
|
35
|
+
}
|
|
36
|
+
.subtitle {
|
|
37
|
+
font-size: 0.95rem;
|
|
38
|
+
color: #666666;
|
|
39
|
+
}
|
|
40
|
+
.content {
|
|
41
|
+
padding: 1.5rem;
|
|
42
|
+
}
|
|
43
|
+
.profile-section {
|
|
44
|
+
margin-bottom: 2.5rem;
|
|
45
|
+
}
|
|
46
|
+
.profile-title {
|
|
47
|
+
font-size: 1.1rem;
|
|
48
|
+
color: #111111;
|
|
49
|
+
margin-bottom: 0.75rem;
|
|
50
|
+
border-bottom: 0.0625rem solid #e0e0e0;
|
|
51
|
+
padding-bottom: 0.375rem;
|
|
52
|
+
}
|
|
53
|
+
.report-grid {
|
|
54
|
+
display: grid;
|
|
55
|
+
grid-template-columns: repeat(auto-fill, minmax(15.625rem, 1fr));
|
|
56
|
+
gap: 1.25rem;
|
|
57
|
+
margin-bottom: 1.875rem;
|
|
58
|
+
}
|
|
59
|
+
.report-card {
|
|
60
|
+
border: 0.0625rem solid #e0e0e0;
|
|
61
|
+
border-radius: 0.5rem;
|
|
62
|
+
padding: 1rem;
|
|
63
|
+
background: #fafafa;
|
|
64
|
+
}
|
|
65
|
+
.report-card.success {
|
|
66
|
+
border-color: #c8e6c9;
|
|
67
|
+
background: #f4f9f4;
|
|
68
|
+
}
|
|
69
|
+
.report-card.failed {
|
|
70
|
+
border-color: #ffcdd2;
|
|
71
|
+
background: #fdf5f6;
|
|
72
|
+
}
|
|
73
|
+
.browser-name {
|
|
74
|
+
font-size: 1rem;
|
|
75
|
+
font-weight: bold;
|
|
76
|
+
color: #222222;
|
|
77
|
+
margin-bottom: 0.625rem;
|
|
78
|
+
text-transform: capitalize;
|
|
79
|
+
}
|
|
80
|
+
.status {
|
|
81
|
+
display: inline-block;
|
|
82
|
+
padding: 0.25rem 0.75rem;
|
|
83
|
+
border-radius: 0.75rem;
|
|
84
|
+
font-size: 0.85em;
|
|
85
|
+
font-weight: bold;
|
|
86
|
+
margin-bottom: 0.625rem;
|
|
87
|
+
}
|
|
88
|
+
.status.success {
|
|
89
|
+
background: #2e7d32;
|
|
90
|
+
color: white;
|
|
91
|
+
}
|
|
92
|
+
.status.failed {
|
|
93
|
+
background: #c62828;
|
|
94
|
+
color: white;
|
|
95
|
+
}
|
|
96
|
+
.report-link {
|
|
97
|
+
display: inline-block;
|
|
98
|
+
margin-top: 0.625rem;
|
|
99
|
+
padding: 0.5rem 1rem;
|
|
100
|
+
background: #1976d2;
|
|
101
|
+
color: white;
|
|
102
|
+
text-decoration: none;
|
|
103
|
+
border-radius: 0.375rem;
|
|
104
|
+
transition: background 0.3s ease;
|
|
105
|
+
}
|
|
106
|
+
.report-link:hover {
|
|
107
|
+
background: #115293;
|
|
108
|
+
}
|
|
109
|
+
.timestamp {
|
|
110
|
+
font-size: 0.85em;
|
|
111
|
+
color: #777777;
|
|
112
|
+
margin-top: 0.5rem;
|
|
113
|
+
}
|
|
114
|
+
.summary {
|
|
115
|
+
background: #fafafa;
|
|
116
|
+
padding: 1rem 1.125rem;
|
|
117
|
+
border-radius: 0.375rem;
|
|
118
|
+
margin-bottom: 1.875rem;
|
|
119
|
+
border: 0.0625rem solid #e0e0e0;
|
|
120
|
+
}
|
|
121
|
+
.summary h2 {
|
|
122
|
+
color: #111111;
|
|
123
|
+
margin-bottom: 0.625rem;
|
|
124
|
+
font-size: 1rem;
|
|
125
|
+
}
|
|
126
|
+
.summary-stats {
|
|
127
|
+
display: flex;
|
|
128
|
+
gap: 1.25rem;
|
|
129
|
+
flex-wrap: wrap;
|
|
130
|
+
}
|
|
131
|
+
.stat {
|
|
132
|
+
display: flex;
|
|
133
|
+
flex-direction: column;
|
|
134
|
+
}
|
|
135
|
+
.stat-value {
|
|
136
|
+
font-size: 1.4rem;
|
|
137
|
+
font-weight: bold;
|
|
138
|
+
color: #1976d2;
|
|
139
|
+
}
|
|
140
|
+
.stat-label {
|
|
141
|
+
font-size: 0.9em;
|
|
142
|
+
color: #777777;
|
|
143
|
+
text-transform: uppercase;
|
|
144
|
+
letter-spacing: 0.0625rem;
|
|
145
|
+
}
|
|
146
|
+
.combined-report {
|
|
147
|
+
margin-bottom: 1.5rem;
|
|
148
|
+
padding: 0.875rem 1rem;
|
|
149
|
+
border-radius: 0.375rem;
|
|
150
|
+
border: 0.0625rem solid #d0d0d0;
|
|
151
|
+
background: #f9fafb;
|
|
152
|
+
display: flex;
|
|
153
|
+
align-items: center;
|
|
154
|
+
justify-content: space-between;
|
|
155
|
+
gap: 0.75rem;
|
|
156
|
+
}
|
|
157
|
+
.combined-report-title {
|
|
158
|
+
font-size: 0.95rem;
|
|
159
|
+
font-weight: 500;
|
|
160
|
+
color: #111111;
|
|
161
|
+
}
|
|
162
|
+
.combined-report-subtitle {
|
|
163
|
+
font-size: 0.85rem;
|
|
164
|
+
color: #777777;
|
|
165
|
+
margin-top: 0.125rem;
|
|
166
|
+
}
|
|
167
|
+
.combined-report-button {
|
|
168
|
+
padding: 0.5rem 1rem;
|
|
169
|
+
border-radius: 0.25rem;
|
|
170
|
+
border: 0.0625rem solid #1976d2;
|
|
171
|
+
background: #1976d2;
|
|
172
|
+
color: #ffffff;
|
|
173
|
+
text-decoration: none;
|
|
174
|
+
font-size: 0.9rem;
|
|
175
|
+
font-weight: 500;
|
|
176
|
+
white-space: nowrap;
|
|
177
|
+
}
|
|
178
|
+
.combined-report-button:hover {
|
|
179
|
+
background: #115293;
|
|
180
|
+
border-color: #115293;
|
|
181
|
+
}
|
|
182
|
+
.screenshot-list {
|
|
183
|
+
list-style: none;
|
|
184
|
+
padding-left: 0;
|
|
185
|
+
margin-top: 0.5rem;
|
|
186
|
+
}
|
|
187
|
+
.no-report {
|
|
188
|
+
color: #999;
|
|
189
|
+
font-size: 0.9em;
|
|
190
|
+
}
|
|
191
|
+
</style>
|
|
192
|
+
</head>
|
|
193
|
+
<body>
|
|
194
|
+
<div class="container">
|
|
195
|
+
<header>
|
|
196
|
+
<h1>Cypress Test Reports</h1>
|
|
197
|
+
<p class="subtitle">Profile and browser run summary</p>
|
|
198
|
+
</header>
|
|
199
|
+
<div class="content">
|
|
200
|
+
<% if (hasCombinedReport) { %>
|
|
201
|
+
<div class="combined-report">
|
|
202
|
+
<div>
|
|
203
|
+
<div class="combined-report-title">Combined report for all profiles and browsers</div>
|
|
204
|
+
<div class="combined-report-subtitle">
|
|
205
|
+
<% if (combinedTotalTests !== null && combinedPassedTests !== null) { %>
|
|
206
|
+
<%= combinedPassedTests %>/<%= combinedTotalTests %> tests passing in this run.
|
|
207
|
+
<% } else { %>
|
|
208
|
+
View a single consolidated Mochawesome report for this run.
|
|
209
|
+
<% } %>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
<a href="all-runs.html" class="combined-report-button" target="_blank">Open combined report</a>
|
|
213
|
+
</div>
|
|
214
|
+
<% } %>
|
|
215
|
+
|
|
216
|
+
<div class="summary">
|
|
217
|
+
<h2>Summary</h2>
|
|
218
|
+
<div class="summary-stats">
|
|
219
|
+
<div class="stat">
|
|
220
|
+
<div class="stat-value"><%= totalRuns %></div>
|
|
221
|
+
<div class="stat-label">Total Runs</div>
|
|
222
|
+
</div>
|
|
223
|
+
<div class="stat">
|
|
224
|
+
<div class="stat-value"><%= passedRuns %></div>
|
|
225
|
+
<div class="stat-label">Passed</div>
|
|
226
|
+
</div>
|
|
227
|
+
<div class="stat">
|
|
228
|
+
<div class="stat-value"><%= failedRuns %></div>
|
|
229
|
+
<div class="stat-label">Failed</div>
|
|
230
|
+
</div>
|
|
231
|
+
<div class="stat">
|
|
232
|
+
<div class="stat-value"><%= profileCount %></div>
|
|
233
|
+
<div class="stat-label">Profiles</div>
|
|
234
|
+
</div>
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
|
|
238
|
+
<% Object.entries(reportsByProfile).forEach(([profileName, profileReports]) => { %>
|
|
239
|
+
<div class="profile-section">
|
|
240
|
+
<h2 class="profile-title">📋 Profile: <%= profileName %></h2>
|
|
241
|
+
<div class="report-grid">
|
|
242
|
+
<% profileReports.forEach((report) => { %>
|
|
243
|
+
<div class="report-card <%= report.success ? 'success' : 'failed' %>">
|
|
244
|
+
<div class="browser-name">🌐 <%= report.browser %></div>
|
|
245
|
+
<span class="status <%= report.success ? 'success' : 'failed' %>">
|
|
246
|
+
<%= report.success ? '✅ Passed' : '❌ Failed' %>
|
|
247
|
+
</span>
|
|
248
|
+
<% if (report.totalTests !== undefined && report.passedTests !== undefined) { %>
|
|
249
|
+
<div class="timestamp"><%= report.passedTests %>/<%= report.totalTests %> tests passing</div>
|
|
250
|
+
<% } %>
|
|
251
|
+
<div class="timestamp"><%= report.timestamp %></div>
|
|
252
|
+
<% if (report.relativeReportPath) { %>
|
|
253
|
+
<a href="<%= report.relativeReportPath %>" class="report-link" target="_blank">View Report</a>
|
|
254
|
+
<% } else { %>
|
|
255
|
+
<p class="no-report">Report not available</p>
|
|
256
|
+
<% } %>
|
|
257
|
+
<% if (report.screenshots && report.screenshots.length > 0) { %>
|
|
258
|
+
<ul class="screenshot-list">
|
|
259
|
+
<% report.screenshots.forEach((screenshot) => { %>
|
|
260
|
+
<li><a href="<%= screenshot.href %>" class="report-link" target="_blank"><%= screenshot.name %></a></li>
|
|
261
|
+
<% }) %>
|
|
262
|
+
</ul>
|
|
263
|
+
<% } %>
|
|
264
|
+
</div>
|
|
265
|
+
<% }) %>
|
|
266
|
+
</div>
|
|
267
|
+
</div>
|
|
268
|
+
<% }) %>
|
|
269
|
+
</div>
|
|
270
|
+
</div>
|
|
271
|
+
</body>
|
|
272
|
+
</html>
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
|
|
3
|
+
// Import libs
|
|
4
|
+
import { spawn } from 'child_process';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
|
|
8
|
+
// Import helpers
|
|
9
|
+
import getRootPath from './getRootPath';
|
|
10
|
+
import generateReporterConfig from './generateReporterConfig';
|
|
11
|
+
import mergeReports from './mergeReports';
|
|
12
|
+
import generateHtmlReport from './generateHtmlReport';
|
|
13
|
+
|
|
14
|
+
// Import shared types
|
|
15
|
+
import RunResult from '../types/RunResult';
|
|
16
|
+
|
|
17
|
+
// Import constants
|
|
18
|
+
import DEFAULT_THREADS_PER_COMBO from '../constants/DEFAULT_THREADS_PER_COMBO';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Run Cypress in headless mode for a single profile and browser using cypress-parallel
|
|
22
|
+
* @author Yuen Ler Chow
|
|
23
|
+
* @param opts - object of arguments
|
|
24
|
+
* @param opts.profileName - The profile name to use
|
|
25
|
+
* @param opts.browser - The browser to use
|
|
26
|
+
* @param opts.outputDir - The output directory for results
|
|
27
|
+
* @param [opts.numThreads] - The number of parallel threads to use (default: 2)
|
|
28
|
+
* @returns Promise that resolves with run result
|
|
29
|
+
*/
|
|
30
|
+
const runCypressHeadless = (opts: {
|
|
31
|
+
profileName: string,
|
|
32
|
+
browser: string,
|
|
33
|
+
outputDir: string,
|
|
34
|
+
numThreads?: number,
|
|
35
|
+
}): Promise<RunResult> => {
|
|
36
|
+
const {
|
|
37
|
+
profileName,
|
|
38
|
+
browser,
|
|
39
|
+
outputDir,
|
|
40
|
+
numThreads = DEFAULT_THREADS_PER_COMBO,
|
|
41
|
+
} = opts;
|
|
42
|
+
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
const root = getRootPath();
|
|
45
|
+
|
|
46
|
+
// Ensure output directory exists
|
|
47
|
+
if (!fs.existsSync(outputDir)) {
|
|
48
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Create subdirectory for this profile+browser combination
|
|
52
|
+
const comboDir = path.join(outputDir, `${profileName}-${browser}`);
|
|
53
|
+
if (!fs.existsSync(comboDir)) {
|
|
54
|
+
fs.mkdirSync(comboDir, { recursive: true });
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Create per-combo screenshots directory
|
|
58
|
+
const comboScreenshotsDir = path.join(comboDir, 'screenshots');
|
|
59
|
+
if (!fs.existsSync(comboScreenshotsDir)) {
|
|
60
|
+
fs.mkdirSync(comboScreenshotsDir, { recursive: true });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const env = {
|
|
64
|
+
...process.env,
|
|
65
|
+
CYPRESS_PROFILE: profileName,
|
|
66
|
+
BROWSER: browser,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
console.log(`\n🚀 Starting Cypress headless: ${profileName} + ${browser}`);
|
|
70
|
+
console.log(`Output: ${comboDir}\n`);
|
|
71
|
+
|
|
72
|
+
// Create reporter config for cypress-multi-reporters
|
|
73
|
+
const reporterConfigPath = path.join(comboDir, 'reporter-config.json');
|
|
74
|
+
const reporterConfig = generateReporterConfig({
|
|
75
|
+
resultsDir: outputDir,
|
|
76
|
+
profileName,
|
|
77
|
+
browserName: browser,
|
|
78
|
+
});
|
|
79
|
+
fs.writeFileSync(reporterConfigPath, JSON.stringify(reporterConfig, null, 2));
|
|
80
|
+
|
|
81
|
+
// Cypress parallel run command with browser, threads, and reporter config
|
|
82
|
+
const cypressArgsString = `--headless --browser ${browser} --config screenshotsFolder=${comboScreenshotsDir} --reporter cypress-multi-reporters --reporter-options configFile=${reporterConfigPath}`;
|
|
83
|
+
|
|
84
|
+
console.log(`Reporter config path: ${reporterConfigPath}`);
|
|
85
|
+
console.log(`Granular results dir: ${path.join(comboDir, 'granular-results')}`);
|
|
86
|
+
|
|
87
|
+
const args = [
|
|
88
|
+
'cypress-parallel',
|
|
89
|
+
'-s',
|
|
90
|
+
'cy:run',
|
|
91
|
+
'--threads',
|
|
92
|
+
numThreads.toString(),
|
|
93
|
+
'-d',
|
|
94
|
+
'cypress/e2e/**/*',
|
|
95
|
+
'-a',
|
|
96
|
+
// eslint-disable-next-line quotes
|
|
97
|
+
`'"${cypressArgsString}"'`,
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
const cypressProcess = spawn('npx', args, {
|
|
101
|
+
cwd: root,
|
|
102
|
+
env,
|
|
103
|
+
stdio: 'inherit',
|
|
104
|
+
shell: true,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
cypressProcess.on('close', (code) => {
|
|
108
|
+
const success = code === 0;
|
|
109
|
+
|
|
110
|
+
// Merge granular mochawesome JSON and generate a single HTML report
|
|
111
|
+
let reportGenerated = true;
|
|
112
|
+
try {
|
|
113
|
+
// Merge all json test suites (test files) into one report
|
|
114
|
+
mergeReports({
|
|
115
|
+
resultsDir: outputDir,
|
|
116
|
+
profileName,
|
|
117
|
+
browserName: browser,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Generate combined HTML report for all test suites for this single browser+profile combo
|
|
121
|
+
generateHtmlReport({
|
|
122
|
+
resultsDir: outputDir,
|
|
123
|
+
profileName,
|
|
124
|
+
browserName: browser,
|
|
125
|
+
});
|
|
126
|
+
} catch (reportError) {
|
|
127
|
+
console.error(`\n⚠️ Report generation failed for ${profileName} + ${browser}:`, reportError);
|
|
128
|
+
reportGenerated = false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// By default, marge names the HTML after the JSON basename: report-data.html
|
|
132
|
+
const reportPath = path.join(
|
|
133
|
+
outputDir,
|
|
134
|
+
`${profileName}-${browser}`,
|
|
135
|
+
'report',
|
|
136
|
+
'report-data.html',
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
const result: RunResult = {
|
|
140
|
+
profileName,
|
|
141
|
+
browser,
|
|
142
|
+
success: success && reportGenerated,
|
|
143
|
+
outputDir: comboDir,
|
|
144
|
+
reportPath: reportGenerated ? reportPath : undefined,
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
if (success && reportGenerated) {
|
|
148
|
+
console.log(`\n✅ Completed: ${profileName} + ${browser}`);
|
|
149
|
+
} else if (!reportGenerated) {
|
|
150
|
+
console.log(`\n⚠️ Tests ran but report generation failed: ${profileName} + ${browser}`);
|
|
151
|
+
} else {
|
|
152
|
+
console.log(`\n❌ Failed: ${profileName} + ${browser} (exit code: ${code})`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
resolve(result);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
cypressProcess.on('error', (error) => {
|
|
159
|
+
reject(error);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export default runCypressHeadless;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { spawn } from 'child_process';
|
|
3
|
+
|
|
4
|
+
// Import helpers
|
|
5
|
+
import getRootPath from './getRootPath';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Run Cypress in visible/interactive mode with a profile
|
|
9
|
+
* @author Yuen Ler Chow
|
|
10
|
+
* @param profileName - The profile name to use
|
|
11
|
+
* @returns Promise that resolves when Cypress closes
|
|
12
|
+
*/
|
|
13
|
+
const runCypressVisible = (profileName: string): Promise<void> => {
|
|
14
|
+
return new Promise((resolve, reject) => {
|
|
15
|
+
const root = getRootPath();
|
|
16
|
+
const env = {
|
|
17
|
+
...process.env,
|
|
18
|
+
CYPRESS_PROFILE: profileName,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
console.log(`\n🚀 Launching Cypress in interactive mode with profile: ${profileName}`);
|
|
22
|
+
console.log(` CYPRESS_PROFILE=${profileName}\n`);
|
|
23
|
+
|
|
24
|
+
const cypressProcess = spawn('npx', ['cypress', 'open'], {
|
|
25
|
+
cwd: root,
|
|
26
|
+
env,
|
|
27
|
+
stdio: 'inherit',
|
|
28
|
+
shell: true,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
cypressProcess.on('close', (code) => {
|
|
32
|
+
if (code === 0) {
|
|
33
|
+
resolve();
|
|
34
|
+
} else {
|
|
35
|
+
reject(new Error(`Cypress exited with code ${code}`));
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
cypressProcess.on('error', (error) => {
|
|
40
|
+
reject(error);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default runCypressVisible;
|
package/start/index.ts
CHANGED
|
@@ -17,9 +17,11 @@ import findProfilesByNames from './helpers/findProfilesByNames';
|
|
|
17
17
|
import validateBrowsers from './helpers/validateBrowsers';
|
|
18
18
|
import extractArgValue from './helpers/extractArgValue';
|
|
19
19
|
import getRootPath from './helpers/getRootPath';
|
|
20
|
+
import executeCypress from './helpers/executeCypress';
|
|
20
21
|
|
|
21
22
|
// Import constants
|
|
22
23
|
import AVAILABLE_BROWSERS from './constants/AVAILABLE_BROWSERS';
|
|
24
|
+
import DEFAULT_THREADS_PER_COMBO from './constants/DEFAULT_THREADS_PER_COMBO';
|
|
23
25
|
|
|
24
26
|
// Get the project directory
|
|
25
27
|
const pwd = getRootPath();
|
|
@@ -86,6 +88,20 @@ const headlessFlagValue = extractArgValue(args, '--headless');
|
|
|
86
88
|
const hasHeadlessFlag = headlessFlagValue !== undefined;
|
|
87
89
|
isHeadless = !!(envHeadlessRaw && envHeadlessRaw.toLowerCase() !== 'false') || hasHeadlessFlag;
|
|
88
90
|
|
|
91
|
+
// Check for THREADS_PER_COMBO (env var or CLI arg)
|
|
92
|
+
const envThreadsRaw = process.env.THREADS_PER_COMBO;
|
|
93
|
+
const argThreadsRaw = extractArgValue(args, '--threadsPerCombo');
|
|
94
|
+
const threadsRaw = envThreadsRaw || argThreadsRaw;
|
|
95
|
+
let threadsPerCombo: number | undefined;
|
|
96
|
+
if (threadsRaw) {
|
|
97
|
+
const parsed = Number.parseInt(threadsRaw, 10);
|
|
98
|
+
if (!Number.isNaN(parsed) && parsed > 0) {
|
|
99
|
+
threadsPerCombo = parsed;
|
|
100
|
+
} else {
|
|
101
|
+
console.warn(`⚠️ Invalid THREADS_PER_COMBO value: "${threadsRaw}". Using default (${DEFAULT_THREADS_PER_COMBO}).`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
89
105
|
// If headless wasn't specified, ask the user to choose
|
|
90
106
|
if (!envHeadlessRaw && !hasHeadlessFlag) {
|
|
91
107
|
const choices = showChooser({
|
|
@@ -157,8 +173,10 @@ if (
|
|
|
157
173
|
selectedProfiles = choices.map((choice) => { return profiles[choice.index]; });
|
|
158
174
|
}
|
|
159
175
|
|
|
160
|
-
// Execute
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
176
|
+
// Execute Cypress with selected configuration
|
|
177
|
+
executeCypress({
|
|
178
|
+
selectedProfiles,
|
|
179
|
+
selectedBrowsers,
|
|
180
|
+
isHeadless,
|
|
181
|
+
threadsPerCombo,
|
|
182
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mochawesome reporter configuration
|
|
3
|
+
* @author Yuen Ler Chow
|
|
4
|
+
*/
|
|
5
|
+
type MochawesomeReporterConfig = {
|
|
6
|
+
// The reporter(s) to enable (e.g., "mochawesome")
|
|
7
|
+
reporterEnabled: string;
|
|
8
|
+
// Options for the mochawesome reporter
|
|
9
|
+
mochawesomeReporterOptions: {
|
|
10
|
+
// Directory where report files will be saved
|
|
11
|
+
reportDir: string;
|
|
12
|
+
// Filename pattern for report files (supports [name] placeholder)
|
|
13
|
+
reportFilename: string;
|
|
14
|
+
// Whether to overwrite existing report files
|
|
15
|
+
overwrite: boolean;
|
|
16
|
+
// Whether to generate HTML reports
|
|
17
|
+
html: boolean;
|
|
18
|
+
// Whether to generate JSON reports
|
|
19
|
+
json: boolean;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default MochawesomeReporterConfig;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile configuration
|
|
3
|
+
* @author Yuen Ler Chow
|
|
4
|
+
*/
|
|
5
|
+
type Profile = {
|
|
6
|
+
// The filename of the profile (e.g., "prod.Profile.ts")
|
|
7
|
+
file: string;
|
|
8
|
+
// The name of the profile extracted from the filename (e.g., "prod")
|
|
9
|
+
profileName: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default Profile;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Information about a generated report
|
|
3
|
+
* @author Yuen Ler Chow
|
|
4
|
+
*/
|
|
5
|
+
type ReportInfo = {
|
|
6
|
+
// The name of the profile (e.g., "prod", "stage")
|
|
7
|
+
profileName: string;
|
|
8
|
+
// The browser used (e.g., "chrome", "edge")
|
|
9
|
+
browser: string;
|
|
10
|
+
// Path to the generated HTML report file
|
|
11
|
+
reportPath: string;
|
|
12
|
+
// True if the test run was successful
|
|
13
|
+
success: boolean;
|
|
14
|
+
// Human-readable timestamp of when the report was generated
|
|
15
|
+
timestamp: string;
|
|
16
|
+
// Total number of tests in the report
|
|
17
|
+
totalTests?: number;
|
|
18
|
+
// Number of tests that passed
|
|
19
|
+
passedTests?: number;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default ReportInfo;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Result from a Cypress headless run
|
|
3
|
+
* @author Yuen Ler Chow
|
|
4
|
+
*/
|
|
5
|
+
type RunResult = {
|
|
6
|
+
// The name of the profile used for this run (e.g., "prod", "stage")
|
|
7
|
+
profileName: string;
|
|
8
|
+
// The browser used for this run (e.g., "chrome", "edge")
|
|
9
|
+
browser: string;
|
|
10
|
+
// Whether the test run completed successfully (all tests passed and report generated)
|
|
11
|
+
success: boolean;
|
|
12
|
+
// The output directory for this specific profile+browser combination
|
|
13
|
+
outputDir: string;
|
|
14
|
+
// Path to the generated HTML report file, undefined if report generation failed
|
|
15
|
+
reportPath?: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default RunResult;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Information about a screenshot captured during a Cypress test run,
|
|
3
|
+
* used for linking screenshots in the report homepage
|
|
4
|
+
* @author Yuen Ler Chow
|
|
5
|
+
*/
|
|
6
|
+
type ScreenshotInfo = {
|
|
7
|
+
// Relative URL path to the screenshot file from the report homepage
|
|
8
|
+
href: string;
|
|
9
|
+
// Display name for the screenshot (typically the relative file path)
|
|
10
|
+
name: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default ScreenshotInfo;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import ReportInfo from './ReportInfo';
|
|
2
|
+
import ScreenshotInfo from './ScreenshotInfo';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Extended version of ReportInfo with additional computed fields
|
|
6
|
+
* needed for rendering the EJS report homepage template
|
|
7
|
+
* @author Yuen Ler Chow
|
|
8
|
+
*/
|
|
9
|
+
type TemplateReportInfo = ReportInfo & {
|
|
10
|
+
// Relative URL path to the HTML report file, or null if report doesn't exist
|
|
11
|
+
relativeReportPath: string | null;
|
|
12
|
+
// List of screenshots captured during this test run
|
|
13
|
+
screenshots: ScreenshotInfo[];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default TemplateReportInfo;
|