dceky 1.0.0-beta.6 → 1.0.3

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 (190) hide show
  1. package/.eslintrc.js +93 -0
  2. package/README.md +41 -0
  3. package/cypress/e2e/profile-test.cy.ts +10 -0
  4. package/cypress/fixtures/example.json +5 -0
  5. package/cypress/support/commands.ts +37 -0
  6. package/cypress/support/e2e.ts +17 -0
  7. package/cypress.config.ts +9 -0
  8. package/docs/GlobalsAndProfiles.md +23 -0
  9. package/lib/setup/addToGitIgnore.d.ts +6 -0
  10. package/lib/setup/addToGitIgnore.js +47 -0
  11. package/lib/setup/addToGitIgnore.js.map +1 -0
  12. package/lib/setup/checkRequiredFiles.d.ts +6 -0
  13. package/lib/setup/checkRequiredFiles.js +59 -0
  14. package/lib/setup/checkRequiredFiles.js.map +1 -0
  15. package/lib/setup/genCommandImportFile.d.ts +7 -0
  16. package/lib/setup/genCommandImportFile.js +67 -0
  17. package/lib/setup/genCommandImportFile.js.map +1 -0
  18. package/lib/setup/genDynamicConfigFile.d.ts +5 -0
  19. package/lib/setup/genDynamicConfigFile.js +29 -0
  20. package/lib/setup/genDynamicConfigFile.js.map +1 -0
  21. package/lib/setup/helpers/getRootPath.d.ts +7 -0
  22. package/lib/setup/helpers/getRootPath.js +17 -0
  23. package/lib/setup/helpers/getRootPath.js.map +1 -0
  24. package/lib/setup/index.d.ts +1 -0
  25. package/lib/setup/index.js +16 -0
  26. package/lib/setup/index.js.map +1 -0
  27. package/lib/setup/setupCypressDependencies.d.ts +6 -0
  28. package/lib/setup/setupCypressDependencies.js +40 -0
  29. package/lib/setup/setupCypressDependencies.js.map +1 -0
  30. package/lib/src/commands/assertDoesNotHaveClass.d.ts +20 -0
  31. package/lib/src/commands/assertDoesNotHaveClass.js +17 -0
  32. package/lib/src/commands/assertDoesNotHaveClass.js.map +1 -0
  33. package/lib/src/commands/assertHasClass.d.ts +20 -0
  34. package/lib/src/commands/assertHasClass.js +17 -0
  35. package/lib/src/commands/assertHasClass.js.map +1 -0
  36. package/lib/src/commands/assertNumElements.d.ts +19 -0
  37. package/lib/src/commands/assertNumElements.js +17 -0
  38. package/lib/src/commands/assertNumElements.js.map +1 -0
  39. package/lib/src/commands/extractDataFromClass.d.ts +18 -0
  40. package/lib/src/commands/extractDataFromClass.js +25 -0
  41. package/lib/src/commands/extractDataFromClass.js.map +1 -0
  42. package/lib/src/commands/extractDataFromClassByContents.d.ts +19 -0
  43. package/lib/src/commands/extractDataFromClassByContents.js +26 -0
  44. package/lib/src/commands/extractDataFromClassByContents.js.map +1 -0
  45. package/lib/src/commands/getJSON.d.ts +16 -0
  46. package/lib/src/commands/getJSON.js +21 -0
  47. package/lib/src/commands/getJSON.js.map +1 -0
  48. package/lib/src/commands/getNumElements.d.ts +15 -0
  49. package/lib/src/commands/getNumElements.js +19 -0
  50. package/lib/src/commands/getNumElements.js.map +1 -0
  51. package/lib/src/commands/handleHarvardKey.d.ts +15 -0
  52. package/lib/src/commands/handleHarvardKey.js +53 -0
  53. package/lib/src/commands/handleHarvardKey.js.map +1 -0
  54. package/lib/src/commands/launchAs.d.ts +25 -0
  55. package/lib/src/commands/launchAs.js +66 -0
  56. package/lib/src/commands/launchAs.js.map +1 -0
  57. package/lib/src/commands/launchLTIUsingToken.d.ts +21 -0
  58. package/lib/src/commands/launchLTIUsingToken.js +68 -0
  59. package/lib/src/commands/launchLTIUsingToken.js.map +1 -0
  60. package/lib/src/commands/navigateToHref.d.ts +15 -0
  61. package/lib/src/commands/navigateToHref.js +35 -0
  62. package/lib/src/commands/navigateToHref.js.map +1 -0
  63. package/lib/src/commands/runScript.d.ts +15 -0
  64. package/lib/src/commands/runScript.js +20 -0
  65. package/lib/src/commands/runScript.js.map +1 -0
  66. package/lib/src/commands/typeInto.d.ts +24 -0
  67. package/lib/src/commands/typeInto.js +41 -0
  68. package/lib/src/commands/typeInto.js.map +1 -0
  69. package/lib/src/commands/visitCanvasGETEndpoint.d.ts +20 -0
  70. package/lib/src/commands/visitCanvasGETEndpoint.js +26 -0
  71. package/lib/src/commands/visitCanvasGETEndpoint.js.map +1 -0
  72. package/lib/src/commands/waitForElementVisible.d.ts +16 -0
  73. package/lib/src/commands/waitForElementVisible.js +19 -0
  74. package/lib/src/commands/waitForElementVisible.js.map +1 -0
  75. package/lib/src/genConfiguration/helpers/getRootPath.d.ts +7 -0
  76. package/lib/src/genConfiguration/helpers/getRootPath.js +17 -0
  77. package/lib/src/genConfiguration/helpers/getRootPath.js.map +1 -0
  78. package/lib/src/genConfiguration/helpers/resolveDependents.d.ts +13 -0
  79. package/lib/src/genConfiguration/helpers/resolveDependents.js +50 -0
  80. package/lib/src/genConfiguration/helpers/resolveDependents.js.map +1 -0
  81. package/lib/src/genConfiguration/helpers/splitEnv.d.ts +10 -0
  82. package/lib/src/genConfiguration/helpers/splitEnv.js +27 -0
  83. package/lib/src/genConfiguration/helpers/splitEnv.js.map +1 -0
  84. package/{src/genConfiguration.ts → lib/src/genConfiguration/index.d.ts} +3 -6
  85. package/lib/src/genConfiguration/index.js +89 -0
  86. package/lib/src/genConfiguration/index.js.map +1 -0
  87. package/lib/src/genConfiguration/types/DependentValue.d.ts +11 -0
  88. package/lib/src/genConfiguration/types/DependentValue.js +3 -0
  89. package/lib/src/genConfiguration/types/DependentValue.js.map +1 -0
  90. package/lib/src/genConfiguration/types/GlobalsOrProfile.d.ts +9 -0
  91. package/lib/src/genConfiguration/types/GlobalsOrProfile.js +3 -0
  92. package/lib/src/genConfiguration/types/GlobalsOrProfile.js.map +1 -0
  93. package/lib/src/genConfiguration/types/SplitEnv.d.ts +13 -0
  94. package/lib/src/genConfiguration/types/SplitEnv.js +3 -0
  95. package/lib/src/genConfiguration/types/SplitEnv.js.map +1 -0
  96. package/lib/{index.d.ts → src/index.d.ts} +1 -1
  97. package/lib/{index.js → src/index.js} +6 -3
  98. package/lib/src/index.js.map +1 -0
  99. package/lib/src/init.d.ts +6 -0
  100. package/lib/src/init.js +45 -0
  101. package/lib/src/init.js.map +1 -0
  102. package/lib/start/constants/AVAILABLE_BROWSERS.d.ts +9 -0
  103. package/lib/start/constants/AVAILABLE_BROWSERS.js +27 -0
  104. package/lib/start/constants/AVAILABLE_BROWSERS.js.map +1 -0
  105. package/lib/start/helpers/exec.d.ts +8 -0
  106. package/lib/start/helpers/exec.js +18 -0
  107. package/lib/start/helpers/exec.js.map +1 -0
  108. package/lib/start/helpers/extractArgValue.d.ts +10 -0
  109. package/lib/start/helpers/extractArgValue.js +39 -0
  110. package/lib/start/helpers/extractArgValue.js.map +1 -0
  111. package/lib/start/helpers/findProfilesByNames.d.ts +16 -0
  112. package/lib/start/helpers/findProfilesByNames.js +35 -0
  113. package/lib/start/helpers/findProfilesByNames.js.map +1 -0
  114. package/lib/start/helpers/getRootPath.d.ts +7 -0
  115. package/lib/start/helpers/getRootPath.js +17 -0
  116. package/lib/start/helpers/getRootPath.js.map +1 -0
  117. package/lib/start/helpers/parseCommaSeparated.d.ts +8 -0
  118. package/lib/start/helpers/parseCommaSeparated.js +23 -0
  119. package/lib/start/helpers/parseCommaSeparated.js.map +1 -0
  120. package/lib/start/helpers/print.d.ts +38 -0
  121. package/lib/start/helpers/print.js +145 -0
  122. package/lib/start/helpers/print.js.map +1 -0
  123. package/lib/start/helpers/prompt.d.ts +8 -0
  124. package/lib/start/helpers/prompt.js +25 -0
  125. package/lib/start/helpers/prompt.js.map +1 -0
  126. package/lib/start/helpers/showChooser.d.ts +21 -0
  127. package/lib/start/helpers/showChooser.js +116 -0
  128. package/lib/start/helpers/showChooser.js.map +1 -0
  129. package/lib/start/helpers/validateBrowsers.d.ts +8 -0
  130. package/lib/start/helpers/validateBrowsers.js +36 -0
  131. package/lib/start/helpers/validateBrowsers.js.map +1 -0
  132. package/lib/start/index.d.ts +7 -0
  133. package/lib/start/index.js +140 -0
  134. package/lib/start/index.js.map +1 -0
  135. package/lib/start/types/ChooserOption.d.ts +10 -0
  136. package/lib/start/types/ChooserOption.js +3 -0
  137. package/lib/start/types/ChooserOption.js.map +1 -0
  138. package/package.json +28 -8
  139. package/setup/addToGitIgnore.ts +48 -0
  140. package/setup/checkRequiredFiles.ts +63 -0
  141. package/setup/genCommandImportFile.ts +76 -0
  142. package/setup/genDynamicConfigFile.ts +29 -0
  143. package/setup/helpers/getRootPath.ts +13 -0
  144. package/setup/index.ts +11 -0
  145. package/setup/setupCypressDependencies.ts +38 -0
  146. package/src/commands/assertDoesNotHaveClass.ts +51 -0
  147. package/src/commands/assertHasClass.ts +51 -0
  148. package/src/commands/assertNumElements.ts +50 -0
  149. package/src/commands/extractDataFromClass.ts +52 -0
  150. package/src/commands/extractDataFromClassByContents.ts +55 -0
  151. package/src/commands/getJSON.ts +45 -0
  152. package/src/commands/getNumElements.ts +45 -0
  153. package/src/commands/handleHarvardKey.ts +91 -0
  154. package/src/commands/launchAs.ts +120 -0
  155. package/src/commands/launchLTIUsingToken.ts +115 -0
  156. package/src/commands/navigateToHref.ts +60 -0
  157. package/src/commands/runScript.ts +44 -0
  158. package/src/commands/typeInto.ts +88 -0
  159. package/src/commands/visitCanvasGETEndpoint.ts +61 -0
  160. package/src/commands/waitForElementVisible.ts +49 -0
  161. package/src/genConfiguration/helpers/getRootPath.ts +13 -0
  162. package/src/genConfiguration/helpers/resolveDependents.ts +46 -0
  163. package/src/genConfiguration/helpers/splitEnv.ts +30 -0
  164. package/src/genConfiguration/index.ts +95 -0
  165. package/src/genConfiguration/types/DependentValue.ts +14 -0
  166. package/src/genConfiguration/types/GlobalsOrProfile.ts +12 -0
  167. package/src/genConfiguration/types/SplitEnv.ts +18 -0
  168. package/src/index.ts +7 -4
  169. package/src/init.ts +36 -17
  170. package/start/constants/AVAILABLE_BROWSERS.ts +28 -0
  171. package/start/helpers/exec.ts +17 -0
  172. package/start/helpers/extractArgValue.ts +42 -0
  173. package/start/helpers/findProfilesByNames.ts +39 -0
  174. package/start/helpers/getRootPath.ts +13 -0
  175. package/start/helpers/parseCommaSeparated.ts +23 -0
  176. package/start/helpers/print.ts +155 -0
  177. package/start/helpers/prompt.ts +23 -0
  178. package/start/helpers/showChooser.ts +140 -0
  179. package/start/helpers/validateBrowsers.ts +35 -0
  180. package/start/index.ts +164 -0
  181. package/start/types/ChooserOption.ts +11 -0
  182. package/tsconfig.json +3 -4
  183. package/.eslintrc.json +0 -58
  184. package/lib/genConfiguration.d.ts +0 -8
  185. package/lib/genConfiguration.js +0 -13
  186. package/lib/genConfiguration.js.map +0 -1
  187. package/lib/index.js.map +0 -1
  188. package/lib/init.d.ts +0 -13
  189. package/lib/init.js +0 -10
  190. package/lib/init.js.map +0 -1
@@ -0,0 +1,155 @@
1
+ /* eslint-disable no-console */
2
+
3
+ /**
4
+ * Get the left buffer for a centered message
5
+ * @author Gabe Abrams
6
+ * @param message message to print
7
+ * @param padding amount of padding to add
8
+ * @returns number of chars in the buffer
9
+ */
10
+ const leftBuffer = (message: string, padding: number): number => {
11
+ return (Math.floor(process.stdout.columns / 2) - padding - Math.ceil(message.length / 2));
12
+ };
13
+
14
+ /**
15
+ * Get the right buffer for a centered message
16
+ * @author Gabe Abrams
17
+ * @param message message to print
18
+ * @param padding amount of padding to add
19
+ * @returns number of chars in the buffer
20
+ */
21
+ const rightBuffer = (message: string, padding: number): number => {
22
+ return (Math.ceil(process.stdout.columns / 2) - padding - Math.floor(message.length / 2));
23
+ };
24
+
25
+ /**
26
+ * Surround text with a border and spaces
27
+ * @author Gabe Abrams
28
+ * @param str text to print
29
+ * @param border single character to use as a border
30
+ * @returns text to print
31
+ */
32
+ const surroundWithBuffer = (str: string, border: string): string => {
33
+ return (
34
+ border
35
+ + ' '.repeat(leftBuffer(str, border.length))
36
+ + str
37
+ + ' '.repeat(rightBuffer(str, border.length))
38
+ + border
39
+ );
40
+ };
41
+
42
+ /**
43
+ * Surround text with a character as the buffer
44
+ * @author Gabe Abrams
45
+ * @param str text to print
46
+ * @param char character to place as the buffer
47
+ * @returns text to print
48
+ */
49
+ const surroundWithChars = (str: string, char: string): string => {
50
+ if (str.length > process.stdout.columns) {
51
+ return str;
52
+ }
53
+ if (str.length === process.stdout.columns - 1) {
54
+ return char + str;
55
+ }
56
+ if (str.length === process.stdout.columns - 2) {
57
+ return char + str + char;
58
+ }
59
+ return (
60
+ char.repeat(leftBuffer(str, 1))
61
+ + ' '
62
+ + str
63
+ + ' '
64
+ + char.repeat(rightBuffer(str, 1))
65
+ );
66
+ };
67
+
68
+ // Prompt instance
69
+ let cachedPrompt: any;
70
+
71
+ const print = {
72
+ /**
73
+ * Print a title
74
+ * @author Gabe Abrams
75
+ * @param str text to print
76
+ */
77
+ title: (str: string) => {
78
+ if (str.length > process.stdout.columns) {
79
+ return console.log(str);
80
+ }
81
+ console.log('\u2554' + '\u2550'.repeat(process.stdout.columns - 2) + '\u2557');
82
+ console.log(surroundWithBuffer(str, '\u2551'));
83
+ console.log('\u255A' + '\u2550'.repeat(process.stdout.columns - 2) + '\u255D');
84
+ },
85
+ /**
86
+ * Print a sub title (subheading)
87
+ * @author Gabe Abrams
88
+ * @param str text to print
89
+ */
90
+ subtitle: (str: string) => {
91
+ if (str.length > process.stdout.columns) {
92
+ return console.log(str);
93
+ }
94
+ console.log(surroundWithChars(str, '\u257C'));
95
+ },
96
+ /**
97
+ * Print centered text
98
+ * @author Gabe Abrams
99
+ * @param str text to print
100
+ */
101
+ centered: (str: string) => {
102
+ const lines = [];
103
+ let index = 0;
104
+ while (index < str.length) {
105
+ lines.push(str.substring(index, Math.min(index + process.stdout.columns, str.length)));
106
+ index += process.stdout.columns;
107
+ }
108
+ lines.forEach((line, lineIndex) => {
109
+ if (lineIndex !== lines.length - 1) {
110
+ // No need to center: fills whole line
111
+ console.log(line);
112
+ } else {
113
+ // This line needs to be centered
114
+ console.log(surroundWithChars(line, ' '));
115
+ }
116
+ });
117
+ },
118
+ /**
119
+ * Print a fatal error message
120
+ * @author Gabe Abrams
121
+ * @param err error message
122
+ */
123
+ fatalError: (err: string) => {
124
+ console.log('\n');
125
+ const errLine1 = err.substring(0, process.stdout.columns - 6);
126
+ const errLine2 = err.substring(process.stdout.columns - 6);
127
+ console.log('\u2554' + '\u2550'.repeat(3) + '\u2557 ');
128
+ console.log(`\u2551 ! \u2551 ${errLine1}`);
129
+ console.log('\u255A' + '\u2550'.repeat(3) + '\u255D ' + errLine2);
130
+ process.exit(0);
131
+ },
132
+ /**
133
+ * Save a copy of the prompt instance
134
+ * @author Gabe Abrams
135
+ * @param promptInstance instance of prompt-sync
136
+ */
137
+ savePrompt: (promptInstance: any) => {
138
+ cachedPrompt = promptInstance;
139
+ },
140
+ /**
141
+ * Ask the user to press enter before continuing
142
+ * @author Gabe Abrams
143
+ */
144
+ enterToContinue: () => {
145
+ const res = cachedPrompt(
146
+ surroundWithChars('enter to continue, ctrl+c to quit', '\u257C'),
147
+ true,
148
+ );
149
+ if (res === null) {
150
+ process.exit(0);
151
+ }
152
+ },
153
+ };
154
+
155
+ export default print;
@@ -0,0 +1,23 @@
1
+ import initPrompt from 'prompt-sync';
2
+ import print from './print';
3
+
4
+ const promptSync = initPrompt();
5
+
6
+ /**
7
+ * Ask the user a question
8
+ * @param title title of the question
9
+ * @param notRequired true if question is not required
10
+ * @returns response
11
+ */
12
+ const prompt = (title: string, notRequired?: boolean): string => {
13
+ const val = promptSync(title);
14
+ if (val === null || (!notRequired && !val)) {
15
+ process.exit(0);
16
+ }
17
+ return val;
18
+ };
19
+
20
+ // Save the prompt for use later
21
+ print.savePrompt(prompt);
22
+
23
+ export default prompt;
@@ -0,0 +1,140 @@
1
+ /* eslint-disable no-console */
2
+ import clear from 'clear';
3
+
4
+ // Import shared helpers
5
+ import print from './print';
6
+ import prompt from './prompt';
7
+ import parseCommaSeparated from './parseCommaSeparated';
8
+
9
+ // Import shared types
10
+ import ChooserOption from '../types/ChooserOption';
11
+
12
+ /**
13
+ * Show a chooser between many options
14
+ * @author Gabe Abrams
15
+ * @author Yuen Ler Chow
16
+ * @param opts object of arguments
17
+ * @param opts.question the question to ask
18
+ * @param opts.options list of options to choose from
19
+ * @param opts.title main title to show above the choices
20
+ * @param opts.dontClear if true, don't clear the console before
21
+ * @param opts.allowMulti if true, allow multiple selections (comma-separated)
22
+ * @returns array of chosen option(s)
23
+ */
24
+ const showChooser = (
25
+ opts: {
26
+ question: string,
27
+ options: ChooserOption[],
28
+ title?: string,
29
+ dontClear?: boolean,
30
+ allowMulti?: boolean,
31
+ },
32
+ ): ChooserOption[] => {
33
+ const {
34
+ question,
35
+ options,
36
+ title,
37
+ dontClear,
38
+ allowMulti = false,
39
+ } = opts;
40
+
41
+ // Helper to re-display the chooser after an invalid selection
42
+ const retryWithMessage = (message: string) => {
43
+ clear();
44
+ print.title('Invalid Choice');
45
+ console.log(message);
46
+ console.log('');
47
+ print.enterToContinue();
48
+ return showChooser({
49
+ question,
50
+ options,
51
+ title,
52
+ dontClear,
53
+ allowMulti,
54
+ });
55
+ };
56
+
57
+ // Print the header
58
+ if (!dontClear) {
59
+ clear();
60
+ }
61
+ if (title) {
62
+ print.title(title);
63
+ console.log('');
64
+ }
65
+ print.subtitle(question);
66
+
67
+ // Make sure all options have tags
68
+ let nextNumber = 1;
69
+ const optionsWithTags = options.map((option) => {
70
+ // Get/generate a tag
71
+ let { tag } = option;
72
+ if (!tag) {
73
+ tag = String(nextNumber);
74
+ nextNumber += 1;
75
+ }
76
+
77
+ // Return complete option
78
+ return {
79
+ ...option,
80
+ tag,
81
+ };
82
+ });
83
+
84
+ // Print options
85
+ optionsWithTags.forEach((option) => {
86
+ console.log(`${option.tag} - ${option.description}`);
87
+ });
88
+
89
+ // Ask user to choose
90
+ const response = prompt('> ').trim();
91
+
92
+ // Always parse as comma-separated (treat all inputs with multi-select logic)
93
+ const selectedTags = parseCommaSeparated(response);
94
+
95
+ // Fail fast if multi-select is not allowed but multiple selections were made
96
+ if (!allowMulti && selectedTags.length > 1) {
97
+ return retryWithMessage(
98
+ 'Multiple selections are not allowed. Please select only one option.',
99
+ );
100
+ }
101
+
102
+ // Find matching options
103
+ const selected: Array<{ description: string; tag: string; index: number }> = [];
104
+ const invalidTags: string[] = [];
105
+
106
+ selectedTags.forEach((tag) => {
107
+ const lowerTag = tag.toLowerCase();
108
+ let found = false;
109
+ optionsWithTags.forEach((opt, idx) => {
110
+ if (opt.tag.toLowerCase() === lowerTag) {
111
+ selected.push({
112
+ description: opt.description,
113
+ tag: opt.tag,
114
+ index: idx,
115
+ });
116
+ found = true;
117
+ }
118
+ });
119
+
120
+ if (!found) {
121
+ invalidTags.push(tag);
122
+ }
123
+ });
124
+
125
+ // Handle invalid tags
126
+ if (invalidTags.length > 0) {
127
+ return retryWithMessage(
128
+ `The following selections are not valid: ${invalidTags.join(', ')}`,
129
+ );
130
+ }
131
+
132
+ // Handle no selections
133
+ if (selected.length === 0) {
134
+ return retryWithMessage('No valid selections made.');
135
+ }
136
+
137
+ return selected;
138
+ };
139
+
140
+ export default showChooser;
@@ -0,0 +1,35 @@
1
+ /* eslint-disable no-console */
2
+ import AVAILABLE_BROWSERS from '../constants/AVAILABLE_BROWSERS';
3
+
4
+ /**
5
+ * Validate browsers (supports multiple)
6
+ * @author Yuen Ler Chow
7
+ * @param browserNames array of browser names to validate
8
+ * @returns array of valid browser names (lowercased)
9
+ */
10
+ const validateBrowsers = (browserNames: string[]): string[] => {
11
+ const valid: string[] = [];
12
+ const invalid: string[] = [];
13
+
14
+ // Convert all browser names to lowercase for comparison
15
+ const lowercaseBrowserNames = browserNames.map((browser) => { return browser.toLowerCase(); });
16
+
17
+ // Validate each browser
18
+ lowercaseBrowserNames.forEach((browser) => {
19
+ if (AVAILABLE_BROWSERS.some((b) => { return b.name.toLowerCase() === browser.toLowerCase(); })) {
20
+ valid.push(browser);
21
+ } else {
22
+ invalid.push(browser);
23
+ }
24
+ });
25
+
26
+ // If there are invalid browsers, log error and exit
27
+ if (invalid.length > 0) {
28
+ console.error(`Browser(s) invalid: ${invalid.join(', ')}. Available browsers: ${AVAILABLE_BROWSERS.join(', ')}`);
29
+ process.exit(1);
30
+ }
31
+
32
+ return valid;
33
+ };
34
+
35
+ export default validateBrowsers;
package/start/index.ts ADDED
@@ -0,0 +1,164 @@
1
+ /* eslint-disable no-console */
2
+ /**
3
+ * Checks arguments and environment variables (for PROFILE, BROWSER, and HEADLESS),
4
+ * asks user for missing selections, and launches Cypress
5
+ * @author Gardenia Liu
6
+ * @author Yuen Ler Chow
7
+ */
8
+
9
+ // Import libs
10
+ import fs from 'fs';
11
+ import path from 'path';
12
+
13
+ // Import helpers
14
+ import showChooser from './helpers/showChooser';
15
+ import parseCommaSeparated from './helpers/parseCommaSeparated';
16
+ import findProfilesByNames from './helpers/findProfilesByNames';
17
+ import validateBrowsers from './helpers/validateBrowsers';
18
+ import extractArgValue from './helpers/extractArgValue';
19
+ import getRootPath from './helpers/getRootPath';
20
+
21
+ // Import constants
22
+ import AVAILABLE_BROWSERS from './constants/AVAILABLE_BROWSERS';
23
+
24
+ // Get the project directory
25
+ const pwd = getRootPath();
26
+
27
+ // Find available profiles under /cypress/profiles
28
+ const profilesDir = path.join(pwd, 'cypress/profiles');
29
+ if (!fs.existsSync(profilesDir)) {
30
+ console.warn(`[cypress.config] Could not load profile '${profilesDir}'`);
31
+ process.exit(1);
32
+ }
33
+
34
+ // Find all files matching the pattern: {ProfileName}.Profile.ts
35
+ const profileFiles = (
36
+ fs
37
+ .readdirSync(profilesDir)
38
+ .filter((f) => {
39
+ return f.endsWith('.Profile.ts');
40
+ })
41
+ );
42
+
43
+ // Get profile names by removing '.Profile.ts'
44
+ const profiles = profileFiles.map((file) => {
45
+ const profileName = file.replace('.Profile.ts', '');
46
+ return { file, profileName };
47
+ });
48
+
49
+ // Exit if no profiles found
50
+ if (profiles.length === 0) {
51
+ console.error(`No profiles found in '${profilesDir}'`);
52
+ process.exit(1);
53
+ }
54
+
55
+ // Parse CLI arguments
56
+ const args = process.argv.slice(2);
57
+
58
+ // Get selections from environment variables or CLI arguments
59
+ let selectedProfiles: { file: string; profileName: string }[] = [];
60
+ let selectedBrowsers: string[] = [];
61
+ let isHeadless = false;
62
+
63
+ // Check for PROFILE (env var or CLI arg)
64
+ const envProfileRaw = process.env.PROFILE;
65
+ const argProfileRaw = extractArgValue(args, '--profile');
66
+ const profileRaw = envProfileRaw || argProfileRaw;
67
+
68
+ if (profileRaw) {
69
+ const profileNames = parseCommaSeparated(profileRaw);
70
+ selectedProfiles = findProfilesByNames(profileNames, profiles);
71
+ }
72
+
73
+ // Check for BROWSER (env var or CLI arg)
74
+ const envBrowserRaw = process.env.BROWSER;
75
+ const argBrowserRaw = extractArgValue(args, '--browser');
76
+ const browserRaw = envBrowserRaw || argBrowserRaw;
77
+
78
+ if (browserRaw) {
79
+ const browserNames = parseCommaSeparated(browserRaw);
80
+ selectedBrowsers = validateBrowsers(browserNames);
81
+ }
82
+
83
+ // Check for HEADLESS (env var or CLI flag)
84
+ const envHeadlessRaw = process.env.HEADLESS;
85
+ const headlessFlagValue = extractArgValue(args, '--headless');
86
+ const hasHeadlessFlag = headlessFlagValue !== undefined;
87
+ isHeadless = !!(envHeadlessRaw && envHeadlessRaw.toLowerCase() !== 'false') || hasHeadlessFlag;
88
+
89
+ // If headless wasn't specified, ask the user to choose
90
+ if (!envHeadlessRaw && !hasHeadlessFlag) {
91
+ const choices = showChooser({
92
+ question: 'Run in headless mode?',
93
+ options: [
94
+ { tag: '1', description: 'Yes (headless)' },
95
+ { tag: '2', description: 'No (interactive)' },
96
+ ],
97
+ title: 'Select mode',
98
+ allowMulti: false,
99
+ });
100
+
101
+ isHeadless = choices[0].tag === '1';
102
+ }
103
+
104
+ // If running headless and no browsers were selected, ask the user to choose
105
+ if (isHeadless && selectedBrowsers.length === 0) {
106
+ const options = AVAILABLE_BROWSERS.map(({ tag, name }) => {
107
+ return {
108
+ tag,
109
+ description: name,
110
+ };
111
+ });
112
+
113
+ const choices = showChooser({
114
+ question: 'Choose browser(s) (commas for multiple: C,F)',
115
+ options,
116
+ title: 'Select browser(s)',
117
+ allowMulti: true,
118
+ });
119
+
120
+ selectedBrowsers = (
121
+ choices
122
+ .map((choice) => {
123
+ return AVAILABLE_BROWSERS[choice.index];
124
+ })
125
+ .map(({ name }) => {
126
+ return name;
127
+ })
128
+ );
129
+ }
130
+
131
+ // If no profiles were selected, ask the user to choose
132
+ // - In headless mode, allow selecting multiple profiles
133
+ // - In visible mode, only allow selecting a single profile
134
+ // In the case where their environment selected more than one profile, but they are not headless, make them re-choose
135
+ if (
136
+ selectedProfiles.length === 0
137
+ || (!isHeadless && selectedProfiles.length > 1)
138
+ ) {
139
+ const options = profiles.map((p, idx) => {
140
+ return {
141
+ tag: String(idx + 1),
142
+ description: p.profileName,
143
+ };
144
+ });
145
+
146
+ const choices = showChooser({
147
+ question: (
148
+ isHeadless
149
+ ? 'Choose profile(s) (commas for multiple: 1,2):'
150
+ : 'Choose profile:'
151
+ ),
152
+ options,
153
+ title: `Choose profile${isHeadless ? 's' : ''}`,
154
+ allowMulti: isHeadless,
155
+ });
156
+
157
+ selectedProfiles = choices.map((choice) => { return profiles[choice.index]; });
158
+ }
159
+
160
+ // Execute commands for each combination of profile and browser (not yet implemented)
161
+ console.log('Starting Cypress with the following configuration:');
162
+ console.log(`Profiles: ${selectedProfiles.map((p) => { return p.profileName; }).join(', ')}`);
163
+ console.log(`Browsers: ${selectedBrowsers.join(', ')}`);
164
+ console.log(`Headless: ${isHeadless}`);
@@ -0,0 +1,11 @@
1
+ /**
2
+ * An option that can be put into a chooser
3
+ * @author Gabe Abrams
4
+ */
5
+ type ChooserOption = {
6
+ description: string,
7
+ tag?: string,
8
+ index?: number,
9
+ };
10
+
11
+ export default ChooserOption;
package/tsconfig.json CHANGED
@@ -8,12 +8,11 @@
8
8
  "declaration": true,
9
9
  "sourceMap": true,
10
10
  "target": "es5",
11
+ "lib": ["es5", "es2015.promise", "es2017.object", "dom"],
11
12
  "outDir": "./lib"
12
13
  },
13
- "include": [
14
- "./src"
15
- ],
14
+ "include": [ "./src", "setup", "start" ],
16
15
  "ts-node": {
17
16
  "files": true
18
17
  }
19
- }
18
+ }
package/.eslintrc.json DELETED
@@ -1,58 +0,0 @@
1
- {
2
- "extends": "airbnb",
3
- "env": {
4
- "browser": true,
5
- "node": true
6
- },
7
- "rules": {
8
- "arrow-body-style": [
9
- "warn",
10
- "always"
11
- ],
12
- "arrow-parens": [ "warn", "always" ],
13
- "comma-dangle": [ "error", {
14
- "arrays": "always-multiline",
15
- "objects": "always-multiline",
16
- "imports": "always-multiline",
17
- "exports": "always-multiline",
18
- "functions": "never"
19
- }
20
- ],
21
- "consistent-return": "off",
22
- "id-length": "off",
23
- "max-len": [ "error",
24
- {
25
- "code": 80,
26
- "ignoreStrings": true,
27
- "ignoreTemplateLiterals": true,
28
- "ignoreUrls": true
29
- }
30
- ],
31
- "newline-per-chained-call": [
32
- "error",
33
- {
34
- "ignoreChainWithDepth": 2
35
- }
36
- ],
37
- "no-plusplus": [ "warn", { "allowForLoopAfterthoughts": true }],
38
- "prefer-template": "off",
39
- "prefer-destructuring": [ "error",
40
- {
41
- "VariableDeclarator": {
42
- "array": false,
43
- "object": true
44
- },
45
- "AssignmentExpression": {
46
- "array": false,
47
- "object": true
48
- }
49
- },
50
- {
51
- "enforceForRenamedProperties": false
52
- }
53
- ],
54
- "radix": "off",
55
- "no-underscore-dangle": "off",
56
- "max-params": [ "warn", { "max": 3 } ]
57
- }
58
- }
@@ -1,8 +0,0 @@
1
- /**
2
- * Generate Cypress configuration based on global credentials,
3
- * variables, resources, and profiles
4
- * @author Yuen Ler Chow
5
- * ...
6
- */
7
- declare const genConfiguration: () => {};
8
- export default genConfiguration;
@@ -1,13 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- /**
4
- * Generate Cypress configuration based on global credentials,
5
- * variables, resources, and profiles
6
- * @author Yuen Ler Chow
7
- * ...
8
- */
9
- var genConfiguration = function () {
10
- return {};
11
- };
12
- exports.default = genConfiguration;
13
- //# sourceMappingURL=genConfiguration.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"genConfiguration.js","sourceRoot":"","sources":["../src/genConfiguration.ts"],"names":[],"mappings":";;AAAA;;;;;GAKG;AACH,IAAM,gBAAgB,GAAG;IACvB,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC;AAEF,kBAAe,gBAAgB,CAAC"}
package/lib/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAAA,gDAA0B;AASxB,eATK,cAAI,CASL;AARN,wEAAkD;AAOhD,2BAPK,0BAAgB,CAOL;AALlB,sDAAsD;AACtD,IAAA,cAAI,GAAE,CAAC"}
package/lib/init.d.ts DELETED
@@ -1,13 +0,0 @@
1
- declare global {
2
- namespace Cypress {
3
- interface Chainable {
4
- /**
5
- * Custom command to click an element by selector
6
- * @example cy.clickSomething('.my-button')
7
- */
8
- clickSomething(selector: string): Chainable<Element>;
9
- }
10
- }
11
- }
12
- declare const init: () => void;
13
- export default init;
package/lib/init.js DELETED
@@ -1,10 +0,0 @@
1
- "use strict";
2
- /// <reference types="cypress" />
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- var init = function () {
5
- Cypress.Commands.add('clickSomething', function (selector) {
6
- cy.get(selector).click();
7
- });
8
- };
9
- exports.default = init;
10
- //# sourceMappingURL=init.js.map
package/lib/init.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":";AAAA,iCAAiC;;AAejC,IAAM,IAAI,GAAG;IACX,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,gBAAgB,EAAE,UAAC,QAAgB;QACtD,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,kBAAe,IAAI,CAAC"}