dceky 1.0.0-beta-profile.1 → 1.0.0-beta-yuenler.1
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/lib/commands/assertDoesNotHaveClass.d.ts +19 -0
- package/lib/commands/assertDoesNotHaveClass.js +17 -0
- package/lib/commands/assertDoesNotHaveClass.js.map +1 -0
- package/lib/commands/assertHasClass.d.ts +19 -0
- package/lib/commands/assertHasClass.js +17 -0
- package/lib/commands/assertHasClass.js.map +1 -0
- package/lib/commands/assertNumElements.d.ts +19 -0
- package/lib/commands/assertNumElements.js +17 -0
- package/lib/commands/assertNumElements.js.map +1 -0
- package/lib/commands/clickWithRetry.d.ts +16 -0
- package/lib/commands/clickWithRetry.js +29 -0
- package/lib/commands/clickWithRetry.js.map +1 -0
- package/lib/commands/getNumElements.d.ts +15 -0
- package/lib/commands/getNumElements.js +19 -0
- package/lib/commands/getNumElements.js.map +1 -0
- package/lib/commands/handleHarvardKey.d.ts +14 -0
- package/lib/commands/handleHarvardKey.js +59 -0
- package/lib/commands/handleHarvardKey.js.map +1 -0
- package/lib/commands/launchAs.d.ts +23 -0
- package/lib/commands/launchAs.js +65 -0
- package/lib/commands/launchAs.js.map +1 -0
- package/lib/commands/launchLTIUsingToken.d.ts +16 -0
- package/lib/commands/launchLTIUsingToken.js +57 -0
- package/lib/commands/launchLTIUsingToken.js.map +1 -0
- package/lib/commands/navigateToHref.d.ts +20 -0
- package/lib/commands/navigateToHref.js +23 -0
- package/lib/commands/navigateToHref.js.map +1 -0
- package/lib/commands/runScript.d.ts +17 -0
- package/lib/commands/runScript.js +25 -0
- package/lib/commands/runScript.js.map +1 -0
- package/lib/commands/typeInto.d.ts +21 -0
- package/lib/commands/typeInto.js +28 -0
- package/lib/commands/typeInto.js.map +1 -0
- package/lib/commands/visitCanvasGETEndpoint.d.ts +20 -0
- package/lib/commands/visitCanvasGETEndpoint.js +26 -0
- package/lib/commands/visitCanvasGETEndpoint.js.map +1 -0
- package/lib/commands/waitForElementVisible.d.ts +15 -0
- package/lib/commands/waitForElementVisible.js +20 -0
- package/lib/commands/waitForElementVisible.js.map +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/init.d.ts +4 -11
- package/lib/init.js +35 -4
- package/lib/init.js.map +1 -1
- package/package.json +4 -20
- package/src/commands/assertDoesNotHaveClass.ts +40 -0
- package/src/commands/assertHasClass.ts +40 -0
- package/src/commands/assertNumElements.ts +37 -0
- package/src/commands/clickWithRetry.ts +51 -0
- package/src/commands/getNumElements.ts +38 -0
- package/src/commands/handleHarvardKey.ts +87 -0
- package/src/commands/launchAs.ts +104 -0
- package/src/commands/launchLTIUsingToken.ts +84 -0
- package/src/commands/navigateToHref.ts +45 -0
- package/src/commands/runScript.ts +42 -0
- package/src/commands/typeInto.ts +57 -0
- package/src/commands/visitCanvasGETEndpoint.ts +48 -0
- package/src/commands/waitForElementVisible.ts +40 -0
- package/src/genConfiguration.ts +11 -0
- package/src/index.ts +2 -7
- package/src/init.ts +26 -2
- package/tsconfig.json +0 -1
- package/docs/GlobalsAndProfiles.md +0 -23
- package/profileChooser/chooseProfile.ts +0 -35
- package/profileChooser/helpers/print.ts +0 -155
- package/profileChooser/helpers/prompt.ts +0 -23
- package/profileChooser/helpers/showChooser.ts +0 -95
- package/profileChooser/types/ChooserOption.ts +0 -11
- package/src/commands/clickSomething.ts +0 -33
- package/src/genConfiguration/helpers/resolveDependents.ts +0 -47
- package/src/genConfiguration/helpers/splitEnv.ts +0 -30
- package/src/genConfiguration/index.ts +0 -83
- package/src/genConfiguration/types/DependentValue.ts +0 -14
- package/src/genConfiguration/types/GlobalsOrProfile.ts +0 -12
- package/src/genConfiguration/types/SplitEnv.ts +0 -18
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/// <reference types="cypress" />
|
|
2
|
+
|
|
3
|
+
/*----------------------------------------*/
|
|
4
|
+
/* ---------------- Type ---------------- */
|
|
5
|
+
/*----------------------------------------*/
|
|
6
|
+
|
|
7
|
+
declare global {
|
|
8
|
+
namespace Cypress {
|
|
9
|
+
interface Chainable {
|
|
10
|
+
/**
|
|
11
|
+
* Log into Canvas using an access token and launch an LTI app
|
|
12
|
+
* @param accessToken the user's Canvas access token
|
|
13
|
+
* @param courseId the Canvas ID of the course to launch from
|
|
14
|
+
* @param appName the name of the app as it appears in the course's left-hand nav
|
|
15
|
+
* @example cy.launchLTIUsingToken('your_access_token', 12345, 'My LTI App')
|
|
16
|
+
*/
|
|
17
|
+
launchLTIUsingToken(accessToken: string, courseId: number, appName: string): Chainable<void>;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/*----------------------------------------*/
|
|
23
|
+
/* --------------- Command -------------- */
|
|
24
|
+
/*----------------------------------------*/
|
|
25
|
+
|
|
26
|
+
const launchLTIUsingToken = () => {
|
|
27
|
+
Cypress.Commands.add('launchLTIUsingToken', (accessToken: string, courseId: number, appName: string) => {
|
|
28
|
+
cy.log(`Launch LTI app "${appName}" in course ${courseId} using access token`);
|
|
29
|
+
|
|
30
|
+
// Get the external tools for the course
|
|
31
|
+
cy.visitCanvasGETEndpoint({
|
|
32
|
+
path: `/courses/${courseId}/external_tools`,
|
|
33
|
+
accessToken: accessToken
|
|
34
|
+
}).then((externalTools: any[]) => {
|
|
35
|
+
cy.log(`Found ${externalTools.length} external tools`);
|
|
36
|
+
|
|
37
|
+
// Find the external tool of interest
|
|
38
|
+
let toolId = 0;
|
|
39
|
+
|
|
40
|
+
for (const externalTool of externalTools) {
|
|
41
|
+
// Skip non-nav items
|
|
42
|
+
if (!externalTool.course_navigation || typeof externalTool.course_navigation !== 'object') {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Skip non-labeled items
|
|
47
|
+
if (!externalTool.course_navigation.text) {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Check if this app matches the name
|
|
52
|
+
const thisAppName = externalTool.course_navigation.text.trim().toLowerCase();
|
|
53
|
+
if (thisAppName === appName.trim().toLowerCase()) {
|
|
54
|
+
toolId = externalTool.id;
|
|
55
|
+
cy.log(`Found matching app: "${externalTool.course_navigation.text}" with ID ${toolId}`);
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Make sure we found the app
|
|
61
|
+
if (toolId === 0) {
|
|
62
|
+
throw new Error(`Could not find any apps named "${appName}" in course ${courseId}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Get a sessionless launch URL
|
|
66
|
+
cy.visitCanvasGETEndpoint({
|
|
67
|
+
path: `/courses/${courseId}/external_tools/sessionless_launch?id=${toolId}`,
|
|
68
|
+
accessToken: accessToken
|
|
69
|
+
}).then((sessionlessLaunchInfo: any) => {
|
|
70
|
+
const launchURL = sessionlessLaunchInfo.url;
|
|
71
|
+
cy.log(`Launching LTI app at: ${launchURL}`);
|
|
72
|
+
|
|
73
|
+
// Launch the tool
|
|
74
|
+
cy.visit(launchURL);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/*----------------------------------------*/
|
|
81
|
+
/* --------------- Export --------------- */
|
|
82
|
+
/*----------------------------------------*/
|
|
83
|
+
|
|
84
|
+
export default launchLTIUsingToken;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/// <reference types="cypress" />
|
|
2
|
+
|
|
3
|
+
/*----------------------------------------*/
|
|
4
|
+
/* ---------------- Type ---------------- */
|
|
5
|
+
/*----------------------------------------*/
|
|
6
|
+
|
|
7
|
+
declare global {
|
|
8
|
+
namespace Cypress {
|
|
9
|
+
interface Chainable {
|
|
10
|
+
/**
|
|
11
|
+
* Navigate to href attribute of Harvard identity provider button
|
|
12
|
+
* @param opts object containing all arguments
|
|
13
|
+
* @param opts.item the CSS selector of interest
|
|
14
|
+
* @param opts.domain the domain of the page
|
|
15
|
+
* @returns The full URL constructed from the href
|
|
16
|
+
* @example cy.navigateToHref({ item: '#login-button', domain: 'https://example.com' })
|
|
17
|
+
*/
|
|
18
|
+
navigateToHref(opts: { item: string; domain: string }): Chainable<string>;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/*----------------------------------------*/
|
|
24
|
+
/* --------------- Command -------------- */
|
|
25
|
+
/*----------------------------------------*/
|
|
26
|
+
|
|
27
|
+
const navigateToHref = () => {
|
|
28
|
+
Cypress.Commands.add('navigateToHref', (opts: { item: string; domain: string }) => {
|
|
29
|
+
const { item, domain } = opts;
|
|
30
|
+
|
|
31
|
+
cy.waitForElementVisible(item);
|
|
32
|
+
return cy
|
|
33
|
+
.get(item)
|
|
34
|
+
.invoke('attr', 'href')
|
|
35
|
+
.then((href: any) => {
|
|
36
|
+
return domain + href;
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/*----------------------------------------*/
|
|
42
|
+
/* --------------- Export --------------- */
|
|
43
|
+
/*----------------------------------------*/
|
|
44
|
+
|
|
45
|
+
export default navigateToHref;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/// <reference types="cypress" />
|
|
2
|
+
|
|
3
|
+
/*----------------------------------------*/
|
|
4
|
+
/* ---------------- Type ---------------- */
|
|
5
|
+
/*----------------------------------------*/
|
|
6
|
+
|
|
7
|
+
declare global {
|
|
8
|
+
namespace Cypress {
|
|
9
|
+
interface Chainable {
|
|
10
|
+
/**
|
|
11
|
+
* Run a script on the page
|
|
12
|
+
* @param scriptLines the script to run in an anonymous function on the page.
|
|
13
|
+
* If multiple script arguments are included, each argument will be considered a
|
|
14
|
+
* new line of the script.
|
|
15
|
+
* @returns return value of the script
|
|
16
|
+
* @example cy.runScript('console.log("Hello");', 'return document.title;')
|
|
17
|
+
*/
|
|
18
|
+
runScript(...scriptLines: string[]): Chainable<any>;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/*----------------------------------------*/
|
|
24
|
+
/* --------------- Command -------------- */
|
|
25
|
+
/*----------------------------------------*/
|
|
26
|
+
|
|
27
|
+
const runScript = () => {
|
|
28
|
+
Cypress.Commands.add('runScript', (...scriptLines: string[]) => {
|
|
29
|
+
cy.log('Running script');
|
|
30
|
+
const fullScript = scriptLines.join('\n');
|
|
31
|
+
return cy.window().then((win: any) => {
|
|
32
|
+
const result = win.eval(fullScript);
|
|
33
|
+
return cy.wrap(result);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/*----------------------------------------*/
|
|
39
|
+
/* --------------- Export --------------- */
|
|
40
|
+
/*----------------------------------------*/
|
|
41
|
+
|
|
42
|
+
export default runScript;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/// <reference types="cypress" />
|
|
2
|
+
|
|
3
|
+
/*----------------------------------------*/
|
|
4
|
+
/* ---------------- Type ---------------- */
|
|
5
|
+
/*----------------------------------------*/
|
|
6
|
+
|
|
7
|
+
declare global {
|
|
8
|
+
namespace Cypress {
|
|
9
|
+
interface Chainable {
|
|
10
|
+
/**
|
|
11
|
+
* Type text into an element. This function first removes the previous text in the element
|
|
12
|
+
* @param opts object containing all arguments
|
|
13
|
+
* @param opts.item the CSS selector of interest
|
|
14
|
+
* @param opts.text the text to type
|
|
15
|
+
* @param opts.pressEnter if true, after typing into the text field, simulate pressing enter
|
|
16
|
+
* @example cy.typeInto({ item: '#username', text: 'john_doe', pressEnter: false })
|
|
17
|
+
*/
|
|
18
|
+
typeInto(opts: {
|
|
19
|
+
item: string;
|
|
20
|
+
text: string;
|
|
21
|
+
pressEnter?: boolean;
|
|
22
|
+
}): Chainable<Element>;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/*----------------------------------------*/
|
|
28
|
+
/* --------------- Command -------------- */
|
|
29
|
+
/*----------------------------------------*/
|
|
30
|
+
|
|
31
|
+
const typeInto = () => {
|
|
32
|
+
Cypress.Commands.add('typeInto', (opts: { item: string; text: string; pressEnter?: boolean }) => {
|
|
33
|
+
const { item, text, pressEnter } = opts;
|
|
34
|
+
cy.log(`Type "${text}" into ${item}`);
|
|
35
|
+
|
|
36
|
+
// Check if the text contains an enter key press
|
|
37
|
+
const enterAtEndOfText = text.charAt(text.length - 1) === '\n';
|
|
38
|
+
|
|
39
|
+
// Type the text without a trailing enter if there was one
|
|
40
|
+
const textWithoutTrailingEnter = enterAtEndOfText
|
|
41
|
+
? text.substring(0, text.length - 1)
|
|
42
|
+
: text;
|
|
43
|
+
|
|
44
|
+
cy.get(item).clear().type(textWithoutTrailingEnter);
|
|
45
|
+
|
|
46
|
+
// Press enter if explicitly requested or if text ended with newline
|
|
47
|
+
if (pressEnter || enterAtEndOfText) {
|
|
48
|
+
cy.get(item).type('{enter}');
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/*----------------------------------------*/
|
|
54
|
+
/* --------------- Export --------------- */
|
|
55
|
+
/*----------------------------------------*/
|
|
56
|
+
|
|
57
|
+
export default typeInto;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/// <reference types="cypress" />
|
|
2
|
+
|
|
3
|
+
/*----------------------------------------*/
|
|
4
|
+
/* ---------------- Type ---------------- */
|
|
5
|
+
/*----------------------------------------*/
|
|
6
|
+
|
|
7
|
+
declare global {
|
|
8
|
+
namespace Cypress {
|
|
9
|
+
interface Chainable {
|
|
10
|
+
/**
|
|
11
|
+
* Makes a GET request to Canvas API endpoint
|
|
12
|
+
* @param opts object containing all arguments
|
|
13
|
+
* @param opts.path The API path (e.g., '/courses', '/users/self')
|
|
14
|
+
* @param opts.accessToken The Canvas access token
|
|
15
|
+
* @returns The API response body
|
|
16
|
+
* @example cy.visitCanvasGETEndpoint({ path: '/courses', accessToken: 'your_token' })
|
|
17
|
+
*/
|
|
18
|
+
visitCanvasGETEndpoint(opts: { path: string; accessToken: string }): Chainable<any>;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/*----------------------------------------*/
|
|
24
|
+
/* --------------- Command -------------- */
|
|
25
|
+
/*----------------------------------------*/
|
|
26
|
+
|
|
27
|
+
const visitCanvasGETEndpoint = () => {
|
|
28
|
+
Cypress.Commands.add('visitCanvasGETEndpoint', (opts: { path: string; accessToken: string }) => {
|
|
29
|
+
cy.log('Visiting Canvas GET endpoint');
|
|
30
|
+
const { path, accessToken } = opts;
|
|
31
|
+
|
|
32
|
+
cy.log('Canvas API: ' + path);
|
|
33
|
+
return cy.request({
|
|
34
|
+
method: 'GET',
|
|
35
|
+
url: 'https://canvas.harvard.edu/api/v1' + path,
|
|
36
|
+
qs: {
|
|
37
|
+
per_page: 200,
|
|
38
|
+
access_token: accessToken
|
|
39
|
+
}
|
|
40
|
+
}).its('body');
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/*----------------------------------------*/
|
|
45
|
+
/* --------------- Export --------------- */
|
|
46
|
+
/*----------------------------------------*/
|
|
47
|
+
|
|
48
|
+
export default visitCanvasGETEndpoint;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/// <reference types="cypress" />
|
|
2
|
+
|
|
3
|
+
/*----------------------------------------*/
|
|
4
|
+
/* ---------------- Type ---------------- */
|
|
5
|
+
/*----------------------------------------*/
|
|
6
|
+
|
|
7
|
+
declare global {
|
|
8
|
+
namespace Cypress {
|
|
9
|
+
interface Chainable {
|
|
10
|
+
/**
|
|
11
|
+
* Wait for an element to be visible
|
|
12
|
+
* @param item the CSS selector of interest
|
|
13
|
+
* @param timeoutSec the number of seconds to wait before timing out (default: 10)
|
|
14
|
+
* @example cy.waitForElementVisible('#submit-button', 15)
|
|
15
|
+
*/
|
|
16
|
+
waitForElementVisible(item: string, timeoutSec?: number): Chainable<JQuery<HTMLElement>>;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/*----------------------------------------*/
|
|
22
|
+
/* --------------- Command -------------- */
|
|
23
|
+
/*----------------------------------------*/
|
|
24
|
+
|
|
25
|
+
const waitForElementVisible = () => {
|
|
26
|
+
Cypress.Commands.add('waitForElementVisible', (item: string, timeoutSec?: number) => {
|
|
27
|
+
cy.log('Waiting for element to be visible');
|
|
28
|
+
timeoutSec = timeoutSec || 10;
|
|
29
|
+
|
|
30
|
+
const timeoutMs = timeoutSec * 1000;
|
|
31
|
+
cy.log(`Wait for ${item} to be visible`);
|
|
32
|
+
return cy.get(item, { timeout: timeoutMs }).should('be.visible');
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/*----------------------------------------*/
|
|
37
|
+
/* --------------- Export --------------- */
|
|
38
|
+
/*----------------------------------------*/
|
|
39
|
+
|
|
40
|
+
export default waitForElementVisible;
|
package/src/index.ts
CHANGED
|
@@ -2,16 +2,11 @@
|
|
|
2
2
|
import init from './init';
|
|
3
3
|
import genConfiguration from './genConfiguration';
|
|
4
4
|
|
|
5
|
-
// Import types
|
|
6
|
-
import GlobalsOrProfile from './genConfiguration/types/GlobalsOrProfile';
|
|
7
|
-
|
|
8
5
|
// Automatically initialize upon importing the library
|
|
9
6
|
init();
|
|
10
7
|
|
|
8
|
+
// Export key functions
|
|
11
9
|
export {
|
|
12
|
-
// Helpers
|
|
13
|
-
init,
|
|
14
10
|
genConfiguration,
|
|
15
|
-
|
|
16
|
-
GlobalsOrProfile,
|
|
11
|
+
init,
|
|
17
12
|
};
|
package/src/init.ts
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
// Import all commands
|
|
2
|
-
import
|
|
2
|
+
import assertDoesNotHaveClass from './commands/assertDoesNotHaveClass';
|
|
3
|
+
import assertHasClass from './commands/assertHasClass';
|
|
4
|
+
import assertNumElements from './commands/assertNumElements';
|
|
5
|
+
import clickWithRetry from './commands/clickWithRetry';
|
|
6
|
+
import getNumElements from './commands/getNumElements';
|
|
7
|
+
import handleHarvardKey from './commands/handleHarvardKey';
|
|
8
|
+
import launchAs from './commands/launchAs';
|
|
9
|
+
import launchLTIUsingToken from './commands/launchLTIUsingToken';
|
|
10
|
+
import navigateToHref from './commands/navigateToHref';
|
|
11
|
+
import runScript from './commands/runScript';
|
|
12
|
+
import typeInto from './commands/typeInto';
|
|
13
|
+
import visitCanvasGETEndpoint from './commands/visitCanvasGETEndpoint';
|
|
14
|
+
import waitForElementVisible from './commands/waitForElementVisible';
|
|
3
15
|
|
|
4
16
|
/**
|
|
5
17
|
* Initialize custom commands
|
|
@@ -7,7 +19,19 @@ import clickSomething from './commands/clickSomething';
|
|
|
7
19
|
*/
|
|
8
20
|
const init = () => {
|
|
9
21
|
// Execute each command adder
|
|
10
|
-
|
|
22
|
+
assertDoesNotHaveClass();
|
|
23
|
+
assertHasClass();
|
|
24
|
+
assertNumElements();
|
|
25
|
+
clickWithRetry();
|
|
26
|
+
getNumElements();
|
|
27
|
+
handleHarvardKey();
|
|
28
|
+
launchAs();
|
|
29
|
+
launchLTIUsingToken();
|
|
30
|
+
navigateToHref();
|
|
31
|
+
runScript();
|
|
32
|
+
typeInto();
|
|
33
|
+
visitCanvasGETEndpoint();
|
|
34
|
+
waitForElementVisible();
|
|
11
35
|
};
|
|
12
36
|
|
|
13
37
|
export default init;
|
package/tsconfig.json
CHANGED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# Globals and Profiles Configuration
|
|
2
|
-
|
|
3
|
-
### Configuration Setup
|
|
4
|
-
|
|
5
|
-
The configuration setup involves the following steps:
|
|
6
|
-
|
|
7
|
-
1. Split each globals/profiles map into two: `basic` values and `dependsOn` values.
|
|
8
|
-
2. Merge all `basic` values into a running env object (in order so last ones processed are the highest priority).
|
|
9
|
-
3. Go through each `dependsOn` value, look up the value it depends on in the running env object.
|
|
10
|
-
4. Add `dependsOn` values into the running env object (in order so last ones processed are the highest priority).
|
|
11
|
-
5. Wrap the env object into a config.
|
|
12
|
-
|
|
13
|
-
### Assumptions
|
|
14
|
-
|
|
15
|
-
* `dependsOn` values must depend on a basic `value`, not on another `dependsOn` value.
|
|
16
|
-
|
|
17
|
-
### DependsOn Value
|
|
18
|
-
|
|
19
|
-
The `dependsOn` value is an object that has the following structure:
|
|
20
|
-
|
|
21
|
-
* `dependsOn`: the key of the `basic` value that we are depending on
|
|
22
|
-
* `value`: the value that we are depending on (can be a string, number, boolean, etc.)
|
|
23
|
-
* `default`: the default value if the `dependsOn` value is not found
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
// TODO: implement a *synchronous* profile chooser that executes the correct launch command
|
|
2
|
-
|
|
3
|
-
// Import libs
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import fs from 'fs';
|
|
6
|
-
|
|
7
|
-
// Import helpers
|
|
8
|
-
import print from './helpers/print';
|
|
9
|
-
import showChooser from './helpers/showChooser';
|
|
10
|
-
|
|
11
|
-
// Get the project directory
|
|
12
|
-
const pwd = path.join(process.env.PWD || process.env.CWD || __dirname, '../..');
|
|
13
|
-
// NOTE: this is a dependency of the main project, so the actual project
|
|
14
|
-
// directory is up two levels (outside this folder, then outside node_modules)
|
|
15
|
-
console.log('Project directory:', pwd);
|
|
16
|
-
|
|
17
|
-
// TODO: explore the file tree to figure out which profiles exist
|
|
18
|
-
// (Build a chooser based on what you find)
|
|
19
|
-
// Maybe: /cypress/profiles/[Name].Profile.ts
|
|
20
|
-
|
|
21
|
-
print.title('Here\'s a title');
|
|
22
|
-
|
|
23
|
-
console.log('Let us do the thing.');
|
|
24
|
-
print.enterToContinue();
|
|
25
|
-
|
|
26
|
-
const choice = showChooser({
|
|
27
|
-
question: 'Choose an option:',
|
|
28
|
-
options: [
|
|
29
|
-
{ tag: 'A', description: 'First option' },
|
|
30
|
-
{ tag: 'B', description: 'Second option' },
|
|
31
|
-
{ tag: 'C', description: 'Third option' },
|
|
32
|
-
],
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
console.log('You chose:', choice);
|
|
@@ -1,155 +0,0 @@
|
|
|
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;
|
|
@@ -1,23 +0,0 @@
|
|
|
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;
|