dceky 1.0.0-beta.6 → 1.0.2
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/.eslintrc.js +93 -0
- package/README.md +41 -0
- package/cypress/e2e/profile-test.cy.ts +10 -0
- package/cypress/fixtures/example.json +5 -0
- package/cypress/support/commands.ts +37 -0
- package/cypress/support/e2e.ts +17 -0
- package/cypress.config.ts +9 -0
- package/docs/GlobalsAndProfiles.md +23 -0
- package/lib/setup/addToGitIgnore.d.ts +6 -0
- package/lib/setup/addToGitIgnore.js +46 -0
- package/lib/setup/addToGitIgnore.js.map +1 -0
- package/lib/setup/checkRequiredFiles.d.ts +6 -0
- package/lib/setup/checkRequiredFiles.js +58 -0
- package/lib/setup/checkRequiredFiles.js.map +1 -0
- package/lib/setup/genCommandImportFile.d.ts +7 -0
- package/lib/setup/genCommandImportFile.js +66 -0
- package/lib/setup/genCommandImportFile.js.map +1 -0
- package/lib/setup/genConfiguration/helpers/resolveDependents.d.ts +13 -0
- package/lib/setup/genConfiguration/helpers/resolveDependents.js +50 -0
- package/lib/setup/genConfiguration/helpers/resolveDependents.js.map +1 -0
- package/lib/setup/genConfiguration/helpers/splitEnv.d.ts +10 -0
- package/lib/setup/genConfiguration/helpers/splitEnv.js +27 -0
- package/lib/setup/genConfiguration/helpers/splitEnv.js.map +1 -0
- package/lib/setup/genConfiguration/index.d.ts +15 -0
- package/lib/setup/genConfiguration/index.js +86 -0
- package/lib/setup/genConfiguration/index.js.map +1 -0
- package/lib/setup/genConfiguration/types/DependentValue.d.ts +11 -0
- package/lib/setup/genConfiguration/types/DependentValue.js +3 -0
- package/lib/setup/genConfiguration/types/DependentValue.js.map +1 -0
- package/lib/setup/genConfiguration/types/GlobalsOrProfile.d.ts +9 -0
- package/lib/setup/genConfiguration/types/GlobalsOrProfile.js +3 -0
- package/lib/setup/genConfiguration/types/GlobalsOrProfile.js.map +1 -0
- package/lib/setup/genConfiguration/types/SplitEnv.d.ts +13 -0
- package/lib/setup/genConfiguration/types/SplitEnv.js +3 -0
- package/lib/setup/genConfiguration/types/SplitEnv.js.map +1 -0
- package/lib/setup/genConfigurationFile.d.ts +2 -0
- package/lib/setup/genConfigurationFile.js +63 -0
- package/lib/setup/genConfigurationFile.js.map +1 -0
- package/lib/setup/genDynamicConfigFile.d.ts +5 -0
- package/lib/setup/genDynamicConfigFile.js +28 -0
- package/lib/setup/genDynamicConfigFile.js.map +1 -0
- package/lib/setup/index.d.ts +1 -0
- package/lib/setup/index.js +16 -0
- package/lib/setup/index.js.map +1 -0
- package/lib/setup/setupCypressDependencies.d.ts +6 -0
- package/lib/setup/setupCypressDependencies.js +40 -0
- package/lib/setup/setupCypressDependencies.js.map +1 -0
- package/lib/src/commands/assertDoesNotHaveClass.d.ts +20 -0
- package/lib/src/commands/assertDoesNotHaveClass.js +17 -0
- package/lib/src/commands/assertDoesNotHaveClass.js.map +1 -0
- package/lib/src/commands/assertHasClass.d.ts +20 -0
- package/lib/src/commands/assertHasClass.js +17 -0
- package/lib/src/commands/assertHasClass.js.map +1 -0
- package/lib/src/commands/assertNumElements.d.ts +19 -0
- package/lib/src/commands/assertNumElements.js +17 -0
- package/lib/src/commands/assertNumElements.js.map +1 -0
- package/lib/src/commands/extractDataFromClass.d.ts +18 -0
- package/lib/src/commands/extractDataFromClass.js +25 -0
- package/lib/src/commands/extractDataFromClass.js.map +1 -0
- package/lib/src/commands/extractDataFromClassByContents.d.ts +19 -0
- package/lib/src/commands/extractDataFromClassByContents.js +26 -0
- package/lib/src/commands/extractDataFromClassByContents.js.map +1 -0
- package/lib/src/commands/getJSON.d.ts +16 -0
- package/lib/src/commands/getJSON.js +21 -0
- package/lib/src/commands/getJSON.js.map +1 -0
- package/lib/src/commands/getNumElements.d.ts +15 -0
- package/lib/src/commands/getNumElements.js +19 -0
- package/lib/src/commands/getNumElements.js.map +1 -0
- package/lib/src/commands/handleHarvardKey.d.ts +15 -0
- package/lib/src/commands/handleHarvardKey.js +53 -0
- package/lib/src/commands/handleHarvardKey.js.map +1 -0
- package/lib/src/commands/launchAs.d.ts +25 -0
- package/lib/src/commands/launchAs.js +66 -0
- package/lib/src/commands/launchAs.js.map +1 -0
- package/lib/src/commands/launchLTIUsingToken.d.ts +21 -0
- package/lib/src/commands/launchLTIUsingToken.js +68 -0
- package/lib/src/commands/launchLTIUsingToken.js.map +1 -0
- package/lib/src/commands/navigateToHref.d.ts +15 -0
- package/lib/src/commands/navigateToHref.js +35 -0
- package/lib/src/commands/navigateToHref.js.map +1 -0
- package/lib/src/commands/runScript.d.ts +15 -0
- package/lib/src/commands/runScript.js +20 -0
- package/lib/src/commands/runScript.js.map +1 -0
- package/lib/src/commands/typeInto.d.ts +24 -0
- package/lib/src/commands/typeInto.js +41 -0
- package/lib/src/commands/typeInto.js.map +1 -0
- package/lib/src/commands/visitCanvasGETEndpoint.d.ts +20 -0
- package/lib/src/commands/visitCanvasGETEndpoint.js +26 -0
- package/lib/src/commands/visitCanvasGETEndpoint.js.map +1 -0
- package/lib/src/commands/waitForElementVisible.d.ts +16 -0
- package/lib/src/commands/waitForElementVisible.js +19 -0
- package/lib/src/commands/waitForElementVisible.js.map +1 -0
- package/lib/src/genConfiguration/helpers/resolveDependents.d.ts +13 -0
- package/lib/src/genConfiguration/helpers/resolveDependents.js +50 -0
- package/lib/src/genConfiguration/helpers/resolveDependents.js.map +1 -0
- package/lib/src/genConfiguration/helpers/splitEnv.d.ts +10 -0
- package/lib/src/genConfiguration/helpers/splitEnv.js +27 -0
- package/lib/src/genConfiguration/helpers/splitEnv.js.map +1 -0
- package/{src/genConfiguration.ts → lib/src/genConfiguration/index.d.ts} +3 -6
- package/lib/src/genConfiguration/index.js +88 -0
- package/lib/src/genConfiguration/index.js.map +1 -0
- package/lib/src/genConfiguration/types/DependentValue.d.ts +11 -0
- package/lib/src/genConfiguration/types/DependentValue.js +3 -0
- package/lib/src/genConfiguration/types/DependentValue.js.map +1 -0
- package/lib/src/genConfiguration/types/GlobalsOrProfile.d.ts +9 -0
- package/lib/src/genConfiguration/types/GlobalsOrProfile.js +3 -0
- package/lib/src/genConfiguration/types/GlobalsOrProfile.js.map +1 -0
- package/lib/src/genConfiguration/types/SplitEnv.d.ts +13 -0
- package/lib/src/genConfiguration/types/SplitEnv.js +3 -0
- package/lib/src/genConfiguration/types/SplitEnv.js.map +1 -0
- package/lib/{index.d.ts → src/index.d.ts} +1 -1
- package/lib/{index.js → src/index.js} +6 -3
- package/lib/src/index.js.map +1 -0
- package/lib/src/init.d.ts +6 -0
- package/lib/src/init.js +45 -0
- package/lib/src/init.js.map +1 -0
- package/lib/start/constants/AVAILABLE_BROWSERS.d.ts +9 -0
- package/lib/start/constants/AVAILABLE_BROWSERS.js +27 -0
- package/lib/start/constants/AVAILABLE_BROWSERS.js.map +1 -0
- package/lib/start/helpers/exec.d.ts +8 -0
- package/lib/start/helpers/exec.js +18 -0
- package/lib/start/helpers/exec.js.map +1 -0
- package/lib/start/helpers/extractArgValue.d.ts +10 -0
- package/lib/start/helpers/extractArgValue.js +39 -0
- package/lib/start/helpers/extractArgValue.js.map +1 -0
- package/lib/start/helpers/findProfilesByNames.d.ts +16 -0
- package/lib/start/helpers/findProfilesByNames.js +35 -0
- package/lib/start/helpers/findProfilesByNames.js.map +1 -0
- package/lib/start/helpers/parseCommaSeparated.d.ts +8 -0
- package/lib/start/helpers/parseCommaSeparated.js +23 -0
- package/lib/start/helpers/parseCommaSeparated.js.map +1 -0
- package/lib/start/helpers/print.d.ts +38 -0
- package/lib/start/helpers/print.js +145 -0
- package/lib/start/helpers/print.js.map +1 -0
- package/lib/start/helpers/prompt.d.ts +8 -0
- package/lib/start/helpers/prompt.js +25 -0
- package/lib/start/helpers/prompt.js.map +1 -0
- package/lib/start/helpers/showChooser.d.ts +21 -0
- package/lib/start/helpers/showChooser.js +116 -0
- package/lib/start/helpers/showChooser.js.map +1 -0
- package/lib/start/helpers/validateBrowsers.d.ts +8 -0
- package/lib/start/helpers/validateBrowsers.js +36 -0
- package/lib/start/helpers/validateBrowsers.js.map +1 -0
- package/lib/start/index.d.ts +7 -0
- package/lib/start/index.js +139 -0
- package/lib/start/index.js.map +1 -0
- package/lib/start/types/ChooserOption.d.ts +10 -0
- package/lib/start/types/ChooserOption.js +3 -0
- package/lib/start/types/ChooserOption.js.map +1 -0
- package/package.json +28 -8
- package/setup/addToGitIgnore.ts +47 -0
- package/setup/checkRequiredFiles.ts +62 -0
- package/setup/genCommandImportFile.ts +75 -0
- package/setup/genDynamicConfigFile.ts +28 -0
- package/setup/index.ts +11 -0
- package/setup/setupCypressDependencies.ts +38 -0
- package/src/commands/assertDoesNotHaveClass.ts +51 -0
- package/src/commands/assertHasClass.ts +51 -0
- package/src/commands/assertNumElements.ts +50 -0
- package/src/commands/extractDataFromClass.ts +52 -0
- package/src/commands/extractDataFromClassByContents.ts +55 -0
- package/src/commands/getJSON.ts +45 -0
- package/src/commands/getNumElements.ts +45 -0
- package/src/commands/handleHarvardKey.ts +91 -0
- package/src/commands/launchAs.ts +120 -0
- package/src/commands/launchLTIUsingToken.ts +115 -0
- package/src/commands/navigateToHref.ts +60 -0
- package/src/commands/runScript.ts +44 -0
- package/src/commands/typeInto.ts +88 -0
- package/src/commands/visitCanvasGETEndpoint.ts +61 -0
- package/src/commands/waitForElementVisible.ts +49 -0
- package/src/genConfiguration/helpers/resolveDependents.ts +47 -0
- package/src/genConfiguration/helpers/splitEnv.ts +30 -0
- package/src/genConfiguration/index.ts +94 -0
- package/src/genConfiguration/types/DependentValue.ts +14 -0
- package/src/genConfiguration/types/GlobalsOrProfile.ts +12 -0
- package/src/genConfiguration/types/SplitEnv.ts +18 -0
- package/src/index.ts +7 -4
- package/src/init.ts +36 -17
- package/start/constants/AVAILABLE_BROWSERS.ts +28 -0
- package/start/helpers/exec.ts +17 -0
- package/start/helpers/extractArgValue.ts +42 -0
- package/start/helpers/findProfilesByNames.ts +39 -0
- package/start/helpers/parseCommaSeparated.ts +23 -0
- package/start/helpers/print.ts +155 -0
- package/start/helpers/prompt.ts +23 -0
- package/start/helpers/showChooser.ts +140 -0
- package/start/helpers/validateBrowsers.ts +35 -0
- package/start/index.ts +163 -0
- package/start/types/ChooserOption.ts +11 -0
- package/tsconfig.json +3 -4
- package/.eslintrc.json +0 -58
- package/lib/genConfiguration.d.ts +0 -8
- package/lib/genConfiguration.js +0 -13
- package/lib/genConfiguration.js.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/init.d.ts +0 -13
- package/lib/init.js +0 -10
- package/lib/init.js.map +0 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Import shared types
|
|
2
|
+
import type GlobalsOrProfile from '../types/GlobalsOrProfile';
|
|
3
|
+
import type DependentValue from '../types/DependentValue';
|
|
4
|
+
import type SplitEnv from '../types/SplitEnv';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Split one map into basic and dependent values
|
|
8
|
+
* @author Gardenia Liu
|
|
9
|
+
* @param map to split
|
|
10
|
+
* @returns split basic and dependent values map
|
|
11
|
+
*/
|
|
12
|
+
const splitEnv = (map: GlobalsOrProfile): SplitEnv => {
|
|
13
|
+
const basic: GlobalsOrProfile = {};
|
|
14
|
+
const dependent: { [k: string]: DependentValue } = {};
|
|
15
|
+
|
|
16
|
+
Object.entries(map).forEach(([k, v]) => {
|
|
17
|
+
// If entry has dependsOn relationship, add it to dependent dictionary
|
|
18
|
+
if (typeof v === 'object' && 'dependsOn' in v) {
|
|
19
|
+
dependent[k] = v as DependentValue;
|
|
20
|
+
// Otherwise, add it to basic dictionary
|
|
21
|
+
} else {
|
|
22
|
+
basic[k] = v;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Returns separated basic and dependent values
|
|
27
|
+
return { basic, dependent };
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export default splitEnv;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
/* eslint-disable global-require */
|
|
3
|
+
/* eslint-disable import/no-dynamic-require */
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
// Import cypress
|
|
7
|
+
import { defineConfig } from 'cypress';
|
|
8
|
+
|
|
9
|
+
// Import external libraries
|
|
10
|
+
import deepmerge from 'deepmerge';
|
|
11
|
+
|
|
12
|
+
// Import helpers
|
|
13
|
+
import splitEnv from './helpers/splitEnv';
|
|
14
|
+
import resolveDependents from './helpers/resolveDependents';
|
|
15
|
+
|
|
16
|
+
// Import types
|
|
17
|
+
import type SplitEnv from './types/SplitEnv';
|
|
18
|
+
import type GlobalsOrProfile from './types/GlobalsOrProfile';
|
|
19
|
+
|
|
20
|
+
// Determine project directory
|
|
21
|
+
const CWD = path.join(__dirname, '../..');
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Generate Cypress configuration based on global credentials,
|
|
25
|
+
* variables, resources, and profiles
|
|
26
|
+
* @author Gardenia Liu
|
|
27
|
+
* @author Gabe Abrams
|
|
28
|
+
*/
|
|
29
|
+
const genConfiguration = () => {
|
|
30
|
+
// Define paths
|
|
31
|
+
const GLOBALS_PATH = path.join(CWD, '/cypress/globals');
|
|
32
|
+
const PROFILES_PATH = path.join(CWD, '/cypress/profiles');
|
|
33
|
+
|
|
34
|
+
// Import global env var objects
|
|
35
|
+
const GlobalCredentials: GlobalsOrProfile = require(path.join(GLOBALS_PATH, '/GlobalCredentials'));
|
|
36
|
+
const GlobalResources: GlobalsOrProfile = require(path.join(GLOBALS_PATH, '/GlobalResources'));
|
|
37
|
+
const GlobalValues: GlobalsOrProfile = require(path.join(GLOBALS_PATH, '/GlobalValues'));
|
|
38
|
+
|
|
39
|
+
// Determine profile file name (default is stage)
|
|
40
|
+
const profileName = process.env.CYPRESS_PROFILE || 'stage';
|
|
41
|
+
|
|
42
|
+
// Load in chosen profile configuration
|
|
43
|
+
let profileModules: GlobalsOrProfile = {};
|
|
44
|
+
try {
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
46
|
+
const mod = require(path.join(PROFILES_PATH, `/${profileName}.Profile`));
|
|
47
|
+
profileModules = (mod?.default ?? mod ?? {}) as GlobalsOrProfile;
|
|
48
|
+
} catch (e) {
|
|
49
|
+
console.warn(`[cypress.config] Could not load profile '${profileName}.Profile'`, e);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// NOTE: Order matters (later overrides earlier)
|
|
54
|
+
const sources: GlobalsOrProfile[] = [GlobalCredentials, GlobalResources, GlobalValues, profileModules];
|
|
55
|
+
|
|
56
|
+
// Split all sources into basic and dependent
|
|
57
|
+
const splits: SplitEnv[] = sources.map((source) => {
|
|
58
|
+
return splitEnv(source);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Extract basic and dependent values from splits
|
|
62
|
+
const basicValues = splits.map((s) => {
|
|
63
|
+
return s.basic;
|
|
64
|
+
});
|
|
65
|
+
const dependentValues = splits.map((s) => {
|
|
66
|
+
return s.dependent;
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Merge all of the basics
|
|
70
|
+
const basics: GlobalsOrProfile = deepmerge.all<GlobalsOrProfile>(basicValues);
|
|
71
|
+
|
|
72
|
+
// Resolve dependencies
|
|
73
|
+
const dependents: GlobalsOrProfile = resolveDependents(dependentValues, basics);
|
|
74
|
+
|
|
75
|
+
// Add basics, depends, and profileName into the final env
|
|
76
|
+
const finalEnv: GlobalsOrProfile = {
|
|
77
|
+
...basics,
|
|
78
|
+
...dependents,
|
|
79
|
+
profileName,
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const baseUrl = finalEnv.baseURL;
|
|
83
|
+
|
|
84
|
+
// Return the configuration object
|
|
85
|
+
return defineConfig({
|
|
86
|
+
e2e: {
|
|
87
|
+
experimentalOriginDependencies: true,
|
|
88
|
+
baseUrl,
|
|
89
|
+
env: finalEnv,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export default genConfiguration;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Value for a dependent entry
|
|
3
|
+
* @author Gardenia Liu
|
|
4
|
+
*/
|
|
5
|
+
type DependentValue = {
|
|
6
|
+
dependsOn: string,
|
|
7
|
+
} & {
|
|
8
|
+
// Environment, global variables, profile values, etc.
|
|
9
|
+
[k: string]: any,
|
|
10
|
+
// Default value if the dependsOn value is not found
|
|
11
|
+
default?: any,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default DependentValue;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Object containing global variables, profile values, etc.
|
|
3
|
+
* @author Gardenia Liu
|
|
4
|
+
*/
|
|
5
|
+
type GlobalsOrProfile = {
|
|
6
|
+
// Base URL to prefix all paths with
|
|
7
|
+
baseURL?: string,
|
|
8
|
+
// Environment, global variables, profile values, etc.
|
|
9
|
+
[k: string]: any,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default GlobalsOrProfile;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Import shared types
|
|
2
|
+
import type GlobalsOrProfile from './GlobalsOrProfile';
|
|
3
|
+
import type DependentValue from './DependentValue';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Env type where basic and dependent entries are separated
|
|
7
|
+
* @author Gardenia Liu
|
|
8
|
+
*/
|
|
9
|
+
type SplitEnv = {
|
|
10
|
+
// Basic entries
|
|
11
|
+
basic: GlobalsOrProfile,
|
|
12
|
+
// Dependent entries
|
|
13
|
+
dependent: {
|
|
14
|
+
[k: string]: DependentValue,
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default SplitEnv;
|
package/src/index.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
// Import helpers
|
|
1
2
|
import init from './init';
|
|
2
3
|
import genConfiguration from './genConfiguration';
|
|
3
4
|
|
|
4
|
-
// Automatically initialize upon importing the library
|
|
5
|
-
|
|
5
|
+
// Automatically initialize upon importing the library, only run in Cypress context
|
|
6
|
+
if (typeof Cypress !== 'undefined') {
|
|
7
|
+
init();
|
|
8
|
+
}
|
|
6
9
|
|
|
7
|
-
// Exports
|
|
8
10
|
export {
|
|
9
|
-
|
|
11
|
+
// Helpers
|
|
10
12
|
init,
|
|
13
|
+
genConfiguration,
|
|
11
14
|
};
|
package/src/init.ts
CHANGED
|
@@ -1,22 +1,41 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
// Import all commands
|
|
2
|
+
import assertDoesNotHaveClass from './commands/assertDoesNotHaveClass';
|
|
3
|
+
import assertHasClass from './commands/assertHasClass';
|
|
4
|
+
import assertNumElements from './commands/assertNumElements';
|
|
5
|
+
import extractDataFromClass from './commands/extractDataFromClass';
|
|
6
|
+
import extractDataFromClassByContents from './commands/extractDataFromClassByContents';
|
|
7
|
+
import getJSON from './commands/getJSON';
|
|
8
|
+
import getNumElements from './commands/getNumElements';
|
|
9
|
+
import handleHarvardKey from './commands/handleHarvardKey';
|
|
10
|
+
import launchAs from './commands/launchAs';
|
|
11
|
+
import launchLTIUsingToken from './commands/launchLTIUsingToken';
|
|
12
|
+
import navigateToHref from './commands/navigateToHref';
|
|
13
|
+
import runScript from './commands/runScript';
|
|
14
|
+
import typeInto from './commands/typeInto';
|
|
15
|
+
import visitCanvasGETEndpoint from './commands/visitCanvasGETEndpoint';
|
|
16
|
+
import waitForElementVisible from './commands/waitForElementVisible';
|
|
15
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Initialize custom commands
|
|
20
|
+
* @author Gabe Abrams
|
|
21
|
+
*/
|
|
16
22
|
const init = () => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
23
|
+
// Execute each command adder
|
|
24
|
+
assertDoesNotHaveClass();
|
|
25
|
+
assertHasClass();
|
|
26
|
+
assertNumElements();
|
|
27
|
+
getNumElements();
|
|
28
|
+
handleHarvardKey();
|
|
29
|
+
launchAs();
|
|
30
|
+
launchLTIUsingToken();
|
|
31
|
+
navigateToHref();
|
|
32
|
+
runScript();
|
|
33
|
+
typeInto();
|
|
34
|
+
visitCanvasGETEndpoint();
|
|
35
|
+
waitForElementVisible();
|
|
36
|
+
extractDataFromClass();
|
|
37
|
+
extractDataFromClassByContents();
|
|
38
|
+
getJSON();
|
|
20
39
|
};
|
|
21
40
|
|
|
22
41
|
export default init;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Available browsers for Cypress tests
|
|
3
|
+
* @author Yuen Ler Chow
|
|
4
|
+
*/
|
|
5
|
+
const AVAILABLE_BROWSERS: {
|
|
6
|
+
name: string,
|
|
7
|
+
tag: string,
|
|
8
|
+
}[] = [
|
|
9
|
+
{
|
|
10
|
+
name: 'chrome',
|
|
11
|
+
tag: 'C',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
name: 'firefox',
|
|
15
|
+
tag: 'F',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: 'edge',
|
|
19
|
+
tag: 'E',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'safari',
|
|
23
|
+
tag: 'S',
|
|
24
|
+
},
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
// Export only the browser names in lowercase
|
|
28
|
+
export default AVAILABLE_BROWSERS;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Execute a command
|
|
5
|
+
* @author Gabe Abrams
|
|
6
|
+
* @param command the command to execute
|
|
7
|
+
* @param printToStdOut if true, print to standard out instead of returning
|
|
8
|
+
*/
|
|
9
|
+
const exec = (command: string, printToStdOut?: boolean): string => {
|
|
10
|
+
if (printToStdOut) {
|
|
11
|
+
execSync(command, { stdio: 'inherit' });
|
|
12
|
+
return '';
|
|
13
|
+
}
|
|
14
|
+
return execSync(command).toString();
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default exec;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract CLI argument value or check if flag exists
|
|
3
|
+
* @author Gardenia Liu
|
|
4
|
+
* @author Yuen Ler Chow
|
|
5
|
+
* @param args array of CLI arguments
|
|
6
|
+
* @param argName the argument name to look for (e.g., '--profile' or '--headless')
|
|
7
|
+
* @returns the argument value if found, empty string if flag exists without value, undefined otherwise
|
|
8
|
+
*/
|
|
9
|
+
const extractArgValue = (args: string[], argName: string): string | undefined => {
|
|
10
|
+
let matchedValue: string | undefined;
|
|
11
|
+
args.some((rawArg, index) => {
|
|
12
|
+
const normalizedArg = rawArg.toLowerCase();
|
|
13
|
+
|
|
14
|
+
// Case 1: flag and value combined, e.g. "--profile=stage"
|
|
15
|
+
if (normalizedArg.startsWith(`${argName}=`)) {
|
|
16
|
+
const [, value] = rawArg.split('=');
|
|
17
|
+
matchedValue = value;
|
|
18
|
+
return true; // stop scanning
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Case 2: flag by itself, possibly followed by a separate value
|
|
22
|
+
if (normalizedArg === argName) {
|
|
23
|
+
const nextArg = args[index + 1];
|
|
24
|
+
|
|
25
|
+
// If the next token exists and isn't another flag, treat it as the value
|
|
26
|
+
if (nextArg && !nextArg.startsWith('--')) {
|
|
27
|
+
matchedValue = nextArg;
|
|
28
|
+
} else {
|
|
29
|
+
// Flag exists but no value given (boolean-style flag) (e.g. "--headless")
|
|
30
|
+
matchedValue = '';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return true; // stop scanning
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return false;
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
return matchedValue;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default extractArgValue;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Find profiles by names
|
|
3
|
+
* @author Gardenia Liu
|
|
4
|
+
* @author Yuen Ler Chow
|
|
5
|
+
* @param names array of profile names to find
|
|
6
|
+
* @param profiles array of available profiles
|
|
7
|
+
* @returns array of found profiles
|
|
8
|
+
*/
|
|
9
|
+
const findProfilesByNames = (
|
|
10
|
+
names: string[],
|
|
11
|
+
profiles: Array<{ file: string; profileName: string }>,
|
|
12
|
+
): Array<{ file: string; profileName: string }> => {
|
|
13
|
+
const found: Array<{ file: string; profileName: string }> = [];
|
|
14
|
+
const notFound: string[] = [];
|
|
15
|
+
|
|
16
|
+
names.forEach((name) => {
|
|
17
|
+
const target = name.toLowerCase();
|
|
18
|
+
|
|
19
|
+
// Find matching profile (case-insensitive)
|
|
20
|
+
const match = profiles.find((p) => {
|
|
21
|
+
return p.profileName.toLowerCase() === target;
|
|
22
|
+
});
|
|
23
|
+
if (match) {
|
|
24
|
+
found.push(match);
|
|
25
|
+
} else {
|
|
26
|
+
notFound.push(name);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
if (notFound.length > 0) {
|
|
31
|
+
// eslint-disable-next-line no-console
|
|
32
|
+
console.error(`Profile(s) not found: ${notFound.join(', ')}. Available profiles: ${profiles.map((p) => { return p.profileName; }).join(', ')}`);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return found;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default findProfilesByNames;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse comma-separated values into an array
|
|
3
|
+
* @author Yuen Ler Chow
|
|
4
|
+
* @param commaSeparatedString the comma-separated string to parse
|
|
5
|
+
* @returns array of trimmed, non-empty values
|
|
6
|
+
*/
|
|
7
|
+
const parseCommaSeparated = (commaSeparatedString?: string): string[] => {
|
|
8
|
+
if (!commaSeparatedString) {
|
|
9
|
+
return [];
|
|
10
|
+
}
|
|
11
|
+
return (
|
|
12
|
+
commaSeparatedString
|
|
13
|
+
.split(',')
|
|
14
|
+
.map((value) => {
|
|
15
|
+
return value.trim();
|
|
16
|
+
})
|
|
17
|
+
.filter((value) => {
|
|
18
|
+
return value.length > 0;
|
|
19
|
+
})
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default parseCommaSeparated;
|
|
@@ -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;
|