dceky 1.0.25 → 1.0.27
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/src/commands/getProfileValue.d.ts +1 -1
- package/lib/src/commands/getProfileValue.js +1 -3
- package/lib/src/commands/getProfileValue.js.map +1 -1
- package/lib/src/commands/helpers/getFormData.d.ts +20 -0
- package/lib/src/commands/helpers/getFormData.js +37 -0
- package/lib/src/commands/helpers/getFormData.js.map +1 -0
- package/lib/src/commands/launchAs.js +12 -6
- package/lib/src/commands/launchAs.js.map +1 -1
- package/lib/src/commands/logIntoPorta.js +8 -29
- package/lib/src/commands/logIntoPorta.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/getProfileValue.ts +2 -7
- package/src/commands/helpers/getFormData.ts +50 -0
- package/src/commands/launchAs.ts +10 -7
- package/src/commands/logIntoPorta.ts +8 -27
|
@@ -5,9 +5,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
5
5
|
/* --------------- Command -------------- */
|
|
6
6
|
/*----------------------------------------*/
|
|
7
7
|
var getProfileValue = function () {
|
|
8
|
-
|
|
9
|
-
return Cypress.expose(key);
|
|
10
|
-
});
|
|
8
|
+
cy.getProfileValue = Cypress.expose;
|
|
11
9
|
};
|
|
12
10
|
/*----------------------------------------*/
|
|
13
11
|
/* --------------- Export --------------- */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getProfileValue.js","sourceRoot":"","sources":["../../../src/commands/getProfileValue.ts"],"names":[],"mappings":";AAAA,iCAAiC;;AAsBjC,4CAA4C;AAC5C,4CAA4C;AAC5C,4CAA4C;AAE5C,IAAM,eAAe,GAAG;IACtB,
|
|
1
|
+
{"version":3,"file":"getProfileValue.js","sourceRoot":"","sources":["../../../src/commands/getProfileValue.ts"],"names":[],"mappings":";AAAA,iCAAiC;;AAsBjC,4CAA4C;AAC5C,4CAA4C;AAC5C,4CAA4C;AAE5C,IAAM,eAAe,GAAG;IACtB,EAAE,CAAC,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC;AACtC,CAAC,CAAC;AAEF,4CAA4C;AAC5C,4CAA4C;AAC5C,4CAA4C;AAE5C,kBAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse HTML and extract form action URL, method, and input fields.
|
|
3
|
+
* @author Yuen Ler Chow
|
|
4
|
+
* @param options.html - Raw HTML string to parse
|
|
5
|
+
* @param options.formSelector - CSS selector for the form (default: 'form')
|
|
6
|
+
* @param options.isHiddenForm - If true, only input[type=hidden]. If false, all inputs/selects/textareas. Default: true
|
|
7
|
+
* @returns Object with action URL, method (default 'get'), and field name/value pairs
|
|
8
|
+
*/
|
|
9
|
+
declare const getFormData: (opts: {
|
|
10
|
+
html: string;
|
|
11
|
+
formSelector?: string;
|
|
12
|
+
isHiddenForm?: boolean;
|
|
13
|
+
}) => {
|
|
14
|
+
action: string;
|
|
15
|
+
method: string;
|
|
16
|
+
fields: {
|
|
17
|
+
[key: string]: string;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export default getFormData;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* Parse HTML and extract form action URL, method, and input fields.
|
|
5
|
+
* @author Yuen Ler Chow
|
|
6
|
+
* @param options.html - Raw HTML string to parse
|
|
7
|
+
* @param options.formSelector - CSS selector for the form (default: 'form')
|
|
8
|
+
* @param options.isHiddenForm - If true, only input[type=hidden]. If false, all inputs/selects/textareas. Default: true
|
|
9
|
+
* @returns Object with action URL, method (default 'get'), and field name/value pairs
|
|
10
|
+
*/
|
|
11
|
+
var getFormData = function (opts) {
|
|
12
|
+
var _a, _b;
|
|
13
|
+
var html = opts.html, _c = opts.formSelector, formSelector = _c === void 0 ? 'form' : _c, _d = opts.isHiddenForm, isHiddenForm = _d === void 0 ? true : _d;
|
|
14
|
+
var doc = new DOMParser().parseFromString(html, 'text/html');
|
|
15
|
+
var form = doc.querySelector(formSelector);
|
|
16
|
+
var action = (_a = form === null || form === void 0 ? void 0 : form.getAttribute('action')) !== null && _a !== void 0 ? _a : '';
|
|
17
|
+
var method = ((_b = form === null || form === void 0 ? void 0 : form.getAttribute('method')) !== null && _b !== void 0 ? _b : 'GET').toUpperCase();
|
|
18
|
+
var fields = {};
|
|
19
|
+
// Iterate through all input fields in the form and extract the name and value
|
|
20
|
+
var selector = isHiddenForm
|
|
21
|
+
? 'input[type=hidden]'
|
|
22
|
+
: 'input, select, textarea';
|
|
23
|
+
form === null || form === void 0 ? void 0 : form.querySelectorAll(selector).forEach(function (input) {
|
|
24
|
+
var _a;
|
|
25
|
+
var name = input.getAttribute('name');
|
|
26
|
+
if (name) {
|
|
27
|
+
fields[name] = (_a = input.getAttribute('value')) !== null && _a !== void 0 ? _a : '';
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
return {
|
|
31
|
+
action: action,
|
|
32
|
+
method: method,
|
|
33
|
+
fields: fields,
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
exports.default = getFormData;
|
|
37
|
+
//# sourceMappingURL=getFormData.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getFormData.js","sourceRoot":"","sources":["../../../../src/commands/helpers/getFormData.ts"],"names":[],"mappings":";;AAAA;;;;;;;GAOG;AACH,IAAM,WAAW,GAAG,UAAC,IAIpB;;IAMG,IAAA,IAAI,GAGF,IAAI,KAHF,EACJ,KAEE,IAAI,aAFe,EAArB,YAAY,mBAAG,MAAM,KAAA,EACrB,KACE,IAAI,aADa,EAAnB,YAAY,mBAAG,IAAI,KAAA,CACZ;IAET,IAAM,GAAG,GAAG,IAAI,SAAS,EAAE,CAAC,eAAe,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAC/D,IAAM,IAAI,GAAG,GAAG,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;IAC7C,IAAM,MAAM,GAAG,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,YAAY,CAAC,QAAQ,CAAC,mCAAI,EAAE,CAAC;IAClD,IAAM,MAAM,GAAG,CAAC,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,YAAY,CAAC,QAAQ,CAAC,mCAAI,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;IACrE,IAAM,MAAM,GAA8B,EAAE,CAAC;IAE7C,8EAA8E;IAC9E,IAAM,QAAQ,GAAG,YAAY;QAC3B,CAAC,CAAC,oBAAoB;QACtB,CAAC,CAAC,yBAAyB,CAAC;IAC9B,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CACtC,UAAC,KAAK;;QACJ,IAAM,IAAI,GAAG,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACxC,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,CAAC,IAAI,CAAC,GAAG,MAAA,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,mCAAI,EAAE,CAAC;QACnD,CAAC;IACH,CAAC,CACF,CAAC;IAEF,OAAO;QACL,MAAM,QAAA;QACN,MAAM,QAAA;QACN,MAAM,QAAA;KACP,CAAC;AACJ,CAAC,CAAC;AAEF,kBAAe,WAAW,CAAC"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/// <reference types="cypress" />
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
3
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
var getFormData_1 = __importDefault(require("./helpers/getFormData"));
|
|
4
8
|
/*----------------------------------------*/
|
|
5
9
|
/* --------------- Command -------------- */
|
|
6
10
|
/*----------------------------------------*/
|
|
@@ -11,9 +15,6 @@ var launchAs = function () {
|
|
|
11
15
|
cy.log("\uD83D\uDE80 Launch as ".concat(name));
|
|
12
16
|
// Destructure opts
|
|
13
17
|
var courseId = opts.courseId, appName = opts.appName;
|
|
14
|
-
// Visit the base URL to set default origin
|
|
15
|
-
var baseURL = Cypress.config('baseUrl');
|
|
16
|
-
cy.visit(baseURL);
|
|
17
18
|
// Get courseId from environment variables if not provided
|
|
18
19
|
if (!courseId) {
|
|
19
20
|
var envCourseId = Cypress.expose('courseId');
|
|
@@ -43,7 +44,6 @@ var launchAs = function () {
|
|
|
43
44
|
method: 'GET',
|
|
44
45
|
url: "https://canvas.harvard.edu/api/v1/courses/".concat(courseId, "/external_tools"),
|
|
45
46
|
body: {
|
|
46
|
-
per_page: 200,
|
|
47
47
|
access_token: accessToken,
|
|
48
48
|
},
|
|
49
49
|
})
|
|
@@ -87,7 +87,6 @@ var launchAs = function () {
|
|
|
87
87
|
method: 'GET',
|
|
88
88
|
url: "https://canvas.harvard.edu/api/v1/courses/".concat(courseId, "/external_tools/sessionless_launch?id=").concat(toolId),
|
|
89
89
|
body: {
|
|
90
|
-
per_page: 200,
|
|
91
90
|
access_token: accessToken,
|
|
92
91
|
},
|
|
93
92
|
})
|
|
@@ -103,7 +102,14 @@ var launchAs = function () {
|
|
|
103
102
|
});
|
|
104
103
|
// Launch via the sessionless launch URL
|
|
105
104
|
var launchURL = sessionlessLaunchInfo.url;
|
|
106
|
-
cy.
|
|
105
|
+
cy.request(launchURL).then(function (response) {
|
|
106
|
+
var _a = (0, getFormData_1.default)({ html: response.body }), action = _a.action, fields = _a.fields;
|
|
107
|
+
cy.visit({
|
|
108
|
+
url: action,
|
|
109
|
+
method: 'POST',
|
|
110
|
+
body: fields,
|
|
111
|
+
});
|
|
112
|
+
});
|
|
107
113
|
}));
|
|
108
114
|
});
|
|
109
115
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"launchAs.js","sourceRoot":"","sources":["../../../src/commands/launchAs.ts"],"names":[],"mappings":";AAAA,iCAAiC
|
|
1
|
+
{"version":3,"file":"launchAs.js","sourceRoot":"","sources":["../../../src/commands/launchAs.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,7 +11,11 @@ var __assign = (this && this.__assign) || function () {
|
|
|
11
11
|
};
|
|
12
12
|
return __assign.apply(this, arguments);
|
|
13
13
|
};
|
|
14
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
15
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
|
+
};
|
|
14
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
var getFormData_1 = __importDefault(require("./helpers/getFormData"));
|
|
15
19
|
/*----------------------------------------*/
|
|
16
20
|
/* ---------------- Constants ----------------- */
|
|
17
21
|
/*----------------------------------------*/
|
|
@@ -22,31 +26,6 @@ var IDP_BASE_URL = 'https://apps.cirrusidentity.com';
|
|
|
22
26
|
// HarvardKey IdP button ID on Cirrus discovery page
|
|
23
27
|
var HARVARDKEY_IDP_BUTTON_ID = 'idp_1001962798_button';
|
|
24
28
|
/*----------------------------------------*/
|
|
25
|
-
/* -------------- Helpers --------------- */
|
|
26
|
-
/*----------------------------------------*/
|
|
27
|
-
/**
|
|
28
|
-
* Parse HTML and extract form action URL and hidden input fields.
|
|
29
|
-
* @author Yuen Ler Chow
|
|
30
|
-
* @param html - Raw HTML string to parse
|
|
31
|
-
* @param formSelector - CSS selector for the form (default: 'form')
|
|
32
|
-
* @returns Object with action URL and record of hidden field name/value pairs
|
|
33
|
-
*/
|
|
34
|
-
var getFormData = function (html, formSelector) {
|
|
35
|
-
var _a;
|
|
36
|
-
if (formSelector === void 0) { formSelector = 'form'; }
|
|
37
|
-
var doc = new DOMParser().parseFromString(html, 'text/html');
|
|
38
|
-
var form = doc.querySelector(formSelector);
|
|
39
|
-
var action = (_a = form === null || form === void 0 ? void 0 : form.getAttribute('action')) !== null && _a !== void 0 ? _a : '';
|
|
40
|
-
var fields = {};
|
|
41
|
-
form === null || form === void 0 ? void 0 : form.querySelectorAll('input[type=hidden]').forEach(function (input) {
|
|
42
|
-
var _a;
|
|
43
|
-
var name = input.getAttribute('name');
|
|
44
|
-
if (name)
|
|
45
|
-
fields[name] = (_a = input.getAttribute('value')) !== null && _a !== void 0 ? _a : '';
|
|
46
|
-
});
|
|
47
|
-
return { action: action, fields: fields };
|
|
48
|
-
};
|
|
49
|
-
/*----------------------------------------*/
|
|
50
29
|
/* --------------- Command -------------- */
|
|
51
30
|
/*----------------------------------------*/
|
|
52
31
|
var logIntoPorta = function () {
|
|
@@ -85,13 +64,13 @@ var logIntoPorta = function () {
|
|
|
85
64
|
headers: htmlHeaders,
|
|
86
65
|
}).then(function (loginPageRes) {
|
|
87
66
|
// Parse login form action and hidden fields
|
|
88
|
-
var _a =
|
|
67
|
+
var _a = (0, getFormData_1.default)({ html: loginPageRes.body }), loginFormUrl = _a.action, loginMethod = _a.method, loginHiddenFields = _a.fields;
|
|
89
68
|
if (!loginFormUrl) {
|
|
90
69
|
throw new Error('Could not find login form action on HarvardKey page');
|
|
91
70
|
}
|
|
92
71
|
// Request 3: POST credentials to HarvardKey login form
|
|
93
72
|
cy.request({
|
|
94
|
-
method:
|
|
73
|
+
method: loginMethod,
|
|
95
74
|
url: loginFormUrl,
|
|
96
75
|
form: true,
|
|
97
76
|
followRedirect: true,
|
|
@@ -100,13 +79,13 @@ var logIntoPorta = function () {
|
|
|
100
79
|
body: __assign(__assign({}, loginHiddenFields), { username: username, password: password }),
|
|
101
80
|
}).then(function (authRes) {
|
|
102
81
|
// Parse SAML form from login response
|
|
103
|
-
var _a =
|
|
82
|
+
var _a = (0, getFormData_1.default)({ html: authRes.body, formSelector: 'form[action*="saml2-acs"]' }), samlFormUrl = _a.action, samlMethod = _a.method, samlHiddenFields = _a.fields;
|
|
104
83
|
if (!samlFormUrl) {
|
|
105
84
|
throw new Error('Could not find SAML form in login response');
|
|
106
85
|
}
|
|
107
86
|
// Request 4: POST SAML assertion to ACS
|
|
108
87
|
return cy.request({
|
|
109
|
-
method:
|
|
88
|
+
method: samlMethod,
|
|
110
89
|
url: samlFormUrl,
|
|
111
90
|
form: true,
|
|
112
91
|
followRedirect: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logIntoPorta.js","sourceRoot":"","sources":["../../../src/commands/logIntoPorta.ts"],"names":[],"mappings":";AAAA,iCAAiC
|
|
1
|
+
{"version":3,"file":"logIntoPorta.js","sourceRoot":"","sources":["../../../src/commands/logIntoPorta.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -15,7 +15,7 @@ declare global {
|
|
|
15
15
|
*/
|
|
16
16
|
getProfileValue(
|
|
17
17
|
key: string,
|
|
18
|
-
):
|
|
18
|
+
): any;
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
}
|
|
@@ -25,12 +25,7 @@ declare global {
|
|
|
25
25
|
/*----------------------------------------*/
|
|
26
26
|
|
|
27
27
|
const getProfileValue = () => {
|
|
28
|
-
Cypress.
|
|
29
|
-
'getProfileValue',
|
|
30
|
-
(key) => {
|
|
31
|
-
return Cypress.expose(key);
|
|
32
|
-
},
|
|
33
|
-
);
|
|
28
|
+
cy.getProfileValue = Cypress.expose;
|
|
34
29
|
};
|
|
35
30
|
|
|
36
31
|
/*----------------------------------------*/
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse HTML and extract form action URL, method, and input fields.
|
|
3
|
+
* @author Yuen Ler Chow
|
|
4
|
+
* @param options.html - Raw HTML string to parse
|
|
5
|
+
* @param options.formSelector - CSS selector for the form (default: 'form')
|
|
6
|
+
* @param options.isHiddenForm - If true, only input[type=hidden]. If false, all inputs/selects/textareas. Default: true
|
|
7
|
+
* @returns Object with action URL, method (default 'get'), and field name/value pairs
|
|
8
|
+
*/
|
|
9
|
+
const getFormData = (opts: {
|
|
10
|
+
html: string;
|
|
11
|
+
formSelector?: string;
|
|
12
|
+
isHiddenForm?: boolean;
|
|
13
|
+
}): {
|
|
14
|
+
action: string;
|
|
15
|
+
method: string;
|
|
16
|
+
fields: { [key: string]: string };
|
|
17
|
+
} => {
|
|
18
|
+
const {
|
|
19
|
+
html,
|
|
20
|
+
formSelector = 'form',
|
|
21
|
+
isHiddenForm = true,
|
|
22
|
+
} = opts;
|
|
23
|
+
|
|
24
|
+
const doc = new DOMParser().parseFromString(html, 'text/html');
|
|
25
|
+
const form = doc.querySelector(formSelector);
|
|
26
|
+
const action = form?.getAttribute('action') ?? '';
|
|
27
|
+
const method = (form?.getAttribute('method') ?? 'GET').toUpperCase();
|
|
28
|
+
const fields: { [key: string]: string } = {};
|
|
29
|
+
|
|
30
|
+
// Iterate through all input fields in the form and extract the name and value
|
|
31
|
+
const selector = isHiddenForm
|
|
32
|
+
? 'input[type=hidden]'
|
|
33
|
+
: 'input, select, textarea';
|
|
34
|
+
form?.querySelectorAll(selector).forEach(
|
|
35
|
+
(input) => {
|
|
36
|
+
const name = input.getAttribute('name');
|
|
37
|
+
if (name) {
|
|
38
|
+
fields[name] = input.getAttribute('value') ?? '';
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
action,
|
|
45
|
+
method,
|
|
46
|
+
fields,
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default getFormData;
|
package/src/commands/launchAs.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/// <reference types="cypress" />
|
|
2
2
|
|
|
3
|
+
import getFormData from './helpers/getFormData';
|
|
4
|
+
|
|
3
5
|
/*----------------------------------------*/
|
|
4
6
|
/* ---------------- Type ---------------- */
|
|
5
7
|
/*----------------------------------------*/
|
|
@@ -52,10 +54,6 @@ const launchAs = () => {
|
|
|
52
54
|
// Destructure opts
|
|
53
55
|
let { courseId, appName } = opts;
|
|
54
56
|
|
|
55
|
-
// Visit the base URL to set default origin
|
|
56
|
-
const baseURL = Cypress.config('baseUrl');
|
|
57
|
-
cy.visit(baseURL);
|
|
58
|
-
|
|
59
57
|
// Get courseId from environment variables if not provided
|
|
60
58
|
if (!courseId) {
|
|
61
59
|
const envCourseId = Cypress.expose('courseId');
|
|
@@ -89,7 +87,6 @@ const launchAs = () => {
|
|
|
89
87
|
method: 'GET',
|
|
90
88
|
url: `https://canvas.harvard.edu/api/v1/courses/${courseId}/external_tools`,
|
|
91
89
|
body: {
|
|
92
|
-
per_page: 200,
|
|
93
90
|
access_token: accessToken,
|
|
94
91
|
},
|
|
95
92
|
})
|
|
@@ -142,7 +139,6 @@ const launchAs = () => {
|
|
|
142
139
|
method: 'GET',
|
|
143
140
|
url: `https://canvas.harvard.edu/api/v1/courses/${courseId}/external_tools/sessionless_launch?id=${toolId}`,
|
|
144
141
|
body: {
|
|
145
|
-
per_page: 200,
|
|
146
142
|
access_token: accessToken,
|
|
147
143
|
},
|
|
148
144
|
})
|
|
@@ -160,7 +156,14 @@ const launchAs = () => {
|
|
|
160
156
|
|
|
161
157
|
// Launch via the sessionless launch URL
|
|
162
158
|
const launchURL = sessionlessLaunchInfo.url;
|
|
163
|
-
cy.
|
|
159
|
+
cy.request(launchURL).then((response) => {
|
|
160
|
+
const { action, fields } = getFormData({ html: response.body });
|
|
161
|
+
cy.visit({
|
|
162
|
+
url: action,
|
|
163
|
+
method: 'POST',
|
|
164
|
+
body: fields,
|
|
165
|
+
});
|
|
166
|
+
});
|
|
164
167
|
})
|
|
165
168
|
);
|
|
166
169
|
});
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/// <reference types="cypress" />
|
|
2
2
|
|
|
3
|
+
import getFormData from './helpers/getFormData';
|
|
4
|
+
|
|
3
5
|
/*----------------------------------------*/
|
|
4
6
|
/* ---------------- Type ---------------- */
|
|
5
7
|
/*----------------------------------------*/
|
|
@@ -38,29 +40,6 @@ const IDP_BASE_URL = 'https://apps.cirrusidentity.com';
|
|
|
38
40
|
// HarvardKey IdP button ID on Cirrus discovery page
|
|
39
41
|
const HARVARDKEY_IDP_BUTTON_ID = 'idp_1001962798_button';
|
|
40
42
|
|
|
41
|
-
/*----------------------------------------*/
|
|
42
|
-
/* -------------- Helpers --------------- */
|
|
43
|
-
/*----------------------------------------*/
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Parse HTML and extract form action URL and hidden input fields.
|
|
47
|
-
* @author Yuen Ler Chow
|
|
48
|
-
* @param html - Raw HTML string to parse
|
|
49
|
-
* @param formSelector - CSS selector for the form (default: 'form')
|
|
50
|
-
* @returns Object with action URL and record of hidden field name/value pairs
|
|
51
|
-
*/
|
|
52
|
-
const getFormData = (html: string, formSelector = 'form') => {
|
|
53
|
-
const doc = new DOMParser().parseFromString(html, 'text/html');
|
|
54
|
-
const form = doc.querySelector(formSelector);
|
|
55
|
-
const action = form?.getAttribute('action') ?? '';
|
|
56
|
-
const fields: { [key: string]: string } = {};
|
|
57
|
-
form?.querySelectorAll('input[type=hidden]').forEach((input) => {
|
|
58
|
-
const name = input.getAttribute('name');
|
|
59
|
-
if (name) fields[name] = input.getAttribute('value') ?? '';
|
|
60
|
-
});
|
|
61
|
-
return { action, fields };
|
|
62
|
-
};
|
|
63
|
-
|
|
64
43
|
/*----------------------------------------*/
|
|
65
44
|
/* --------------- Command -------------- */
|
|
66
45
|
/*----------------------------------------*/
|
|
@@ -116,15 +95,16 @@ const logIntoPorta = () => {
|
|
|
116
95
|
// Parse login form action and hidden fields
|
|
117
96
|
const {
|
|
118
97
|
action: loginFormUrl,
|
|
98
|
+
method: loginMethod,
|
|
119
99
|
fields: loginHiddenFields,
|
|
120
|
-
} = getFormData(loginPageRes.body);
|
|
100
|
+
} = getFormData({ html: loginPageRes.body });
|
|
121
101
|
if (!loginFormUrl) {
|
|
122
102
|
throw new Error('Could not find login form action on HarvardKey page');
|
|
123
103
|
}
|
|
124
104
|
|
|
125
105
|
// Request 3: POST credentials to HarvardKey login form
|
|
126
106
|
cy.request({
|
|
127
|
-
method:
|
|
107
|
+
method: loginMethod,
|
|
128
108
|
url: loginFormUrl,
|
|
129
109
|
form: true,
|
|
130
110
|
followRedirect: true,
|
|
@@ -139,15 +119,16 @@ const logIntoPorta = () => {
|
|
|
139
119
|
// Parse SAML form from login response
|
|
140
120
|
const {
|
|
141
121
|
action: samlFormUrl,
|
|
122
|
+
method: samlMethod,
|
|
142
123
|
fields: samlHiddenFields,
|
|
143
|
-
} = getFormData(authRes.body, 'form[action*="saml2-acs"]');
|
|
124
|
+
} = getFormData({ html: authRes.body, formSelector: 'form[action*="saml2-acs"]' });
|
|
144
125
|
if (!samlFormUrl) {
|
|
145
126
|
throw new Error('Could not find SAML form in login response');
|
|
146
127
|
}
|
|
147
128
|
|
|
148
129
|
// Request 4: POST SAML assertion to ACS
|
|
149
130
|
return cy.request({
|
|
150
|
-
method:
|
|
131
|
+
method: samlMethod,
|
|
151
132
|
url: samlFormUrl,
|
|
152
133
|
form: true,
|
|
153
134
|
followRedirect: true,
|