cassproject 5.0.20 → 5.0.23
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/package.json +49 -52
- package/src/com/eduworks/ec/array/EcArray.js +1 -1
- package/src/com/eduworks/ec/array/EcAsyncHelper.js +1 -1
- package/src/com/eduworks/ec/array/EcObject.js +1 -1
- package/src/com/eduworks/ec/crypto/EcAes.js +1 -1
- package/src/com/eduworks/ec/crypto/EcAesCtrAsync.js +20 -22
- package/src/com/eduworks/ec/crypto/EcCrypto.js +8 -4
- package/src/com/eduworks/ec/crypto/EcPk.js +7 -7
- package/src/com/eduworks/ec/crypto/EcPpk.js +7 -7
- package/src/com/eduworks/ec/crypto/EcRsaOaepAsync.js +20 -19
- package/src/com/eduworks/ec/crypto/EcRsaOaepAsyncWorker.js +7 -6
- package/src/com/eduworks/ec/crypto/forgeAsync.js +1 -9
- package/src/com/eduworks/ec/crypto/forgeAsyncNode.js +8 -8
- package/src/com/eduworks/ec/graph/EcDirectedGraph.js +1 -2
- package/src/com/eduworks/ec/graph/EcFrameworkGraph.js +18 -24
- package/src/com/eduworks/ec/promises/helpers.js +1 -3
- package/src/com/eduworks/ec/remote/EcRemote.js +9 -9
- package/src/com/eduworks/ec/task/EcAsyncTask.js +5 -20
- package/src/com/eduworks/ec/task/EcAsyncTaskManager.js +3 -4
- package/src/com/eduworks/ec/task/EcAsyncTaskWorker.js +9 -11
- package/src/com/eduworks/schema/cfd/competency/CfdFramework.js +36 -37
- package/src/com/eduworks/schema/ebac/EbacContact.js +3 -9
- package/src/com/eduworks/schema/ebac/EbacContactGrant.js +3 -9
- package/src/com/eduworks/schema/ebac/EbacCredential.js +3 -9
- package/src/com/eduworks/schema/ebac/EbacCredentialCommit.js +3 -9
- package/src/com/eduworks/schema/ebac/EbacCredentialRequest.js +3 -9
- package/src/com/eduworks/schema/ebac/EbacCredentials.js +3 -9
- package/src/com/eduworks/schema/ebac/EbacEncryptedSecret.js +3 -9
- package/src/com/eduworks/schema/ebac/EbacEncryptedValue.js +5 -12
- package/src/com/eduworks/schema/ebac/EbacSignature.js +1 -6
- package/src/index/env.js +6 -3
- package/src/index/polyfills.js +13 -27
- package/src/org/angles/schema/angles/VideoStory.js +1 -1
- package/src/org/cass/competency/EcCompetency.js +1 -2
- package/src/org/cass/competency/EcDirectory.js +1 -2
- package/src/org/cass/competency/EcFramework.js +9 -12
- package/src/org/cass/exporter/CSVExport.js +12 -13
- package/src/org/cass/importer/ASNImport.js +3 -6
- package/src/org/cass/importer/CSVImport.js +9 -17
- package/src/org/cass/importer/CTDLASNCSVConceptImport.js +25 -121
- package/src/org/cass/importer/CTDLASNCSVImport.js +88 -133
- package/src/org/cass/importer/FrameworkImport.js +16 -30
- package/src/org/cass/importer/MedbiqImport.js +3 -4
- package/src/org/cass/importer/TabStructuredImport.js +6 -6
- package/src/org/cass/profile/EcAssertion.js +40 -51
- package/src/org/cassproject/ebac/identity/EcContactGrant.js +2 -2
- package/src/org/cassproject/ebac/identity/EcIdentityManager.js +56 -62
- package/src/org/cassproject/ebac/identity/EcRekeyRequest.js +3 -2
- package/src/org/cassproject/ebac/identity/remote/EcRemoteIdentityManager.js +51 -62
- package/src/org/cassproject/ebac/identity/remote/OAuth2FileBasedRemoteIdentityManager.js +56 -70
- package/src/org/cassproject/ebac/identity/remote/RemoteIdentityManagerInterface.js +3 -3
- package/src/org/cassproject/ebac/repository/EcEncryptedValue.js +51 -44
- package/src/org/cassproject/ebac/repository/EcRepository.js +228 -301
- package/src/org/cassproject/general/repository/GeneralFile.js +8 -9
- package/src/org/cassproject/schema/cass/competency/Competency.js +10 -11
- package/src/org/cassproject/schema/cass/competency/Framework.js +10 -11
- package/src/org/cassproject/schema/cass/competency/Level.js +10 -11
- package/src/org/cassproject/schema/cass/competency/Relation.js +10 -11
- package/src/org/cassproject/schema/cass/competency/RollupRule.js +7 -7
- package/src/org/cassproject/schema/cass/profile/Assertion.js +20 -27
- package/src/org/cassproject/schema/cass/profile/AssertionEnvelope.js +3 -5
- package/src/org/cassproject/schema/general/EcRemoteLinkedData.js +41 -44
- package/src/org/json/ld/EcLinkedData.js +10 -12
- package/src/org/schema/EcOrganization.js +10 -10
- package/src/org/schema/EcQuestion.js +8 -8
- package/src/org/w3/skos/Concept.js +6 -6
- package/src/org/w3/skos/ConceptScheme.js +6 -6
- package/src/org/w3/skos/EcConcept.js +1 -2
- package/src/org/w3/skos/EcConceptScheme.js +1 -2
- package/src/test/0.start.test.js +1 -1
- package/src/test/0.testLibraries.test.js +172 -0
- package/src/test/1.ASNImport.test.js +122 -0
- package/src/test/1.CSVExport.test.js +57 -0
- package/src/test/1.CSVImport.test.js +185 -0
- package/src/test/1.CTDLASNCSVConceptImport.test.js +348 -0
- package/src/test/1.CTDLASNCSVImport.import.test.js +497 -0
- package/src/test/1.Ebac.schema.test.js +107 -0
- package/src/test/1.EcAssertion.decrypt.test.js +98 -0
- package/src/test/1.EcAssertion.pinned.test.js +160 -0
- package/src/test/1.EcCrypto.formats.test.js +293 -0
- package/src/test/1.EcCrypto.generateUUID.test.js +47 -0
- package/src/test/1.EcEncryptedValue.helpers.test.js +236 -0
- package/src/test/1.EcHelpers.misc.test.js +259 -0
- package/src/test/1.EcIdentityManager.keys.test.js +439 -0
- package/src/test/1.EcOrganization.rekey.test.js +68 -0
- package/src/test/1.EcRemote.responses.test.js +155 -0
- package/src/test/1.EcRemoteIdentityManager.flows.test.js +326 -0
- package/src/test/1.EcRemoteLinkedData.pinned.test.js +473 -0
- package/src/test/1.EcRepository.l0.test.js +14 -5
- package/src/test/1.EcRepository.l1.test.js +16 -7
- package/src/test/1.EcRepository.l2.test.js +20 -11
- package/src/test/1.EcRepository.unit.test.js +961 -0
- package/src/test/1.EcRsaOaep.test.js +2 -12
- package/src/test/1.EcRsaOaepAsync.test.js +2 -12
- package/src/test/1.EcRsaOaepAsyncWorker.test.js +2 -12
- package/src/test/1.EcRsaOaepAsyncWorker.workers.test.js +147 -0
- package/src/test/1.FrameworkImport.test.js +170 -0
- package/src/test/1.MedbiqImport.test.js +92 -0
- package/src/test/1.OAuth2FileBasedRemoteIdentityManager.test.js +399 -0
- package/src/test/1.TabStructuredImport.test.js +61 -0
- package/src/test/1.polyfills.test.js +89 -0
- package/src/test/1.schema.competency.pinned.test.js +384 -0
- package/src/test/3.EcFrameworkGraph.test.js +3 -2
- package/src/test/4.schema.test.js +33 -28
- package/src/test/4.skyId.test.js +4 -2
- package/src/test/cypressValue.js +9 -0
- package/src/test/2.EcCompetency.test.js +0 -17
|
@@ -71,8 +71,8 @@ module.exports = class EcOrganization extends schema.Organization {
|
|
|
71
71
|
throw new Error("Employee is not Array");
|
|
72
72
|
let ary = this.employee;
|
|
73
73
|
let psid = person.shortId();
|
|
74
|
-
for (let
|
|
75
|
-
if (
|
|
74
|
+
for (let employee of ary) {
|
|
75
|
+
if (employee == psid) return;
|
|
76
76
|
}
|
|
77
77
|
ary.push(psid);
|
|
78
78
|
}
|
|
@@ -110,7 +110,7 @@ module.exports = class EcOrganization extends schema.Organization {
|
|
|
110
110
|
let empAry = this.employee;
|
|
111
111
|
for (let i = 0; i < membAry.length; i++) {
|
|
112
112
|
let id = membAry[i];
|
|
113
|
-
if (id.toLowerCase().
|
|
113
|
+
if (id.toLowerCase().includes("person")) {
|
|
114
114
|
if (empAry.indexOf(id) <= -1) {
|
|
115
115
|
empAry.push(id);
|
|
116
116
|
}
|
|
@@ -132,8 +132,8 @@ module.exports = class EcOrganization extends schema.Organization {
|
|
|
132
132
|
if (ppkList == null) return JSON.stringify([]);
|
|
133
133
|
else {
|
|
134
134
|
let pemArray = [];
|
|
135
|
-
for (let
|
|
136
|
-
pemArray.push(
|
|
135
|
+
for (let ppk of ppkList) {
|
|
136
|
+
pemArray.push(ppk.toPem());
|
|
137
137
|
}
|
|
138
138
|
return JSON.stringify(pemArray);
|
|
139
139
|
}
|
|
@@ -167,7 +167,6 @@ module.exports = class EcOrganization extends schema.Organization {
|
|
|
167
167
|
let msg = "Repository cannot be null for a rekey operation";
|
|
168
168
|
if (failure != null) failure(msg);
|
|
169
169
|
else global.auditLogger.report(global.auditLogger.LogCategory.SYSTEM, global.auditLogger.Severity.ERROR, "EcOrgRekeyAndSave", msg);
|
|
170
|
-
return;
|
|
171
170
|
} else {
|
|
172
171
|
let oldKey = await this.getCurrentOrgKey();
|
|
173
172
|
let newKey = EcPpk.generateKey();
|
|
@@ -180,7 +179,7 @@ module.exports = class EcOrganization extends schema.Organization {
|
|
|
180
179
|
oldKey,
|
|
181
180
|
newKey
|
|
182
181
|
);
|
|
183
|
-
this.addOrgKey(newKey);
|
|
182
|
+
await this.addOrgKey(newKey);
|
|
184
183
|
let newKeys = await EcEncryptedValue.encryptValue(
|
|
185
184
|
this.ppkListToPemArrayString(await this.getOrgKeys()),
|
|
186
185
|
EcOrganization.ORG_PPK_SET_KEY,
|
|
@@ -247,8 +246,8 @@ module.exports = class EcOrganization extends schema.Organization {
|
|
|
247
246
|
let ev = new EcEncryptedValue();
|
|
248
247
|
ev.copyFrom(o);
|
|
249
248
|
let orgKeysPPKPems = JSON.parse(await ev.decryptIntoString(null, null, eim));
|
|
250
|
-
for (let
|
|
251
|
-
orgKeys.push(EcPpk.fromPem(
|
|
249
|
+
for (let pem of orgKeysPPKPems) {
|
|
250
|
+
orgKeys.push(EcPpk.fromPem(pem));
|
|
252
251
|
}
|
|
253
252
|
} else if (o) {
|
|
254
253
|
orgKeys = o;
|
|
@@ -281,7 +280,8 @@ module.exports = class EcOrganization extends schema.Organization {
|
|
|
281
280
|
upgrade(eim) {
|
|
282
281
|
super.upgrade();
|
|
283
282
|
this.movePersonMembersToEmployee();
|
|
284
|
-
|
|
283
|
+
//upgrade() is synchronous; the key move finishes in the background as before.
|
|
284
|
+
void this.moveKeyField(eim);
|
|
285
285
|
}
|
|
286
286
|
/**
|
|
287
287
|
* Attempts to find and return the organization's fingerprint from the id.
|
|
@@ -52,14 +52,14 @@ module.exports = class EcQuestion extends schema.Question {
|
|
|
52
52
|
return EcQuestion.HAND_GRADED_ESSAY;
|
|
53
53
|
}
|
|
54
54
|
if (this.suggestedAnswer == null) {
|
|
55
|
-
if (this.text
|
|
55
|
+
if (this.text?.includes("__")) {
|
|
56
56
|
return EcQuestion.FILL_IN_THE_BLANK;
|
|
57
57
|
}
|
|
58
58
|
return EcQuestion.SHORT_ANSWER;
|
|
59
59
|
}
|
|
60
60
|
let l = this.suggestedAnswer.length;
|
|
61
61
|
if (l == 0) {
|
|
62
|
-
if (this.text
|
|
62
|
+
if (this.text?.includes("__")) {
|
|
63
63
|
return EcQuestion.FILL_IN_THE_BLANK;
|
|
64
64
|
}
|
|
65
65
|
return EcQuestion.SHORT_ANSWER;
|
|
@@ -75,7 +75,7 @@ module.exports = class EcQuestion extends schema.Question {
|
|
|
75
75
|
cementAnswerId(id) {
|
|
76
76
|
if (this.acceptedAnswer != null) {
|
|
77
77
|
if (!EcArray.isArray(this.acceptedAnswer)) {
|
|
78
|
-
throw new Error("Accepted Answer is not Array");
|
|
78
|
+
throw new Error("Accepted Answer is not Array"); // NOSONAR - A TypeError would change the name and toString() callers see.
|
|
79
79
|
}
|
|
80
80
|
let ary = this.acceptedAnswer;
|
|
81
81
|
for (let i = 0; i < ary.length; i++) {
|
|
@@ -89,7 +89,7 @@ module.exports = class EcQuestion extends schema.Question {
|
|
|
89
89
|
}
|
|
90
90
|
if (this.suggestedAnswer != null) {
|
|
91
91
|
if (!EcArray.isArray(this.suggestedAnswer)) {
|
|
92
|
-
throw new Error("Suggested Answer is not Array");
|
|
92
|
+
throw new Error("Suggested Answer is not Array"); // NOSONAR - A TypeError would change the name and toString() callers see.
|
|
93
93
|
}
|
|
94
94
|
let ary = this.suggestedAnswer;
|
|
95
95
|
for (let i = 0; i < ary.length; i++) {
|
|
@@ -119,7 +119,7 @@ module.exports = class EcQuestion extends schema.Question {
|
|
|
119
119
|
this["acceptedAnswer"] = [];
|
|
120
120
|
}
|
|
121
121
|
if (!EcArray.isArray(this.acceptedAnswer)) {
|
|
122
|
-
throw new Error("Accepted Answer is not Array");
|
|
122
|
+
throw new Error("Accepted Answer is not Array"); // NOSONAR - A TypeError would change the name and toString() callers see.
|
|
123
123
|
}
|
|
124
124
|
let ary = this.acceptedAnswer;
|
|
125
125
|
ary.push(answer.id);
|
|
@@ -129,7 +129,7 @@ module.exports = class EcQuestion extends schema.Question {
|
|
|
129
129
|
this["suggestedAnswer"] = [];
|
|
130
130
|
}
|
|
131
131
|
if (!EcArray.isArray(this.suggestedAnswer)) {
|
|
132
|
-
throw new Error("Suggested Answer is not Array");
|
|
132
|
+
throw new Error("Suggested Answer is not Array"); // NOSONAR - A TypeError would change the name and toString() callers see.
|
|
133
133
|
}
|
|
134
134
|
let ary = this.suggestedAnswer;
|
|
135
135
|
ary.push(answer.id);
|
|
@@ -139,7 +139,7 @@ module.exports = class EcQuestion extends schema.Question {
|
|
|
139
139
|
return;
|
|
140
140
|
}
|
|
141
141
|
if (!EcArray.isArray(this.suggestedAnswer)) {
|
|
142
|
-
throw new Error("Suggested Answer is not Array");
|
|
142
|
+
throw new Error("Suggested Answer is not Array"); // NOSONAR - A TypeError would change the name and toString() callers see.
|
|
143
143
|
}
|
|
144
144
|
let ary = this.suggestedAnswer;
|
|
145
145
|
for (let i = 0; i < ary.length; i++) {
|
|
@@ -156,7 +156,7 @@ module.exports = class EcQuestion extends schema.Question {
|
|
|
156
156
|
return;
|
|
157
157
|
}
|
|
158
158
|
if (!EcArray.isArray(this.acceptedAnswer)) {
|
|
159
|
-
throw new Error("Accepted Answer is not Array");
|
|
159
|
+
throw new Error("Accepted Answer is not Array"); // NOSONAR - A TypeError would change the name and toString() callers see.
|
|
160
160
|
}
|
|
161
161
|
let ary = this.acceptedAnswer;
|
|
162
162
|
for (let i = 0; i < ary.length; i++) {
|
|
@@ -14,7 +14,7 @@ module.exports = class Concept extends EcRemoteLinkedData {
|
|
|
14
14
|
super("https://schema.cassproject.org/0.4/skos/", "Concept");
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
static TYPE_0_1 = "http://schema.cassproject.org/0.3/skos/Concept";
|
|
17
|
+
static TYPE_0_1 = "http://schema.cassproject.org/0.3/skos/Concept"; // NOSONAR - JSON-LD identifier, never fetched
|
|
18
18
|
static TYPE_0_2 = "https://schema.cassproject.org/0.3/skos/Concept";
|
|
19
19
|
static TYPE_0_3 = "https://schema.cassproject.org/0.4/skos/Concept";
|
|
20
20
|
static myType = this.TYPE_0_3;
|
|
@@ -48,10 +48,10 @@ module.exports = class Concept extends EcRemoteLinkedData {
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
getTypes() {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
return [
|
|
52
|
+
Concept.TYPE_0_3,
|
|
53
|
+
Concept.TYPE_0_2,
|
|
54
|
+
Concept.TYPE_0_1,
|
|
55
|
+
];
|
|
56
56
|
}
|
|
57
57
|
};
|
|
@@ -14,7 +14,7 @@ module.exports = class ConceptScheme extends EcRemoteLinkedData {
|
|
|
14
14
|
constructor() {
|
|
15
15
|
super("https://schema.cassproject.org/0.4/skos/", "ConceptScheme");
|
|
16
16
|
}
|
|
17
|
-
static TYPE_0_1 = "http://schema.cassproject.org/0.3/skos/ConceptScheme";
|
|
17
|
+
static TYPE_0_1 = "http://schema.cassproject.org/0.3/skos/ConceptScheme"; // NOSONAR - JSON-LD identifier, never fetched
|
|
18
18
|
static TYPE_0_2 = "https://schema.cassproject.org/0.3/skos/ConceptScheme";
|
|
19
19
|
static TYPE_0_3 = "https://schema.cassproject.org/0.4/skos/ConceptScheme";
|
|
20
20
|
static myType = this.TYPE_0_3;
|
|
@@ -41,10 +41,10 @@ module.exports = class ConceptScheme extends EcRemoteLinkedData {
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
getTypes() {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
return [
|
|
45
|
+
ConceptScheme.TYPE_0_3,
|
|
46
|
+
ConceptScheme.TYPE_0_2,
|
|
47
|
+
ConceptScheme.TYPE_0_1,
|
|
48
|
+
];
|
|
49
49
|
}
|
|
50
50
|
};
|
|
@@ -6,12 +6,11 @@ const EcRepository = require("../../cassproject/ebac/repository/EcRepository");
|
|
|
6
6
|
module.exports = class EcConcept extends Concept {
|
|
7
7
|
constructor() {
|
|
8
8
|
super();
|
|
9
|
-
let me = this;
|
|
10
9
|
if (EcConcept.template != null) {
|
|
11
10
|
let you = EcConcept.template;
|
|
12
11
|
for (let key in you) {
|
|
13
12
|
if (typeof you[key] != "function")
|
|
14
|
-
|
|
13
|
+
this[key.replace("@", "")] = you[key];
|
|
15
14
|
}
|
|
16
15
|
}
|
|
17
16
|
}
|
|
@@ -6,12 +6,11 @@ const EcRepository = require("../../cassproject/ebac/repository/EcRepository");
|
|
|
6
6
|
module.exports = class EcConceptScheme extends ConceptScheme {
|
|
7
7
|
constructor() {
|
|
8
8
|
super();
|
|
9
|
-
let me = this;
|
|
10
9
|
if (EcConceptScheme.template != null) {
|
|
11
10
|
let you = EcConceptScheme.template;
|
|
12
11
|
for (let key in you) {
|
|
13
12
|
if (typeof you[key] != "function")
|
|
14
|
-
|
|
13
|
+
this[key.replace("@", "")] = you[key];
|
|
15
14
|
}
|
|
16
15
|
}
|
|
17
16
|
}
|
package/src/test/0.start.test.js
CHANGED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// Checks that the parts of chai and sinon these tests rely on still behave as
|
|
2
|
+
// expected, so an upgrade cannot make assertions pass for the wrong reason.
|
|
3
|
+
const chai = require('chai');
|
|
4
|
+
const sinon = require('sinon');
|
|
5
|
+
|
|
6
|
+
const assert = chai.assert;
|
|
7
|
+
const expect = chai.expect;
|
|
8
|
+
|
|
9
|
+
// Runs fn and returns its chai AssertionError, failing if it did not throw one.
|
|
10
|
+
function failure(fn) {
|
|
11
|
+
try {
|
|
12
|
+
fn();
|
|
13
|
+
} catch (e) {
|
|
14
|
+
if (e instanceof chai.AssertionError) return e;
|
|
15
|
+
throw e;
|
|
16
|
+
}
|
|
17
|
+
throw new Error('assertion did not fail');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe('chai', () => {
|
|
21
|
+
it('assert passes and fails as expected', () => {
|
|
22
|
+
assert.equal(1, '1');
|
|
23
|
+
failure(() => assert.equal(1, 2));
|
|
24
|
+
assert.strictEqual(1, 1);
|
|
25
|
+
failure(() => assert.strictEqual(1, '1'));
|
|
26
|
+
assert.deepEqual({ a: [1, { b: 2 }] }, { a: [1, { b: 2 }] });
|
|
27
|
+
failure(() => assert.deepEqual({ a: [1] }, { a: [2] }));
|
|
28
|
+
assert.notEqual(1, 2);
|
|
29
|
+
failure(() => assert.notEqual(1, 1));
|
|
30
|
+
assert.isTrue(true);
|
|
31
|
+
failure(() => assert.isTrue(1));
|
|
32
|
+
assert.isFalse(false);
|
|
33
|
+
failure(() => assert.isFalse(0));
|
|
34
|
+
assert.isNull(null);
|
|
35
|
+
failure(() => assert.isNull(undefined));
|
|
36
|
+
assert.isNotNull(0);
|
|
37
|
+
failure(() => assert.isNotNull(null));
|
|
38
|
+
assert.isUndefined(undefined);
|
|
39
|
+
failure(() => assert.isUndefined(null));
|
|
40
|
+
assert.isDefined(null);
|
|
41
|
+
failure(() => assert.isDefined(undefined));
|
|
42
|
+
assert.isString('s');
|
|
43
|
+
failure(() => assert.isString(1));
|
|
44
|
+
assert.isObject({});
|
|
45
|
+
failure(() => assert.isObject('s'));
|
|
46
|
+
assert.isFunction(() => 0);
|
|
47
|
+
failure(() => assert.isFunction({}));
|
|
48
|
+
assert.isNaN(NaN);
|
|
49
|
+
failure(() => assert.isNaN(1));
|
|
50
|
+
assert.isAbove(2, 1);
|
|
51
|
+
failure(() => assert.isAbove(1, 1));
|
|
52
|
+
assert.isBelow(1, 2);
|
|
53
|
+
failure(() => assert.isBelow(2, 2));
|
|
54
|
+
assert.include([1, 2], 2);
|
|
55
|
+
assert.include('abc', 'b');
|
|
56
|
+
failure(() => assert.include([1, 2], 3));
|
|
57
|
+
assert.match('abc', /b/);
|
|
58
|
+
failure(() => assert.match('abc', /d/));
|
|
59
|
+
assert.lengthOf([1, 2], 2);
|
|
60
|
+
failure(() => assert.lengthOf([1], 2));
|
|
61
|
+
assert.exists(0);
|
|
62
|
+
failure(() => assert.exists(null));
|
|
63
|
+
class A { }
|
|
64
|
+
class B extends A { }
|
|
65
|
+
assert.instanceOf(new B(), A);
|
|
66
|
+
failure(() => assert.instanceOf({}, A));
|
|
67
|
+
assert.notInstanceOf(new A(), B);
|
|
68
|
+
failure(() => assert.notInstanceOf(new B(), A));
|
|
69
|
+
failure(() => assert.fail('message'));
|
|
70
|
+
assert.equal(failure(() => assert.fail('message')).message, 'message');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('expect passes and fails as expected', () => {
|
|
74
|
+
expect(1).to.equal(1);
|
|
75
|
+
failure(() => expect(1).to.equal(2));
|
|
76
|
+
expect({ a: [1] }).to.deep.equal({ a: [1] });
|
|
77
|
+
failure(() => expect({ a: [1] }).to.deep.equal({ a: [2] }));
|
|
78
|
+
expect(true).to.be.true;
|
|
79
|
+
failure(() => expect(1).to.be.true);
|
|
80
|
+
expect(false).to.be.false;
|
|
81
|
+
failure(() => expect(0).to.be.false);
|
|
82
|
+
expect([1]).to.be.an('array').with.lengthOf(1);
|
|
83
|
+
failure(() => expect([1]).to.be.an('array').with.lengthOf(2));
|
|
84
|
+
expect('s').to.be.a('string');
|
|
85
|
+
failure(() => expect(1).to.be.a('string'));
|
|
86
|
+
expect(new Date()).to.be.an.instanceof(Date);
|
|
87
|
+
failure(() => expect({}).to.be.an.instanceof(Date));
|
|
88
|
+
expect('Row 2: x').to.contain('Row 2');
|
|
89
|
+
failure(() => expect('Row 2').to.contain('Row 3'));
|
|
90
|
+
expect([1, 2]).to.include(2);
|
|
91
|
+
failure(() => expect([1, 2]).to.include(3));
|
|
92
|
+
expect([1, 2]).to.not.include(3);
|
|
93
|
+
failure(() => expect([1, 2]).to.not.include(2));
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('should is available', () => {
|
|
97
|
+
const should = chai.should();
|
|
98
|
+
(1).should.equal(1);
|
|
99
|
+
failure(() => (1).should.equal(2));
|
|
100
|
+
should.not.exist(null);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
describe('sinon', () => {
|
|
105
|
+
afterEach(() => sinon.restore());
|
|
106
|
+
|
|
107
|
+
it('spies record calls and arguments', () => {
|
|
108
|
+
const target = { f: (a) => a * 2 };
|
|
109
|
+
const spy = sinon.spy(target, 'f');
|
|
110
|
+
assert.isFalse(spy.called);
|
|
111
|
+
assert.equal(target.f(3), 6);
|
|
112
|
+
assert.isTrue(spy.called);
|
|
113
|
+
assert.isTrue(spy.calledOnce);
|
|
114
|
+
assert.equal(spy.callCount, 1);
|
|
115
|
+
assert.isTrue(spy.calledWith(3));
|
|
116
|
+
assert.isFalse(spy.calledWith(4));
|
|
117
|
+
assert.deepEqual(spy.firstCall.args, [3]);
|
|
118
|
+
assert.isTrue(spy.calledWith(sinon.match.any));
|
|
119
|
+
assert.isTrue(spy.calledWith(sinon.match.number));
|
|
120
|
+
assert.isFalse(spy.calledWith(sinon.match.string));
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('stubs resolve, reject, return and call fakes', async () => {
|
|
124
|
+
const target = { a: () => 1, b: () => 1, c: () => 1, d: () => 1 };
|
|
125
|
+
sinon.stub(target, 'a').resolves(5);
|
|
126
|
+
sinon.stub(target, 'b').rejects(new Error('no'));
|
|
127
|
+
sinon.stub(target, 'c').returns(7);
|
|
128
|
+
sinon.stub(target, 'd').callsFake((x) => x + 1);
|
|
129
|
+
assert.equal(await target.a(), 5);
|
|
130
|
+
let error;
|
|
131
|
+
await target.b().catch((e) => { error = e; });
|
|
132
|
+
assert.equal(error.message, 'no');
|
|
133
|
+
assert.equal(target.c(), 7);
|
|
134
|
+
assert.equal(target.d(1), 2);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('stubs can be changed after creation and expose the original', () => {
|
|
138
|
+
const target = { f: () => 'original' };
|
|
139
|
+
const stub = sinon.stub(target, 'f').returns('first');
|
|
140
|
+
assert.equal(target.f(), 'first');
|
|
141
|
+
stub.callsFake(() => 'second');
|
|
142
|
+
assert.equal(target.f(), 'second');
|
|
143
|
+
assert.equal(stub.wrappedMethod(), 'original');
|
|
144
|
+
stub.rejects(new Error('later'));
|
|
145
|
+
return target.f().then(() => assert.fail('should reject'), (e) => assert.equal(e.message, 'later'));
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('restores originals, individually and all at once', () => {
|
|
149
|
+
const target = { f: () => 'f', g: () => 'g' };
|
|
150
|
+
const f = sinon.stub(target, 'f').returns('stubbed');
|
|
151
|
+
sinon.stub(target, 'g').returns('stubbed');
|
|
152
|
+
f.restore();
|
|
153
|
+
assert.equal(target.f(), 'f');
|
|
154
|
+
assert.equal(target.g(), 'stubbed');
|
|
155
|
+
sinon.restore();
|
|
156
|
+
assert.equal(target.g(), 'g');
|
|
157
|
+
assert.isUndefined(target.f.restore);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('fake timers freeze the clock and restore it', () => {
|
|
161
|
+
const clock = sinon.useFakeTimers({ now: 1700000000000 });
|
|
162
|
+
try {
|
|
163
|
+
assert.equal(new Date().getTime(), 1700000000000);
|
|
164
|
+
assert.equal(Date.now(), 1700000000000);
|
|
165
|
+
clock.tick(5);
|
|
166
|
+
assert.equal(Date.now(), 1700000000005);
|
|
167
|
+
} finally {
|
|
168
|
+
clock.restore();
|
|
169
|
+
}
|
|
170
|
+
assert.isAbove(Date.now(), 1700000000005);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
require('../../index.js');
|
|
2
|
+
const chai = require('chai');
|
|
3
|
+
const sinon = require('sinon');
|
|
4
|
+
const EcRepository = require('../org/cassproject/ebac/repository/EcRepository.js');
|
|
5
|
+
|
|
6
|
+
const assert = chai.assert;
|
|
7
|
+
|
|
8
|
+
const SERVER = "http://repo.test/api/";
|
|
9
|
+
const TYPE = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type";
|
|
10
|
+
const TITLE = "http://purl.org/dc/elements/1.1/title";
|
|
11
|
+
const DESC = "http://purl.org/dc/terms/description";
|
|
12
|
+
const CHILD = "http://purl.org/gem/qualifiers/hasChild";
|
|
13
|
+
const STATEMENT = "http://purl.org/ASN/schema/core/Statement";
|
|
14
|
+
const DOCUMENT = "http://purl.org/ASN/schema/core/StandardDocument";
|
|
15
|
+
|
|
16
|
+
function asnDocument() {
|
|
17
|
+
return {
|
|
18
|
+
"http://asn.test/D1": { [TYPE]: [{ value: DOCUMENT }], [TITLE]: [{ value: "Doc" }], [DESC]: [{ value: "Doc desc" }], [CHILD]: [{ value: "http://asn.test/S1" }] },
|
|
19
|
+
"http://asn.test/S1": { [TYPE]: [{ value: STATEMENT }], [DESC]: [{ value: "Statement one" }], [CHILD]: [{ value: "http://asn.test/S2" }, { value: "http://asn.test/S3" }] },
|
|
20
|
+
"http://asn.test/S2": { [TYPE]: [{ value: STATEMENT }], [TITLE]: [{ value: "Two" }] },
|
|
21
|
+
"http://asn.test/S3": { [TYPE]: [{ value: STATEMENT }], [TITLE]: [{ value: "Three" }], [DESC]: [{ value: "Three desc" }] }
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
describe('ASNImport', () => {
|
|
26
|
+
afterEach(() => sinon.restore());
|
|
27
|
+
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
ASNImport.jsonCompetencies = {};
|
|
30
|
+
ASNImport.jsonFramework = null;
|
|
31
|
+
ASNImport.frameworkUrl = "";
|
|
32
|
+
ASNImport.lookThroughSource(asnDocument());
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const run = (serverUrl, createFramework, repo) => new Promise((resolve, reject) => {
|
|
36
|
+
const failures = [];
|
|
37
|
+
ASNImport.importCompetencies(serverUrl, null, createFramework, (comps, fw) => resolve({ comps, fw, failures }), (e) => { failures.push(e); reject(e); }, () => { }, repo);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('finds the framework, competencies and relation count', () => {
|
|
41
|
+
assert.equal(ASNImport.frameworkUrl, "http://asn.test/D1");
|
|
42
|
+
assert.deepEqual(Object.keys(ASNImport.jsonCompetencies), ["http://asn.test/S1", "http://asn.test/S2", "http://asn.test/S3"]);
|
|
43
|
+
assert.equal(ASNImport.competencyCount, 3);
|
|
44
|
+
assert.equal(ASNImport.relationCount, 2);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('imports competencies keyed by their ASN ids and narrows relations with versioned ids', async () => {
|
|
48
|
+
const saved = [];
|
|
49
|
+
const repo = { selectedServer: SERVER, saveTo: (o, s) => { saved.push(o); s("ok"); } };
|
|
50
|
+
const { comps, fw } = await run(SERVER, false, repo);
|
|
51
|
+
assert.isNull(fw);
|
|
52
|
+
assert.deepEqual(comps.map(c => [c.id, c.name, c.description]), [
|
|
53
|
+
["http://asn.test/S1", "Statement one", "Statement one"],
|
|
54
|
+
["http://asn.test/S2", "Two", undefined],
|
|
55
|
+
["http://asn.test/S3", "Three", "Three desc"]
|
|
56
|
+
]);
|
|
57
|
+
const relations = saved.filter(o => o instanceof EcAlignment);
|
|
58
|
+
assert.deepEqual(relations.map(r => [r.source, r.target, r.relationType]).sort(), [
|
|
59
|
+
["http://asn.test/S2", "http://asn.test/S1", "narrows"],
|
|
60
|
+
["http://asn.test/S3", "http://asn.test/S1", "narrows"]
|
|
61
|
+
]);
|
|
62
|
+
for (const r of relations) {
|
|
63
|
+
assert.isTrue(r.id.startsWith(SERVER));
|
|
64
|
+
assert.notEqual(r.id, r.shortId());
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('generates short relation ids when the repository server does not contain the server url', async () => {
|
|
69
|
+
const saved = [];
|
|
70
|
+
const repo = { selectedServer: SERVER, saveTo: (o, s) => { saved.push(o); s("ok"); } };
|
|
71
|
+
await run("http://other.test/", false, repo);
|
|
72
|
+
const relations = saved.filter(o => o instanceof EcAlignment);
|
|
73
|
+
assert.lengthOf(relations, 2);
|
|
74
|
+
for (const r of relations) {
|
|
75
|
+
assert.isTrue(r.id.startsWith("http://other.test/"));
|
|
76
|
+
assert.equal(r.id, r.shortId());
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('generates versioned relation ids and saves through EcRepository without a repository', async () => {
|
|
81
|
+
const saved = [];
|
|
82
|
+
sinon.stub(EcRepository, 'save').callsFake((o, s) => { saved.push(o); s("ok"); });
|
|
83
|
+
const { fw } = await run(SERVER, true, null);
|
|
84
|
+
const relations = saved.filter(o => o instanceof EcAlignment);
|
|
85
|
+
assert.lengthOf(relations, 2);
|
|
86
|
+
for (const r of relations)
|
|
87
|
+
assert.notEqual(r.id, r.shortId());
|
|
88
|
+
assert.equal(fw.id, "http://asn.test/D1");
|
|
89
|
+
assert.equal(fw.name, "Doc");
|
|
90
|
+
assert.equal(fw.description, "Doc desc");
|
|
91
|
+
assert.deepEqual(fw.competency, ["http://asn.test/S1", "http://asn.test/S2", "http://asn.test/S3"]);
|
|
92
|
+
assert.lengthOf(fw.relation, 2);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe('createFramework without a framework url', () => {
|
|
96
|
+
const create = (serverUrl, repo) => new Promise((resolve, reject) => {
|
|
97
|
+
ASNImport.importedFramework = new EcFramework();
|
|
98
|
+
ASNImport.frameworkUrl = null;
|
|
99
|
+
ASNImport.competencies = {};
|
|
100
|
+
ASNImport.createFramework(serverUrl, null, (comps, fw) => resolve(fw), reject, repo);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('generates a versioned id when the repository server contains the server url', async () => {
|
|
104
|
+
const fw = await create(SERVER, { selectedServer: SERVER, saveTo: (o, s) => s("ok") });
|
|
105
|
+
assert.isTrue(fw.id.startsWith(SERVER));
|
|
106
|
+
assert.notEqual(fw.id, fw.shortId());
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('generates a short id when the repository server does not contain the server url', async () => {
|
|
110
|
+
const fw = await create("http://other.test/", { selectedServer: SERVER, saveTo: (o, s) => s("ok") });
|
|
111
|
+
assert.isTrue(fw.id.startsWith("http://other.test/"));
|
|
112
|
+
assert.equal(fw.id, fw.shortId());
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('generates a versioned id without a repository', async () => {
|
|
116
|
+
sinon.stub(EcRepository, 'save').callsFake((o, s) => s("ok"));
|
|
117
|
+
const fw = await create(SERVER, null);
|
|
118
|
+
assert.isTrue(fw.id.startsWith(SERVER));
|
|
119
|
+
assert.notEqual(fw.id, fw.shortId());
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require('../../index.js');
|
|
2
|
+
const chai = require('chai');
|
|
3
|
+
|
|
4
|
+
const assert = chai.assert;
|
|
5
|
+
|
|
6
|
+
const CTX = "https://schema.cassproject.org/0.4";
|
|
7
|
+
|
|
8
|
+
describe('CSVExport.CSVExportProcess', () => {
|
|
9
|
+
const competency = (props) => Object.assign({ "@context": CTX, "@type": "Competency" }, props);
|
|
10
|
+
|
|
11
|
+
it('skips falsy entries when building the export', () => {
|
|
12
|
+
const p = new CSVExport.CSVExportProcess();
|
|
13
|
+
p.buildExport([null, competency({ "@id": "http://x/1", name: "One" }), undefined, 0, "", false, competency({ "@id": "http://x/2", name: "Two" })], false);
|
|
14
|
+
assert.lengthOf(p.csvOutput, 2);
|
|
15
|
+
assert.equal(p.csvOutput[0].name, "One");
|
|
16
|
+
assert.equal(p.csvOutput[1].name, "Two");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('flattens nested objects with dotted names when not piped', () => {
|
|
20
|
+
const p = new CSVExport.CSVExportProcess();
|
|
21
|
+
p.buildExport([competency({ "@id": "http://x/1", name: { "@language": "en", "@value": "One" } })], false);
|
|
22
|
+
assert.equal(p.csvOutput[0]["name.@language"], "en");
|
|
23
|
+
assert.equal(p.csvOutput[0]["name.@value"], "One");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('joins piped arrays and objects with |', () => {
|
|
27
|
+
const p = new CSVExport.CSVExportProcess();
|
|
28
|
+
p.buildExport([competency({
|
|
29
|
+
"@id": "http://x/1",
|
|
30
|
+
"ceasn:keyword": ["a", "b"],
|
|
31
|
+
"ceasn:nested": { first: "x", second: ["y", "z"] }
|
|
32
|
+
})], true);
|
|
33
|
+
assert.equal(p.csvOutput[0]["ceasn:keyword"], "a|b");
|
|
34
|
+
assert.equal(p.csvOutput[0]["ceasn:nested"], "x|y|z");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('formats piped ceterms:versionIdentifier entries as code~type~uri', () => {
|
|
38
|
+
const p = new CSVExport.CSVExportProcess();
|
|
39
|
+
p.buildExport([competency({
|
|
40
|
+
"@id": "http://x/1",
|
|
41
|
+
"ceterms:versionIdentifier": [
|
|
42
|
+
{ "ceterms:identifierValueCode": "1.0", "ceterms:identifierTypeName": { "en-us": "Version" }, "ceterms:identifierType": "http://t/1" },
|
|
43
|
+
{ "ceterms:identifierValueCode": "2.0" },
|
|
44
|
+
{ "ceterms:identifierTypeName": { "en-us": "Only" } }
|
|
45
|
+
]
|
|
46
|
+
})], true);
|
|
47
|
+
// Entries without an identifierType get no "|" separator; the final character is always dropped.
|
|
48
|
+
assert.equal(p.csvOutput[0]["ceterms:versionIdentifier"], "1.0~Version~http://t/1|2.0~Only");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('fills missing columns with empty strings on earlier rows', () => {
|
|
52
|
+
const p = new CSVExport.CSVExportProcess();
|
|
53
|
+
p.buildExport([competency({ "@id": "http://x/1", name: "One" }), competency({ "@id": "http://x/2", name: "Two", description: "D" })], false);
|
|
54
|
+
assert.strictEqual(p.csvOutput[0].description, "");
|
|
55
|
+
assert.equal(p.csvOutput[1].description, "D");
|
|
56
|
+
});
|
|
57
|
+
});
|