dceky 1.0.5-beta.ky-declarations.13 → 1.0.6

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/checkRequiredFiles/index.js +7 -0
  88. package/lib/setup/checkRequiredFiles/index.js.map +1 -1
  89. package/lib/src/commands/extractDataFromClass.d.ts +7 -4
  90. package/lib/src/commands/extractDataFromClass.js +2 -1
  91. package/lib/src/commands/extractDataFromClass.js.map +1 -1
  92. package/lib/src/commands/extractDataFromClassByContents.d.ts +9 -5
  93. package/lib/src/commands/extractDataFromClassByContents.js +2 -1
  94. package/lib/src/commands/extractDataFromClassByContents.js.map +1 -1
  95. package/lib/src/commands/genTextOfLength.d.ts +20 -0
  96. package/lib/src/commands/genTextOfLength.js +20 -0
  97. package/lib/src/commands/genTextOfLength.js.map +1 -0
  98. package/lib/src/commands/getAttribute.d.ts +20 -0
  99. package/lib/src/commands/getAttribute.js +22 -0
  100. package/lib/src/commands/getAttribute.js.map +1 -0
  101. package/lib/src/commands/getClassName.d.ts +15 -0
  102. package/lib/src/commands/getClassName.js +21 -0
  103. package/lib/src/commands/getClassName.js.map +1 -0
  104. package/lib/src/commands/getCurrentDateInfo.d.ts +21 -0
  105. package/lib/src/commands/getCurrentDateInfo.js +25 -0
  106. package/lib/src/commands/getCurrentDateInfo.js.map +1 -0
  107. package/lib/src/commands/getId.d.ts +15 -0
  108. package/lib/src/commands/getId.js +21 -0
  109. package/lib/src/commands/getId.js.map +1 -0
  110. package/lib/src/commands/getJSON.d.ts +0 -1
  111. package/lib/src/commands/getJSON.js +1 -4
  112. package/lib/src/commands/getJSON.js.map +1 -1
  113. package/lib/src/commands/getSpecialChars.d.ts +14 -0
  114. package/lib/src/commands/getSpecialChars.js +16 -0
  115. package/lib/src/commands/getSpecialChars.js.map +1 -0
  116. package/lib/src/commands/getTitle.d.ts +13 -0
  117. package/lib/src/commands/getTitle.js +20 -0
  118. package/lib/src/commands/getTitle.js.map +1 -0
  119. package/lib/src/commands/index.js +29 -5
  120. package/lib/src/commands/index.js.map +1 -1
  121. package/lib/src/commands/launchLTIUsingToken.js +12 -4
  122. package/lib/src/commands/launchLTIUsingToken.js.map +1 -1
  123. package/lib/src/commands/listSelectLabels.d.ts +15 -0
  124. package/lib/src/commands/listSelectLabels.js +24 -0
  125. package/lib/src/commands/listSelectLabels.js.map +1 -0
  126. package/lib/src/commands/listSelectValues.d.ts +15 -0
  127. package/lib/src/commands/listSelectValues.js +27 -0
  128. package/lib/src/commands/listSelectValues.js.map +1 -0
  129. package/lib/src/commands/padWithZeros.d.ts +20 -0
  130. package/lib/src/commands/padWithZeros.js +24 -0
  131. package/lib/src/commands/padWithZeros.js.map +1 -0
  132. package/lib/src/commands/uniquify.d.ts +15 -0
  133. package/lib/src/commands/uniquify.js +26 -0
  134. package/lib/src/commands/uniquify.js.map +1 -0
  135. package/lib/src/commands/visitCanvasEndpoint.d.ts +26 -0
  136. package/lib/src/commands/visitCanvasEndpoint.js +36 -0
  137. package/lib/src/commands/visitCanvasEndpoint.js.map +1 -0
  138. package/lib/src/commands/waitForAtLeastOneElementPresent.d.ts +23 -0
  139. package/lib/src/commands/waitForAtLeastOneElementPresent.js +28 -0
  140. package/lib/src/commands/waitForAtLeastOneElementPresent.js.map +1 -0
  141. package/lib/src/genConfiguration/index.js +21 -3
  142. package/lib/src/genConfiguration/index.js.map +1 -1
  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/checkRequiredFiles/index.ts +7 -0
  204. package/src/commands/extractDataFromClass.ts +17 -6
  205. package/src/commands/extractDataFromClassByContents.ts +21 -8
  206. package/src/commands/genTextOfLength.ts +54 -0
  207. package/src/commands/getAttribute.ts +58 -0
  208. package/src/commands/getClassName.ts +44 -0
  209. package/src/commands/getCurrentDateInfo.ts +57 -0
  210. package/src/commands/getId.ts +44 -0
  211. package/src/commands/getJSON.ts +0 -4
  212. package/src/commands/getSpecialChars.ts +34 -0
  213. package/src/commands/getTitle.ts +39 -0
  214. package/src/commands/index.ts +29 -5
  215. package/src/commands/launchLTIUsingToken.ts +12 -4
  216. package/src/commands/listSelectLabels.ts +47 -0
  217. package/src/commands/listSelectValues.ts +50 -0
  218. package/src/commands/padWithZeros.ts +53 -0
  219. package/src/commands/uniquify.ts +49 -0
  220. package/src/commands/visitCanvasEndpoint.ts +75 -0
  221. package/src/commands/waitForAtLeastOneElementPresent.ts +64 -0
  222. package/src/genConfiguration/index.ts +20 -2
  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,47 @@
1
+ /// <reference types="cypress" />
2
+
3
+ /*----------------------------------------*/
4
+ /* ---------------- Type ---------------- */
5
+ /*----------------------------------------*/
6
+
7
+ declare global {
8
+ namespace Cypress {
9
+ interface Chainable {
10
+ /**
11
+ * Get the labels of all the options within a select element
12
+ * @author Allison Zhang
13
+ * @param selector the CSS selector of the select element
14
+ * @returns an array of strings representing the labels of the options
15
+ */
16
+ listSelectLabels(
17
+ selector: string,
18
+ ): Chainable<String[]>;
19
+ }
20
+ }
21
+ }
22
+
23
+ /*----------------------------------------*/
24
+ /* --------------- Command -------------- */
25
+ /*----------------------------------------*/
26
+
27
+ const listSelectLabels = () => {
28
+ Cypress.Commands.add('listSelectLabels', (selector: string) => {
29
+ const labels: string[] = [];
30
+ return (
31
+ cy
32
+ .get(`${selector} option`)
33
+ .each((option) => {
34
+ labels.push(option.attr('label') || option.text());
35
+ })
36
+ .then(() => {
37
+ return labels;
38
+ })
39
+ );
40
+ });
41
+ };
42
+
43
+ /*----------------------------------------*/
44
+ /* --------------- Export --------------- */
45
+ /*----------------------------------------*/
46
+
47
+ export default listSelectLabels;
@@ -0,0 +1,50 @@
1
+ /// <reference types="cypress" />
2
+
3
+ /*----------------------------------------*/
4
+ /* ---------------- Type ---------------- */
5
+ /*----------------------------------------*/
6
+
7
+ declare global {
8
+ namespace Cypress {
9
+ interface Chainable {
10
+ /**
11
+ * Get the values of all the options within a select element
12
+ * @author Allison Zhang
13
+ * @param selector the CSS selector of the select element
14
+ * @returns an array of strings representing the values of the options
15
+ */
16
+ listSelectValues(
17
+ selector: string,
18
+ ): Chainable<String[]>;
19
+ }
20
+ }
21
+ }
22
+
23
+ /*----------------------------------------*/
24
+ /* --------------- Command -------------- */
25
+ /*----------------------------------------*/
26
+
27
+ const listSelectValues = () => {
28
+ Cypress.Commands.add('listSelectValues', (selector: string) => {
29
+ const vals: string[] = [];
30
+ return (
31
+ cy
32
+ .get(`${selector} option`)
33
+ .each((option) => {
34
+ cy.wrap(option).invoke('attr', 'value')
35
+ .then((value) => {
36
+ vals.push(value || option.text());
37
+ });
38
+ })
39
+ .then(() => {
40
+ return vals;
41
+ })
42
+ );
43
+ });
44
+ };
45
+
46
+ /*----------------------------------------*/
47
+ /* --------------- Export --------------- */
48
+ /*----------------------------------------*/
49
+
50
+ export default listSelectValues;
@@ -0,0 +1,53 @@
1
+ /// <reference types="cypress" />
2
+
3
+ /*----------------------------------------*/
4
+ /* ---------------- Type ---------------- */
5
+ /*----------------------------------------*/
6
+
7
+ declare global {
8
+ namespace Cypress {
9
+ interface Chainable {
10
+ /**
11
+ * Pads a number with leading zeros to a user-defined length.
12
+ * @author Allison Zhang
13
+ * @param opts options object
14
+ * @param opts.length the desired total length of the output string, must be larger than the length of the number
15
+ * @param opts.number the number to be padded with leading zeros
16
+ * @returns padded string with leading zeros
17
+ */
18
+ padWithZeros(opts: {
19
+ length: number,
20
+ number: number,
21
+ }): Chainable<string>;
22
+ }
23
+ }
24
+ }
25
+
26
+ /*----------------------------------------*/
27
+ /* --------------- Command -------------- */
28
+ /*----------------------------------------*/
29
+
30
+ const padWithZeros = () => {
31
+ Cypress.Commands.add('padWithZeros', (opts: { length: number, number: number }) => {
32
+ const {
33
+ length,
34
+ number,
35
+ } = opts;
36
+ return (
37
+ cy
38
+ .then(() => {
39
+ let numberString = number.toString();
40
+ while (numberString.length < length) {
41
+ numberString = `0${numberString}`;
42
+ }
43
+ return numberString;
44
+ })
45
+ );
46
+ });
47
+ };
48
+
49
+ /*----------------------------------------*/
50
+ /* --------------- Export --------------- */
51
+ /*----------------------------------------*/
52
+
53
+ export default padWithZeros;
@@ -0,0 +1,49 @@
1
+ /// <reference types="cypress" />
2
+
3
+ /*----------------------------------------*/
4
+ /* ---------------- Type ---------------- */
5
+ /*----------------------------------------*/
6
+
7
+ declare global {
8
+ namespace Cypress {
9
+ interface Chainable {
10
+ /**
11
+ * Makes a string unique by appending a timestamp and a counter.
12
+ * @author Allison Zhang
13
+ * @param text the original string
14
+ * @returns the uniquified string
15
+ */
16
+ uniquify(text: string): string;
17
+ }
18
+ }
19
+ }
20
+
21
+ /*----------------------------------------*/
22
+ /* --------------- Helpers -------------- */
23
+ /*----------------------------------------*/
24
+
25
+ let uniqueCounter = 1;
26
+
27
+ const shorten = (num: number): string => {
28
+ return Number(num).toString(36);
29
+ };
30
+
31
+ const id = shorten(Math.floor(Math.random() * 10000));
32
+
33
+ /*----------------------------------------*/
34
+ /* --------------- Command -------------- */
35
+ /*----------------------------------------*/
36
+
37
+ const uniquify = () => {
38
+ Cypress.Commands.add('uniquify', (text: string) => {
39
+ const thisCounter = uniqueCounter;
40
+ uniqueCounter += 1;
41
+ return `${text} [${shorten(Number.parseInt(`${Date.now()}${thisCounter}${id}`, 10))}]`;
42
+ });
43
+ };
44
+
45
+ /*----------------------------------------*/
46
+ /* --------------- Export --------------- */
47
+ /*----------------------------------------*/
48
+
49
+ export default uniquify;
@@ -0,0 +1,75 @@
1
+ /// <reference types="cypress" />
2
+
3
+ /*----------------------------------------*/
4
+ /* ---------------- Type ---------------- */
5
+ /*----------------------------------------*/
6
+
7
+ declare global {
8
+ namespace Cypress {
9
+ interface Chainable {
10
+ /**
11
+ * Send a request to a Canvas API endpoint.
12
+ * @author Allison Zhang
13
+ * @param opts options object
14
+ * @param opts.method the HTTP method (e.g., 'GET', 'POST', 'DELETE')
15
+ * @param opts.path the API endpoint path excluding 'https://canvas.harvard.edu', (e.g., '/api/v1/courses/123')
16
+ * @param opts.accessToken the access token for authentication
17
+ * @param opts.params the request params (if any)
18
+ * @returns Cypress chainable containing the Canvas API response body
19
+ */
20
+ visitCanvasEndpoint(
21
+ opts: {
22
+ method: string,
23
+ path: string,
24
+ accessToken: string,
25
+ params?: { [k: string]: any },
26
+ },
27
+ ): Chainable<any>;
28
+ }
29
+ }
30
+ }
31
+
32
+ /*----------------------------------------*/
33
+ /* --------------- Command -------------- */
34
+ /*----------------------------------------*/
35
+
36
+ const visitCanvasEndpoint = () => {
37
+ Cypress.Commands.add('visitCanvasEndpoint', (
38
+ opts: {
39
+ method: string,
40
+ path: string,
41
+ accessToken: string,
42
+ params: {
43
+ [k: string]: any
44
+ }
45
+ },
46
+ ) => {
47
+ const {
48
+ method,
49
+ path,
50
+ accessToken,
51
+ params,
52
+ } = opts;
53
+ cy.log(`Visiting Canvas ${method} endpoint`);
54
+ cy.log(`Canvas API: ${path}`);
55
+
56
+ return (
57
+ cy
58
+ .request({
59
+ method,
60
+ url: `https://canvas.harvard.edu${path}`,
61
+ body: {
62
+ ...(params || {}),
63
+ access_token: accessToken,
64
+ },
65
+ })
66
+ .its('body')
67
+ );
68
+ });
69
+ };
70
+
71
+ /*----------------------------------------*/
72
+ /* --------------- Export --------------- */
73
+ /*----------------------------------------*/
74
+
75
+ export default visitCanvasEndpoint;
@@ -0,0 +1,64 @@
1
+ /// <reference types="cypress" />
2
+
3
+ /*----------------------------------------*/
4
+ /* ---------------- Type ---------------- */
5
+ /*----------------------------------------*/
6
+
7
+ declare global {
8
+ namespace Cypress {
9
+ interface Chainable {
10
+ /**
11
+ * Wait for any element in a list to be present (check every tenth
12
+ * of a second for status)
13
+ * @author Gardenia Liu
14
+ * @param opts object containing all arguments
15
+ * @param opts.items list of CSS selectors of interest
16
+ * @param [opts.timeoutSec] the number of seconds to wait before
17
+ * timing out
18
+ * @returns the selector of the item that was found first, ties
19
+ * broken by which item shows up in the list first
20
+ */
21
+ waitForAtLeastOneElementPresent(
22
+ opts: {
23
+ items: string[],
24
+ timeoutSec?: number,
25
+ }
26
+ ): Chainable<string>;
27
+ }
28
+ }
29
+ }
30
+
31
+ /*----------------------------------------*/
32
+ /* --------------- Command -------------- */
33
+ /*----------------------------------------*/
34
+
35
+ const waitForAtLeastOneElementPresent = () => {
36
+ Cypress.Commands.add(
37
+ 'waitForAtLeastOneElementPresent',
38
+ (opts: { items: string[], timeoutSec?: number }) => {
39
+ const { items, timeoutSec } = opts;
40
+ // Set timeout seconds to 10 if not specified
41
+ const timeoutMs = (timeoutSec || 10) * 1000;
42
+
43
+ // Combined selector for all items
44
+ const combinedSelector = items.join(', ');
45
+
46
+ // Wait for any of the elements to be visible
47
+ return (
48
+ cy
49
+ .get(combinedSelector, { timeout: timeoutMs })
50
+ .should(($els) => { return expect($els.is(':visible'), `at least one of [${combinedSelector}] visible`).to.be.true; })
51
+ .then(($els) => {
52
+ const $firstVisible = $els.filter(':visible').first();
53
+ return items.find((sel) => { return $firstVisible.is(sel); });
54
+ })
55
+ );
56
+ },
57
+ );
58
+ };
59
+
60
+ /*----------------------------------------*/
61
+ /* --------------- Export --------------- */
62
+ /*----------------------------------------*/
63
+
64
+ export default waitForAtLeastOneElementPresent;
@@ -38,7 +38,8 @@ const genConfiguration = () => {
38
38
  const GlobalValues: GlobalsOrProfile = require(path.join(GLOBALS_PATH, '/GlobalValues'));
39
39
 
40
40
  // Determine profile file name (default is stage)
41
- const profileName = process.env.CYPRESS_PROFILE || 'stage';
41
+ const profileName = process.env.CYPRESS_PROFILE || 'Stage';
42
+ const defaultProfileName = 'Default';
42
43
 
43
44
  // Load in chosen profile configuration
44
45
  let profileModules: GlobalsOrProfile = {};
@@ -51,8 +52,25 @@ const genConfiguration = () => {
51
52
  process.exit(1);
52
53
  }
53
54
 
55
+ // Load default profile configuration
56
+ let defaultProfileModules: GlobalsOrProfile = {};
57
+ try {
58
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
59
+ const mod = require(path.join(PROFILES_PATH, `/${defaultProfileName}.Profile`));
60
+ defaultProfileModules = (mod?.default ?? mod ?? {}) as GlobalsOrProfile;
61
+ } catch (e) {
62
+ console.warn(`[cypress.config] Could not load profile '${defaultProfileName}.Profile'`, e);
63
+ process.exit(1);
64
+ }
65
+
54
66
  // NOTE: Order matters (later overrides earlier)
55
- const sources: GlobalsOrProfile[] = [GlobalCredentials, GlobalResources, GlobalValues, profileModules];
67
+ const sources: GlobalsOrProfile[] = [
68
+ GlobalCredentials,
69
+ GlobalResources,
70
+ GlobalValues,
71
+ profileModules,
72
+ defaultProfileModules,
73
+ ];
56
74
 
57
75
  // Split all sources into basic and dependent
58
76
  const splits: SplitEnv[] = sources.map((source) => {
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Default number of threads per combo
3
+ * @author Yuen Ler Chow
4
+ */
5
+ const DEFAULT_THREADS_PER_COMBO = 2;
6
+
7
+ export default DEFAULT_THREADS_PER_COMBO;
@@ -0,0 +1,25 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+
4
+ /**
5
+ * Collect all PNG files recursively from a directory
6
+ * @author Yuen Ler Chow
7
+ * @param dir - Directory to search
8
+ * @param prefix - Path prefix for relative paths
9
+ * @returns Array of relative file paths
10
+ */
11
+ const collectPngFiles = (dir: string, prefix = ''): string[] => {
12
+ const files: string[] = [];
13
+ const dirEntries = fs.readdirSync(dir, { withFileTypes: true });
14
+ dirEntries.forEach((entry) => {
15
+ const fullPath = path.join(dir, entry.name);
16
+ if (entry.isDirectory()) {
17
+ files.push(...collectPngFiles(fullPath, path.join(prefix, entry.name)));
18
+ } else if (entry.isFile() && entry.name.toLowerCase().endsWith('.png')) {
19
+ files.push(path.join(prefix, entry.name));
20
+ }
21
+ });
22
+ return files;
23
+ };
24
+
25
+ export default collectPngFiles;
@@ -0,0 +1,92 @@
1
+ /* eslint-disable no-console */
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+
5
+ // Import helpers
6
+ import runCypressHeadless from './runCypressHeadless';
7
+ import getDateLabeledDir from './getDateLabeledDir';
8
+ import generateReportHomepage from './generateReportHomepage';
9
+ import mergeAllReportsAndGenerateHtml from './mergeAllReportsAndGenerateHtml';
10
+
11
+ // Import shared types
12
+ import Profile from '../types/Profile';
13
+
14
+ /**
15
+ * Execute all headless Cypress test combinations in parallel
16
+ * @author Yuen Ler Chow
17
+ * @param opts - object of arguments
18
+ * @param opts.selectedProfiles - Array of selected profiles
19
+ * @param opts.selectedBrowsers - Array of selected browsers
20
+ * @param [opts.threadsPerCombo] - Number of parallel threads per combo (default: 2)
21
+ */
22
+ const executeAllHeadlessCombinations = async (
23
+ opts: {
24
+ selectedProfiles: Profile[],
25
+ selectedBrowsers: string[],
26
+ threadsPerCombo?: number,
27
+ },
28
+ ): Promise<void> => {
29
+ const { selectedProfiles, selectedBrowsers, threadsPerCombo } = opts;
30
+
31
+ // Create date-labeled output directory
32
+ const outputDir = getDateLabeledDir();
33
+ if (!fs.existsSync(outputDir)) {
34
+ fs.mkdirSync(outputDir, { recursive: true });
35
+ }
36
+
37
+ console.log(`šŸ“ Results will be saved to: ${outputDir}\n`);
38
+
39
+ // Generate all Profile+Browser combinations
40
+ const combinations: { profileName: string; browser: string }[] = [];
41
+ selectedProfiles.forEach((profile) => {
42
+ selectedBrowsers.forEach((browser) => {
43
+ combinations.push({
44
+ profileName: profile.profileName,
45
+ browser,
46
+ });
47
+ });
48
+ });
49
+
50
+ console.log(`šŸ”„ Running ${combinations.length} test combination(s) in parallel...\n`);
51
+
52
+ // Run all combinations in parallel
53
+ const runPromises = combinations.map((combo) => {
54
+ return runCypressHeadless({
55
+ profileName: combo.profileName,
56
+ browser: combo.browser,
57
+ outputDir,
58
+ numThreads: threadsPerCombo,
59
+ });
60
+ });
61
+ const results = await Promise.all(runPromises);
62
+
63
+ // Generate combined HTML report across all profile+browser combinations
64
+ mergeAllReportsAndGenerateHtml(outputDir, results);
65
+
66
+ // Generate report homepage
67
+ const reportInfos = results.map((result) => {
68
+ return {
69
+ profileName: result.profileName,
70
+ browser: result.browser,
71
+ reportPath: result.reportPath || '',
72
+ success: result.success,
73
+ timestamp: new Date().toLocaleString(),
74
+ };
75
+ });
76
+
77
+ generateReportHomepage(reportInfos, outputDir);
78
+
79
+ // Print summary
80
+ const passed = results.filter((r) => { return r.success; }).length;
81
+ const failed = results.filter((r) => { return !r.success; }).length;
82
+
83
+ console.log('\n═══════════════════════════════════════════════════════════');
84
+ console.log('šŸ“Š Execution Summary:');
85
+ console.log(` Total: ${results.length}`);
86
+ console.log(` āœ… Passed: ${passed}`);
87
+ console.log(` āŒ Failed: ${failed}`);
88
+ console.log(` šŸ“„ Report homepage: file://${path.join(outputDir, 'index.html')}`);
89
+ console.log('═══════════════════════════════════════════════════════════\n');
90
+ };
91
+
92
+ export default executeAllHeadlessCombinations;
@@ -0,0 +1,66 @@
1
+ /* eslint-disable no-console */
2
+
3
+ // Import shared types
4
+ import Profile from '../types/Profile';
5
+
6
+ // Import helpers
7
+ import runCypressVisible from './runCypressVisible';
8
+ import executeAllHeadlessCombinations from './executeAllHeadlessCombinations';
9
+
10
+ // Import constants
11
+ import DEFAULT_THREADS_PER_COMBO from '../constants/DEFAULT_THREADS_PER_COMBO';
12
+
13
+ /**
14
+ * Execute Cypress tests in either headless or visible mode
15
+ * @author Yuen Ler Chow
16
+ * @param opts - object of arguments
17
+ * @param opts.selectedProfiles - Array of selected profiles
18
+ * @param opts.selectedBrowsers - Array of selected browsers
19
+ * @param opts.isHeadless - Whether to run in headless mode
20
+ * @param [opts.threadsPerCombo] - Number of parallel threads per combo (default: 2)
21
+ */
22
+ const executeCypress = async (
23
+ opts: {
24
+ selectedProfiles: Profile[],
25
+ selectedBrowsers: string[],
26
+ isHeadless: boolean,
27
+ threadsPerCombo?: number,
28
+ },
29
+ ): Promise<void> => {
30
+ const {
31
+ selectedProfiles,
32
+ selectedBrowsers,
33
+ isHeadless,
34
+ threadsPerCombo,
35
+ } = opts;
36
+
37
+ console.log('\n═══════════════════════════════════════════════════════════');
38
+ console.log('Starting Cypress with the following configuration:');
39
+ console.log(`Profile(s): ${selectedProfiles.map((p) => { return p.profileName; }).join(', ')}`);
40
+ console.log(`Browser(s): ${selectedBrowsers.join(', ')}`);
41
+ console.log(`Headless: ${isHeadless}`);
42
+ if (isHeadless) {
43
+ console.log(`Threads per combo: ${threadsPerCombo ?? DEFAULT_THREADS_PER_COMBO}`);
44
+ }
45
+ console.log('═══════════════════════════════════════════════════════════\n');
46
+
47
+ try {
48
+ if (!isHeadless) {
49
+ // Visible mode: run with single profile
50
+ const { profileName } = selectedProfiles[0];
51
+ await runCypressVisible(profileName);
52
+ } else {
53
+ // Headless mode: run parallel instances for each Profile+Browser combination
54
+ await executeAllHeadlessCombinations({
55
+ selectedProfiles,
56
+ selectedBrowsers,
57
+ threadsPerCombo,
58
+ });
59
+ }
60
+ } catch (error) {
61
+ console.error('\nāŒ Error during execution:', error);
62
+ process.exit(1);
63
+ }
64
+ };
65
+
66
+ export default executeCypress;
@@ -0,0 +1,71 @@
1
+ /* eslint-disable no-console */
2
+ import { execSync } from 'child_process';
3
+ import path from 'path';
4
+ import { existsSync } from 'fs';
5
+ import getRootPath from './getRootPath';
6
+
7
+ /**
8
+ * Generate HTML report from merged JSON report using mochawesome-report-generator (marge)
9
+ * @author Yuen Ler Chow
10
+ * @param opts - object of arguments
11
+ * @param opts.resultsDir - Results directory
12
+ * @param opts.profileName - Profile name
13
+ * @param opts.browserName - Browser name
14
+ */
15
+ const generateHtmlReport = (
16
+ opts: {
17
+ resultsDir: string;
18
+ profileName: string;
19
+ browserName: string;
20
+ },
21
+ ): void => {
22
+ const { resultsDir, profileName, browserName } = opts;
23
+
24
+ const reportDataPath = path.join(
25
+ resultsDir,
26
+ `${profileName}-${browserName}`,
27
+ 'report-data.json',
28
+ );
29
+ const reportDir = path.join(
30
+ resultsDir,
31
+ `${profileName}-${browserName}`,
32
+ 'report',
33
+ );
34
+ const expectedHtmlPath = path.join(reportDir, 'report-data.html');
35
+
36
+ console.log(`\nšŸ“„ Generate HTML Report Debug for ${profileName} + ${browserName}:`);
37
+ console.log(` Report data path: ${reportDataPath}`);
38
+ console.log(` Report output dir: ${reportDir}`);
39
+
40
+ if (!existsSync(reportDataPath)) {
41
+ const errorMsg = `āŒ ERROR: Report data JSON does not exist: ${reportDataPath}`;
42
+ console.error(errorMsg);
43
+ throw new Error(errorMsg);
44
+ }
45
+
46
+ try {
47
+ const command = `npx marge "${reportDataPath}" --reportDir "${reportDir}"`;
48
+
49
+ console.log(` Running: ${command}`);
50
+ console.log(`Generating HTML report for ${profileName} + ${browserName}...`);
51
+
52
+ execSync(command, {
53
+ stdio: 'inherit',
54
+ cwd: getRootPath(),
55
+ });
56
+
57
+ // Verify the HTML report was created
58
+ if (!existsSync(expectedHtmlPath)) {
59
+ const errorMsg = `āŒ ERROR: HTML report was not created at: ${expectedHtmlPath}`;
60
+ console.error(errorMsg);
61
+ throw new Error(errorMsg);
62
+ }
63
+
64
+ console.log(` āœ… HTML report generated successfully at: ${expectedHtmlPath}`);
65
+ } catch (e) {
66
+ console.error(`Error generating HTML report for ${profileName} + ${browserName}:`, e);
67
+ throw e;
68
+ }
69
+ };
70
+
71
+ export default generateHtmlReport;