@adobe/acc-js-sdk 1.0.3 → 1.0.7
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/.github/workflows/codeql-analysis.yml +70 -0
- package/.vscode/launch.json +0 -1
- package/CHANGELOG.md +37 -1
- package/README.md +63 -3
- package/compile.js +2 -0
- package/package-lock.json +2438 -3367
- package/package.json +10 -7
- package/samples/002 - basics - schemas.js +3 -3
- package/samples/020 - encryption.js +5 -5
- package/src/application.js +66 -5
- package/src/cache.js +275 -0
- package/src/campaign.js +35 -22
- package/src/client.js +246 -125
- package/src/crypto.js +5 -2
- package/src/domUtil.js +53 -20
- package/src/entityAccessor.js +4 -2
- package/src/index.js +107 -105
- package/src/methodCache.js +55 -46
- package/src/optionCache.js +40 -28
- package/src/soap.js +53 -23
- package/src/transport.js +11 -7
- package/src/util.js +103 -64
- package/src/xtkCaster.js +66 -11
- package/src/xtkEntityCache.js +42 -24
- package/test/application.test.js +40 -1
- package/test/caches.test.js +214 -14
- package/test/client.test.js +485 -30
- package/test/crypto.test.js +16 -12
- package/test/domUtil.test.js +23 -0
- package/test/mock.js +52 -10
- package/test/soap.test.js +13 -6
- package/test/util.test.js +151 -1
- package/test/xtkCaster.test.js +97 -0
package/src/xtkEntityCache.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/*
|
|
3
2
|
Copyright 2020 Adobe. All rights reserved.
|
|
4
3
|
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
@@ -10,7 +9,11 @@ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTA
|
|
|
10
9
|
OF ANY KIND, either express or implied. See the License for the specific language
|
|
11
10
|
governing permissions and limitations under the License.
|
|
12
11
|
*/
|
|
12
|
+
(function() {
|
|
13
|
+
"use strict";
|
|
14
|
+
|
|
13
15
|
const DomUtil = require('./domUtil.js').DomUtil;
|
|
16
|
+
const { Cache } = require('./cache.js');
|
|
14
17
|
|
|
15
18
|
|
|
16
19
|
/**********************************************************************************
|
|
@@ -19,14 +22,40 @@ const DomUtil = require('./domUtil.js').DomUtil;
|
|
|
19
22
|
*
|
|
20
23
|
*********************************************************************************/
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
/**
|
|
26
|
+
* @private
|
|
27
|
+
* @class
|
|
28
|
+
* @constructor
|
|
29
|
+
* @memberof Campaign
|
|
30
|
+
*/
|
|
31
|
+
class XtkEntityCache extends Cache {
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
/**
|
|
34
|
+
* A in-memory cache for xtk entities. Not intended to be used directly,
|
|
35
|
+
* but an internal cache for the Campaign.Client object.
|
|
36
|
+
*
|
|
37
|
+
* Cached object are made of
|
|
38
|
+
* - the key is a string in the form <entityType>|<entityName>, such as "xtk:schema|nms:recipient"
|
|
39
|
+
* - the value is a DOM element corresponding to the entity. It's always a DOM element, regardless of the client representation
|
|
40
|
+
*
|
|
41
|
+
* @param {Storage} storage is an optional Storage object, such as localStorage or sessionStorage
|
|
42
|
+
* @param {string} rootKey is an optional root key to use for the storage object
|
|
43
|
+
* @param {number} ttl is the TTL for objects in ms. Defaults to 5 mins
|
|
44
|
+
*/
|
|
45
|
+
constructor(storage, rootKey, ttl) {
|
|
46
|
+
super(storage, rootKey, ttl, (entityType, entityFullName) => entityType + "|" + entityFullName, (item, serDeser) => {
|
|
47
|
+
if (serDeser) {
|
|
48
|
+
if (!item || !item.value) throw Error(`Cannot serialize falsy cached item`);
|
|
49
|
+
const value = Object.assign({}, item);
|
|
50
|
+
value.value = DomUtil.toXMLString(item.value);
|
|
51
|
+
return JSON.stringify(value);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
const json = JSON.parse(item);
|
|
55
|
+
json.value = DomUtil.parse(json.value).documentElement;
|
|
56
|
+
return json;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
30
59
|
}
|
|
31
60
|
|
|
32
61
|
/**
|
|
@@ -36,9 +65,7 @@ class XtkEntityCache {
|
|
|
36
65
|
* @returns {*} the cached entity, or undefined if not found
|
|
37
66
|
*/
|
|
38
67
|
get(entityType, entityFullName) {
|
|
39
|
-
|
|
40
|
-
var entity = this.cache[key]
|
|
41
|
-
return entity;
|
|
68
|
+
return super.get(entityType, entityFullName);
|
|
42
69
|
}
|
|
43
70
|
|
|
44
71
|
/**
|
|
@@ -48,31 +75,22 @@ class XtkEntityCache {
|
|
|
48
75
|
* @param {*} entity is the entity
|
|
49
76
|
*/
|
|
50
77
|
put(entityType, entityFullName, entity) {
|
|
51
|
-
|
|
52
|
-
this.cache[key] = entity;
|
|
53
|
-
|
|
78
|
+
super.put(entityType, entityFullName, entity);
|
|
54
79
|
// For schemas, cache interfaces
|
|
55
80
|
if (entityType == "xtk:schema") {
|
|
56
81
|
const namespace = entity.getAttribute("namespace");
|
|
57
82
|
var interfaceElement = DomUtil.getFirstChildElement(entity, "interface");
|
|
58
83
|
while (interfaceElement) {
|
|
59
84
|
const name = `${namespace}:${interfaceElement.getAttribute("name")}`;
|
|
60
|
-
|
|
61
|
-
this.cache[key] = interfaceElement;
|
|
85
|
+
super.put(entityType, name, interfaceElement);
|
|
62
86
|
interfaceElement = DomUtil.getNextSiblingElement(interfaceElement, "interface");
|
|
63
87
|
}
|
|
64
88
|
}
|
|
65
89
|
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Clears the cache
|
|
69
|
-
*/
|
|
70
|
-
clear() {
|
|
71
|
-
this.cache = {};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
90
|
}
|
|
75
91
|
|
|
76
92
|
|
|
77
93
|
// Public exports
|
|
78
94
|
exports.XtkEntityCache = XtkEntityCache;
|
|
95
|
+
|
|
96
|
+
})();
|
package/test/application.test.js
CHANGED
|
@@ -290,7 +290,10 @@ describe('Schemas', function() {
|
|
|
290
290
|
<value name="prospect" label="Prospect" value="0" img=""/>
|
|
291
291
|
<value name="customer" label="Client" value="1" img=""/>
|
|
292
292
|
</enumeration>
|
|
293
|
-
<element name='recipient' label='Recipients'
|
|
293
|
+
<element name='recipient' label='Recipients'>
|
|
294
|
+
<attribute advanced="true" desc="Recipient sex" enum="nms:recipient:gender"
|
|
295
|
+
label="Gender" name="gender" sqlname="iGender" type="byte"/>
|
|
296
|
+
</element>
|
|
294
297
|
</schema>`);
|
|
295
298
|
var schema = newSchema(xml);
|
|
296
299
|
var enumerations = schema.enumerations;
|
|
@@ -303,6 +306,7 @@ describe('Schemas', function() {
|
|
|
303
306
|
// at least one img attribute
|
|
304
307
|
expect(enumerations.status2.name).toBe("status2");
|
|
305
308
|
expect(enumerations.status2.hasImage).toBe(false);
|
|
309
|
+
expect(schema.root.children["@gender"].enum).toBe("nms:recipient:gender");
|
|
306
310
|
})
|
|
307
311
|
|
|
308
312
|
it("Should list enumeration values", () => {
|
|
@@ -383,6 +387,41 @@ describe('Schemas', function() {
|
|
|
383
387
|
})
|
|
384
388
|
});
|
|
385
389
|
|
|
390
|
+
describe("Link", () => {
|
|
391
|
+
it("Should have a link element", () => {
|
|
392
|
+
var xml = DomUtil.parse(`<schema namespace='nms' name='recipient'>
|
|
393
|
+
<element name='recipient' label='Recipients'>
|
|
394
|
+
<element integrity="neutral" label="Info on the email" name="emailInfo"
|
|
395
|
+
target="nms:address" type="link" unbound="true">
|
|
396
|
+
<join xpath-dst="@address" xpath-src="@email"/>
|
|
397
|
+
<join xpath-dst="@dst" xpath-src="@source"/>
|
|
398
|
+
</element>
|
|
399
|
+
</element>
|
|
400
|
+
</schema>`);
|
|
401
|
+
var schema = newSchema(xml);
|
|
402
|
+
var link = schema.root.children["emailInfo"];
|
|
403
|
+
expect(link.target).toBe("nms:address");
|
|
404
|
+
expect(link.integrity).toBe("neutral");
|
|
405
|
+
expect(link.isUnbound()).toBe(true);
|
|
406
|
+
expect(link.joins.length).toBe(2);
|
|
407
|
+
expect(link.joins[0].dst).toBe("@address");
|
|
408
|
+
expect(link.joins[0].src).toBe("@email");
|
|
409
|
+
|
|
410
|
+
xml = DomUtil.parse(`<schema namespace='nms' name='recipient'>
|
|
411
|
+
<element name='recipient' label='Recipients'>
|
|
412
|
+
<element integrity="neutral" label="Info on the email" name="emailInfo"
|
|
413
|
+
target="nms:address" type="link">
|
|
414
|
+
<join xpath-dst="@address" xpath-src="@email"/>
|
|
415
|
+
<join xpath-dst="@dst" xpath-src="@source"/>
|
|
416
|
+
</element>
|
|
417
|
+
</element>
|
|
418
|
+
</schema>`);
|
|
419
|
+
schema = newSchema(xml);
|
|
420
|
+
link = schema.root.children["emailInfo"];
|
|
421
|
+
expect(link.isUnbound()).toBe(false);
|
|
422
|
+
})
|
|
423
|
+
})
|
|
424
|
+
|
|
386
425
|
describe("getnodepath", () => {
|
|
387
426
|
var xml = DomUtil.parse(`<schema namespace='nms' name='recipient'>
|
|
388
427
|
<element name='recipient' label='Recipients'>
|
package/test/caches.test.js
CHANGED
|
@@ -18,6 +18,7 @@ governing permissions and limitations under the License.
|
|
|
18
18
|
*********************************************************************************/
|
|
19
19
|
|
|
20
20
|
const assert = require('assert');
|
|
21
|
+
const { Cache, SafeStorage } = require('../src/cache.js');
|
|
21
22
|
const OptionCache = require('../src/optionCache.js').OptionCache;
|
|
22
23
|
const MethodCache = require('../src/methodCache.js').MethodCache;
|
|
23
24
|
const XtkEntityCache = require('../src/xtkEntityCache.js').XtkEntityCache;
|
|
@@ -25,6 +26,36 @@ const { DomUtil } = require('../src/domUtil.js');
|
|
|
25
26
|
|
|
26
27
|
describe('Caches', function() {
|
|
27
28
|
|
|
29
|
+
describe("Generic cache", () => {
|
|
30
|
+
it("Should cache with default TTL and default key function", () => {
|
|
31
|
+
const cache = new Cache();
|
|
32
|
+
cache.put("Hello", "World");
|
|
33
|
+
expect(cache.get("Hello")).toBe("World");
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it("Should expires after TTL", () => {
|
|
37
|
+
const cache = new Cache(undefined, undefined, -1); // negative TTL => will immediately expire
|
|
38
|
+
cache.put("Hello", "World");
|
|
39
|
+
expect(cache.get("Hello")).toBeUndefined();
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it("Should support custom key function", () => {
|
|
43
|
+
const cache = new Cache(undefined, undefined, 300000, ((a, b) => a + "||" + b));
|
|
44
|
+
cache.put("key-part-1", "key-part-2", "value");
|
|
45
|
+
expect(cache.get("key-part-1")).toBeUndefined();
|
|
46
|
+
expect(cache.get("key-part-2")).toBeUndefined();
|
|
47
|
+
expect(cache.get("key-part-1", "key-part-2")).toBe("value");
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it("Should clear cache", () => {
|
|
51
|
+
const cache = new Cache();
|
|
52
|
+
cache.put("Hello", "World");
|
|
53
|
+
expect(cache.get("Hello")).toBe("World");
|
|
54
|
+
cache.clear();
|
|
55
|
+
expect(cache.get("Hello")).toBeUndefined();
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
|
|
28
59
|
describe("Entity cache", function() {
|
|
29
60
|
it("Should cache value", function() {
|
|
30
61
|
const cache = new XtkEntityCache();
|
|
@@ -55,15 +86,15 @@ describe('Caches', function() {
|
|
|
55
86
|
it("Should cache value", function() {
|
|
56
87
|
const cache = new OptionCache();
|
|
57
88
|
expect(cache.get("hello")).toBeUndefined();
|
|
58
|
-
cache.
|
|
89
|
+
cache.put("hello", ["world", 6]);
|
|
59
90
|
expect(cache.get("hello")).toBe("world");
|
|
60
91
|
expect(cache.getOption("hello")).toEqual({"rawValue": "world", "type": 6, "value": "world"});
|
|
61
92
|
});
|
|
62
93
|
|
|
63
94
|
it("Should cache multiple value", function() {
|
|
64
95
|
const cache = new OptionCache();
|
|
65
|
-
cache.
|
|
66
|
-
cache.
|
|
96
|
+
cache.put("hello", ["world", 6]);
|
|
97
|
+
cache.put("foo", ["bar", 6]);
|
|
67
98
|
expect(cache.get("hello")).toBe("world");
|
|
68
99
|
expect(cache.getOption("hello")).toEqual({"rawValue": "world", "type": 6, "value": "world"});
|
|
69
100
|
expect(cache.get("foo")).toBe("bar");
|
|
@@ -72,17 +103,17 @@ describe('Caches', function() {
|
|
|
72
103
|
|
|
73
104
|
it("Should overwrite cached value", function() {
|
|
74
105
|
const cache = new OptionCache();
|
|
75
|
-
cache.
|
|
106
|
+
cache.put("hello", ["world", 6]);
|
|
76
107
|
expect(cache.get("hello")).toBe( "world");
|
|
77
108
|
expect(cache.getOption("hello")).toEqual({"rawValue": "world", "type": 6, "value": "world"});
|
|
78
|
-
cache.
|
|
109
|
+
cache.put("hello", ["cruel world", 6]);
|
|
79
110
|
expect(cache.get("hello")).toBe("cruel world");
|
|
80
111
|
expect(cache.getOption("hello")).toEqual({"rawValue": "cruel world", "type": 6, "value": "cruel world"});
|
|
81
112
|
});
|
|
82
113
|
|
|
83
114
|
it("Should clear cache", function() {
|
|
84
115
|
const cache = new OptionCache();
|
|
85
|
-
cache.
|
|
116
|
+
cache.put("hello", ["world", 6]);
|
|
86
117
|
expect(cache.get("hello")).toBe("world");
|
|
87
118
|
expect(cache.getOption("hello")).toEqual({"rawValue": "world", "type": 6, "value": "world"});
|
|
88
119
|
cache.clear();
|
|
@@ -96,13 +127,19 @@ describe('Caches', function() {
|
|
|
96
127
|
expect(cache.getOption("hello")).toBeUndefined();
|
|
97
128
|
});
|
|
98
129
|
|
|
130
|
+
it("Deprecated cache methods should now replaced with put", () => {
|
|
131
|
+
const cache = new OptionCache();
|
|
132
|
+
cache.cache("hello", ["world", 6]);
|
|
133
|
+
expect(cache.get("hello")).toBe("world");
|
|
134
|
+
expect(cache.getOption("hello")).toEqual({"rawValue": "world", "type": 6, "value": "world"});
|
|
135
|
+
});
|
|
99
136
|
});
|
|
100
137
|
|
|
101
138
|
describe("Method cache", function() {
|
|
102
139
|
it("Should cache methods", function() {
|
|
103
140
|
const cache = new MethodCache();
|
|
104
141
|
var schema = DomUtil.parse("<schema namespace='nms' name='recipient'><methods><method name='Delete'/><method name='Create'/></methods></schema>");
|
|
105
|
-
cache.
|
|
142
|
+
cache.put(schema.documentElement);
|
|
106
143
|
|
|
107
144
|
var found = cache.get("nms:recipient", "Delete");
|
|
108
145
|
assert.ok(found !== null && found !== undefined);
|
|
@@ -118,7 +155,7 @@ describe('Caches', function() {
|
|
|
118
155
|
it("Should cache interface methods", function() {
|
|
119
156
|
const cache = new MethodCache();
|
|
120
157
|
var schema = DomUtil.parse("<schema namespace='nms' name='recipient' implements='nms:i'><interface name='i'><method name='Update'/></interface><element name='recipient'/><methods><method name='Delete'/><method name='Create'/></methods></schema>");
|
|
121
|
-
cache.
|
|
158
|
+
cache.put(schema.documentElement);
|
|
122
159
|
// interface method should be on schema
|
|
123
160
|
var found = cache.get("nms:recipient", "Update");
|
|
124
161
|
assert.ok(found !== null && found !== undefined);
|
|
@@ -127,10 +164,10 @@ describe('Caches', function() {
|
|
|
127
164
|
assert.ok(found !== null && found !== undefined);
|
|
128
165
|
});
|
|
129
166
|
|
|
130
|
-
it("Should
|
|
167
|
+
it("Should clear the cache", function() {
|
|
131
168
|
const cache = new MethodCache();
|
|
132
169
|
var schema = DomUtil.parse("<schema namespace='nms' name='recipient'><methods><method name='Delete'/><method name='Create'/></methods></schema>");
|
|
133
|
-
cache.
|
|
170
|
+
cache.put(schema.documentElement);
|
|
134
171
|
|
|
135
172
|
var found = cache.get("nms:recipient", "Delete");
|
|
136
173
|
assert.ok(found !== null && found !== undefined);
|
|
@@ -143,7 +180,7 @@ describe('Caches', function() {
|
|
|
143
180
|
it("Should ignore non-method nodes", function() {
|
|
144
181
|
const cache = new MethodCache();
|
|
145
182
|
var schema = DomUtil.parse("<schema namespace='nms' name='recipient'><methods><method name='Delete'/><dummy name='Update'/><method name='Create'/></methods></schema>");
|
|
146
|
-
cache.
|
|
183
|
+
cache.put(schema.documentElement);
|
|
147
184
|
|
|
148
185
|
var found = cache.get("nms:recipient", "Delete");
|
|
149
186
|
assert.ok(found !== null && found !== undefined);
|
|
@@ -152,6 +189,33 @@ describe('Caches', function() {
|
|
|
152
189
|
found = cache.get("nms:recipient", "Create");
|
|
153
190
|
assert.ok(found !== null && found !== undefined);
|
|
154
191
|
});
|
|
192
|
+
|
|
193
|
+
it("Deprecated cache methods should now replaced with put", () => {
|
|
194
|
+
const cache = new MethodCache();
|
|
195
|
+
var schema = DomUtil.parse("<schema namespace='nms' name='recipient'><methods><method name='Delete'/><method name='Create'/></methods></schema>");
|
|
196
|
+
cache.cache(schema.documentElement);
|
|
197
|
+
|
|
198
|
+
var found = cache.get("nms:recipient", "Delete");
|
|
199
|
+
assert.ok(found !== null && found !== undefined);
|
|
200
|
+
assert.equal(found.nodeName, "method");
|
|
201
|
+
assert.equal(found.getAttribute("name"), "Delete");
|
|
202
|
+
|
|
203
|
+
found = cache.get("nms:recipient", "Create");
|
|
204
|
+
assert.ok(found !== null && found !== undefined);
|
|
205
|
+
assert.equal(found.nodeName, "method");
|
|
206
|
+
assert.equal(found.getAttribute("name"), "Create");
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
it("Deserialized method should be a DOM element", () => {
|
|
210
|
+
const cache = new MethodCache();
|
|
211
|
+
const serDeser = cache._storage._serDeser;
|
|
212
|
+
const cached = {value: { x:3, method:DomUtil.parse("<hello/>")} };
|
|
213
|
+
const serialized = serDeser(cached, true);
|
|
214
|
+
const deserialized = serDeser(serialized, false);
|
|
215
|
+
const method = deserialized.value.method;
|
|
216
|
+
// should be a DOM element, not a DOM document
|
|
217
|
+
expect(method.nodeType).toBe(1);
|
|
218
|
+
})
|
|
155
219
|
});
|
|
156
220
|
|
|
157
221
|
describe("Method cache for interfaces", function() {
|
|
@@ -160,7 +224,7 @@ describe('Caches', function() {
|
|
|
160
224
|
// Test for fix in verion 0.1.23. The xtk:session schema has a direct method "Logon" but also implements the
|
|
161
225
|
// xtk:persist interface.
|
|
162
226
|
var schema = DomUtil.parse("<schema namespace='xtk' name='session' implements='xtk:persist'><interface name='persist'><method name='Write' static='true'/></interface><methods><method name='Logon'/></methods></schema>");
|
|
163
|
-
cache.
|
|
227
|
+
cache.put(schema.documentElement);
|
|
164
228
|
|
|
165
229
|
// Logon method should be found in xtk:session and have the xtk:session URN (for SOAP action)
|
|
166
230
|
var found = cache.get("xtk:session", "Logon");
|
|
@@ -196,7 +260,7 @@ describe('Caches', function() {
|
|
|
196
260
|
it("Edge cases for getSoapUrn", () => {
|
|
197
261
|
const cache = new MethodCache();
|
|
198
262
|
var schema = DomUtil.parse("<schema namespace='xtk' name='session' implements='xtk:persist'><interface name='persist'><method name='Write' static='true'/></interface><methods><method name='Logon'/></methods></schema>");
|
|
199
|
-
cache.
|
|
263
|
+
cache.put(schema.documentElement);
|
|
200
264
|
|
|
201
265
|
// Schema and method exist
|
|
202
266
|
var urn = cache.getSoapUrn("xtk:session", "Logon");
|
|
@@ -215,7 +279,7 @@ describe('Caches', function() {
|
|
|
215
279
|
const cache = new MethodCache();
|
|
216
280
|
// Schema has xtk:persist interface but does not implement it
|
|
217
281
|
var schema = DomUtil.parse("<schema namespace='xtk' name='session'><interface name='persist'><method name='Write' static='true'/></interface><methods><method name='Logon'/></methods></schema>");
|
|
218
|
-
cache.
|
|
282
|
+
cache.put(schema.documentElement);
|
|
219
283
|
|
|
220
284
|
// Logon method should be found in xtk:session and have the xtk:session URN (for SOAP action)
|
|
221
285
|
var found = cache.get("xtk:session", "Logon");
|
|
@@ -226,4 +290,140 @@ describe('Caches', function() {
|
|
|
226
290
|
assert.strictEqual(urn, "xtk:session");
|
|
227
291
|
});
|
|
228
292
|
});
|
|
293
|
+
|
|
294
|
+
describe("SafeStorage", () => {
|
|
295
|
+
|
|
296
|
+
describe("JSON safe storage", () => {
|
|
297
|
+
|
|
298
|
+
it("Should find mock json from the cache", () => {
|
|
299
|
+
const map = {};
|
|
300
|
+
const delegate = {
|
|
301
|
+
getItem: jest.fn((key) => map[key]),
|
|
302
|
+
setItem: jest.fn((key, value) => map[key] = value)
|
|
303
|
+
}
|
|
304
|
+
const storage = new SafeStorage(delegate, "");
|
|
305
|
+
expect(storage.getItem("not_found")).toBeUndefined();
|
|
306
|
+
map["k1"] = `{ "hello": "world" }`;
|
|
307
|
+
expect(storage.getItem("k1")).toMatchObject({ hello: "world" });
|
|
308
|
+
map["k2"] = `{ "value": { "hello": "world" } }`;
|
|
309
|
+
expect(storage.getItem("k2")).toMatchObject({ value: { hello: "world" } });
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
describe("XML safe storage", () => {
|
|
314
|
+
|
|
315
|
+
const xmlSerDeser = (item, serDeser) => {
|
|
316
|
+
if (serDeser) {
|
|
317
|
+
const xml = DomUtil.toXMLString(item.value);
|
|
318
|
+
const value = {...item, value: xml };
|
|
319
|
+
return JSON.stringify(value);
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
const json = JSON.parse(item);
|
|
323
|
+
const dom = DomUtil.parse(json.value);
|
|
324
|
+
return {...json, value:dom.documentElement};
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
it("Should find mock xml from the cache", () => {
|
|
329
|
+
const map = {};
|
|
330
|
+
const delegate = {
|
|
331
|
+
getItem: jest.fn((key) => map[key]),
|
|
332
|
+
setItem: jest.fn((key, value) => map[key] = value)
|
|
333
|
+
}
|
|
334
|
+
const storage = new SafeStorage(delegate, "", xmlSerDeser);
|
|
335
|
+
expect(storage.getItem("not_found")).toBeUndefined();
|
|
336
|
+
map["k1"] = `{ "hello": "world" }`;
|
|
337
|
+
expect(storage.getItem("k1")).toBeUndefined(); // k1 cached object does not have "value" attribute containing serialized XML
|
|
338
|
+
map["k1"] = `{ "hello": "world", "value": "" }`;
|
|
339
|
+
expect(storage.getItem("k1")).toBeUndefined(); // k1 cached object does not have "value" attribute containing serialized XML
|
|
340
|
+
map["k1"] = `{ "value": { "hello": "world" } }`;
|
|
341
|
+
expect(storage.getItem("k2")).toBeUndefined(); // k1 cached object does not have "value" attribute but it's not valid XML
|
|
342
|
+
map["k1"] = `{ "value": "" } }`;
|
|
343
|
+
expect(storage.getItem("k1")).toBeUndefined(); // k1 cached object does not have "value" attribute but it's not valid XML
|
|
344
|
+
map["k1"] = `{ "value": "bad" } }`;
|
|
345
|
+
expect(storage.getItem("k1")).toBeUndefined(); // k1 cached object does not have "value" attribute but it's not valid XML
|
|
346
|
+
map["k2"] = `{ "value": "<hello/>" }`;
|
|
347
|
+
expect(storage.getItem("k2").value.tagName).toBe("hello");
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
describe("Cache seralizers", () => {
|
|
353
|
+
it("Should serialize json", () => {
|
|
354
|
+
const cache = new OptionCache();
|
|
355
|
+
const serDeser = cache._storage._serDeser;
|
|
356
|
+
expect(serDeser({ hello: "World" }, true)).toBe('{"hello":"World"}');
|
|
357
|
+
expect(serDeser({ }, true)).toBe('{}');
|
|
358
|
+
expect(() => {serDeser(null, true)}).toThrow("Cannot serialize");
|
|
359
|
+
expect(() => {serDeser(undefined, true)}).toThrow("Cannot serialize");
|
|
360
|
+
expect(() => {serDeser("", true)}).toThrow("Cannot serialize");
|
|
361
|
+
expect(() => {serDeser("Hello", true)}).toThrow("Cannot serialize");
|
|
362
|
+
})
|
|
363
|
+
|
|
364
|
+
it("Should deserialize json", () => {
|
|
365
|
+
const cache = new OptionCache();
|
|
366
|
+
const serDeser = cache._storage._serDeser;
|
|
367
|
+
expect(serDeser('{"hello":"World"}', false)).toMatchObject({ hello: "World" });
|
|
368
|
+
expect(serDeser('{}', false)).toMatchObject({ });
|
|
369
|
+
expect(() => {serDeser(null, false)}).toThrow("Cannot deserialize");
|
|
370
|
+
expect(() => {serDeser(undefined, false)}).toThrow("Cannot deserialize");
|
|
371
|
+
expect(() => {serDeser("", false)}).toThrow("Cannot deserialize");
|
|
372
|
+
expect(() => {serDeser("Hello", false)}).toThrow("Unexpected token");
|
|
373
|
+
})
|
|
374
|
+
|
|
375
|
+
it("Should serialize XML entity", () => {
|
|
376
|
+
const cache = new XtkEntityCache();
|
|
377
|
+
const serDeser = cache._storage._serDeser;
|
|
378
|
+
expect(serDeser({value: DomUtil.parse("<hello/>")}, true)).toBe('{"value":"<hello/>"}')
|
|
379
|
+
expect(() => { serDeser({}, true); }).toThrow();
|
|
380
|
+
expect(() => { serDeser(null, true); }).toThrow();
|
|
381
|
+
expect(() => { serDeser(undefined, true); }).toThrow();
|
|
382
|
+
expect(() => { serDeser("", true); }).toThrow();
|
|
383
|
+
expect(() => { serDeser("Hello", true); }).toThrow();
|
|
384
|
+
})
|
|
385
|
+
|
|
386
|
+
it("Should deserialize XML entity", () => {
|
|
387
|
+
const cache = new XtkEntityCache();
|
|
388
|
+
const serDeser = cache._storage._serDeser;
|
|
389
|
+
expect(DomUtil.toXMLString(serDeser(`{"value":"<hello/>"}`, false).value)).toBe("<hello/>");
|
|
390
|
+
expect(() => {serDeser(null, false)}).toThrow();
|
|
391
|
+
expect(() => {serDeser(undefined, false)}).toThrow();
|
|
392
|
+
expect(() => {serDeser("", false)}).toThrow();
|
|
393
|
+
expect(() => {serDeser("Hello", false)}).toThrow();
|
|
394
|
+
})
|
|
395
|
+
|
|
396
|
+
it("Should serialize methods", () => {
|
|
397
|
+
const cache = new MethodCache();
|
|
398
|
+
const serDeser = cache._storage._serDeser;
|
|
399
|
+
expect(serDeser({value: { x:3, method:DomUtil.parse("<hello/>")} }, true)).toBe('{"value":{"x":3,"method":"<hello/>"}}')
|
|
400
|
+
expect(() => { serDeser({value: { x:3 }}, true); }).toThrow();
|
|
401
|
+
expect(() => { serDeser({}, true); }).toThrow();
|
|
402
|
+
expect(() => { serDeser(null, true); }).toThrow();
|
|
403
|
+
expect(() => { serDeser(undefined, true); }).toThrow();
|
|
404
|
+
expect(() => { serDeser("", true); }).toThrow();
|
|
405
|
+
expect(() => { serDeser("Hello", true); }).toThrow();
|
|
406
|
+
})
|
|
407
|
+
|
|
408
|
+
it("Should deserialize methods", () => {
|
|
409
|
+
const cache = new MethodCache();
|
|
410
|
+
const serDeser = cache._storage._serDeser;
|
|
411
|
+
expect(DomUtil.toXMLString(serDeser('{"value":{"x":3,"method":"<hello/>"}}', false).value.method)).toBe("<hello/>");
|
|
412
|
+
expect(() => { serDeser('{"value":{"x":3}}', false); }).toThrow();
|
|
413
|
+
expect(() => { serDeser({}, false); }).toThrow();
|
|
414
|
+
expect(() => { serDeser(null, false); }).toThrow();
|
|
415
|
+
expect(() => { serDeser(undefined, false); }).toThrow();
|
|
416
|
+
expect(() => { serDeser("", false); }).toThrow();
|
|
417
|
+
expect(() => { serDeser("Hello", false); }).toThrow();
|
|
418
|
+
})
|
|
419
|
+
|
|
420
|
+
it("Method serialization should not change initial object", () => {
|
|
421
|
+
const cache = new MethodCache();
|
|
422
|
+
const serDeser = cache._storage._serDeser;
|
|
423
|
+
const cached = {value: { x:3, method:DomUtil.parse("<hello/>")} };
|
|
424
|
+
serDeser(cached, true); // make sure this call does not change the input parameter "cached"
|
|
425
|
+
expect(cached.value.x).toBe(3);
|
|
426
|
+
expect(cached.value.method.documentElement.tagName).toBe("hello");
|
|
427
|
+
})
|
|
428
|
+
})
|
|
229
429
|
});
|