@adobe/acc-js-sdk 1.1.6 → 1.1.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/.eslintrc.js +1 -0
- package/CHANGELOG.md +7 -0
- package/README.md +28 -2
- package/package-lock.json +5 -4
- package/package.json +1 -1
- package/src/cache.js +19 -0
- package/src/cacheRefresher.js +53 -13
- package/src/campaign.js +29 -28
- package/src/client.js +342 -104
- package/src/transport.js +11 -10
- package/test/caches.test.js +6 -0
- package/test/client.test.js +272 -31
- package/test/mock.js +160 -46
- package/test/observability.test.js +267 -0
package/src/transport.js
CHANGED
|
@@ -10,7 +10,7 @@ OF ANY KIND, either express or implied. See the License for the specific languag
|
|
|
10
10
|
governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
(function() {
|
|
13
|
-
"use strict";
|
|
13
|
+
"use strict";
|
|
14
14
|
|
|
15
15
|
const { Util } = require('./util.js');
|
|
16
16
|
|
|
@@ -41,9 +41,9 @@ class HttpError {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/**********************************************************************************
|
|
44
|
-
*
|
|
44
|
+
*
|
|
45
45
|
* Node implementation
|
|
46
|
-
*
|
|
46
|
+
*
|
|
47
47
|
*********************************************************************************/
|
|
48
48
|
/* istanbul ignore else */
|
|
49
49
|
if (!Util.isBrowser()) {
|
|
@@ -52,13 +52,13 @@ if (!Util.isBrowser()) {
|
|
|
52
52
|
const axios = require('axios');
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
|
-
*
|
|
55
|
+
*
|
|
56
56
|
* Request body (options)
|
|
57
57
|
* - headers (kv)
|
|
58
58
|
* - method
|
|
59
59
|
* - url
|
|
60
60
|
* - data
|
|
61
|
-
*
|
|
61
|
+
*
|
|
62
62
|
* Response
|
|
63
63
|
* - data
|
|
64
64
|
* - statusCode
|
|
@@ -96,11 +96,11 @@ if (!Util.isBrowser()) {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
/**********************************************************************************
|
|
99
|
-
*
|
|
99
|
+
*
|
|
100
100
|
* Browser-side implementation of the request-promise-native node module.
|
|
101
101
|
* This simply wraps the fetch API
|
|
102
102
|
* From https://www.npmjs.com/package/request-promise-native
|
|
103
|
-
*
|
|
103
|
+
*
|
|
104
104
|
*********************************************************************************/
|
|
105
105
|
else {
|
|
106
106
|
|
|
@@ -109,11 +109,12 @@ if (!Util.isBrowser()) {
|
|
|
109
109
|
const headers = new Headers();
|
|
110
110
|
for (var k in options.headers) {
|
|
111
111
|
headers.append(k, options.headers[k]);
|
|
112
|
-
}
|
|
112
|
+
}
|
|
113
113
|
const r = new Request(options.url, {
|
|
114
114
|
method: options.method,
|
|
115
115
|
headers: headers,
|
|
116
|
-
body: options.data
|
|
116
|
+
body: options.data,
|
|
117
|
+
credentials: options.credentials || 'same-origin'
|
|
117
118
|
});
|
|
118
119
|
|
|
119
120
|
const p = fetch(r).then(async (response) => {
|
|
@@ -135,4 +136,4 @@ if (!Util.isBrowser()) {
|
|
|
135
136
|
|
|
136
137
|
}
|
|
137
138
|
|
|
138
|
-
})();
|
|
139
|
+
})();
|
package/test/caches.test.js
CHANGED
|
@@ -30,13 +30,16 @@ describe('Caches', function() {
|
|
|
30
30
|
it("Should cache with default TTL and default key function", () => {
|
|
31
31
|
const cache = new Cache();
|
|
32
32
|
cache.put("Hello", "World");
|
|
33
|
+
expect(cache._stats).toMatchObject({ reads: 0, writes: 1 });
|
|
33
34
|
expect(cache.get("Hello")).toBe("World");
|
|
35
|
+
expect(cache._stats).toMatchObject({ reads: 1, writes: 1, memoryHits: 1, storageHits: 0 });
|
|
34
36
|
})
|
|
35
37
|
|
|
36
38
|
it("Should expires after TTL", () => {
|
|
37
39
|
const cache = new Cache(undefined, undefined, -1); // negative TTL => will immediately expire
|
|
38
40
|
cache.put("Hello", "World");
|
|
39
41
|
expect(cache.get("Hello")).toBeUndefined();
|
|
42
|
+
expect(cache._stats).toMatchObject({ reads: 1, writes: 1, memoryHits: 0, storageHits: 0 });
|
|
40
43
|
})
|
|
41
44
|
|
|
42
45
|
it("Should support custom key function", () => {
|
|
@@ -53,6 +56,7 @@ describe('Caches', function() {
|
|
|
53
56
|
expect(cache.get("Hello")).toBe("World");
|
|
54
57
|
cache.clear();
|
|
55
58
|
expect(cache.get("Hello")).toBeUndefined();
|
|
59
|
+
expect(cache._stats).toMatchObject({ reads: 2, writes: 1, memoryHits: 1, storageHits: 0, clears: 1 });
|
|
56
60
|
})
|
|
57
61
|
|
|
58
62
|
it("Should remove key in cache", () => {
|
|
@@ -61,9 +65,11 @@ describe('Caches', function() {
|
|
|
61
65
|
cache.put("Hi", "A");
|
|
62
66
|
expect(cache.get("Hello")).toBe("World");
|
|
63
67
|
expect(cache.get("Hi")).toBe("A");
|
|
68
|
+
expect(cache._stats).toMatchObject({ reads: 2, writes: 2, memoryHits: 2 });
|
|
64
69
|
cache.remove("Hello");
|
|
65
70
|
expect(cache.get("Hello")).toBeUndefined();
|
|
66
71
|
expect(cache.get("Hi")).toBe("A");
|
|
72
|
+
expect(cache._stats).toMatchObject({ reads: 4, writes: 2, memoryHits: 3, removals: 1 });
|
|
67
73
|
// should support removing a key which has already been removed
|
|
68
74
|
cache.remove("Hello");
|
|
69
75
|
expect(cache.get("Hello")).toBeUndefined();
|
package/test/client.test.js
CHANGED
|
@@ -12,9 +12,9 @@ governing permissions and limitations under the License.
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
/**********************************************************************************
|
|
15
|
-
*
|
|
15
|
+
*
|
|
16
16
|
* Unit tests for the ACC client
|
|
17
|
-
*
|
|
17
|
+
*
|
|
18
18
|
*********************************************************************************/
|
|
19
19
|
|
|
20
20
|
const sdk = require('../src/index.js');
|
|
@@ -24,6 +24,8 @@ const Mock = require('./mock.js').Mock;
|
|
|
24
24
|
const { HttpError } = require('../src/transport.js');
|
|
25
25
|
const { Cipher } = require('../src/crypto.js');
|
|
26
26
|
const { EntityAccessor } = require('../src/entityAccessor.js');
|
|
27
|
+
const { JSDOM } = require('jsdom');
|
|
28
|
+
const dom = new JSDOM();
|
|
27
29
|
|
|
28
30
|
describe('ACC Client', function () {
|
|
29
31
|
|
|
@@ -73,7 +75,7 @@ describe('ACC Client', function () {
|
|
|
73
75
|
var sessionInfoXml = client.getSessionInfo("xml");
|
|
74
76
|
expect(DomUtil.findElement(sessionInfoXml, "serverInfo", true).getAttribute("buildNumber")).toBe("9219");
|
|
75
77
|
await client.NLWS.xtkSession.logoff();
|
|
76
|
-
expect(client.isLogged()).toBe(false);
|
|
78
|
+
expect(client.isLogged()).toBe(false);
|
|
77
79
|
})
|
|
78
80
|
expect(logs.length).toBe(4);
|
|
79
81
|
expect(logs[0]).toMatch(/SOAP.*request.*Logon/is)
|
|
@@ -285,7 +287,7 @@ describe('ACC Client', function () {
|
|
|
285
287
|
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
286
288
|
client._transport.mockReturnValueOnce(Mock.GET_XTK_SESSION_SCHEMA_RESPONSE);
|
|
287
289
|
await client.NLWS.xtkSession.logon();
|
|
288
|
-
|
|
290
|
+
|
|
289
291
|
// Setting an option for the first time will
|
|
290
292
|
// - try to read the option from the database (as it's not in cache yet): xtk:session#GetOption
|
|
291
293
|
// - use a writer to write the result to the database
|
|
@@ -308,7 +310,7 @@ describe('ACC Client', function () {
|
|
|
308
310
|
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
309
311
|
client._transport.mockReturnValueOnce(Mock.GET_XTK_SESSION_SCHEMA_RESPONSE);
|
|
310
312
|
await client.NLWS.xtkSession.logon();
|
|
311
|
-
|
|
313
|
+
|
|
312
314
|
// Setting an option for the first time will
|
|
313
315
|
// - try to read the option from the database (as it's not in cache yet): xtk:session#GetOption
|
|
314
316
|
// - use a writer to write the result to the database
|
|
@@ -331,7 +333,7 @@ describe('ACC Client', function () {
|
|
|
331
333
|
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
332
334
|
client._transport.mockReturnValueOnce(Mock.GET_XTK_SESSION_SCHEMA_RESPONSE);
|
|
333
335
|
await client.NLWS.xtkSession.logon();
|
|
334
|
-
|
|
336
|
+
|
|
335
337
|
// Setting an option for the first time will
|
|
336
338
|
// - try to read the option from the database (as it's not in cache yet): xtk:session#GetOption. In this case, it will return a numeric option
|
|
337
339
|
// - use a writer to write the result to the database
|
|
@@ -416,7 +418,7 @@ describe('ACC Client', function () {
|
|
|
416
418
|
expect(schema["@name"]).toBe("extAccount");
|
|
417
419
|
|
|
418
420
|
// Ask with invalid representation
|
|
419
|
-
await expect(client.getSchema("nms:extAccount", "invalid")).rejects.toMatchObject({ errorCode: 'SDK-000004' });
|
|
421
|
+
await expect(client.getSchema("nms:extAccount", "invalid")).rejects.toMatchObject({ errorCode: 'SDK-000004' });
|
|
420
422
|
|
|
421
423
|
// Get missing schema
|
|
422
424
|
client.clearAllCaches();
|
|
@@ -474,7 +476,7 @@ describe('ACC Client', function () {
|
|
|
474
476
|
await expect(client.getSysEnum("encryptionType", startSchema)).rejects.toMatchObject({ errorCode: "SDK-000006" });
|
|
475
477
|
client._representation = "xml";
|
|
476
478
|
|
|
477
|
-
// Get non-cached XML representation
|
|
479
|
+
// Get non-cached XML representation
|
|
478
480
|
client.clearAllCaches();
|
|
479
481
|
client._transport.mockReturnValueOnce(Mock.GET_NMS_EXTACCOUNT_SCHEMA_RESPONSE);
|
|
480
482
|
sysEnum = await client.getSysEnum("nms:extAccount:encryptionType");
|
|
@@ -690,7 +692,7 @@ describe('ACC Client', function () {
|
|
|
690
692
|
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
691
693
|
await client.NLWS.xtkSession.logon();
|
|
692
694
|
const key = Mock.makeKey();
|
|
693
|
-
|
|
695
|
+
|
|
694
696
|
client._transport.mockReturnValueOnce(Mock.GET_XTK_SESSION_SCHEMA_RESPONSE);
|
|
695
697
|
client._transport.mockReturnValueOnce(Mock.GET_SECRET_KEY_OPTION_RESPONSE(key));
|
|
696
698
|
var cipher = await client._getSecretKeyCipher();
|
|
@@ -1008,13 +1010,13 @@ describe('ACC Client', function () {
|
|
|
1008
1010
|
});
|
|
1009
1011
|
|
|
1010
1012
|
it("Should support mutable calls", async () => {
|
|
1011
|
-
// Some methods can mutate the object on which they apply. This is for instance the case of the xtk:queryDef#SelectAll method.
|
|
1012
|
-
// You call it on a queryDef, and it internally returns a new query definition which contain select nodes for all the nodes of the schema.
|
|
1013
|
+
// Some methods can mutate the object on which they apply. This is for instance the case of the xtk:queryDef#SelectAll method.
|
|
1014
|
+
// You call it on a queryDef, and it internally returns a new query definition which contain select nodes for all the nodes of the schema.
|
|
1013
1015
|
// When such a method is called, the SDK will know how to "mutate" the corresponding object.
|
|
1014
1016
|
const client = await Mock.makeClient();
|
|
1015
1017
|
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
1016
1018
|
await client.NLWS.xtkSession.logon();
|
|
1017
|
-
|
|
1019
|
+
|
|
1018
1020
|
var queryDef = {
|
|
1019
1021
|
"schema": "xtk:option",
|
|
1020
1022
|
"operation": "getIfExists",
|
|
@@ -1050,7 +1052,7 @@ describe('ACC Client', function () {
|
|
|
1050
1052
|
</SOAP-ENV:Body>
|
|
1051
1053
|
</SOAP-ENV:Envelope>`));
|
|
1052
1054
|
await query.selectAll(false);
|
|
1053
|
-
|
|
1055
|
+
|
|
1054
1056
|
// Check that query has new nodes
|
|
1055
1057
|
const object = query.inspect(); // JSON query object
|
|
1056
1058
|
expect(object.select.node.length).toBe(14);
|
|
@@ -1288,7 +1290,7 @@ describe('ACC Client', function () {
|
|
|
1288
1290
|
|
|
1289
1291
|
describe("Logon with session token", () => {
|
|
1290
1292
|
// With session token logon, the session token is passed by the caller, and therefore the will be no "Logon" call
|
|
1291
|
-
|
|
1293
|
+
|
|
1292
1294
|
it("Should create logged client", async() => {
|
|
1293
1295
|
const connectionParameters = sdk.ConnectionParameters.ofSessionToken("http://acc-sdk:8080", "mc/");
|
|
1294
1296
|
const client = await sdk.init(connectionParameters);
|
|
@@ -1304,7 +1306,7 @@ describe('ACC Client', function () {
|
|
|
1304
1306
|
|
|
1305
1307
|
describe("Anonymous login", () => {
|
|
1306
1308
|
// With anonymous login, one is always logged
|
|
1307
|
-
|
|
1309
|
+
|
|
1308
1310
|
it("Should create anonymous client", async() => {
|
|
1309
1311
|
const connectionParameters = sdk.ConnectionParameters.ofAnonymousUser("http://acc-sdk:8080");
|
|
1310
1312
|
const client = await sdk.init(connectionParameters);
|
|
@@ -1553,7 +1555,7 @@ describe('ACC Client', function () {
|
|
|
1553
1555
|
"xtk:session#GetOption", true,
|
|
1554
1556
|
];
|
|
1555
1557
|
const observed = [];
|
|
1556
|
-
|
|
1558
|
+
|
|
1557
1559
|
client.registerObserver({
|
|
1558
1560
|
onSOAPCall: (soapCall) => {
|
|
1559
1561
|
const request = soapCall.request;
|
|
@@ -1598,7 +1600,7 @@ describe('ACC Client', function () {
|
|
|
1598
1600
|
</SOAP-ENV:Envelope>`));
|
|
1599
1601
|
await expect(client.getOption("XtkDatabaseId")).rejects.toMatchObject({ errorCode: "XXX-000000" });
|
|
1600
1602
|
expect(observedException).toMatchObject({ errorCode: "XXX-000000" });
|
|
1601
|
-
|
|
1603
|
+
|
|
1602
1604
|
});
|
|
1603
1605
|
|
|
1604
1606
|
it("Should ignore unregistering non-existant observers", async () => {
|
|
@@ -1613,7 +1615,7 @@ describe('ACC Client', function () {
|
|
|
1613
1615
|
const client = await Mock.makeClient();
|
|
1614
1616
|
var countCalls = 0;
|
|
1615
1617
|
var countSuccesses = 0;
|
|
1616
|
-
|
|
1618
|
+
|
|
1617
1619
|
const observer1 = {
|
|
1618
1620
|
onSOAPCall: () => { countCalls = countCalls + 1; },
|
|
1619
1621
|
onSOAPCallSuccess: () => { countSuccesses = countSuccesses + 1; }
|
|
@@ -1643,7 +1645,7 @@ describe('ACC Client', function () {
|
|
|
1643
1645
|
const client = await Mock.makeClient();
|
|
1644
1646
|
var countCalls = 0;
|
|
1645
1647
|
var countSuccesses = 0;
|
|
1646
|
-
|
|
1648
|
+
|
|
1647
1649
|
const observer1 = {
|
|
1648
1650
|
onSOAPCall: () => { countCalls = countCalls + 1; },
|
|
1649
1651
|
onSOAPCallSuccess: () => { countSuccesses = countSuccesses + 1; }
|
|
@@ -1668,7 +1670,7 @@ describe('ACC Client', function () {
|
|
|
1668
1670
|
expect(countCalls).toBe(1);
|
|
1669
1671
|
expect(countSuccesses).toBe(2);
|
|
1670
1672
|
});
|
|
1671
|
-
|
|
1673
|
+
|
|
1672
1674
|
it("Should observe internal SOAP calls", async () => {
|
|
1673
1675
|
const client = await Mock.makeClient();
|
|
1674
1676
|
const expected = [
|
|
@@ -1678,7 +1680,7 @@ describe('ACC Client', function () {
|
|
|
1678
1680
|
"xtk:session#GetOption", false,
|
|
1679
1681
|
];
|
|
1680
1682
|
const observed = [];
|
|
1681
|
-
|
|
1683
|
+
|
|
1682
1684
|
client.registerObserver({
|
|
1683
1685
|
onSOAPCall: (soapCall) => {
|
|
1684
1686
|
const request = soapCall.request;
|
|
@@ -1703,7 +1705,7 @@ describe('ACC Client', function () {
|
|
|
1703
1705
|
client.traceAPICalls(true);
|
|
1704
1706
|
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
1705
1707
|
await client.NLWS.xtkSession.logon();
|
|
1706
|
-
|
|
1708
|
+
|
|
1707
1709
|
client._transport.mockReturnValueOnce(Mock.PING);
|
|
1708
1710
|
const ping = await client.ping();
|
|
1709
1711
|
expect(ping.status).toBe("OK");
|
|
@@ -1727,7 +1729,7 @@ describe('ACC Client', function () {
|
|
|
1727
1729
|
expect(logs[0]).toMatch(/HTTP.*request.*GET.*test.com/is)
|
|
1728
1730
|
expect(logs[1]).toMatch(/HTTP.*response/is)
|
|
1729
1731
|
})
|
|
1730
|
-
|
|
1732
|
+
|
|
1731
1733
|
it("Should trace HTTP call with data and no answer", async () => {
|
|
1732
1734
|
const logs = await Mock.withMockConsole(async () => {
|
|
1733
1735
|
const client = await Mock.makeClient();
|
|
@@ -1782,7 +1784,7 @@ describe('ACC Client', function () {
|
|
|
1782
1784
|
url: "http://acc-sdk:8080/nl/jsp/ping.jsp"
|
|
1783
1785
|
});
|
|
1784
1786
|
expect(observer.onHTTPCall.mock.calls[0][1]).toBeUndefined();
|
|
1785
|
-
|
|
1787
|
+
|
|
1786
1788
|
expect(observer.onHTTPCallSuccess.mock.calls.length).toBe(1);
|
|
1787
1789
|
expect(observer.onHTTPCallSuccess.mock.calls[0].length).toBe(2); // 2 arguments
|
|
1788
1790
|
expect(observer.onHTTPCallSuccess.mock.calls[0][0]).toMatchObject({
|
|
@@ -1903,7 +1905,7 @@ describe('ACC Client', function () {
|
|
|
1903
1905
|
expect(client.isLogged()).toBeFalsy();
|
|
1904
1906
|
// Ensure logoff has been called
|
|
1905
1907
|
expect(logoff.mock.calls.length).toBe(1);
|
|
1906
|
-
})
|
|
1908
|
+
})
|
|
1907
1909
|
})
|
|
1908
1910
|
|
|
1909
1911
|
describe("Bearer token authentication", () => {
|
|
@@ -1967,7 +1969,7 @@ describe('ACC Client', function () {
|
|
|
1967
1969
|
await newClient.logon();
|
|
1968
1970
|
return newClient;
|
|
1969
1971
|
}
|
|
1970
|
-
const connectionParameters = sdk.ConnectionParameters.ofBearerToken("http://acc-sdk:8080",
|
|
1972
|
+
const connectionParameters = sdk.ConnectionParameters.ofBearerToken("http://acc-sdk:8080",
|
|
1971
1973
|
"$token$", {refreshClient: refreshClient});
|
|
1972
1974
|
const client = await sdk.init(connectionParameters);
|
|
1973
1975
|
client.traceAPICalls(true);
|
|
@@ -2332,7 +2334,7 @@ describe('ACC Client', function () {
|
|
|
2332
2334
|
expect(cached.value).toMatch("<schema");
|
|
2333
2335
|
|
|
2334
2336
|
// Now simulate reusing the local storage. We need a new client to make sure we do not reuse
|
|
2335
|
-
// the in-memory cache of the client.
|
|
2337
|
+
// the in-memory cache of the client.
|
|
2336
2338
|
client = await Mock.makeClient({ storage: storage });
|
|
2337
2339
|
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
2338
2340
|
await client.NLWS.xtkSession.logon();
|
|
@@ -2444,7 +2446,7 @@ describe('ACC Client', function () {
|
|
|
2444
2446
|
await newClient.logon();
|
|
2445
2447
|
return newClient;
|
|
2446
2448
|
}
|
|
2447
|
-
const connectionParameters = sdk.ConnectionParameters.ofBearerToken("http://acc-sdk:8080",
|
|
2449
|
+
const connectionParameters = sdk.ConnectionParameters.ofBearerToken("http://acc-sdk:8080",
|
|
2448
2450
|
"$token$", {refreshClient: refreshClient});
|
|
2449
2451
|
const client = await sdk.init(connectionParameters);
|
|
2450
2452
|
jest.useFakeTimers();
|
|
@@ -2511,7 +2513,7 @@ describe('ACC Client', function () {
|
|
|
2511
2513
|
const method = scope["staticP1"]; // SOAP method to call
|
|
2512
2514
|
const paramsFn = jest.fn(); // function returning SOAP call parameters
|
|
2513
2515
|
paramsFn.mockReturnValueOnce(["XtkDatabaseId"]);
|
|
2514
|
-
|
|
2516
|
+
|
|
2515
2517
|
client._transport.mockReturnValueOnce(Promise.resolve(`<?xml version='1.0'?>
|
|
2516
2518
|
<SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:xtk:session' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
|
|
2517
2519
|
<SOAP-ENV:Body>
|
|
@@ -2539,7 +2541,7 @@ describe('ACC Client', function () {
|
|
|
2539
2541
|
const method = scope["nonStaticP1"]; // SOAP method to call
|
|
2540
2542
|
const paramsFn = jest.fn(); // function returning SOAP call parameters
|
|
2541
2543
|
paramsFn.mockReturnValueOnce(["XtkDatabaseId"]);
|
|
2542
|
-
|
|
2544
|
+
|
|
2543
2545
|
client._transport.mockReturnValueOnce(Promise.resolve(`<?xml version='1.0'?>
|
|
2544
2546
|
<SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='urn:xtk:session' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
|
|
2545
2547
|
<SOAP-ENV:Body>
|
|
@@ -3098,7 +3100,7 @@ describe('ACC Client', function () {
|
|
|
3098
3100
|
}
|
|
3099
3101
|
|
|
3100
3102
|
client._unregisterAllCacheChangeListeners();
|
|
3101
|
-
|
|
3103
|
+
|
|
3102
3104
|
const listener = new Listener();
|
|
3103
3105
|
listener.add("nms:recipient");
|
|
3104
3106
|
listener.add("xtk:operator");
|
|
@@ -3111,4 +3113,243 @@ describe('ACC Client', function () {
|
|
|
3111
3113
|
client._unregisterCacheChangeListener(listener);
|
|
3112
3114
|
});
|
|
3113
3115
|
});
|
|
3116
|
+
describe('File uploader - on server', () => {
|
|
3117
|
+
it('is not supported', async ()=> {
|
|
3118
|
+
const client = await Mock.makeClient();
|
|
3119
|
+
expect(client.fileUploader).toBeDefined()
|
|
3120
|
+
await expect(client.fileUploader.upload({name: 'abcd.txt'})).rejects.toMatchObject({"cause": undefined, "detail": "File uploading is only supported in browser based calls.", "errorCode": "SDK-000013", "faultCode": 16384, "faultString": "\"Failed to upload file abcd.txt", "message": "500 - Error 16384: SDK-000013 \"Failed to upload file abcd.txt. File uploading is only supported in browser based calls.", "methodCall": undefined, "name": "CampaignException", "statusCode": 500})
|
|
3121
|
+
})
|
|
3122
|
+
})
|
|
3123
|
+
|
|
3124
|
+
describe('File uploader - on browser', () => {
|
|
3125
|
+
beforeEach(() => {
|
|
3126
|
+
global.document = dom.window.document
|
|
3127
|
+
global.window = dom.window
|
|
3128
|
+
global.FormData = function () {
|
|
3129
|
+
this.append = jest.fn()
|
|
3130
|
+
}
|
|
3131
|
+
|
|
3132
|
+
// Evaluates JavaScript code returned by the upload.jsp. Evaluation is done in the context
|
|
3133
|
+
// of an iframe and will call the parent window document.controller uploadFileCallBack
|
|
3134
|
+
// function
|
|
3135
|
+
function evalJSReturnedByUploadJSP(js) {
|
|
3136
|
+
const data = eval(`
|
|
3137
|
+
(function () {
|
|
3138
|
+
var result = undefined;
|
|
3139
|
+
window = {
|
|
3140
|
+
parent: {
|
|
3141
|
+
document: {
|
|
3142
|
+
controller: {
|
|
3143
|
+
uploadFileCallBack: (data) => {
|
|
3144
|
+
result = data;
|
|
3145
|
+
}
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
}
|
|
3149
|
+
};
|
|
3150
|
+
${js};
|
|
3151
|
+
return result;
|
|
3152
|
+
}())
|
|
3153
|
+
`);
|
|
3154
|
+
// Call real callback
|
|
3155
|
+
global.document.controller.uploadFileCallBack(data);
|
|
3156
|
+
}
|
|
3157
|
+
|
|
3158
|
+
// Dynamically mock the iframe.contentWindow.document.close(); function
|
|
3159
|
+
const handler = {
|
|
3160
|
+
get: function (target, prop) {
|
|
3161
|
+
if (prop === 'contentWindow') {
|
|
3162
|
+
target.contentWindow.document.close = () => {
|
|
3163
|
+
var scripts = target.contentWindow.document.getElementsByTagName('script');
|
|
3164
|
+
for (let i = 0; i < scripts.length; i++) {
|
|
3165
|
+
const script = scripts[i];
|
|
3166
|
+
const js = DomUtil.elementValue(script);
|
|
3167
|
+
evalJSReturnedByUploadJSP(js);
|
|
3168
|
+
}
|
|
3169
|
+
}
|
|
3170
|
+
}
|
|
3171
|
+
return Reflect.get(...arguments);
|
|
3172
|
+
}
|
|
3173
|
+
};
|
|
3174
|
+
|
|
3175
|
+
|
|
3176
|
+
// Intercept creation of iframe. returns a proxy which will intercept the iframe.contentWindow.document.close(); function
|
|
3177
|
+
const _origiinalCreateElement = document.createElement;
|
|
3178
|
+
global.document.createElement = (tagName) => {
|
|
3179
|
+
const r = _origiinalCreateElement.call(document, tagName);
|
|
3180
|
+
if (tagName === 'iframe') {
|
|
3181
|
+
const p = new Proxy(r, handler);
|
|
3182
|
+
return p;
|
|
3183
|
+
}
|
|
3184
|
+
return r;
|
|
3185
|
+
};
|
|
3186
|
+
|
|
3187
|
+
});
|
|
3188
|
+
|
|
3189
|
+
it('works with successful post upload calls', async () => {
|
|
3190
|
+
// Create a mock client and logon
|
|
3191
|
+
const client = await Mock.makeClient();
|
|
3192
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
3193
|
+
await client.NLWS.xtkSession.logon();
|
|
3194
|
+
|
|
3195
|
+
// Mock the upload protocol
|
|
3196
|
+
// - the upload.jsp (which returns the content of an iframe and JS to eval)
|
|
3197
|
+
// - call to xtk:counter#IncreaseValue (first, retrieve the schema xtk:counter then call the function)
|
|
3198
|
+
// - call to xtk:session#Write
|
|
3199
|
+
// - call to xtk:fileRes#PublishIfNeeded
|
|
3200
|
+
// - call to xtk:fileRes#GetURL
|
|
3201
|
+
|
|
3202
|
+
client._transport.mockReturnValueOnce(Promise.resolve(`Ok
|
|
3203
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
3204
|
+
<head>
|
|
3205
|
+
<script type="text/javascript">if(window.parent&&window.parent.document.controller&&"function"==typeof window.parent.document.controller.uploadFileCallBack){var aFilesInfo=new Array;aFilesInfo.push({paramName:"file",fileName:"test.txt",newFileName:"d8e8fca2dc0f896fd7cb4cb0031ba249.txt",md5:"d8e8fca2dc0f896fd7cb4cb0031ba249"}),window.parent.document.controller.uploadFileCallBack(aFilesInfo)}</script>
|
|
3206
|
+
</head>
|
|
3207
|
+
<body></body>
|
|
3208
|
+
</html>`)); // upload.jsp
|
|
3209
|
+
|
|
3210
|
+
client._transport.mockReturnValueOnce(Promise.resolve(Mock.GET_XTK_COUNTER_RESPONSE)); // GetEntityIfMoreRecentResponse - counter
|
|
3211
|
+
client._transport.mockReturnValueOnce(Mock.INCREASE_VALUE_RESPONSE); // xtk:counter#IncreaseValue
|
|
3212
|
+
|
|
3213
|
+
client._transport.mockReturnValueOnce(Mock.GET_XTK_SESSION_SCHEMA_RESPONSE); // GetEntityIfMoreRecentResponse - session
|
|
3214
|
+
client._transport.mockReturnValueOnce(Mock.FILE_RES_WRITE_RESPONSE); // xtk:session#Write
|
|
3215
|
+
|
|
3216
|
+
client._transport.mockReturnValueOnce(Promise.resolve(Mock.GET_FILERES_QUERY_SCHEMA_RESPONSE)); // GetEntityIfMoreRecentResponse - fileRes
|
|
3217
|
+
client._transport.mockReturnValueOnce(Promise.resolve(Mock.PUBLISH_IF_NEEDED_RESPONSE)); // xtk:fileRes#PublishIfNeeded
|
|
3218
|
+
|
|
3219
|
+
client._transport.mockReturnValueOnce(Promise.resolve(Mock.GET_URL_RESPONSE)); // xtk:fileRes#GetURL
|
|
3220
|
+
|
|
3221
|
+
// Call upload
|
|
3222
|
+
const result = await client.fileUploader.upload({
|
|
3223
|
+
type: 'text/html',
|
|
3224
|
+
size: 12345
|
|
3225
|
+
})
|
|
3226
|
+
expect(result).toMatchObject({
|
|
3227
|
+
md5: "d8e8fca2dc0f896fd7cb4cb0031ba249",
|
|
3228
|
+
name: "test.txt",
|
|
3229
|
+
size: 12345,
|
|
3230
|
+
type: "text/html",
|
|
3231
|
+
url: "http://hello.com"
|
|
3232
|
+
});
|
|
3233
|
+
})
|
|
3234
|
+
|
|
3235
|
+
it('throws error with dependant failures', async () => {
|
|
3236
|
+
// Create a mock client and logon
|
|
3237
|
+
const client = await Mock.makeClient();
|
|
3238
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
3239
|
+
await client.NLWS.xtkSession.logon();
|
|
3240
|
+
|
|
3241
|
+
// Mock the upload protocol
|
|
3242
|
+
// - the upload.jsp (which returns the content of an iframe and JS to eval)
|
|
3243
|
+
// - call to xtk:counter#IncreaseValue (first, retrieve the schema xtk:counter then call the function)
|
|
3244
|
+
// - call to xtk:session#Write
|
|
3245
|
+
// - call to xtk:fileRes#PublishIfNeeded
|
|
3246
|
+
// - call to xtk:fileRes#GetURL
|
|
3247
|
+
|
|
3248
|
+
client._transport.mockReturnValueOnce(Promise.reject(`Some error occurred!!!`)); // upload.jsp
|
|
3249
|
+
|
|
3250
|
+
client._transport.mockReturnValueOnce(Promise.resolve(Mock.GET_XTK_COUNTER_RESPONSE)); // GetEntityIfMoreRecentResponse - counter
|
|
3251
|
+
client._transport.mockReturnValueOnce(Mock.INCREASE_VALUE_RESPONSE);
|
|
3252
|
+
|
|
3253
|
+
client._transport.mockReturnValueOnce(Mock.GET_XTK_SESSION_SCHEMA_RESPONSE); // GetEntityIfMoreRecentResponse - session
|
|
3254
|
+
client._transport.mockReturnValueOnce(Mock.FILE_RES_WRITE_RESPONSE); // xtk:session#Write
|
|
3255
|
+
|
|
3256
|
+
client._transport.mockReturnValueOnce(Promise.resolve(Mock.GET_FILERES_QUERY_SCHEMA_RESPONSE)); // GetEntityIfMoreRecentResponse - fileRes
|
|
3257
|
+
client._transport.mockReturnValueOnce(Promise.resolve(Mock.PUBLISH_IF_NEEDED_RESPONSE)); // xtk:fileRes#PublishIfNeeded
|
|
3258
|
+
|
|
3259
|
+
client._transport.mockReturnValueOnce(Promise.resolve(Mock.GET_URL_RESPONSE)); // xtk:fileRes#GetURL
|
|
3260
|
+
// For async handling
|
|
3261
|
+
expect.assertions(1)
|
|
3262
|
+
// Call upload
|
|
3263
|
+
await client.fileUploader.upload({
|
|
3264
|
+
type: 'text/html',
|
|
3265
|
+
size: 12345,
|
|
3266
|
+
name: 'abcd.txt'
|
|
3267
|
+
}).catch((ex) => {
|
|
3268
|
+
expect(ex.message).toMatch('500 - Error 16384: SDK-000013 "Failed to upload file abcd.txt. 500 - Error calling method \'/nl/jsp/uploadFile.jsp\': Some error occurred!!!');
|
|
3269
|
+
})
|
|
3270
|
+
|
|
3271
|
+
})
|
|
3272
|
+
|
|
3273
|
+
it('throws error with not okay response', async () => {
|
|
3274
|
+
// Create a mock client and logon
|
|
3275
|
+
const client = await Mock.makeClient();
|
|
3276
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
3277
|
+
await client.NLWS.xtkSession.logon();
|
|
3278
|
+
|
|
3279
|
+
// Mock the upload protocol
|
|
3280
|
+
// - the upload.jsp (which returns the content of an iframe and JS to eval)
|
|
3281
|
+
// - call to xtk:counter#IncreaseValue (first, retrieve the schema xtk:counter then call the function)
|
|
3282
|
+
// - call to xtk:session#Write
|
|
3283
|
+
// - call to xtk:fileRes#PublishIfNeeded
|
|
3284
|
+
// - call to xtk:fileRes#GetURL
|
|
3285
|
+
|
|
3286
|
+
client._transport.mockReturnValueOnce(Promise.resolve(`Some error occurred!!!`)); // upload.jsp
|
|
3287
|
+
|
|
3288
|
+
client._transport.mockReturnValueOnce(Promise.resolve(Mock.GET_XTK_COUNTER_RESPONSE)); // GetEntityIfMoreRecentResponse - counter
|
|
3289
|
+
client._transport.mockReturnValueOnce(Mock.INCREASE_VALUE_RESPONSE);
|
|
3290
|
+
|
|
3291
|
+
client._transport.mockReturnValueOnce(Mock.GET_XTK_SESSION_SCHEMA_RESPONSE); // GetEntityIfMoreRecentResponse - session
|
|
3292
|
+
client._transport.mockReturnValueOnce(Mock.FILE_RES_WRITE_RESPONSE); // xtk:session#Write
|
|
3293
|
+
|
|
3294
|
+
client._transport.mockReturnValueOnce(Promise.resolve(Mock.GET_FILERES_QUERY_SCHEMA_RESPONSE)); // GetEntityIfMoreRecentResponse - fileRes
|
|
3295
|
+
client._transport.mockReturnValueOnce(Promise.resolve(Mock.PUBLISH_IF_NEEDED_RESPONSE)); // xtk:fileRes#PublishIfNeeded
|
|
3296
|
+
|
|
3297
|
+
client._transport.mockReturnValueOnce(Promise.resolve(Mock.GET_URL_RESPONSE)); // xtk:fileRes#GetURL
|
|
3298
|
+
// For async handling
|
|
3299
|
+
expect.assertions(1)
|
|
3300
|
+
// Call upload
|
|
3301
|
+
await client.fileUploader.upload({
|
|
3302
|
+
type: 'text/html',
|
|
3303
|
+
size: 12345,
|
|
3304
|
+
name: 'abcd.txt'
|
|
3305
|
+
}).catch((ex) => {
|
|
3306
|
+
expect(ex.message).toMatch('500 - Error 16384: SDK-000013 "Failed to upload file abcd.txt. Some error occurred!!!');
|
|
3307
|
+
})
|
|
3308
|
+
|
|
3309
|
+
})
|
|
3310
|
+
|
|
3311
|
+
it('throws error with malformed response', async () => {
|
|
3312
|
+
// Create a mock client and logon
|
|
3313
|
+
const client = await Mock.makeClient();
|
|
3314
|
+
client._transport.mockReturnValueOnce(Mock.LOGON_RESPONSE);
|
|
3315
|
+
await client.NLWS.xtkSession.logon();
|
|
3316
|
+
|
|
3317
|
+
// Mock the upload protocol
|
|
3318
|
+
// - the upload.jsp (which returns the content of an iframe and JS to eval)
|
|
3319
|
+
// - call to xtk:counter#IncreaseValue (first, retrieve the schema xtk:counter then call the function)
|
|
3320
|
+
// - call to xtk:session#Write
|
|
3321
|
+
// - call to xtk:fileRes#PublishIfNeeded
|
|
3322
|
+
// - call to xtk:fileRes#GetURL
|
|
3323
|
+
|
|
3324
|
+
client._transport.mockReturnValueOnce(Promise.resolve(`Ok
|
|
3325
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
3326
|
+
<head>
|
|
3327
|
+
<script type="text/javascript">if(window.parent&&window.parent.document.controller&&"function"==typeof window.parent.document.controller.uploadFileCallBack){window.parent.document.controller.uploadFileCallBack([])}</script>
|
|
3328
|
+
</head>
|
|
3329
|
+
<body></body>
|
|
3330
|
+
</html>`)); // upload.jsp
|
|
3331
|
+
|
|
3332
|
+
client._transport.mockReturnValueOnce(Promise.resolve(Mock.GET_XTK_COUNTER_RESPONSE)); // GetEntityIfMoreRecentResponse - counter
|
|
3333
|
+
client._transport.mockReturnValueOnce(Mock.INCREASE_VALUE_RESPONSE);
|
|
3334
|
+
|
|
3335
|
+
client._transport.mockReturnValueOnce(Mock.GET_XTK_SESSION_SCHEMA_RESPONSE); // GetEntityIfMoreRecentResponse - session
|
|
3336
|
+
client._transport.mockReturnValueOnce(Mock.FILE_RES_WRITE_RESPONSE); // xtk:session#Write
|
|
3337
|
+
|
|
3338
|
+
client._transport.mockReturnValueOnce(Promise.resolve(Mock.GET_FILERES_QUERY_SCHEMA_RESPONSE)); // GetEntityIfMoreRecentResponse - fileRes
|
|
3339
|
+
client._transport.mockReturnValueOnce(Promise.resolve(Mock.PUBLISH_IF_NEEDED_RESPONSE)); // xtk:fileRes#PublishIfNeeded
|
|
3340
|
+
|
|
3341
|
+
client._transport.mockReturnValueOnce(Promise.resolve(Mock.GET_URL_RESPONSE)); // xtk:fileRes#GetURL
|
|
3342
|
+
// For async handling
|
|
3343
|
+
expect.assertions(1)
|
|
3344
|
+
// Call upload
|
|
3345
|
+
await client.fileUploader.upload({
|
|
3346
|
+
type: 'text/html',
|
|
3347
|
+
size: 12345,
|
|
3348
|
+
name: 'abcd.txt'
|
|
3349
|
+
}).catch((ex) => {
|
|
3350
|
+
expect(ex.message).toMatch('500 - Error 16384: SDK-000013 "Failed to upload file abcd.txt. Malformed data:');
|
|
3351
|
+
})
|
|
3352
|
+
|
|
3353
|
+
})
|
|
3354
|
+
})
|
|
3114
3355
|
});
|