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.
Files changed (107) hide show
  1. package/package.json +49 -52
  2. package/src/com/eduworks/ec/array/EcArray.js +1 -1
  3. package/src/com/eduworks/ec/array/EcAsyncHelper.js +1 -1
  4. package/src/com/eduworks/ec/array/EcObject.js +1 -1
  5. package/src/com/eduworks/ec/crypto/EcAes.js +1 -1
  6. package/src/com/eduworks/ec/crypto/EcAesCtrAsync.js +20 -22
  7. package/src/com/eduworks/ec/crypto/EcCrypto.js +8 -4
  8. package/src/com/eduworks/ec/crypto/EcPk.js +7 -7
  9. package/src/com/eduworks/ec/crypto/EcPpk.js +7 -7
  10. package/src/com/eduworks/ec/crypto/EcRsaOaepAsync.js +20 -19
  11. package/src/com/eduworks/ec/crypto/EcRsaOaepAsyncWorker.js +7 -6
  12. package/src/com/eduworks/ec/crypto/forgeAsync.js +1 -9
  13. package/src/com/eduworks/ec/crypto/forgeAsyncNode.js +8 -8
  14. package/src/com/eduworks/ec/graph/EcDirectedGraph.js +1 -2
  15. package/src/com/eduworks/ec/graph/EcFrameworkGraph.js +18 -24
  16. package/src/com/eduworks/ec/promises/helpers.js +1 -3
  17. package/src/com/eduworks/ec/remote/EcRemote.js +9 -9
  18. package/src/com/eduworks/ec/task/EcAsyncTask.js +5 -20
  19. package/src/com/eduworks/ec/task/EcAsyncTaskManager.js +3 -4
  20. package/src/com/eduworks/ec/task/EcAsyncTaskWorker.js +9 -11
  21. package/src/com/eduworks/schema/cfd/competency/CfdFramework.js +36 -37
  22. package/src/com/eduworks/schema/ebac/EbacContact.js +3 -9
  23. package/src/com/eduworks/schema/ebac/EbacContactGrant.js +3 -9
  24. package/src/com/eduworks/schema/ebac/EbacCredential.js +3 -9
  25. package/src/com/eduworks/schema/ebac/EbacCredentialCommit.js +3 -9
  26. package/src/com/eduworks/schema/ebac/EbacCredentialRequest.js +3 -9
  27. package/src/com/eduworks/schema/ebac/EbacCredentials.js +3 -9
  28. package/src/com/eduworks/schema/ebac/EbacEncryptedSecret.js +3 -9
  29. package/src/com/eduworks/schema/ebac/EbacEncryptedValue.js +5 -12
  30. package/src/com/eduworks/schema/ebac/EbacSignature.js +1 -6
  31. package/src/index/env.js +6 -3
  32. package/src/index/polyfills.js +13 -27
  33. package/src/org/angles/schema/angles/VideoStory.js +1 -1
  34. package/src/org/cass/competency/EcCompetency.js +1 -2
  35. package/src/org/cass/competency/EcDirectory.js +1 -2
  36. package/src/org/cass/competency/EcFramework.js +9 -12
  37. package/src/org/cass/exporter/CSVExport.js +12 -13
  38. package/src/org/cass/importer/ASNImport.js +3 -6
  39. package/src/org/cass/importer/CSVImport.js +9 -17
  40. package/src/org/cass/importer/CTDLASNCSVConceptImport.js +25 -121
  41. package/src/org/cass/importer/CTDLASNCSVImport.js +88 -133
  42. package/src/org/cass/importer/FrameworkImport.js +16 -30
  43. package/src/org/cass/importer/MedbiqImport.js +3 -4
  44. package/src/org/cass/importer/TabStructuredImport.js +6 -6
  45. package/src/org/cass/profile/EcAssertion.js +40 -51
  46. package/src/org/cassproject/ebac/identity/EcContactGrant.js +2 -2
  47. package/src/org/cassproject/ebac/identity/EcIdentityManager.js +56 -62
  48. package/src/org/cassproject/ebac/identity/EcRekeyRequest.js +3 -2
  49. package/src/org/cassproject/ebac/identity/remote/EcRemoteIdentityManager.js +51 -62
  50. package/src/org/cassproject/ebac/identity/remote/OAuth2FileBasedRemoteIdentityManager.js +56 -70
  51. package/src/org/cassproject/ebac/identity/remote/RemoteIdentityManagerInterface.js +3 -3
  52. package/src/org/cassproject/ebac/repository/EcEncryptedValue.js +51 -44
  53. package/src/org/cassproject/ebac/repository/EcRepository.js +228 -301
  54. package/src/org/cassproject/general/repository/GeneralFile.js +8 -9
  55. package/src/org/cassproject/schema/cass/competency/Competency.js +10 -11
  56. package/src/org/cassproject/schema/cass/competency/Framework.js +10 -11
  57. package/src/org/cassproject/schema/cass/competency/Level.js +10 -11
  58. package/src/org/cassproject/schema/cass/competency/Relation.js +10 -11
  59. package/src/org/cassproject/schema/cass/competency/RollupRule.js +7 -7
  60. package/src/org/cassproject/schema/cass/profile/Assertion.js +20 -27
  61. package/src/org/cassproject/schema/cass/profile/AssertionEnvelope.js +3 -5
  62. package/src/org/cassproject/schema/general/EcRemoteLinkedData.js +41 -44
  63. package/src/org/json/ld/EcLinkedData.js +10 -12
  64. package/src/org/schema/EcOrganization.js +10 -10
  65. package/src/org/schema/EcQuestion.js +8 -8
  66. package/src/org/w3/skos/Concept.js +6 -6
  67. package/src/org/w3/skos/ConceptScheme.js +6 -6
  68. package/src/org/w3/skos/EcConcept.js +1 -2
  69. package/src/org/w3/skos/EcConceptScheme.js +1 -2
  70. package/src/test/0.start.test.js +1 -1
  71. package/src/test/0.testLibraries.test.js +172 -0
  72. package/src/test/1.ASNImport.test.js +122 -0
  73. package/src/test/1.CSVExport.test.js +57 -0
  74. package/src/test/1.CSVImport.test.js +185 -0
  75. package/src/test/1.CTDLASNCSVConceptImport.test.js +348 -0
  76. package/src/test/1.CTDLASNCSVImport.import.test.js +497 -0
  77. package/src/test/1.Ebac.schema.test.js +107 -0
  78. package/src/test/1.EcAssertion.decrypt.test.js +98 -0
  79. package/src/test/1.EcAssertion.pinned.test.js +160 -0
  80. package/src/test/1.EcCrypto.formats.test.js +293 -0
  81. package/src/test/1.EcCrypto.generateUUID.test.js +47 -0
  82. package/src/test/1.EcEncryptedValue.helpers.test.js +236 -0
  83. package/src/test/1.EcHelpers.misc.test.js +259 -0
  84. package/src/test/1.EcIdentityManager.keys.test.js +439 -0
  85. package/src/test/1.EcOrganization.rekey.test.js +68 -0
  86. package/src/test/1.EcRemote.responses.test.js +155 -0
  87. package/src/test/1.EcRemoteIdentityManager.flows.test.js +326 -0
  88. package/src/test/1.EcRemoteLinkedData.pinned.test.js +473 -0
  89. package/src/test/1.EcRepository.l0.test.js +14 -5
  90. package/src/test/1.EcRepository.l1.test.js +16 -7
  91. package/src/test/1.EcRepository.l2.test.js +20 -11
  92. package/src/test/1.EcRepository.unit.test.js +961 -0
  93. package/src/test/1.EcRsaOaep.test.js +2 -12
  94. package/src/test/1.EcRsaOaepAsync.test.js +2 -12
  95. package/src/test/1.EcRsaOaepAsyncWorker.test.js +2 -12
  96. package/src/test/1.EcRsaOaepAsyncWorker.workers.test.js +147 -0
  97. package/src/test/1.FrameworkImport.test.js +170 -0
  98. package/src/test/1.MedbiqImport.test.js +92 -0
  99. package/src/test/1.OAuth2FileBasedRemoteIdentityManager.test.js +399 -0
  100. package/src/test/1.TabStructuredImport.test.js +61 -0
  101. package/src/test/1.polyfills.test.js +89 -0
  102. package/src/test/1.schema.competency.pinned.test.js +384 -0
  103. package/src/test/3.EcFrameworkGraph.test.js +3 -2
  104. package/src/test/4.schema.test.js +33 -28
  105. package/src/test/4.skyId.test.js +4 -2
  106. package/src/test/cypressValue.js +9 -0
  107. package/src/test/2.EcCompetency.test.js +0 -17
@@ -0,0 +1,384 @@
1
+ require("../../index.js");
2
+ const { expect } = require("chai");
3
+ const sinon = require("sinon");
4
+
5
+ const Cass = require("../org/cassproject/schema/cass/Cass.js");
6
+ const General = require("../org/cassproject/schema/general/General.js");
7
+ const EcRepository = require("../org/cassproject/ebac/repository/EcRepository.js");
8
+
9
+ const versioned = [
10
+ ["Competency", () => Competency, 6],
11
+ ["Framework", () => Framework, 6],
12
+ ["Level", () => Level, 6],
13
+ ["Relation", () => Relation, 6],
14
+ ["Assertion", () => Assertion, 6],
15
+ ];
16
+
17
+ describe("Schema classes (pinned getTypes / upgrade)", () => {
18
+ describe("getTypes", () => {
19
+ for (let [name, cls, max] of versioned) {
20
+ it(`${name}.getTypes returns TYPE_0_6 .. TYPE_0_1, newest first, in a fresh array`, () => {
21
+ let C = cls();
22
+ let expected = [];
23
+ for (let i = max; i >= 1; i--) expected.push(C["TYPE_0_" + i]);
24
+ let o = new C();
25
+ let a = o.getTypes();
26
+ expect(a).to.deep.equal(expected);
27
+ expect(o.getTypes()).to.not.equal(a);
28
+ });
29
+ }
30
+ it("RollupRule.getTypes returns TYPE_0_6 .. TYPE_0_2", () => {
31
+ expect(new RollupRule().getTypes()).to.deep.equal([
32
+ RollupRule.TYPE_0_6, RollupRule.TYPE_0_5, RollupRule.TYPE_0_4, RollupRule.TYPE_0_3, RollupRule.TYPE_0_2
33
+ ]);
34
+ });
35
+ it("Concept / ConceptScheme getTypes return TYPE_0_3 .. TYPE_0_1", () => {
36
+ expect(new Concept().getTypes()).to.deep.equal([Concept.TYPE_0_3, Concept.TYPE_0_2, Concept.TYPE_0_1]);
37
+ expect(new ConceptScheme().getTypes()).to.deep.equal([ConceptScheme.TYPE_0_3, ConceptScheme.TYPE_0_2, ConceptScheme.TYPE_0_1]);
38
+ });
39
+ it("GeneralFile.getTypes returns TYPE_0_2, TYPE_0_1", () => {
40
+ expect(new GeneralFile().getTypes()).to.deep.equal([GeneralFile.TYPE_0_2, GeneralFile.TYPE_0_1]);
41
+ });
42
+ });
43
+
44
+ describe("upgrade from 0.1", () => {
45
+ let cases = [
46
+ ["Competency", () => Competency, Cass.context_0_1, Cass.context_0_6],
47
+ ["Framework", () => Framework, Cass.context_0_1, Cass.context_0_6],
48
+ ["Level", () => Level, Cass.context_0_1, Cass.context_0_6],
49
+ ["Relation", () => Relation, Cass.context_0_1, Cass.context_0_6],
50
+ ["Assertion", () => Assertion, Cass.context_0_1, Cass.context_0_6],
51
+ ["GeneralFile", () => GeneralFile, General.context_0_1, General.context_0_2],
52
+ ];
53
+ for (let [name, cls, oldCtx, newCtx] of cases) {
54
+ it(`${name}: copies @schema into @context when @context is missing`, () => {
55
+ let C = cls();
56
+ let o = new C();
57
+ o.context = oldCtx;
58
+ o.type = C.TYPE_0_1;
59
+ o["@schema"] = "SCHEMA";
60
+ o.upgrade();
61
+ expect(o["@context"]).to.equal("SCHEMA");
62
+ expect(o.context).to.equal(newCtx);
63
+ expect(o.getFullType()).to.equal(C.myType);
64
+ let fresh = new C();
65
+ expect(o.type).to.equal(fresh.type);
66
+ });
67
+ it(`${name}: keeps an existing @context and ignores a missing @schema`, () => {
68
+ let C = cls();
69
+ let o = new C();
70
+ o.type = C.TYPE_0_1;
71
+ o["@context"] = "CTX";
72
+ o["@schema"] = "SCHEMA";
73
+ o.upgrade();
74
+ expect(o["@context"]).to.equal("CTX");
75
+ let p = new C();
76
+ p.type = C.TYPE_0_1;
77
+ p.upgrade();
78
+ expect(p["@context"]).to.equal(undefined);
79
+ expect(p.getFullType()).to.equal(C.myType);
80
+ });
81
+ }
82
+ it("Competency: moves url to sameAs only if sameAs is unset", () => {
83
+ let o = new Competency();
84
+ o.type = Competency.TYPE_0_1;
85
+ o.url = "http://u";
86
+ o.upgrade();
87
+ expect(o.sameAs).to.equal("http://u");
88
+ expect(o.url).to.equal(null);
89
+ let p = new Competency();
90
+ p.type = Competency.TYPE_0_1;
91
+ p.url = "http://u";
92
+ p.sameAs = "http://s";
93
+ p.upgrade();
94
+ expect(p.sameAs).to.equal("http://s");
95
+ expect(p.url).to.equal("http://u");
96
+ });
97
+ it("Relation: fixes the isEquivalenTo typo", () => {
98
+ let o = new Relation();
99
+ o.relationType = "isEquivalenTo";
100
+ o.upgrade();
101
+ expect(o.relationType).to.equal(Relation.IS_EQUIVALENT_TO);
102
+ });
103
+ it("RollupRule: upgrades from 0.2", () => {
104
+ let o = new RollupRule();
105
+ o.setContextAndType(Cass.context_0_2, RollupRule.TYPE_0_2);
106
+ o.upgrade();
107
+ expect(o.getFullType()).to.equal(RollupRule.TYPE_0_6);
108
+ expect(o.context).to.equal(Cass.context_0_6);
109
+ });
110
+ it("upgrade from the serialised 0.1 form via copyFrom", () => {
111
+ let o = new Competency().copyFrom({
112
+ "@context": Cass.context_0_1,
113
+ "@type": Competency.TYPE_0_1,
114
+ "@id": "http://x/1",
115
+ url: "http://u",
116
+ });
117
+ expect(o.getFullType()).to.equal(Competency.TYPE_0_6);
118
+ expect(o.sameAs).to.equal("http://u");
119
+ expect(o.url).to.equal(null);
120
+ });
121
+ });
122
+
123
+ describe("Ec* constructors apply the class template", () => {
124
+ let classes = [
125
+ ["EcCompetency", () => EcCompetency],
126
+ ["EcFramework", () => EcFramework],
127
+ ["EcDirectory", () => EcDirectory],
128
+ ["EcConcept", () => EcConcept],
129
+ ["EcConceptScheme", () => EcConceptScheme],
130
+ ];
131
+ for (let [name, cls] of classes) {
132
+ it(`${name}: copies non-function template values, stripping the first @`, () => {
133
+ let C = cls();
134
+ let saved = C.template;
135
+ try {
136
+ C.template = { "@foo": "bar", "x@@y": 1, fn: () => 1, name: "templated" };
137
+ let o = new C();
138
+ expect(o.foo).to.equal("bar");
139
+ expect(o["x@y"]).to.equal(1);
140
+ expect(o.fn).to.equal(undefined);
141
+ expect(o.name).to.equal("templated");
142
+ C.template = null;
143
+ expect(new C().foo).to.equal(undefined);
144
+ } finally {
145
+ C.template = saved;
146
+ }
147
+ });
148
+ }
149
+ });
150
+
151
+ describe("Assertion", () => {
152
+ afterEach(() => sinon.restore());
153
+ let pk = (pem) => ({ toPem: () => pem });
154
+ it("setSubject sets the subject pem and pushes it into reader when no subject readers exist", () => {
155
+ let a = new Assertion();
156
+ a.reader = ["r1"];
157
+ let readers = a.reader;
158
+ a.owner = ["o1"];
159
+ a.setSubject(pk("PEM"));
160
+ expect(a.subject).to.equal("PEM");
161
+ expect(readers).to.deep.equal(["r1", "PEM"]);
162
+ let b = new Assertion();
163
+ b.setSubject(pk("PEM2"));
164
+ expect(b.subject).to.equal("PEM2");
165
+ expect(b.reader).to.equal(null);
166
+ });
167
+ it("setSubject does not mutate reader when the previous subject had readers", () => {
168
+ let a = new Assertion();
169
+ a.reader = ["r1"];
170
+ a.subject = { owner: ["so"], reader: ["sr"] };
171
+ a.setSubject(pk("PEM"));
172
+ expect(a.reader).to.deep.equal(["r1"]);
173
+ expect(a.subject).to.equal("PEM");
174
+ let b = new Assertion();
175
+ b.reader = ["r1"];
176
+ b.subject = { owner: ["so"] };
177
+ b.setSubject(pk("PEM"));
178
+ expect(b.reader).to.deep.equal(["r1", "PEM"]);
179
+ });
180
+ let eim = (identity, contact) => ({
181
+ getIdentity: sinon.stub().returns(identity),
182
+ getContact: sinon.stub().returns(contact),
183
+ });
184
+ let nameCases = [
185
+ [null, null, "Unknown"],
186
+ [{}, null, "Unknown"],
187
+ [{ displayName: "Me" }, null, "Me (You)"],
188
+ [null, {}, "Unknown"],
189
+ [null, { displayName: "Them" }, "Them"],
190
+ [{}, { displayName: "Them" }, "Them"],
191
+ [{ displayName: "Me" }, { displayName: "Them" }, "Me (You)"],
192
+ ];
193
+ for (let [identity, contact, expected] of nameCases) {
194
+ let label = JSON.stringify([identity, contact]);
195
+ it(`getSubjectName / getAgentName ${label}`, () => {
196
+ let a = new Assertion();
197
+ a.subject = "S";
198
+ a.agent = "A";
199
+ sinon.stub(a, "getSubject").returns("SPK");
200
+ sinon.stub(a, "getAgent").returns("APK");
201
+ let e = eim(identity, contact);
202
+ expect(a.getSubjectName(e)).to.equal(expected == "Unknown" ? "Unknown Subject" : expected);
203
+ expect(e.getIdentity.firstCall.args[0]).to.equal("SPK");
204
+ expect(a.getAgentName(e)).to.equal(expected == "Unknown" ? "Unknown Agent" : expected);
205
+ expect(e.getIdentity.secondCall.args[0]).to.equal("APK");
206
+ });
207
+ it(`getSubjectNameAsync / getAgentNameAsync ${label}`, () => {
208
+ let a = new Assertion();
209
+ a.subject = "S";
210
+ a.agent = "A";
211
+ sinon.stub(a, "getSubjectAsync").callsFake((s) => s("SPK"));
212
+ sinon.stub(a, "getAgentAsync").callsFake((s) => s("APK"));
213
+ let e = eim(identity, contact);
214
+ let success = sinon.spy();
215
+ a.getSubjectNameAsync(success, null, e);
216
+ a.getAgentNameAsync(success, null, e);
217
+ expect(success.args).to.deep.equal([
218
+ [expected == "Unknown" ? "Unknown Subject" : expected],
219
+ [expected == "Unknown" ? "Unknown Agent" : expected],
220
+ ]);
221
+ });
222
+ }
223
+ it("name lookups return Nobody without a subject/agent (agent async checks subject)", () => {
224
+ let a = new Assertion();
225
+ let e = eim(null, null);
226
+ expect(a.getSubjectName(e)).to.equal("Nobody");
227
+ expect(a.getAgentName(e)).to.equal("Nobody");
228
+ let success = sinon.spy();
229
+ a.getSubjectNameAsync(success, null, e);
230
+ a.getAgentNameAsync(success, null, e);
231
+ expect(success.args).to.deep.equal([["Nobody"], ["Nobody"]]);
232
+ });
233
+ it("upgrade revives encrypted fields and every evidence entry", () => {
234
+ let a = new Assertion();
235
+ let enc = (payload) => {
236
+ let v = new EcEncryptedValue();
237
+ v.payload = payload;
238
+ return JSON.parse(v.toJson());
239
+ };
240
+ a.evidence = [enc("p1"), enc("p2")];
241
+ a.agent = enc("a");
242
+ a.upgrade();
243
+ expect(a.agent).to.be.instanceOf(EcEncryptedValue);
244
+ expect(a.evidence[0]).to.be.instanceOf(EcEncryptedValue);
245
+ expect(a.evidence[0].payload).to.equal("p1");
246
+ expect(a.evidence[1]).to.be.instanceOf(EcEncryptedValue);
247
+ expect(a.evidence[1].payload).to.equal("p2");
248
+ let b = new Assertion();
249
+ b.upgrade();
250
+ expect(b.evidence).to.equal(null);
251
+ });
252
+ });
253
+
254
+ describe("AssertionEnvelope", () => {
255
+ let ev = (v) => ({ decryptSecret: sinon.stub().resolves(v) });
256
+ it("addAssertion records the decrypted secrets in a codebook", async () => {
257
+ let env = new AssertionEnvelope();
258
+ let eim = {};
259
+ let a = {
260
+ shortId: () => "sid",
261
+ agent: ev("ag"), subject: ev("su"), assertionDate: ev("ad"), expirationDate: ev("ed"),
262
+ decayFunction: ev("df"), negative: ev("ne"),
263
+ evidence: [ev("e1"), ev("e2")],
264
+ };
265
+ await env.addAssertion(a, eim);
266
+ expect(env.assertion).to.deep.equal([a]);
267
+ let cb = env.codebook[0];
268
+ expect(cb).to.be.instanceOf(AssertionCodebook);
269
+ expect(cb.assertionShortId).to.equal("sid");
270
+ expect([cb.agent, cb.subject, cb.assertionDate, cb.expirationDate, cb.decayFunction, cb.negative])
271
+ .to.deep.equal(["ag", "su", "ad", "ed", "df", "ne"]);
272
+ expect(cb.evidence).to.deep.equal(["e1", "e2"]);
273
+ expect(a.evidence[1].decryptSecret.calledWith(eim)).to.equal(true);
274
+ });
275
+ it("addAssertion with no encrypted fields and empty evidence", async () => {
276
+ let env = new AssertionEnvelope();
277
+ await env.addAssertion({ shortId: () => null, evidence: [] });
278
+ let cb = env.codebook[0];
279
+ expect(cb.assertionShortId == null).to.equal(true);
280
+ expect(cb.agent == null).to.equal(true);
281
+ expect(cb.evidence == null).to.equal(true);
282
+ await env.addAssertion({ shortId: () => "b" });
283
+ expect(env.assertion.length).to.equal(2);
284
+ expect(env.codebook.length).to.equal(2);
285
+ });
286
+ it("validate returns false if any assertion is invalid", () => {
287
+ let env = new AssertionEnvelope();
288
+ expect(env.validate()).to.equal(true);
289
+ env.assertion = [{ invalid: () => false }, { invalid: () => false }];
290
+ expect(env.validate()).to.equal(true);
291
+ let third = { invalid: sinon.stub().returns(false) };
292
+ env.assertion = [{ invalid: () => false }, { invalid: () => true }, third];
293
+ expect(env.validate()).to.equal(false);
294
+ expect(third.invalid.called).to.equal(false);
295
+ });
296
+ });
297
+
298
+ describe("EcFramework relationship/level removal", () => {
299
+ afterEach(() => sinon.restore());
300
+ it("removeRelationshipsThatInclude removes matching relations and then calls success", async () => {
301
+ let f = new EcFramework();
302
+ f.relation = ["r1", "r2", "r3", "r4"];
303
+ let rels = {
304
+ r1: { source: "http://x/api/data/c/1", target: "x" },
305
+ r2: { source: "y", target: "z" },
306
+ r3: { source: "y", target: "http://x/api/data/c/1/123" },
307
+ r4: null,
308
+ };
309
+ sinon.stub(EcAlignment, "get").callsFake(async (id, s, fail) => {
310
+ if (id == "r4") return fail("missing");
311
+ return s(rels[id]);
312
+ });
313
+ let success = sinon.spy();
314
+ await f.removeRelationshipsThatInclude("http://x/api/data/c/1/123", 0, success, null);
315
+ expect(f.relation).to.deep.equal(["r2", "r4"]);
316
+ expect(success.calledOnceWithExactly("")).to.equal(true);
317
+ });
318
+ it("removeLevelsThatInclude removes matching levels and then calls success", async () => {
319
+ let f = new EcFramework();
320
+ f.level = ["l1", "l2", "l3"];
321
+ let levels = { l1: { competency: "http://c/1" }, l2: { competency: "http://c/2" }, l3: null };
322
+ sinon.stub(EcLevel, "get").callsFake(async (id, s, fail) => {
323
+ if (id == "l3") return fail("missing");
324
+ return s(levels[id]);
325
+ });
326
+ let success = sinon.spy();
327
+ await f.removeLevelsThatInclude("http://c/1", 0, success, null);
328
+ expect(f.level).to.deep.equal(["l2", "l3"]);
329
+ expect(success.calledOnceWithExactly("")).to.equal(true);
330
+ });
331
+ });
332
+
333
+ describe("CfdFramework._delete", () => {
334
+ afterEach(() => sinon.restore());
335
+ it("deletes the framework once every competency and relation was processed", () => {
336
+ let f = new CfdFramework();
337
+ f.id = "http://f/1";
338
+ f.competency = ["c1", "c2"];
339
+ f.relation = ["r1", "r2"];
340
+ let del = sinon.stub(EcRepository, "DELETE");
341
+ sinon.stub(CfdCompetency, "get").callsFake((id, s, fail) => {
342
+ if (id == "c1") s({ id, _delete: (ok) => ok() });
343
+ else s({ id, _delete: (ok, ko) => ko("nope") });
344
+ });
345
+ sinon.stub(EcAlignment, "get").callsFake((id, s, fail) => {
346
+ if (id == "r1") s({ id, _delete: (ok) => ok() });
347
+ else fail("gone");
348
+ });
349
+ let success = () => { }, failure = sinon.spy();
350
+ f._delete(success, failure, "REPO", "EIM");
351
+ expect(failure.args).to.deep.equal([
352
+ ["Error deleting competency (c2): nope"],
353
+ ["Error retrieving relationship to delete: gone"],
354
+ ]);
355
+ // Pinned: when every callback fires synchronously the framework is DELETEd twice.
356
+ expect(del.callCount).to.equal(2);
357
+ expect(del.firstCall.args).to.deep.equal([f, success, failure, "REPO", "EIM"]);
358
+ expect(CfdFramework.removed[f.shortId()]).to.equal(4);
359
+ expect(CfdFramework.toRemove[f.shortId()]).to.equal(4);
360
+ });
361
+ it("deletes immediately (twice) when there is nothing to remove", () => {
362
+ let f = new CfdFramework();
363
+ f.id = "http://f/2";
364
+ let del = sinon.stub(EcRepository, "DELETE");
365
+ f._delete(null, null);
366
+ expect(del.callCount).to.equal(2);
367
+ });
368
+ it("waits for async callbacks before deleting", () => {
369
+ let f = new CfdFramework();
370
+ f.id = "http://f/3";
371
+ f.competency = ["c1"];
372
+ let del = sinon.stub(EcRepository, "DELETE");
373
+ let pending = null;
374
+ sinon.stub(CfdCompetency, "get").callsFake((id, s, fail) => { pending = fail; });
375
+ let failure = sinon.spy();
376
+ f._delete(null, failure);
377
+ expect(del.called).to.equal(false);
378
+ pending("x");
379
+ expect(failure.args).to.deep.equal([["Error retrieving competency to delete: x"]]);
380
+ expect(del.calledOnce).to.equal(true);
381
+ expect(del.firstCall.args[0]).to.equal(f);
382
+ });
383
+ });
384
+ });
@@ -1,3 +1,4 @@
1
+ const cypressValue = require('./cypressValue.js');
1
2
  const EcPk = require("../com/eduworks/ec/crypto/EcPk.js");
2
3
  const EcPpk = require("../com/eduworks/ec/crypto/EcPpk.js");
3
4
  const EcAes = require("../com/eduworks/ec/crypto/EcAes.js");
@@ -134,8 +135,8 @@ describe("EcFrameworkGraph", () => {
134
135
  it('init', async () => {
135
136
  let newId1, newId2;
136
137
  EcIdentityManager.default.clearIdentities();
137
- if ((typeof Cypress !== 'undefined') && Cypress?.env != null)
138
- process.env.CASS_LOOPBACK = Cypress.env('CASS_LOOPBACK');
138
+ if ((typeof Cypress !== 'undefined') && Cypress != null)
139
+ process.env.CASS_LOOPBACK = cypressValue('CASS_LOOPBACK');
139
140
  console.log(process.env.CASS_LOOPBACK);
140
141
  await repo.init(process.env.CASS_LOOPBACK || "http://localhost/api/", null, null, console.log);
141
142
  newId1 = null;
@@ -24,6 +24,9 @@ const EbacEncryptedValue = require("../com/eduworks/schema/ebac/EbacEncryptedVal
24
24
  global.EcRemoteLinkedData = require("../org/cassproject/schema/general/EcRemoteLinkedData.js");
25
25
  global.ce = {};
26
26
  global.ce.Agent = require("../org/credentialengine/Agent.js");
27
+ // Normally registered by EarningsProfile.js when it is first loaded, which may already
28
+ // have happened in an earlier test file.
29
+ global.ce.AggregateDataProfile = require("../org/credentialengine/AggregateDataProfile.js");
27
30
  global.ce.AlignmentMap = require("../org/credentialengine/AlignmentMap.js");
28
31
  global.ce.Assessment = require("../org/credentialengine/Assessment.js");
29
32
  global.ce.Competency = require("../org/credentialengine/Competency.js");
@@ -1534,32 +1537,34 @@ describe("S3000L", () => {
1534
1537
  }
1535
1538
  });
1536
1539
  describe("EBAC", () => {
1537
- let e = new EbacCredential();
1538
- e.upgrade();
1539
- e.getTypes();
1540
- e = new EbacCredentialCommit();
1541
- e.upgrade();
1542
- e.getTypes();
1543
- e = new EbacCredentialRequest();
1544
- e.upgrade();
1545
- e.getTypes();
1546
- e = new EbacCredentials();
1547
- e.upgrade();
1548
- e.getTypes();
1549
- e = new EbacEncryptedSecret();
1550
- e.upgrade();
1551
- e.getTypes();
1552
- e.iv = e.id = e.secret = e.field = 'v';
1553
- e = EbacEncryptedSecret.fromEncryptableJson(JSON.parse(e.toEncryptableJson()));
1554
- assert.equal(e.iv, 'v');
1555
- assert.equal(e.id, 'v');
1556
- assert.equal(e.secret, 'v');
1557
- assert.equal(e.field, 'v');
1558
- e.iv = e.secret = 'v';
1559
- e = EbacEncryptedSecret.fromEncryptableJson(JSON.parse(e.toEncryptableJson()));
1560
- assert.equal(e.iv, 'v');
1561
- assert.equal(e.secret, 'v');
1562
- e = new EbacEncryptedValue();
1563
- e.upgrade();
1564
- e.getTypes();
1540
+ it("upgrades and round-trips encrypted secrets", () => {
1541
+ let e = new EbacCredential();
1542
+ e.upgrade();
1543
+ e.getTypes();
1544
+ e = new EbacCredentialCommit();
1545
+ e.upgrade();
1546
+ e.getTypes();
1547
+ e = new EbacCredentialRequest();
1548
+ e.upgrade();
1549
+ e.getTypes();
1550
+ e = new EbacCredentials();
1551
+ e.upgrade();
1552
+ e.getTypes();
1553
+ e = new EbacEncryptedSecret();
1554
+ e.upgrade();
1555
+ e.getTypes();
1556
+ e.iv = e.id = e.secret = e.field = 'v';
1557
+ e = EbacEncryptedSecret.fromEncryptableJson(JSON.parse(e.toEncryptableJson()));
1558
+ assert.equal(e.iv, 'v');
1559
+ assert.equal(e.id, 'v');
1560
+ assert.equal(e.secret, 'v');
1561
+ assert.equal(e.field, 'v');
1562
+ e.iv = e.secret = 'v';
1563
+ e = EbacEncryptedSecret.fromEncryptableJson(JSON.parse(e.toEncryptableJson()));
1564
+ assert.equal(e.iv, 'v');
1565
+ assert.equal(e.secret, 'v');
1566
+ e = new EbacEncryptedValue();
1567
+ e.upgrade();
1568
+ e.getTypes();
1569
+ });
1565
1570
  });
@@ -1,3 +1,4 @@
1
+ const cypressValue = require('./cypressValue.js');
1
2
  let chai = require('chai');
2
3
  const EcAes = require('../com/eduworks/ec/crypto/EcAes');
3
4
  const EcPpk = require('../com/eduworks/ec/crypto/EcPpk');
@@ -14,8 +15,8 @@ describe('SkyID Adapter', function() {
14
15
  let newPassword = EcAes.newSecret(6);
15
16
  let name = 'Test User';
16
17
  let ident = null;
17
- if ((typeof Cypress !== 'undefined') && Cypress != null && Cypress.env != null)
18
- process.env.CASS_LOOPBACK = Cypress.env('CASS_LOOPBACK');
18
+ if ((typeof Cypress !== 'undefined') && Cypress != null)
19
+ process.env.CASS_LOOPBACK = cypressValue('CASS_LOOPBACK');
19
20
  console.log(process.env.CASS_LOOPBACK);
20
21
 
21
22
  it('create user', async () => {
@@ -30,6 +31,7 @@ describe('SkyID Adapter', function() {
30
31
  ident.ppk = await EcPpk.generateKeyAsync(null, null);
31
32
  ident.displayName = name;
32
33
  im.addIdentity(ident);
34
+ assert.include(im.ids, ident);
33
35
  await rld.commit(null, null, im);
34
36
  }).timeout(30000);
35
37
 
@@ -0,0 +1,9 @@
1
+ // Reads a value passed to Cypress on the command line, or undefined outside Cypress.
2
+ // Cypress 16 removed Cypress.env() in favour of Cypress.expose() (set with -x/--expose);
3
+ // older versions only have Cypress.env() (set with -e/--env).
4
+ module.exports = function cypressValue(key) {
5
+ if (typeof Cypress === 'undefined' || Cypress == null) return undefined;
6
+ if (typeof Cypress.expose === 'function') return Cypress.expose(key);
7
+ if (typeof Cypress.env === 'function') return Cypress.env(key);
8
+ return undefined;
9
+ };
@@ -1,17 +0,0 @@
1
- const chai = require('chai');
2
- const sinon = require('sinon');
3
- const EcCompetency = require('../org/cass/competency/EcCompetency');
4
- const EcRepository = require('../org/cassproject/ebac/repository/EcRepository');
5
- const EcAlignment = require('../org/cass/competency/EcAlignment');
6
- const EcRollupRule = require('../org/cass/competency/EcRollupRule');
7
- const EcLevel = require('../org/cass/competency/EcLevel');
8
- const EcPpk = require('../com/eduworks/ec/crypto/EcPpk');
9
-
10
- const expect = chai.expect;
11
-
12
- describe('EcCompetency', async function () {
13
- let competency;
14
-
15
- const repo = new EcRepository();
16
- await repo.init(process.env.CASS_LOOPBACK || "http://localhost/api/");
17
- });