@webex/internal-plugin-conversation 2.59.1 → 2.59.3-next.1
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 +6 -6
- package/README.md +47 -47
- package/babel.config.js +3 -3
- package/dist/activities.js +4 -4
- package/dist/activities.js.map +1 -1
- package/dist/activity-thread-ordering.js +34 -34
- package/dist/activity-thread-ordering.js.map +1 -1
- package/dist/config.js +12 -12
- package/dist/config.js.map +1 -1
- package/dist/constants.js.map +1 -1
- package/dist/conversation.js +474 -474
- package/dist/conversation.js.map +1 -1
- package/dist/convo-error.js +4 -4
- package/dist/convo-error.js.map +1 -1
- package/dist/decryption-transforms.js +155 -155
- package/dist/decryption-transforms.js.map +1 -1
- package/dist/encryption-transforms.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/share-activity.js +57 -57
- package/dist/share-activity.js.map +1 -1
- package/dist/to-array.js +7 -7
- package/dist/to-array.js.map +1 -1
- package/jest.config.js +3 -3
- package/package.json +21 -20
- package/process +1 -1
- package/src/activities.js +157 -157
- package/src/activity-thread-ordering.js +283 -283
- package/src/activity-threading.md +282 -282
- package/src/config.js +37 -37
- package/src/constants.js +3 -3
- package/src/conversation.js +2535 -2535
- package/src/convo-error.js +15 -15
- package/src/decryption-transforms.js +541 -541
- package/src/encryption-transforms.js +345 -345
- package/src/index.js +327 -327
- package/src/share-activity.js +436 -436
- package/src/to-array.js +29 -29
- package/test/integration/spec/create.js +290 -290
- package/test/integration/spec/encryption.js +333 -333
- package/test/integration/spec/get.js +1255 -1255
- package/test/integration/spec/mercury.js +94 -94
- package/test/integration/spec/share.js +537 -537
- package/test/integration/spec/verbs.js +1041 -1041
- package/test/unit/spec/conversation.js +823 -823
- package/test/unit/spec/decrypt-transforms.js +460 -460
- package/test/unit/spec/encryption-transforms.js +93 -93
- package/test/unit/spec/share-activity.js +178 -178
|
@@ -1,1255 +1,1255 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import '@webex/internal-plugin-conversation';
|
|
6
|
-
|
|
7
|
-
import WebexCore from '@webex/webex-core';
|
|
8
|
-
import {assert} from '@webex/test-helper-chai';
|
|
9
|
-
import sinon from 'sinon';
|
|
10
|
-
import testUsers from '@webex/test-helper-test-users';
|
|
11
|
-
import fh from '@webex/test-helper-file';
|
|
12
|
-
import makeLocalUrl from '@webex/test-helper-make-local-url';
|
|
13
|
-
import {map, find, findIndex, findLast} from 'lodash';
|
|
14
|
-
import retry from '@webex/test-helper-retry';
|
|
15
|
-
|
|
16
|
-
const postMessage = (webex, convo) => (msg) =>
|
|
17
|
-
webex.internal.conversation.post(convo, {displayName: msg});
|
|
18
|
-
|
|
19
|
-
const postReply = (webex, conversation) => (threadObj) =>
|
|
20
|
-
webex.internal.conversation.post(conversation, threadObj.displayName, {
|
|
21
|
-
parentActivityId: threadObj.parentActivityId,
|
|
22
|
-
activityType: 'reply',
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const threadDisplayNames = ['thread 1', 'thread 2', 'thread 3'];
|
|
26
|
-
const createThreadObjs = (parents) => {
|
|
27
|
-
const threadObjects = [];
|
|
28
|
-
|
|
29
|
-
for (const msg of threadDisplayNames) {
|
|
30
|
-
for (const [ix, parentAct] of parents.entries()) {
|
|
31
|
-
// add threads to every other, plus randoms for variability
|
|
32
|
-
if (ix % 2 || Math.round(Math.random())) {
|
|
33
|
-
threadObjects.push({
|
|
34
|
-
displayName: `${parentAct.object.displayName} ${msg}`,
|
|
35
|
-
parentActivityId: parentAct.id,
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return threadObjects;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
describe('plugin-conversation', function () {
|
|
45
|
-
this.timeout(120000);
|
|
46
|
-
|
|
47
|
-
describe('when fetching conversations', () => {
|
|
48
|
-
let kirk, mccoy, participants, scott, webex, spock, suluEU, checkov;
|
|
49
|
-
|
|
50
|
-
before('create tests users and connect three to mercury', () =>
|
|
51
|
-
Promise.all([
|
|
52
|
-
testUsers.create({count: 5}),
|
|
53
|
-
testUsers.create({count: 1, config: {orgId: process.env.EU_PRIMARY_ORG_ID}}),
|
|
54
|
-
]).then(([users, usersEU]) => {
|
|
55
|
-
[spock, mccoy, kirk, scott, checkov] = users;
|
|
56
|
-
[suluEU] = usersEU;
|
|
57
|
-
participants = [spock, mccoy, kirk];
|
|
58
|
-
|
|
59
|
-
spock.webex = new WebexCore({
|
|
60
|
-
credentials: {
|
|
61
|
-
supertoken: spock.token,
|
|
62
|
-
},
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
webex = spock.webex;
|
|
66
|
-
|
|
67
|
-
suluEU.webex = new WebexCore({
|
|
68
|
-
credentials: {
|
|
69
|
-
supertoken: suluEU.token,
|
|
70
|
-
},
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
checkov.webex = new WebexCore({
|
|
74
|
-
credentials: {
|
|
75
|
-
supertoken: checkov.token,
|
|
76
|
-
},
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
return Promise.all(
|
|
80
|
-
[suluEU, checkov, spock].map((user) =>
|
|
81
|
-
user.webex.internal.services
|
|
82
|
-
.waitForCatalog('postauth')
|
|
83
|
-
.then(() => user.webex.internal.mercury.connect())
|
|
84
|
-
)
|
|
85
|
-
);
|
|
86
|
-
})
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
after(() =>
|
|
90
|
-
Promise.all([suluEU, checkov, spock].map((user) => user.webex.internal.mercury.disconnect()))
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
describe('#download()', () => {
|
|
94
|
-
let sampleImageSmallOnePng = 'sample-image-small-one.png';
|
|
95
|
-
|
|
96
|
-
let conversation, conversationRequestSpy;
|
|
97
|
-
|
|
98
|
-
before('create conversation', () =>
|
|
99
|
-
webex.internal.conversation.create({participants}).then((c) => {
|
|
100
|
-
conversation = c;
|
|
101
|
-
})
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
before('fetch image fixture', () =>
|
|
105
|
-
fh.fetch(sampleImageSmallOnePng).then((res) => {
|
|
106
|
-
sampleImageSmallOnePng = res;
|
|
107
|
-
})
|
|
108
|
-
);
|
|
109
|
-
|
|
110
|
-
beforeEach(() => {
|
|
111
|
-
conversationRequestSpy = sinon.spy(webex.internal.conversation, 'request');
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
afterEach(() => conversationRequestSpy.restore());
|
|
115
|
-
|
|
116
|
-
it('rejects for invalid options argument', () =>
|
|
117
|
-
webex.internal.conversation
|
|
118
|
-
.share(conversation, [sampleImageSmallOnePng])
|
|
119
|
-
.then((activity) => {
|
|
120
|
-
const item = activity.object.files.items[0];
|
|
121
|
-
|
|
122
|
-
item.options = {
|
|
123
|
-
params: {
|
|
124
|
-
allow: 'invalidOption',
|
|
125
|
-
},
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
assert.isRejected(webex.internal.conversation.download(item));
|
|
129
|
-
}));
|
|
130
|
-
|
|
131
|
-
it('downloads and decrypts an encrypted file', () =>
|
|
132
|
-
webex.internal.conversation
|
|
133
|
-
.share(conversation, [sampleImageSmallOnePng])
|
|
134
|
-
.then((activity) => webex.internal.conversation.download(activity.object.files.items[0]))
|
|
135
|
-
.then((f) =>
|
|
136
|
-
fh.isMatchingFile(f, sampleImageSmallOnePng).then((result) => assert.isTrue(result))
|
|
137
|
-
));
|
|
138
|
-
|
|
139
|
-
it('emits download progress events for encrypted files', () =>
|
|
140
|
-
webex.internal.conversation
|
|
141
|
-
.share(conversation, [sampleImageSmallOnePng])
|
|
142
|
-
.then((activity) => {
|
|
143
|
-
const spy = sinon.spy();
|
|
144
|
-
|
|
145
|
-
return webex.internal.conversation
|
|
146
|
-
.download(activity.object.files.items[0])
|
|
147
|
-
.on('progress', spy)
|
|
148
|
-
.then(() => assert.called(spy));
|
|
149
|
-
}));
|
|
150
|
-
|
|
151
|
-
it('downloads and decrypts a file without a scr key', () =>
|
|
152
|
-
webex.internal.conversation
|
|
153
|
-
.download({
|
|
154
|
-
scr: {
|
|
155
|
-
loc: makeLocalUrl('/sample-image-small-one.png'),
|
|
156
|
-
},
|
|
157
|
-
})
|
|
158
|
-
.then((f) =>
|
|
159
|
-
fh.isMatchingFile(f, sampleImageSmallOnePng).then((result) => assert.isTrue(result))
|
|
160
|
-
)
|
|
161
|
-
.then(() =>
|
|
162
|
-
conversationRequestSpy.returnValues[0].then((res) => {
|
|
163
|
-
assert.property(res.options.headers, 'cisco-no-http-redirect');
|
|
164
|
-
assert.property(res.options.headers, 'spark-user-agent');
|
|
165
|
-
assert.property(res.options.headers, 'trackingid');
|
|
166
|
-
})
|
|
167
|
-
));
|
|
168
|
-
|
|
169
|
-
it('downloads and decrypts a non-encrypted file', () =>
|
|
170
|
-
webex.internal.conversation
|
|
171
|
-
.download({url: makeLocalUrl('/sample-image-small-one.png')})
|
|
172
|
-
.then((f) =>
|
|
173
|
-
fh.isMatchingFile(f, sampleImageSmallOnePng).then((result) => assert.isTrue(result))
|
|
174
|
-
)
|
|
175
|
-
.then(() =>
|
|
176
|
-
conversationRequestSpy.returnValues[0].then((res) => {
|
|
177
|
-
assert.property(res.options.headers, 'cisco-no-http-redirect');
|
|
178
|
-
assert.property(res.options.headers, 'spark-user-agent');
|
|
179
|
-
assert.property(res.options.headers, 'trackingid');
|
|
180
|
-
})
|
|
181
|
-
));
|
|
182
|
-
|
|
183
|
-
it('downloads non-encrypted file with specific options headers', () =>
|
|
184
|
-
webex.internal.conversation
|
|
185
|
-
.download(
|
|
186
|
-
{url: makeLocalUrl('/sample-image-small-one.png')},
|
|
187
|
-
{
|
|
188
|
-
headers: {
|
|
189
|
-
'cisco-no-http-redirect': null,
|
|
190
|
-
'spark-user-agent': null,
|
|
191
|
-
trackingid: null,
|
|
192
|
-
},
|
|
193
|
-
}
|
|
194
|
-
)
|
|
195
|
-
.then((f) =>
|
|
196
|
-
fh.isMatchingFile(f, sampleImageSmallOnePng).then((result) => assert.isTrue(result))
|
|
197
|
-
)
|
|
198
|
-
.then(() =>
|
|
199
|
-
conversationRequestSpy.returnValues[0].then((res) => {
|
|
200
|
-
assert.isUndefined(res.options.headers['cisco-no-http-redirect']);
|
|
201
|
-
assert.isUndefined(res.options.headers['spark-user-agent']);
|
|
202
|
-
assert.isUndefined(res.options.headers.trackingid);
|
|
203
|
-
})
|
|
204
|
-
));
|
|
205
|
-
|
|
206
|
-
it('emits download progress events for non-encrypted files', () => {
|
|
207
|
-
const spy = sinon.spy();
|
|
208
|
-
|
|
209
|
-
return webex.internal.conversation
|
|
210
|
-
.download({url: makeLocalUrl('/sample-image-small-one.png')})
|
|
211
|
-
.on('progress', spy)
|
|
212
|
-
.then((f) =>
|
|
213
|
-
fh.isMatchingFile(f, sampleImageSmallOnePng).then((result) => assert.isTrue(result))
|
|
214
|
-
)
|
|
215
|
-
.then(() => assert.called(spy));
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
describe('reads exif data and', () => {
|
|
219
|
-
let fileItem;
|
|
220
|
-
let sampleImagePortraitJpeg = 'Portrait_7.jpg';
|
|
221
|
-
|
|
222
|
-
before('fetch image fixture', () =>
|
|
223
|
-
fh.fetch(sampleImagePortraitJpeg).then((res) => {
|
|
224
|
-
sampleImagePortraitJpeg = res;
|
|
225
|
-
sampleImagePortraitJpeg.displayName = 'Portrait_7.jpg';
|
|
226
|
-
sampleImagePortraitJpeg.mimeType = 'image/jpeg';
|
|
227
|
-
})
|
|
228
|
-
);
|
|
229
|
-
it('does not add exif data', () =>
|
|
230
|
-
webex.internal.conversation
|
|
231
|
-
.share(conversation, [sampleImagePortraitJpeg])
|
|
232
|
-
.then((activity) => {
|
|
233
|
-
fileItem = activity.object.files.items[0];
|
|
234
|
-
|
|
235
|
-
return webex.internal.conversation.download(fileItem, {shouldNotAddExifData: true});
|
|
236
|
-
})
|
|
237
|
-
.then((f) => {
|
|
238
|
-
assert.equal(fileItem.orientation, undefined);
|
|
239
|
-
|
|
240
|
-
return fh.isMatchingFile(f, sampleImagePortraitJpeg);
|
|
241
|
-
})
|
|
242
|
-
.then((result) => assert.isTrue(result)));
|
|
243
|
-
|
|
244
|
-
it('adds exif data', () =>
|
|
245
|
-
webex.internal.conversation
|
|
246
|
-
.share(conversation, [sampleImagePortraitJpeg])
|
|
247
|
-
.then((activity) => {
|
|
248
|
-
fileItem = activity.object.files.items[0];
|
|
249
|
-
|
|
250
|
-
return webex.internal.conversation.download(fileItem);
|
|
251
|
-
})
|
|
252
|
-
.then((f) => {
|
|
253
|
-
assert.equal(fileItem.orientation, 7);
|
|
254
|
-
|
|
255
|
-
return fh.isMatchingFile(f, sampleImagePortraitJpeg);
|
|
256
|
-
})
|
|
257
|
-
.then((result) => assert.isTrue(result)));
|
|
258
|
-
});
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
describe('#get()', () => {
|
|
262
|
-
let conversation, conversation2;
|
|
263
|
-
|
|
264
|
-
before('create conversations', () =>
|
|
265
|
-
Promise.all([
|
|
266
|
-
webex.internal.conversation.create({participants: [mccoy.id]}).then((c) => {
|
|
267
|
-
conversation = c;
|
|
268
|
-
}),
|
|
269
|
-
webex.internal.conversation.create({participants: [scott.id]}).then((c) => {
|
|
270
|
-
conversation2 = c;
|
|
271
|
-
}),
|
|
272
|
-
])
|
|
273
|
-
);
|
|
274
|
-
|
|
275
|
-
it('retrieves a single conversation by url', () =>
|
|
276
|
-
webex.internal.conversation.get({url: conversation.url}).then((c) => {
|
|
277
|
-
assert.equal(c.id, conversation.id);
|
|
278
|
-
assert.equal(c.url, conversation.url);
|
|
279
|
-
}));
|
|
280
|
-
|
|
281
|
-
it('retrieves a single conversation by id', () =>
|
|
282
|
-
webex.internal.conversation.get({id: conversation.id}).then((c) => {
|
|
283
|
-
assert.equal(c.id, conversation.id);
|
|
284
|
-
assert.equal(c.url, conversation.url);
|
|
285
|
-
}));
|
|
286
|
-
|
|
287
|
-
it('retrieves a 1:1 conversation by userId', () =>
|
|
288
|
-
webex.internal.conversation.get({user: mccoy}).then((c) => {
|
|
289
|
-
assert.equal(c.id, conversation.id);
|
|
290
|
-
assert.equal(c.url, conversation.url);
|
|
291
|
-
}));
|
|
292
|
-
|
|
293
|
-
it('retrieves a 1:1 conversation with a deleted user', () =>
|
|
294
|
-
webex.internal.conversation
|
|
295
|
-
.get({user: scott})
|
|
296
|
-
.then((c) => {
|
|
297
|
-
assert.equal(c.id, conversation2.id);
|
|
298
|
-
assert.equal(c.url, conversation2.url);
|
|
299
|
-
})
|
|
300
|
-
.then(() => testUsers.remove([scott]))
|
|
301
|
-
// add retries to address CI propagation delay
|
|
302
|
-
.then(() =>
|
|
303
|
-
retry(() => assert.isRejected(webex.internal.conversation.get({user: scott})))
|
|
304
|
-
)
|
|
305
|
-
.then(() =>
|
|
306
|
-
retry(() =>
|
|
307
|
-
webex.internal.conversation.get({user: scott}, {includeConvWithDeletedUserUUID: true})
|
|
308
|
-
)
|
|
309
|
-
)
|
|
310
|
-
.then((c) => {
|
|
311
|
-
assert.equal(c.id, conversation2.id);
|
|
312
|
-
assert.equal(c.url, conversation2.url);
|
|
313
|
-
}));
|
|
314
|
-
|
|
315
|
-
it('decrypts the contents of activities in the retrieved conversation', () =>
|
|
316
|
-
webex.internal.conversation
|
|
317
|
-
.post(conversation, {
|
|
318
|
-
displayName: 'Test Message',
|
|
319
|
-
})
|
|
320
|
-
.then(() =>
|
|
321
|
-
webex.internal.conversation.get({url: conversation.url}, {activitiesLimit: 50})
|
|
322
|
-
)
|
|
323
|
-
.then((c) => {
|
|
324
|
-
const posts = c.activities.items.filter((activity) => activity.verb === 'post');
|
|
325
|
-
|
|
326
|
-
assert.lengthOf(posts, 1);
|
|
327
|
-
assert.equal(posts[0].object.displayName, 'Test Message');
|
|
328
|
-
}));
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
describe('#list()', () => {
|
|
332
|
-
let conversation1, conversation2;
|
|
333
|
-
|
|
334
|
-
before('create conversations', () =>
|
|
335
|
-
webex.internal.conversation
|
|
336
|
-
.create({
|
|
337
|
-
displayName: 'test 1',
|
|
338
|
-
participants,
|
|
339
|
-
})
|
|
340
|
-
.then((c) => {
|
|
341
|
-
conversation1 = c;
|
|
342
|
-
})
|
|
343
|
-
.then(() =>
|
|
344
|
-
webex.internal.conversation.create({
|
|
345
|
-
displayName: 'test 2',
|
|
346
|
-
participants,
|
|
347
|
-
})
|
|
348
|
-
)
|
|
349
|
-
|
|
350
|
-
.then((c) => {
|
|
351
|
-
conversation2 = c;
|
|
352
|
-
})
|
|
353
|
-
);
|
|
354
|
-
|
|
355
|
-
it('retrieves a set of conversations', () =>
|
|
356
|
-
webex.internal.conversation
|
|
357
|
-
.list({
|
|
358
|
-
conversationsLimit: 2,
|
|
359
|
-
})
|
|
360
|
-
.then((conversations) => {
|
|
361
|
-
assert.include(map(conversations, 'url'), conversation1.url);
|
|
362
|
-
assert.include(map(conversations, 'url'), conversation2.url);
|
|
363
|
-
}));
|
|
364
|
-
|
|
365
|
-
it('retrieves a paginated set of conversations', () =>
|
|
366
|
-
webex.internal.conversation
|
|
367
|
-
.paginate({
|
|
368
|
-
conversationsLimit: 1,
|
|
369
|
-
personRefresh: false,
|
|
370
|
-
paginate: true,
|
|
371
|
-
})
|
|
372
|
-
.then((response) => {
|
|
373
|
-
const conversations = response.page.items;
|
|
374
|
-
|
|
375
|
-
assert.lengthOf(conversations, 1);
|
|
376
|
-
assert.equal(conversations[0].displayName, conversation2.displayName);
|
|
377
|
-
|
|
378
|
-
return webex.internal.conversation.paginate({page: response.page});
|
|
379
|
-
})
|
|
380
|
-
.then((response) => {
|
|
381
|
-
const conversations = response.page.items;
|
|
382
|
-
|
|
383
|
-
assert.lengthOf(conversations, 1);
|
|
384
|
-
assert.equal(conversations[0].displayName, conversation1.displayName);
|
|
385
|
-
}));
|
|
386
|
-
|
|
387
|
-
describe('with summary = true (ConversationsSummary)', () => {
|
|
388
|
-
it('retrieves all conversations using conversationsSummary', () =>
|
|
389
|
-
webex.internal.conversation
|
|
390
|
-
.list({
|
|
391
|
-
summary: true,
|
|
392
|
-
})
|
|
393
|
-
.then((conversations) => {
|
|
394
|
-
assert.include(map(conversations, 'url'), conversation1.url);
|
|
395
|
-
assert.include(map(conversations, 'url'), conversation2.url);
|
|
396
|
-
}));
|
|
397
|
-
|
|
398
|
-
it('retrieves a set of (1) conversations using conversationsLimit', () =>
|
|
399
|
-
webex.internal.conversation
|
|
400
|
-
.list({
|
|
401
|
-
summary: true,
|
|
402
|
-
conversationsLimit: 1,
|
|
403
|
-
})
|
|
404
|
-
.then((conversations) => {
|
|
405
|
-
assert.lengthOf(conversations, 1);
|
|
406
|
-
assert.include(map(conversations, 'url'), conversation2.url);
|
|
407
|
-
assert.include(map(conversations, 'displayName'), conversation2.displayName);
|
|
408
|
-
}));
|
|
409
|
-
});
|
|
410
|
-
|
|
411
|
-
describe('with deferDecrypt = true', () => {
|
|
412
|
-
it('retrieves a non-decrypted set of conversations each with a bound decrypt method', () =>
|
|
413
|
-
webex.internal.conversation
|
|
414
|
-
.list({
|
|
415
|
-
conversationsLimit: 2,
|
|
416
|
-
deferDecrypt: true,
|
|
417
|
-
})
|
|
418
|
-
.then(([c1, c2]) => {
|
|
419
|
-
assert.lengthOf(
|
|
420
|
-
c1.displayName.split('.'),
|
|
421
|
-
5,
|
|
422
|
-
'5 periods implies this is a jwt and not a decrypted string'
|
|
423
|
-
);
|
|
424
|
-
assert.notInclude(['test 1, test 2'], c1.displayName);
|
|
425
|
-
|
|
426
|
-
assert.lengthOf(
|
|
427
|
-
c2.displayName.split('.'),
|
|
428
|
-
5,
|
|
429
|
-
'5 periods implies this is a jwt and not a decrypted string'
|
|
430
|
-
);
|
|
431
|
-
assert.notInclude(['test 1, test 2'], c2.displayName);
|
|
432
|
-
|
|
433
|
-
return Promise.all([
|
|
434
|
-
c1.decrypt().then(() => assert.notInclude(['test 1, test 2'], c1.displayName)),
|
|
435
|
-
c2.decrypt().then(() => assert.notInclude(['test 1, test 2'], c2.displayName)),
|
|
436
|
-
]);
|
|
437
|
-
}));
|
|
438
|
-
});
|
|
439
|
-
|
|
440
|
-
describe('with deferDecrypt && summary = true', () => {
|
|
441
|
-
it('retrieves a non-decrypted set of conversations each with a bound decrypt method', () =>
|
|
442
|
-
webex.internal.conversation
|
|
443
|
-
.list({
|
|
444
|
-
conversationsLimit: 2,
|
|
445
|
-
deferDecrypt: true,
|
|
446
|
-
summary: true,
|
|
447
|
-
})
|
|
448
|
-
.then(([c1, c2]) => {
|
|
449
|
-
assert.lengthOf(
|
|
450
|
-
c1.displayName.split('.'),
|
|
451
|
-
5,
|
|
452
|
-
'5 periods implies this is a jwt and not a decrypted string'
|
|
453
|
-
);
|
|
454
|
-
assert.notInclude(['test 1, test 2'], c1.displayName);
|
|
455
|
-
|
|
456
|
-
assert.lengthOf(
|
|
457
|
-
c2.displayName.split('.'),
|
|
458
|
-
5,
|
|
459
|
-
'5 periods implies this is a jwt and not a decrypted string'
|
|
460
|
-
);
|
|
461
|
-
assert.notInclude(['test 1, test 2'], c2.displayName);
|
|
462
|
-
|
|
463
|
-
return Promise.all([
|
|
464
|
-
c1.decrypt().then(() => assert.notInclude(['test 1, test 2'], c1.displayName)),
|
|
465
|
-
c2.decrypt().then(() => assert.notInclude(['test 1, test 2'], c2.displayName)),
|
|
466
|
-
]);
|
|
467
|
-
}));
|
|
468
|
-
});
|
|
469
|
-
|
|
470
|
-
describe('with conversation from remote clusters', () => {
|
|
471
|
-
let conversation3, conversation4;
|
|
472
|
-
|
|
473
|
-
before('create conversations in EU cluster', () =>
|
|
474
|
-
Promise.all([
|
|
475
|
-
suluEU.webex.internal.conversation
|
|
476
|
-
.create({
|
|
477
|
-
displayName: 'eu test 1',
|
|
478
|
-
participants,
|
|
479
|
-
})
|
|
480
|
-
.then((c) => {
|
|
481
|
-
conversation3 = c;
|
|
482
|
-
}),
|
|
483
|
-
suluEU.webex.internal.conversation
|
|
484
|
-
.create({
|
|
485
|
-
displayName: 'eu test 2',
|
|
486
|
-
participants: [checkov.id, spock.id],
|
|
487
|
-
})
|
|
488
|
-
.then((c) => {
|
|
489
|
-
conversation4 = c;
|
|
490
|
-
}),
|
|
491
|
-
])
|
|
492
|
-
);
|
|
493
|
-
|
|
494
|
-
it('retrieves local + remote cluster conversations', () =>
|
|
495
|
-
webex.internal.conversation.list().then((conversations) => {
|
|
496
|
-
assert.include(map(conversations, 'url'), conversation1.url);
|
|
497
|
-
assert.include(map(conversations, 'url'), conversation2.url);
|
|
498
|
-
assert.include(map(conversations, 'url'), conversation3.url);
|
|
499
|
-
assert.include(map(conversations, 'url'), conversation4.url);
|
|
500
|
-
}));
|
|
501
|
-
|
|
502
|
-
it('retrieves only remote cluter conversations if user does not have any local conversations', () =>
|
|
503
|
-
checkov.webex.internal.conversation.list().then((conversations) => {
|
|
504
|
-
assert.include(map(conversations, 'url'), conversation4.url);
|
|
505
|
-
assert.lengthOf(conversations, 1);
|
|
506
|
-
}));
|
|
507
|
-
});
|
|
508
|
-
});
|
|
509
|
-
|
|
510
|
-
describe('#listLeft()', () => {
|
|
511
|
-
let conversation;
|
|
512
|
-
|
|
513
|
-
before('create conversation', () =>
|
|
514
|
-
webex.internal.conversation.create({participants}).then((c) => {
|
|
515
|
-
conversation = c;
|
|
516
|
-
})
|
|
517
|
-
);
|
|
518
|
-
|
|
519
|
-
it('retrieves the conversations the current user has left', () =>
|
|
520
|
-
webex.internal.conversation
|
|
521
|
-
.listLeft()
|
|
522
|
-
.then((c) => {
|
|
523
|
-
assert.lengthOf(c, 0);
|
|
524
|
-
|
|
525
|
-
return webex.internal.conversation.leave(conversation);
|
|
526
|
-
})
|
|
527
|
-
.then(() => webex.internal.conversation.listLeft())
|
|
528
|
-
.then((c) => {
|
|
529
|
-
assert.lengthOf(c, 1);
|
|
530
|
-
assert.equal(c[0].id, conversation.id);
|
|
531
|
-
}));
|
|
532
|
-
});
|
|
533
|
-
|
|
534
|
-
describe('#listActivities()', () => {
|
|
535
|
-
let conversation;
|
|
536
|
-
|
|
537
|
-
before('create conversation with activity', () =>
|
|
538
|
-
webex.internal.conversation.create({participants}).then((c) => {
|
|
539
|
-
conversation = c;
|
|
540
|
-
assert.lengthOf(conversation.participants.items, 3);
|
|
541
|
-
|
|
542
|
-
return webex.internal.conversation.post(conversation, {displayName: 'first message'});
|
|
543
|
-
})
|
|
544
|
-
);
|
|
545
|
-
|
|
546
|
-
it('retrieves activities for the specified conversation', () =>
|
|
547
|
-
webex.internal.conversation
|
|
548
|
-
.listActivities({conversationUrl: conversation.url})
|
|
549
|
-
.then((activities) => {
|
|
550
|
-
assert.isArray(activities);
|
|
551
|
-
assert.lengthOf(activities, 2);
|
|
552
|
-
}));
|
|
553
|
-
});
|
|
554
|
-
|
|
555
|
-
describe('#listThreads()', () => {
|
|
556
|
-
let webex2;
|
|
557
|
-
|
|
558
|
-
before('connect mccoy to mercury', () => {
|
|
559
|
-
webex2 = new WebexCore({
|
|
560
|
-
credentials: {
|
|
561
|
-
authorization: mccoy.token,
|
|
562
|
-
},
|
|
563
|
-
});
|
|
564
|
-
|
|
565
|
-
return webex2.internal.mercury.connect();
|
|
566
|
-
});
|
|
567
|
-
|
|
568
|
-
after(() => webex2 && webex2.internal.mercury.disconnect());
|
|
569
|
-
|
|
570
|
-
let conversation;
|
|
571
|
-
let parent;
|
|
572
|
-
|
|
573
|
-
before('create conversation', () =>
|
|
574
|
-
webex.internal.conversation.create({participants}).then((c) => {
|
|
575
|
-
conversation = c;
|
|
576
|
-
assert.lengthOf(conversation.participants.items, 3);
|
|
577
|
-
|
|
578
|
-
return webex2.internal.conversation
|
|
579
|
-
.post(conversation, {displayName: 'first message'})
|
|
580
|
-
.then((parentActivity) => {
|
|
581
|
-
parent = parentActivity;
|
|
582
|
-
});
|
|
583
|
-
})
|
|
584
|
-
);
|
|
585
|
-
|
|
586
|
-
it('retrieves threads()', () =>
|
|
587
|
-
webex2.internal.conversation
|
|
588
|
-
.post(conversation, 'thread1', {
|
|
589
|
-
parentActivityId: parent.id,
|
|
590
|
-
activityType: 'reply',
|
|
591
|
-
})
|
|
592
|
-
.then(() => webex2.internal.conversation.listThreads())
|
|
593
|
-
.then((thread) => {
|
|
594
|
-
assert.equal(thread.length, 1);
|
|
595
|
-
const firstThread = thread[0];
|
|
596
|
-
|
|
597
|
-
assert.equal(firstThread.childType, 'reply');
|
|
598
|
-
assert.equal(firstThread.parentActivityId, parent.id);
|
|
599
|
-
assert.equal(firstThread.conversationId, conversation.id);
|
|
600
|
-
assert.equal(firstThread.childActivities.length, 1);
|
|
601
|
-
|
|
602
|
-
const childActivity = firstThread.childActivities[0];
|
|
603
|
-
|
|
604
|
-
assert.equal(childActivity.objectType, 'activity');
|
|
605
|
-
assert.equal(childActivity.object.displayName, 'thread1');
|
|
606
|
-
}));
|
|
607
|
-
});
|
|
608
|
-
|
|
609
|
-
describe('#listMentions()', () => {
|
|
610
|
-
let webex2;
|
|
611
|
-
|
|
612
|
-
before('connect mccoy to mercury', () => {
|
|
613
|
-
webex2 = new WebexCore({
|
|
614
|
-
credentials: {
|
|
615
|
-
authorization: mccoy.token,
|
|
616
|
-
},
|
|
617
|
-
});
|
|
618
|
-
|
|
619
|
-
return webex2.internal.mercury.connect();
|
|
620
|
-
});
|
|
621
|
-
|
|
622
|
-
after(() => webex2 && webex2.internal.mercury.disconnect());
|
|
623
|
-
|
|
624
|
-
let conversation;
|
|
625
|
-
|
|
626
|
-
before('create conversation', () =>
|
|
627
|
-
webex.internal.conversation.create({participants}).then((c) => {
|
|
628
|
-
conversation = c;
|
|
629
|
-
assert.lengthOf(conversation.participants.items, 3);
|
|
630
|
-
})
|
|
631
|
-
);
|
|
632
|
-
|
|
633
|
-
it('retrieves activities in which the current user was mentioned', () =>
|
|
634
|
-
webex2.internal.conversation
|
|
635
|
-
.post(conversation, {
|
|
636
|
-
displayName: 'Green blooded hobgloblin',
|
|
637
|
-
content: `<webex-mention data-object-type="person" data-object-id="${spock.id}">Green blooded hobgloblin</webex-mention>`,
|
|
638
|
-
mentions: {
|
|
639
|
-
items: [
|
|
640
|
-
{
|
|
641
|
-
id: `${spock.id}`,
|
|
642
|
-
objectType: 'person',
|
|
643
|
-
},
|
|
644
|
-
],
|
|
645
|
-
},
|
|
646
|
-
})
|
|
647
|
-
.then((activity) =>
|
|
648
|
-
webex.internal.conversation
|
|
649
|
-
.listMentions({sinceDate: Date.parse(activity.published) - 1})
|
|
650
|
-
.then((mentions) => {
|
|
651
|
-
assert.lengthOf(mentions, 1);
|
|
652
|
-
assert.equal(mentions[0].url, activity.url);
|
|
653
|
-
})
|
|
654
|
-
));
|
|
655
|
-
});
|
|
656
|
-
|
|
657
|
-
// TODO: add testing for bulk_activities_fetch() with clusters later
|
|
658
|
-
describe('#bulkActivitiesFetch()', () => {
|
|
659
|
-
let jenny, maria, dan, convo1, convo2, euConvo1;
|
|
660
|
-
let webex3;
|
|
661
|
-
|
|
662
|
-
before('create tests users and connect one to mercury', () =>
|
|
663
|
-
testUsers.create({count: 4}).then((users) => {
|
|
664
|
-
[jenny, maria, dan] = users;
|
|
665
|
-
|
|
666
|
-
webex3 = new WebexCore({
|
|
667
|
-
credentials: {
|
|
668
|
-
authorization: jenny.token,
|
|
669
|
-
},
|
|
670
|
-
});
|
|
671
|
-
|
|
672
|
-
return webex3.internal.mercury.connect();
|
|
673
|
-
})
|
|
674
|
-
);
|
|
675
|
-
|
|
676
|
-
after(() => webex3 && webex3.internal.mercury.disconnect());
|
|
677
|
-
|
|
678
|
-
before('create conversation 1', () =>
|
|
679
|
-
webex3.internal.conversation.create({participants: [jenny, maria]}).then((c1) => {
|
|
680
|
-
convo1 = c1;
|
|
681
|
-
})
|
|
682
|
-
);
|
|
683
|
-
|
|
684
|
-
before('create conversation 2', () =>
|
|
685
|
-
webex3.internal.conversation.create({participants: [jenny, dan]}).then((c2) => {
|
|
686
|
-
convo2 = c2;
|
|
687
|
-
})
|
|
688
|
-
);
|
|
689
|
-
|
|
690
|
-
before('create conversations in EU cluster', () =>
|
|
691
|
-
suluEU.webex.internal.conversation
|
|
692
|
-
.create({
|
|
693
|
-
displayName: 'eu test 1',
|
|
694
|
-
participants: [jenny, suluEU, dan],
|
|
695
|
-
})
|
|
696
|
-
.then((c) => {
|
|
697
|
-
euConvo1 = c;
|
|
698
|
-
})
|
|
699
|
-
);
|
|
700
|
-
|
|
701
|
-
before('add comments to convo1, and check post requests successfully went through', () =>
|
|
702
|
-
webex3.internal.conversation
|
|
703
|
-
.post(convo1, {displayName: 'BAGELS (O)'})
|
|
704
|
-
.then((c1) => {
|
|
705
|
-
assert.equal(c1.object.displayName, 'BAGELS (O)');
|
|
706
|
-
|
|
707
|
-
return webex3.internal.conversation.post(convo1, {displayName: 'Cream Cheese'});
|
|
708
|
-
})
|
|
709
|
-
.then((c2) => {
|
|
710
|
-
assert.equal(c2.object.displayName, 'Cream Cheese');
|
|
711
|
-
})
|
|
712
|
-
);
|
|
713
|
-
|
|
714
|
-
before('add comments to convo2, and check post requests successfully went through', () =>
|
|
715
|
-
webex3.internal.conversation
|
|
716
|
-
.post(convo2, {displayName: 'Want to head to lunch soon?'})
|
|
717
|
-
.then((c1) => {
|
|
718
|
-
assert.equal(c1.object.displayName, 'Want to head to lunch soon?');
|
|
719
|
-
|
|
720
|
-
return webex3.internal.conversation.post(convo2, {displayName: 'Sure :)'});
|
|
721
|
-
})
|
|
722
|
-
.then((c2) => {
|
|
723
|
-
assert.equal(c2.object.displayName, 'Sure :)');
|
|
724
|
-
|
|
725
|
-
return webex3.internal.conversation.post(convo2, {displayName: 'where?'});
|
|
726
|
-
})
|
|
727
|
-
.then((c3) => {
|
|
728
|
-
assert.equal(c3.object.displayName, 'where?');
|
|
729
|
-
|
|
730
|
-
return webex3.internal.conversation.post(convo2, {displayName: 'Meekong Bar!'});
|
|
731
|
-
})
|
|
732
|
-
.then((c4) => {
|
|
733
|
-
assert.equal(c4.object.displayName, 'Meekong Bar!');
|
|
734
|
-
})
|
|
735
|
-
);
|
|
736
|
-
|
|
737
|
-
before('add comments to euConvo1, and check post requests successfully went through', () =>
|
|
738
|
-
suluEU.webex.internal.conversation.post(euConvo1, {displayName: 'Hello'}).then((c1) => {
|
|
739
|
-
assert.equal(c1.object.displayName, 'Hello');
|
|
740
|
-
})
|
|
741
|
-
);
|
|
742
|
-
|
|
743
|
-
it('retrieves activities from a single conversation', () =>
|
|
744
|
-
webex3.internal.conversation
|
|
745
|
-
.listActivities({conversationUrl: convo1.url})
|
|
746
|
-
.then((convoActivities) => {
|
|
747
|
-
const activityURLs = [];
|
|
748
|
-
const expectedActivities = [];
|
|
749
|
-
|
|
750
|
-
convoActivities.forEach((a) => {
|
|
751
|
-
if (a.verb === 'post') {
|
|
752
|
-
activityURLs.push(a.url);
|
|
753
|
-
expectedActivities.push(a);
|
|
754
|
-
}
|
|
755
|
-
});
|
|
756
|
-
|
|
757
|
-
return webex3.internal.conversation
|
|
758
|
-
.bulkActivitiesFetch(activityURLs)
|
|
759
|
-
.then((bulkFetchedActivities) => {
|
|
760
|
-
assert.lengthOf(bulkFetchedActivities, expectedActivities.length);
|
|
761
|
-
assert.equal(
|
|
762
|
-
bulkFetchedActivities[0].object.displayName,
|
|
763
|
-
expectedActivities[0].object.displayName
|
|
764
|
-
);
|
|
765
|
-
assert.equal(
|
|
766
|
-
bulkFetchedActivities[1].object.displayName,
|
|
767
|
-
expectedActivities[1].object.displayName
|
|
768
|
-
);
|
|
769
|
-
});
|
|
770
|
-
}));
|
|
771
|
-
|
|
772
|
-
it('retrieves activities from multiple conversations', () => {
|
|
773
|
-
const activityURLs = [];
|
|
774
|
-
const expectedActivities = [];
|
|
775
|
-
|
|
776
|
-
return webex3.internal.conversation
|
|
777
|
-
.listActivities({conversationUrl: convo1.url})
|
|
778
|
-
.then((convo1Activities) => {
|
|
779
|
-
// gets all post activity urls from convo1
|
|
780
|
-
convo1Activities.forEach((a1) => {
|
|
781
|
-
if (a1.verb === 'post') {
|
|
782
|
-
activityURLs.push(a1.url);
|
|
783
|
-
expectedActivities.push(a1);
|
|
784
|
-
}
|
|
785
|
-
});
|
|
786
|
-
|
|
787
|
-
return webex3.internal.conversation.listActivities({conversationUrl: convo2.url});
|
|
788
|
-
})
|
|
789
|
-
.then((convo2Activities) => {
|
|
790
|
-
// gets activity urls of only comment 3 and 4 from convo2
|
|
791
|
-
[3, 4].forEach((i) => {
|
|
792
|
-
activityURLs.push(convo2Activities[i].url);
|
|
793
|
-
expectedActivities.push(convo2Activities[i]);
|
|
794
|
-
});
|
|
795
|
-
|
|
796
|
-
return webex3.internal.conversation
|
|
797
|
-
.bulkActivitiesFetch(activityURLs)
|
|
798
|
-
.then((bulkFetchedActivities) => {
|
|
799
|
-
assert.lengthOf(bulkFetchedActivities, expectedActivities.length);
|
|
800
|
-
assert.equal(
|
|
801
|
-
bulkFetchedActivities[0].object.displayName,
|
|
802
|
-
expectedActivities[0].object.displayName
|
|
803
|
-
);
|
|
804
|
-
assert.equal(
|
|
805
|
-
bulkFetchedActivities[1].object.displayName,
|
|
806
|
-
expectedActivities[1].object.displayName
|
|
807
|
-
);
|
|
808
|
-
assert.equal(
|
|
809
|
-
bulkFetchedActivities[2].object.displayName,
|
|
810
|
-
expectedActivities[2].object.displayName
|
|
811
|
-
);
|
|
812
|
-
assert.equal(
|
|
813
|
-
bulkFetchedActivities[3].object.displayName,
|
|
814
|
-
expectedActivities[3].object.displayName
|
|
815
|
-
);
|
|
816
|
-
});
|
|
817
|
-
});
|
|
818
|
-
});
|
|
819
|
-
|
|
820
|
-
it('given a activity url that does not exist, should return []', () => {
|
|
821
|
-
const mockURL =
|
|
822
|
-
'https://conversation-intb.ciscospark.com/conversation/api/v1/activities/6d8c7c90-a770-11e9-bcfb-6616ead99ac3';
|
|
823
|
-
|
|
824
|
-
webex3.internal.conversation
|
|
825
|
-
.bulkActivitiesFetch([mockURL])
|
|
826
|
-
.then((bulkFetchedActivities) => {
|
|
827
|
-
assert.equal(bulkFetchedActivities, []);
|
|
828
|
-
});
|
|
829
|
-
});
|
|
830
|
-
|
|
831
|
-
it('retrieves activities from multiple conversations passing in base convo url', () => {
|
|
832
|
-
const activityURLs = [];
|
|
833
|
-
const expectedActivities = [];
|
|
834
|
-
|
|
835
|
-
return webex3.internal.conversation
|
|
836
|
-
.listActivities({conversationUrl: convo1.url})
|
|
837
|
-
.then((convo1Activities) => {
|
|
838
|
-
// gets all post activity urls from convo1
|
|
839
|
-
convo1Activities.forEach((a1) => {
|
|
840
|
-
if (a1.verb === 'post') {
|
|
841
|
-
activityURLs.push(a1.url);
|
|
842
|
-
expectedActivities.push(a1);
|
|
843
|
-
}
|
|
844
|
-
});
|
|
845
|
-
|
|
846
|
-
return webex3.internal.conversation.listActivities({conversationUrl: convo2.url});
|
|
847
|
-
})
|
|
848
|
-
.then((convo2Activities) => {
|
|
849
|
-
// gets activity urls of only comment 3 and 4 from convo2
|
|
850
|
-
[3, 4].forEach((i) => {
|
|
851
|
-
activityURLs.push(convo2Activities[i].url);
|
|
852
|
-
expectedActivities.push(convo2Activities[i]);
|
|
853
|
-
});
|
|
854
|
-
|
|
855
|
-
return webex3.internal.conversation
|
|
856
|
-
.bulkActivitiesFetch(activityURLs, undefined, {url: process.env.CONVERSATION_SERVICE})
|
|
857
|
-
.then((bulkFetchedActivities) => {
|
|
858
|
-
assert.lengthOf(bulkFetchedActivities, expectedActivities.length);
|
|
859
|
-
assert.equal(
|
|
860
|
-
bulkFetchedActivities[0].object.displayName,
|
|
861
|
-
expectedActivities[0].object.displayName
|
|
862
|
-
);
|
|
863
|
-
assert.equal(
|
|
864
|
-
bulkFetchedActivities[1].object.displayName,
|
|
865
|
-
expectedActivities[1].object.displayName
|
|
866
|
-
);
|
|
867
|
-
assert.equal(
|
|
868
|
-
bulkFetchedActivities[2].object.displayName,
|
|
869
|
-
expectedActivities[2].object.displayName
|
|
870
|
-
);
|
|
871
|
-
assert.equal(
|
|
872
|
-
bulkFetchedActivities[3].object.displayName,
|
|
873
|
-
expectedActivities[3].object.displayName
|
|
874
|
-
);
|
|
875
|
-
});
|
|
876
|
-
});
|
|
877
|
-
});
|
|
878
|
-
|
|
879
|
-
it('retrieves activities from conversations passing in base convo url from another cluster', () => {
|
|
880
|
-
const activityURLs = [];
|
|
881
|
-
const expectedActivities = [];
|
|
882
|
-
|
|
883
|
-
return webex3.internal.conversation
|
|
884
|
-
.listActivities({conversationUrl: euConvo1.url})
|
|
885
|
-
.then((euConvo1Activities) => {
|
|
886
|
-
const convoUrlRegex = /(.*)\/activities/;
|
|
887
|
-
|
|
888
|
-
activityURLs.push(euConvo1Activities[1].url);
|
|
889
|
-
expectedActivities.push(euConvo1Activities[1]);
|
|
890
|
-
const match = convoUrlRegex.exec(euConvo1Activities[1].url);
|
|
891
|
-
const convoUrl = match[1];
|
|
892
|
-
|
|
893
|
-
return webex3.internal.conversation.bulkActivitiesFetch(activityURLs, {url: convoUrl});
|
|
894
|
-
})
|
|
895
|
-
.then((bulkFetchedActivities) => {
|
|
896
|
-
assert.lengthOf(bulkFetchedActivities, 1);
|
|
897
|
-
assert.equal(
|
|
898
|
-
bulkFetchedActivities[0].object.displayName,
|
|
899
|
-
expectedActivities[0].object.displayName
|
|
900
|
-
);
|
|
901
|
-
});
|
|
902
|
-
});
|
|
903
|
-
});
|
|
904
|
-
|
|
905
|
-
describe('#listParentActivityIds', () => {
|
|
906
|
-
let conversation, parent;
|
|
907
|
-
|
|
908
|
-
beforeEach('create conversation with activity', () =>
|
|
909
|
-
webex.internal.conversation
|
|
910
|
-
.create({participants})
|
|
911
|
-
.then((c) => {
|
|
912
|
-
conversation = c;
|
|
913
|
-
|
|
914
|
-
return webex.internal.conversation.post(conversation, {displayName: 'first message'});
|
|
915
|
-
})
|
|
916
|
-
.then((parentAct) => {
|
|
917
|
-
parent = parentAct;
|
|
918
|
-
})
|
|
919
|
-
);
|
|
920
|
-
|
|
921
|
-
it('retrieves parent IDs for thread parents()', () =>
|
|
922
|
-
webex.internal.conversation
|
|
923
|
-
.post(
|
|
924
|
-
conversation,
|
|
925
|
-
{displayName: 'first thread reply'},
|
|
926
|
-
{
|
|
927
|
-
parentActivityId: parent.id,
|
|
928
|
-
activityType: 'reply',
|
|
929
|
-
}
|
|
930
|
-
)
|
|
931
|
-
.then(({parent: parentObj} = {}) => {
|
|
932
|
-
assert.equal(parentObj.type, 'reply');
|
|
933
|
-
assert.equal(parentObj.id, parent.id);
|
|
934
|
-
|
|
935
|
-
return webex.internal.conversation.listParentActivityIds(conversation.url, {
|
|
936
|
-
activityType: 'reply',
|
|
937
|
-
});
|
|
938
|
-
})
|
|
939
|
-
.then(({reply}) => {
|
|
940
|
-
assert.include(reply, parent.id);
|
|
941
|
-
}));
|
|
942
|
-
|
|
943
|
-
it('retrieves parent IDs for edits', () =>
|
|
944
|
-
webex.internal.conversation
|
|
945
|
-
.post(conversation, 'edited', {
|
|
946
|
-
parent: {
|
|
947
|
-
id: parent.id,
|
|
948
|
-
type: 'edit',
|
|
949
|
-
},
|
|
950
|
-
})
|
|
951
|
-
.then((edit) => {
|
|
952
|
-
assert.equal(edit.parent.type, 'edit');
|
|
953
|
-
assert.equal(edit.parent.id, parent.id);
|
|
954
|
-
|
|
955
|
-
return webex.internal.conversation.listParentActivityIds(conversation.url, {
|
|
956
|
-
activityType: 'edit',
|
|
957
|
-
});
|
|
958
|
-
})
|
|
959
|
-
.then(({edit}) => {
|
|
960
|
-
assert.include(edit, parent.id);
|
|
961
|
-
}));
|
|
962
|
-
|
|
963
|
-
it('retrieves parent IDs for reactions', () =>
|
|
964
|
-
webex.internal.conversation
|
|
965
|
-
.addReaction(conversation, 'heart', parent)
|
|
966
|
-
.then((reaction) => {
|
|
967
|
-
assert.equal(reaction.parent.type, 'reaction');
|
|
968
|
-
assert.equal(reaction.parent.id, parent.id);
|
|
969
|
-
|
|
970
|
-
return webex.internal.conversation.listParentActivityIds(conversation.url, {
|
|
971
|
-
activityType: 'reaction',
|
|
972
|
-
});
|
|
973
|
-
})
|
|
974
|
-
.then(({reaction}) => {
|
|
975
|
-
assert.include(reaction, parent.id);
|
|
976
|
-
}));
|
|
977
|
-
});
|
|
978
|
-
|
|
979
|
-
describe('#listChildActivitiesByParentId()', () => {
|
|
980
|
-
let conversation, parent;
|
|
981
|
-
let replies;
|
|
982
|
-
|
|
983
|
-
before('create conversation with thread replies', () =>
|
|
984
|
-
webex.internal.conversation
|
|
985
|
-
.create({participants})
|
|
986
|
-
.then((c) => {
|
|
987
|
-
conversation = c;
|
|
988
|
-
|
|
989
|
-
return webex.internal.conversation.post(conversation, {displayName: 'first message'});
|
|
990
|
-
})
|
|
991
|
-
.then((parentAct) => {
|
|
992
|
-
parent = parentAct;
|
|
993
|
-
|
|
994
|
-
const messages = ['thread 1', 'thread 2', 'thread 3'];
|
|
995
|
-
|
|
996
|
-
return Promise.all(
|
|
997
|
-
messages.map((msg) =>
|
|
998
|
-
webex.internal.conversation.post(conversation, msg, {
|
|
999
|
-
parentActivityId: parent.id,
|
|
1000
|
-
activityType: 'reply',
|
|
1001
|
-
})
|
|
1002
|
-
)
|
|
1003
|
-
);
|
|
1004
|
-
})
|
|
1005
|
-
.then((repliesArr) => {
|
|
1006
|
-
replies = repliesArr;
|
|
1007
|
-
})
|
|
1008
|
-
);
|
|
1009
|
-
|
|
1010
|
-
it('retrieves thread reply activities for a given parent', () =>
|
|
1011
|
-
webex.internal.conversation
|
|
1012
|
-
.listChildActivitiesByParentId(conversation.url, parent.id, 'reply')
|
|
1013
|
-
.then((response) => {
|
|
1014
|
-
const {items} = response.body;
|
|
1015
|
-
|
|
1016
|
-
items.forEach((threadAct) => {
|
|
1017
|
-
assert.include(
|
|
1018
|
-
replies.map((reply) => reply.id),
|
|
1019
|
-
threadAct.id
|
|
1020
|
-
);
|
|
1021
|
-
});
|
|
1022
|
-
}));
|
|
1023
|
-
});
|
|
1024
|
-
|
|
1025
|
-
describe('#_listActivitiesThreadOrdered', () => {
|
|
1026
|
-
let conversation, firstParentBatch, secondParentBatch, getOlder, jumpToActivity;
|
|
1027
|
-
|
|
1028
|
-
const minActivities = 10;
|
|
1029
|
-
const displayNames = [
|
|
1030
|
-
'first message',
|
|
1031
|
-
'second message',
|
|
1032
|
-
'third message',
|
|
1033
|
-
'fourth message',
|
|
1034
|
-
'fifth message',
|
|
1035
|
-
'sixth message',
|
|
1036
|
-
'seventh message',
|
|
1037
|
-
'eighth message',
|
|
1038
|
-
'ninth message',
|
|
1039
|
-
];
|
|
1040
|
-
|
|
1041
|
-
const initializeGenerator = () =>
|
|
1042
|
-
webex.internal.conversation.listActivitiesThreadOrdered({
|
|
1043
|
-
conversationUrl: conversation.url,
|
|
1044
|
-
minActivities,
|
|
1045
|
-
});
|
|
1046
|
-
|
|
1047
|
-
before(() =>
|
|
1048
|
-
webex.internal.conversation
|
|
1049
|
-
.create({participants})
|
|
1050
|
-
.then((c) => {
|
|
1051
|
-
conversation = c;
|
|
1052
|
-
|
|
1053
|
-
return c;
|
|
1054
|
-
})
|
|
1055
|
-
.then((c) => Promise.all(displayNames.slice(0, 5).map(postMessage(webex, c))))
|
|
1056
|
-
.then((parents) => {
|
|
1057
|
-
firstParentBatch = parents;
|
|
1058
|
-
|
|
1059
|
-
return Promise.all(createThreadObjs(parents).map(postReply(webex, conversation)));
|
|
1060
|
-
})
|
|
1061
|
-
.then(() => Promise.all(displayNames.slice(4).map(postMessage(webex, conversation))))
|
|
1062
|
-
.then((parents) => {
|
|
1063
|
-
secondParentBatch = parents;
|
|
1064
|
-
|
|
1065
|
-
return Promise.all(createThreadObjs(parents).map(postReply(webex, conversation)));
|
|
1066
|
-
})
|
|
1067
|
-
);
|
|
1068
|
-
|
|
1069
|
-
beforeEach(() => {
|
|
1070
|
-
const funcs = initializeGenerator();
|
|
1071
|
-
|
|
1072
|
-
getOlder = funcs.getOlder;
|
|
1073
|
-
jumpToActivity = funcs.jumpToActivity;
|
|
1074
|
-
});
|
|
1075
|
-
|
|
1076
|
-
it('should return more than or exactly N minimum activities', () =>
|
|
1077
|
-
getOlder().then(({value}) => {
|
|
1078
|
-
assert.isAtLeast(value.length, minActivities);
|
|
1079
|
-
}));
|
|
1080
|
-
|
|
1081
|
-
it('should return edit activity ID as activity ID when an activity has been edited', () => {
|
|
1082
|
-
const lastParent = secondParentBatch[secondParentBatch.length - 1];
|
|
1083
|
-
|
|
1084
|
-
const message = {
|
|
1085
|
-
displayName: 'edited',
|
|
1086
|
-
content: 'edited',
|
|
1087
|
-
};
|
|
1088
|
-
|
|
1089
|
-
const editingActivity = Object.assign(
|
|
1090
|
-
{
|
|
1091
|
-
parent: {
|
|
1092
|
-
id: lastParent.id,
|
|
1093
|
-
type: 'edit',
|
|
1094
|
-
},
|
|
1095
|
-
},
|
|
1096
|
-
{
|
|
1097
|
-
object: message,
|
|
1098
|
-
}
|
|
1099
|
-
);
|
|
1100
|
-
|
|
1101
|
-
return webex.internal.conversation
|
|
1102
|
-
.post(conversation, message, editingActivity)
|
|
1103
|
-
.then(() => getOlder())
|
|
1104
|
-
.then(({value}) => {
|
|
1105
|
-
const activities = value.map((act) => act.activity);
|
|
1106
|
-
const editedAct = find(activities, (act) => act.editParent);
|
|
1107
|
-
|
|
1108
|
-
assert.equal(editedAct.editParent.id, lastParent.id);
|
|
1109
|
-
assert.notEqual(editedAct.id, lastParent.id);
|
|
1110
|
-
});
|
|
1111
|
-
});
|
|
1112
|
-
|
|
1113
|
-
it('should return activities in thread order', () =>
|
|
1114
|
-
getOlder().then((data) => {
|
|
1115
|
-
const {value} = data;
|
|
1116
|
-
const oldestAct = value[0].activity;
|
|
1117
|
-
const newestAct = value[value.length - 1].activity;
|
|
1118
|
-
|
|
1119
|
-
const oldestThreadIx = findIndex(value, ['activity.parent.type', 'reply']);
|
|
1120
|
-
const oldestParent = value[oldestThreadIx - 1].activity;
|
|
1121
|
-
|
|
1122
|
-
assert.isTrue(oldestAct.published < newestAct.published);
|
|
1123
|
-
|
|
1124
|
-
assert.doesNotHaveAnyKeys(oldestParent, 'parentActivityId');
|
|
1125
|
-
assert.isTrue(oldestParent.object.objectType === 'comment');
|
|
1126
|
-
}));
|
|
1127
|
-
|
|
1128
|
-
it('should return next batch when getOlder is called a second time', () => {
|
|
1129
|
-
let firstBatch;
|
|
1130
|
-
|
|
1131
|
-
return getOlder()
|
|
1132
|
-
.then(({value}) => {
|
|
1133
|
-
firstBatch = value;
|
|
1134
|
-
|
|
1135
|
-
return getOlder();
|
|
1136
|
-
})
|
|
1137
|
-
.then(({value}) => {
|
|
1138
|
-
const secondBatch = value;
|
|
1139
|
-
|
|
1140
|
-
const oldestRootInFirstBatch = find(firstBatch, [
|
|
1141
|
-
'activity.object.objectType',
|
|
1142
|
-
'comment',
|
|
1143
|
-
]).activity;
|
|
1144
|
-
const newestRootInSecondBatch = findLast(secondBatch, [
|
|
1145
|
-
'activity.object.objectType',
|
|
1146
|
-
'comment',
|
|
1147
|
-
]).activity;
|
|
1148
|
-
|
|
1149
|
-
assert.isTrue(oldestRootInFirstBatch.published > newestRootInSecondBatch.published);
|
|
1150
|
-
});
|
|
1151
|
-
});
|
|
1152
|
-
|
|
1153
|
-
it('should return done as true when no more activities can be fetched', () => {
|
|
1154
|
-
const {getOlder: getOlderWithLargeMin} =
|
|
1155
|
-
webex.internal.conversation.listActivitiesThreadOrdered({
|
|
1156
|
-
conversationId: conversation.id,
|
|
1157
|
-
minActivities: 50,
|
|
1158
|
-
});
|
|
1159
|
-
|
|
1160
|
-
return getOlderWithLargeMin().then(({done}) => {
|
|
1161
|
-
assert.isTrue(done);
|
|
1162
|
-
});
|
|
1163
|
-
});
|
|
1164
|
-
|
|
1165
|
-
describe('jumpToActivity()', () => {
|
|
1166
|
-
let _listActivitiesThreadOrderedSpy;
|
|
1167
|
-
|
|
1168
|
-
beforeEach(() => {
|
|
1169
|
-
_listActivitiesThreadOrderedSpy = sinon.spy(
|
|
1170
|
-
webex.internal.conversation,
|
|
1171
|
-
'_listActivitiesThreadOrdered'
|
|
1172
|
-
);
|
|
1173
|
-
});
|
|
1174
|
-
|
|
1175
|
-
afterEach(() => {
|
|
1176
|
-
webex.internal.conversation._listActivitiesThreadOrdered.restore();
|
|
1177
|
-
});
|
|
1178
|
-
|
|
1179
|
-
it('should return searched-for activity with surrounding activities when jumpToActivity is called with an activity', () => {
|
|
1180
|
-
const search = firstParentBatch[firstParentBatch.length - 1];
|
|
1181
|
-
|
|
1182
|
-
return jumpToActivity(search).then(({value}) => {
|
|
1183
|
-
const searchedForActivityIx = findIndex(value, ['id', search.id]);
|
|
1184
|
-
|
|
1185
|
-
assert.isFalse(searchedForActivityIx === -1);
|
|
1186
|
-
assert.isTrue(searchedForActivityIx > 0);
|
|
1187
|
-
assert.isTrue(searchedForActivityIx < value.length);
|
|
1188
|
-
});
|
|
1189
|
-
});
|
|
1190
|
-
|
|
1191
|
-
it('should return all activities in a space when jumping to an activity in a space with less activities than the asked-for activities limit', () =>
|
|
1192
|
-
webex.internal.conversation
|
|
1193
|
-
.create({participants: [scott.id]})
|
|
1194
|
-
.then((c) =>
|
|
1195
|
-
webex.internal.conversation
|
|
1196
|
-
.post(c, {displayName: 'first message'})
|
|
1197
|
-
.then((m) =>
|
|
1198
|
-
webex.internal.conversation
|
|
1199
|
-
.listActivities({conversationUrl: c.url})
|
|
1200
|
-
.then((acts) => jumpToActivity(m).then(() => acts.length))
|
|
1201
|
-
)
|
|
1202
|
-
)
|
|
1203
|
-
.then((actCount) => {
|
|
1204
|
-
assert.isTrue(actCount < minActivities);
|
|
1205
|
-
}));
|
|
1206
|
-
|
|
1207
|
-
it('should return all activities in a space when jumping to an activity in a space with more activities than the asked-for activities limit', () =>
|
|
1208
|
-
webex.internal.conversation
|
|
1209
|
-
.create({participants: [scott.id]})
|
|
1210
|
-
.then((c) => {
|
|
1211
|
-
const $posts = [];
|
|
1212
|
-
|
|
1213
|
-
// eslint-disable-next-line no-plusplus
|
|
1214
|
-
for (let i = 0; i < 15; i++) {
|
|
1215
|
-
$posts.push(webex.internal.conversation.post(c, {displayName: `message ${i}`}));
|
|
1216
|
-
}
|
|
1217
|
-
|
|
1218
|
-
return Promise.all($posts).then(() =>
|
|
1219
|
-
webex.internal.conversation.post(c, {displayName: 'message last'})
|
|
1220
|
-
);
|
|
1221
|
-
})
|
|
1222
|
-
.then((lastPost) => jumpToActivity(lastPost))
|
|
1223
|
-
.then(({value: acts}) => {
|
|
1224
|
-
assert.isAtLeast(acts.length, minActivities);
|
|
1225
|
-
|
|
1226
|
-
const firstAct = acts[0].activity;
|
|
1227
|
-
|
|
1228
|
-
assert.notEqual(firstAct.verb, 'create');
|
|
1229
|
-
}));
|
|
1230
|
-
|
|
1231
|
-
it('should re-initialize _listActivitiesThreadOrdered when jumpToActivity is called with a new URL', () => {
|
|
1232
|
-
let conversation2, msg;
|
|
1233
|
-
|
|
1234
|
-
return webex.internal.conversation
|
|
1235
|
-
.create({participants: [scott.id]})
|
|
1236
|
-
.then((c) => {
|
|
1237
|
-
conversation2 = c;
|
|
1238
|
-
|
|
1239
|
-
return webex.internal.conversation.post(conversation2, {
|
|
1240
|
-
displayName: 'first message',
|
|
1241
|
-
});
|
|
1242
|
-
})
|
|
1243
|
-
.then((m) => {
|
|
1244
|
-
msg = m;
|
|
1245
|
-
|
|
1246
|
-
return jumpToActivity(msg);
|
|
1247
|
-
})
|
|
1248
|
-
.then(() => {
|
|
1249
|
-
assert.isTrue(_listActivitiesThreadOrderedSpy.args[0][0].url === conversation2.url);
|
|
1250
|
-
});
|
|
1251
|
-
});
|
|
1252
|
-
});
|
|
1253
|
-
});
|
|
1254
|
-
});
|
|
1255
|
-
});
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import '@webex/internal-plugin-conversation';
|
|
6
|
+
|
|
7
|
+
import WebexCore from '@webex/webex-core';
|
|
8
|
+
import {assert} from '@webex/test-helper-chai';
|
|
9
|
+
import sinon from 'sinon';
|
|
10
|
+
import testUsers from '@webex/test-helper-test-users';
|
|
11
|
+
import fh from '@webex/test-helper-file';
|
|
12
|
+
import makeLocalUrl from '@webex/test-helper-make-local-url';
|
|
13
|
+
import {map, find, findIndex, findLast} from 'lodash';
|
|
14
|
+
import retry from '@webex/test-helper-retry';
|
|
15
|
+
|
|
16
|
+
const postMessage = (webex, convo) => (msg) =>
|
|
17
|
+
webex.internal.conversation.post(convo, {displayName: msg});
|
|
18
|
+
|
|
19
|
+
const postReply = (webex, conversation) => (threadObj) =>
|
|
20
|
+
webex.internal.conversation.post(conversation, threadObj.displayName, {
|
|
21
|
+
parentActivityId: threadObj.parentActivityId,
|
|
22
|
+
activityType: 'reply',
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const threadDisplayNames = ['thread 1', 'thread 2', 'thread 3'];
|
|
26
|
+
const createThreadObjs = (parents) => {
|
|
27
|
+
const threadObjects = [];
|
|
28
|
+
|
|
29
|
+
for (const msg of threadDisplayNames) {
|
|
30
|
+
for (const [ix, parentAct] of parents.entries()) {
|
|
31
|
+
// add threads to every other, plus randoms for variability
|
|
32
|
+
if (ix % 2 || Math.round(Math.random())) {
|
|
33
|
+
threadObjects.push({
|
|
34
|
+
displayName: `${parentAct.object.displayName} ${msg}`,
|
|
35
|
+
parentActivityId: parentAct.id,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return threadObjects;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
describe('plugin-conversation', function () {
|
|
45
|
+
this.timeout(120000);
|
|
46
|
+
|
|
47
|
+
describe('when fetching conversations', () => {
|
|
48
|
+
let kirk, mccoy, participants, scott, webex, spock, suluEU, checkov;
|
|
49
|
+
|
|
50
|
+
before('create tests users and connect three to mercury', () =>
|
|
51
|
+
Promise.all([
|
|
52
|
+
testUsers.create({count: 5}),
|
|
53
|
+
testUsers.create({count: 1, config: {orgId: process.env.EU_PRIMARY_ORG_ID}}),
|
|
54
|
+
]).then(([users, usersEU]) => {
|
|
55
|
+
[spock, mccoy, kirk, scott, checkov] = users;
|
|
56
|
+
[suluEU] = usersEU;
|
|
57
|
+
participants = [spock, mccoy, kirk];
|
|
58
|
+
|
|
59
|
+
spock.webex = new WebexCore({
|
|
60
|
+
credentials: {
|
|
61
|
+
supertoken: spock.token,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
webex = spock.webex;
|
|
66
|
+
|
|
67
|
+
suluEU.webex = new WebexCore({
|
|
68
|
+
credentials: {
|
|
69
|
+
supertoken: suluEU.token,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
checkov.webex = new WebexCore({
|
|
74
|
+
credentials: {
|
|
75
|
+
supertoken: checkov.token,
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
return Promise.all(
|
|
80
|
+
[suluEU, checkov, spock].map((user) =>
|
|
81
|
+
user.webex.internal.services
|
|
82
|
+
.waitForCatalog('postauth')
|
|
83
|
+
.then(() => user.webex.internal.mercury.connect())
|
|
84
|
+
)
|
|
85
|
+
);
|
|
86
|
+
})
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
after(() =>
|
|
90
|
+
Promise.all([suluEU, checkov, spock].map((user) => user.webex.internal.mercury.disconnect()))
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
describe('#download()', () => {
|
|
94
|
+
let sampleImageSmallOnePng = 'sample-image-small-one.png';
|
|
95
|
+
|
|
96
|
+
let conversation, conversationRequestSpy;
|
|
97
|
+
|
|
98
|
+
before('create conversation', () =>
|
|
99
|
+
webex.internal.conversation.create({participants}).then((c) => {
|
|
100
|
+
conversation = c;
|
|
101
|
+
})
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
before('fetch image fixture', () =>
|
|
105
|
+
fh.fetch(sampleImageSmallOnePng).then((res) => {
|
|
106
|
+
sampleImageSmallOnePng = res;
|
|
107
|
+
})
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
beforeEach(() => {
|
|
111
|
+
conversationRequestSpy = sinon.spy(webex.internal.conversation, 'request');
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
afterEach(() => conversationRequestSpy.restore());
|
|
115
|
+
|
|
116
|
+
it('rejects for invalid options argument', () =>
|
|
117
|
+
webex.internal.conversation
|
|
118
|
+
.share(conversation, [sampleImageSmallOnePng])
|
|
119
|
+
.then((activity) => {
|
|
120
|
+
const item = activity.object.files.items[0];
|
|
121
|
+
|
|
122
|
+
item.options = {
|
|
123
|
+
params: {
|
|
124
|
+
allow: 'invalidOption',
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
assert.isRejected(webex.internal.conversation.download(item));
|
|
129
|
+
}));
|
|
130
|
+
|
|
131
|
+
it('downloads and decrypts an encrypted file', () =>
|
|
132
|
+
webex.internal.conversation
|
|
133
|
+
.share(conversation, [sampleImageSmallOnePng])
|
|
134
|
+
.then((activity) => webex.internal.conversation.download(activity.object.files.items[0]))
|
|
135
|
+
.then((f) =>
|
|
136
|
+
fh.isMatchingFile(f, sampleImageSmallOnePng).then((result) => assert.isTrue(result))
|
|
137
|
+
));
|
|
138
|
+
|
|
139
|
+
it('emits download progress events for encrypted files', () =>
|
|
140
|
+
webex.internal.conversation
|
|
141
|
+
.share(conversation, [sampleImageSmallOnePng])
|
|
142
|
+
.then((activity) => {
|
|
143
|
+
const spy = sinon.spy();
|
|
144
|
+
|
|
145
|
+
return webex.internal.conversation
|
|
146
|
+
.download(activity.object.files.items[0])
|
|
147
|
+
.on('progress', spy)
|
|
148
|
+
.then(() => assert.called(spy));
|
|
149
|
+
}));
|
|
150
|
+
|
|
151
|
+
it('downloads and decrypts a file without a scr key', () =>
|
|
152
|
+
webex.internal.conversation
|
|
153
|
+
.download({
|
|
154
|
+
scr: {
|
|
155
|
+
loc: makeLocalUrl('/sample-image-small-one.png'),
|
|
156
|
+
},
|
|
157
|
+
})
|
|
158
|
+
.then((f) =>
|
|
159
|
+
fh.isMatchingFile(f, sampleImageSmallOnePng).then((result) => assert.isTrue(result))
|
|
160
|
+
)
|
|
161
|
+
.then(() =>
|
|
162
|
+
conversationRequestSpy.returnValues[0].then((res) => {
|
|
163
|
+
assert.property(res.options.headers, 'cisco-no-http-redirect');
|
|
164
|
+
assert.property(res.options.headers, 'spark-user-agent');
|
|
165
|
+
assert.property(res.options.headers, 'trackingid');
|
|
166
|
+
})
|
|
167
|
+
));
|
|
168
|
+
|
|
169
|
+
it('downloads and decrypts a non-encrypted file', () =>
|
|
170
|
+
webex.internal.conversation
|
|
171
|
+
.download({url: makeLocalUrl('/sample-image-small-one.png')})
|
|
172
|
+
.then((f) =>
|
|
173
|
+
fh.isMatchingFile(f, sampleImageSmallOnePng).then((result) => assert.isTrue(result))
|
|
174
|
+
)
|
|
175
|
+
.then(() =>
|
|
176
|
+
conversationRequestSpy.returnValues[0].then((res) => {
|
|
177
|
+
assert.property(res.options.headers, 'cisco-no-http-redirect');
|
|
178
|
+
assert.property(res.options.headers, 'spark-user-agent');
|
|
179
|
+
assert.property(res.options.headers, 'trackingid');
|
|
180
|
+
})
|
|
181
|
+
));
|
|
182
|
+
|
|
183
|
+
it('downloads non-encrypted file with specific options headers', () =>
|
|
184
|
+
webex.internal.conversation
|
|
185
|
+
.download(
|
|
186
|
+
{url: makeLocalUrl('/sample-image-small-one.png')},
|
|
187
|
+
{
|
|
188
|
+
headers: {
|
|
189
|
+
'cisco-no-http-redirect': null,
|
|
190
|
+
'spark-user-agent': null,
|
|
191
|
+
trackingid: null,
|
|
192
|
+
},
|
|
193
|
+
}
|
|
194
|
+
)
|
|
195
|
+
.then((f) =>
|
|
196
|
+
fh.isMatchingFile(f, sampleImageSmallOnePng).then((result) => assert.isTrue(result))
|
|
197
|
+
)
|
|
198
|
+
.then(() =>
|
|
199
|
+
conversationRequestSpy.returnValues[0].then((res) => {
|
|
200
|
+
assert.isUndefined(res.options.headers['cisco-no-http-redirect']);
|
|
201
|
+
assert.isUndefined(res.options.headers['spark-user-agent']);
|
|
202
|
+
assert.isUndefined(res.options.headers.trackingid);
|
|
203
|
+
})
|
|
204
|
+
));
|
|
205
|
+
|
|
206
|
+
it('emits download progress events for non-encrypted files', () => {
|
|
207
|
+
const spy = sinon.spy();
|
|
208
|
+
|
|
209
|
+
return webex.internal.conversation
|
|
210
|
+
.download({url: makeLocalUrl('/sample-image-small-one.png')})
|
|
211
|
+
.on('progress', spy)
|
|
212
|
+
.then((f) =>
|
|
213
|
+
fh.isMatchingFile(f, sampleImageSmallOnePng).then((result) => assert.isTrue(result))
|
|
214
|
+
)
|
|
215
|
+
.then(() => assert.called(spy));
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
describe('reads exif data and', () => {
|
|
219
|
+
let fileItem;
|
|
220
|
+
let sampleImagePortraitJpeg = 'Portrait_7.jpg';
|
|
221
|
+
|
|
222
|
+
before('fetch image fixture', () =>
|
|
223
|
+
fh.fetch(sampleImagePortraitJpeg).then((res) => {
|
|
224
|
+
sampleImagePortraitJpeg = res;
|
|
225
|
+
sampleImagePortraitJpeg.displayName = 'Portrait_7.jpg';
|
|
226
|
+
sampleImagePortraitJpeg.mimeType = 'image/jpeg';
|
|
227
|
+
})
|
|
228
|
+
);
|
|
229
|
+
it('does not add exif data', () =>
|
|
230
|
+
webex.internal.conversation
|
|
231
|
+
.share(conversation, [sampleImagePortraitJpeg])
|
|
232
|
+
.then((activity) => {
|
|
233
|
+
fileItem = activity.object.files.items[0];
|
|
234
|
+
|
|
235
|
+
return webex.internal.conversation.download(fileItem, {shouldNotAddExifData: true});
|
|
236
|
+
})
|
|
237
|
+
.then((f) => {
|
|
238
|
+
assert.equal(fileItem.orientation, undefined);
|
|
239
|
+
|
|
240
|
+
return fh.isMatchingFile(f, sampleImagePortraitJpeg);
|
|
241
|
+
})
|
|
242
|
+
.then((result) => assert.isTrue(result)));
|
|
243
|
+
|
|
244
|
+
it('adds exif data', () =>
|
|
245
|
+
webex.internal.conversation
|
|
246
|
+
.share(conversation, [sampleImagePortraitJpeg])
|
|
247
|
+
.then((activity) => {
|
|
248
|
+
fileItem = activity.object.files.items[0];
|
|
249
|
+
|
|
250
|
+
return webex.internal.conversation.download(fileItem);
|
|
251
|
+
})
|
|
252
|
+
.then((f) => {
|
|
253
|
+
assert.equal(fileItem.orientation, 7);
|
|
254
|
+
|
|
255
|
+
return fh.isMatchingFile(f, sampleImagePortraitJpeg);
|
|
256
|
+
})
|
|
257
|
+
.then((result) => assert.isTrue(result)));
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
describe('#get()', () => {
|
|
262
|
+
let conversation, conversation2;
|
|
263
|
+
|
|
264
|
+
before('create conversations', () =>
|
|
265
|
+
Promise.all([
|
|
266
|
+
webex.internal.conversation.create({participants: [mccoy.id]}).then((c) => {
|
|
267
|
+
conversation = c;
|
|
268
|
+
}),
|
|
269
|
+
webex.internal.conversation.create({participants: [scott.id]}).then((c) => {
|
|
270
|
+
conversation2 = c;
|
|
271
|
+
}),
|
|
272
|
+
])
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
it('retrieves a single conversation by url', () =>
|
|
276
|
+
webex.internal.conversation.get({url: conversation.url}).then((c) => {
|
|
277
|
+
assert.equal(c.id, conversation.id);
|
|
278
|
+
assert.equal(c.url, conversation.url);
|
|
279
|
+
}));
|
|
280
|
+
|
|
281
|
+
it('retrieves a single conversation by id', () =>
|
|
282
|
+
webex.internal.conversation.get({id: conversation.id}).then((c) => {
|
|
283
|
+
assert.equal(c.id, conversation.id);
|
|
284
|
+
assert.equal(c.url, conversation.url);
|
|
285
|
+
}));
|
|
286
|
+
|
|
287
|
+
it('retrieves a 1:1 conversation by userId', () =>
|
|
288
|
+
webex.internal.conversation.get({user: mccoy}).then((c) => {
|
|
289
|
+
assert.equal(c.id, conversation.id);
|
|
290
|
+
assert.equal(c.url, conversation.url);
|
|
291
|
+
}));
|
|
292
|
+
|
|
293
|
+
it('retrieves a 1:1 conversation with a deleted user', () =>
|
|
294
|
+
webex.internal.conversation
|
|
295
|
+
.get({user: scott})
|
|
296
|
+
.then((c) => {
|
|
297
|
+
assert.equal(c.id, conversation2.id);
|
|
298
|
+
assert.equal(c.url, conversation2.url);
|
|
299
|
+
})
|
|
300
|
+
.then(() => testUsers.remove([scott]))
|
|
301
|
+
// add retries to address CI propagation delay
|
|
302
|
+
.then(() =>
|
|
303
|
+
retry(() => assert.isRejected(webex.internal.conversation.get({user: scott})))
|
|
304
|
+
)
|
|
305
|
+
.then(() =>
|
|
306
|
+
retry(() =>
|
|
307
|
+
webex.internal.conversation.get({user: scott}, {includeConvWithDeletedUserUUID: true})
|
|
308
|
+
)
|
|
309
|
+
)
|
|
310
|
+
.then((c) => {
|
|
311
|
+
assert.equal(c.id, conversation2.id);
|
|
312
|
+
assert.equal(c.url, conversation2.url);
|
|
313
|
+
}));
|
|
314
|
+
|
|
315
|
+
it('decrypts the contents of activities in the retrieved conversation', () =>
|
|
316
|
+
webex.internal.conversation
|
|
317
|
+
.post(conversation, {
|
|
318
|
+
displayName: 'Test Message',
|
|
319
|
+
})
|
|
320
|
+
.then(() =>
|
|
321
|
+
webex.internal.conversation.get({url: conversation.url}, {activitiesLimit: 50})
|
|
322
|
+
)
|
|
323
|
+
.then((c) => {
|
|
324
|
+
const posts = c.activities.items.filter((activity) => activity.verb === 'post');
|
|
325
|
+
|
|
326
|
+
assert.lengthOf(posts, 1);
|
|
327
|
+
assert.equal(posts[0].object.displayName, 'Test Message');
|
|
328
|
+
}));
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
describe('#list()', () => {
|
|
332
|
+
let conversation1, conversation2;
|
|
333
|
+
|
|
334
|
+
before('create conversations', () =>
|
|
335
|
+
webex.internal.conversation
|
|
336
|
+
.create({
|
|
337
|
+
displayName: 'test 1',
|
|
338
|
+
participants,
|
|
339
|
+
})
|
|
340
|
+
.then((c) => {
|
|
341
|
+
conversation1 = c;
|
|
342
|
+
})
|
|
343
|
+
.then(() =>
|
|
344
|
+
webex.internal.conversation.create({
|
|
345
|
+
displayName: 'test 2',
|
|
346
|
+
participants,
|
|
347
|
+
})
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
.then((c) => {
|
|
351
|
+
conversation2 = c;
|
|
352
|
+
})
|
|
353
|
+
);
|
|
354
|
+
|
|
355
|
+
it('retrieves a set of conversations', () =>
|
|
356
|
+
webex.internal.conversation
|
|
357
|
+
.list({
|
|
358
|
+
conversationsLimit: 2,
|
|
359
|
+
})
|
|
360
|
+
.then((conversations) => {
|
|
361
|
+
assert.include(map(conversations, 'url'), conversation1.url);
|
|
362
|
+
assert.include(map(conversations, 'url'), conversation2.url);
|
|
363
|
+
}));
|
|
364
|
+
|
|
365
|
+
it('retrieves a paginated set of conversations', () =>
|
|
366
|
+
webex.internal.conversation
|
|
367
|
+
.paginate({
|
|
368
|
+
conversationsLimit: 1,
|
|
369
|
+
personRefresh: false,
|
|
370
|
+
paginate: true,
|
|
371
|
+
})
|
|
372
|
+
.then((response) => {
|
|
373
|
+
const conversations = response.page.items;
|
|
374
|
+
|
|
375
|
+
assert.lengthOf(conversations, 1);
|
|
376
|
+
assert.equal(conversations[0].displayName, conversation2.displayName);
|
|
377
|
+
|
|
378
|
+
return webex.internal.conversation.paginate({page: response.page});
|
|
379
|
+
})
|
|
380
|
+
.then((response) => {
|
|
381
|
+
const conversations = response.page.items;
|
|
382
|
+
|
|
383
|
+
assert.lengthOf(conversations, 1);
|
|
384
|
+
assert.equal(conversations[0].displayName, conversation1.displayName);
|
|
385
|
+
}));
|
|
386
|
+
|
|
387
|
+
describe('with summary = true (ConversationsSummary)', () => {
|
|
388
|
+
it('retrieves all conversations using conversationsSummary', () =>
|
|
389
|
+
webex.internal.conversation
|
|
390
|
+
.list({
|
|
391
|
+
summary: true,
|
|
392
|
+
})
|
|
393
|
+
.then((conversations) => {
|
|
394
|
+
assert.include(map(conversations, 'url'), conversation1.url);
|
|
395
|
+
assert.include(map(conversations, 'url'), conversation2.url);
|
|
396
|
+
}));
|
|
397
|
+
|
|
398
|
+
it('retrieves a set of (1) conversations using conversationsLimit', () =>
|
|
399
|
+
webex.internal.conversation
|
|
400
|
+
.list({
|
|
401
|
+
summary: true,
|
|
402
|
+
conversationsLimit: 1,
|
|
403
|
+
})
|
|
404
|
+
.then((conversations) => {
|
|
405
|
+
assert.lengthOf(conversations, 1);
|
|
406
|
+
assert.include(map(conversations, 'url'), conversation2.url);
|
|
407
|
+
assert.include(map(conversations, 'displayName'), conversation2.displayName);
|
|
408
|
+
}));
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
describe('with deferDecrypt = true', () => {
|
|
412
|
+
it('retrieves a non-decrypted set of conversations each with a bound decrypt method', () =>
|
|
413
|
+
webex.internal.conversation
|
|
414
|
+
.list({
|
|
415
|
+
conversationsLimit: 2,
|
|
416
|
+
deferDecrypt: true,
|
|
417
|
+
})
|
|
418
|
+
.then(([c1, c2]) => {
|
|
419
|
+
assert.lengthOf(
|
|
420
|
+
c1.displayName.split('.'),
|
|
421
|
+
5,
|
|
422
|
+
'5 periods implies this is a jwt and not a decrypted string'
|
|
423
|
+
);
|
|
424
|
+
assert.notInclude(['test 1, test 2'], c1.displayName);
|
|
425
|
+
|
|
426
|
+
assert.lengthOf(
|
|
427
|
+
c2.displayName.split('.'),
|
|
428
|
+
5,
|
|
429
|
+
'5 periods implies this is a jwt and not a decrypted string'
|
|
430
|
+
);
|
|
431
|
+
assert.notInclude(['test 1, test 2'], c2.displayName);
|
|
432
|
+
|
|
433
|
+
return Promise.all([
|
|
434
|
+
c1.decrypt().then(() => assert.notInclude(['test 1, test 2'], c1.displayName)),
|
|
435
|
+
c2.decrypt().then(() => assert.notInclude(['test 1, test 2'], c2.displayName)),
|
|
436
|
+
]);
|
|
437
|
+
}));
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
describe('with deferDecrypt && summary = true', () => {
|
|
441
|
+
it('retrieves a non-decrypted set of conversations each with a bound decrypt method', () =>
|
|
442
|
+
webex.internal.conversation
|
|
443
|
+
.list({
|
|
444
|
+
conversationsLimit: 2,
|
|
445
|
+
deferDecrypt: true,
|
|
446
|
+
summary: true,
|
|
447
|
+
})
|
|
448
|
+
.then(([c1, c2]) => {
|
|
449
|
+
assert.lengthOf(
|
|
450
|
+
c1.displayName.split('.'),
|
|
451
|
+
5,
|
|
452
|
+
'5 periods implies this is a jwt and not a decrypted string'
|
|
453
|
+
);
|
|
454
|
+
assert.notInclude(['test 1, test 2'], c1.displayName);
|
|
455
|
+
|
|
456
|
+
assert.lengthOf(
|
|
457
|
+
c2.displayName.split('.'),
|
|
458
|
+
5,
|
|
459
|
+
'5 periods implies this is a jwt and not a decrypted string'
|
|
460
|
+
);
|
|
461
|
+
assert.notInclude(['test 1, test 2'], c2.displayName);
|
|
462
|
+
|
|
463
|
+
return Promise.all([
|
|
464
|
+
c1.decrypt().then(() => assert.notInclude(['test 1, test 2'], c1.displayName)),
|
|
465
|
+
c2.decrypt().then(() => assert.notInclude(['test 1, test 2'], c2.displayName)),
|
|
466
|
+
]);
|
|
467
|
+
}));
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
describe('with conversation from remote clusters', () => {
|
|
471
|
+
let conversation3, conversation4;
|
|
472
|
+
|
|
473
|
+
before('create conversations in EU cluster', () =>
|
|
474
|
+
Promise.all([
|
|
475
|
+
suluEU.webex.internal.conversation
|
|
476
|
+
.create({
|
|
477
|
+
displayName: 'eu test 1',
|
|
478
|
+
participants,
|
|
479
|
+
})
|
|
480
|
+
.then((c) => {
|
|
481
|
+
conversation3 = c;
|
|
482
|
+
}),
|
|
483
|
+
suluEU.webex.internal.conversation
|
|
484
|
+
.create({
|
|
485
|
+
displayName: 'eu test 2',
|
|
486
|
+
participants: [checkov.id, spock.id],
|
|
487
|
+
})
|
|
488
|
+
.then((c) => {
|
|
489
|
+
conversation4 = c;
|
|
490
|
+
}),
|
|
491
|
+
])
|
|
492
|
+
);
|
|
493
|
+
|
|
494
|
+
it('retrieves local + remote cluster conversations', () =>
|
|
495
|
+
webex.internal.conversation.list().then((conversations) => {
|
|
496
|
+
assert.include(map(conversations, 'url'), conversation1.url);
|
|
497
|
+
assert.include(map(conversations, 'url'), conversation2.url);
|
|
498
|
+
assert.include(map(conversations, 'url'), conversation3.url);
|
|
499
|
+
assert.include(map(conversations, 'url'), conversation4.url);
|
|
500
|
+
}));
|
|
501
|
+
|
|
502
|
+
it('retrieves only remote cluter conversations if user does not have any local conversations', () =>
|
|
503
|
+
checkov.webex.internal.conversation.list().then((conversations) => {
|
|
504
|
+
assert.include(map(conversations, 'url'), conversation4.url);
|
|
505
|
+
assert.lengthOf(conversations, 1);
|
|
506
|
+
}));
|
|
507
|
+
});
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
describe('#listLeft()', () => {
|
|
511
|
+
let conversation;
|
|
512
|
+
|
|
513
|
+
before('create conversation', () =>
|
|
514
|
+
webex.internal.conversation.create({participants}).then((c) => {
|
|
515
|
+
conversation = c;
|
|
516
|
+
})
|
|
517
|
+
);
|
|
518
|
+
|
|
519
|
+
it('retrieves the conversations the current user has left', () =>
|
|
520
|
+
webex.internal.conversation
|
|
521
|
+
.listLeft()
|
|
522
|
+
.then((c) => {
|
|
523
|
+
assert.lengthOf(c, 0);
|
|
524
|
+
|
|
525
|
+
return webex.internal.conversation.leave(conversation);
|
|
526
|
+
})
|
|
527
|
+
.then(() => webex.internal.conversation.listLeft())
|
|
528
|
+
.then((c) => {
|
|
529
|
+
assert.lengthOf(c, 1);
|
|
530
|
+
assert.equal(c[0].id, conversation.id);
|
|
531
|
+
}));
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
describe('#listActivities()', () => {
|
|
535
|
+
let conversation;
|
|
536
|
+
|
|
537
|
+
before('create conversation with activity', () =>
|
|
538
|
+
webex.internal.conversation.create({participants}).then((c) => {
|
|
539
|
+
conversation = c;
|
|
540
|
+
assert.lengthOf(conversation.participants.items, 3);
|
|
541
|
+
|
|
542
|
+
return webex.internal.conversation.post(conversation, {displayName: 'first message'});
|
|
543
|
+
})
|
|
544
|
+
);
|
|
545
|
+
|
|
546
|
+
it('retrieves activities for the specified conversation', () =>
|
|
547
|
+
webex.internal.conversation
|
|
548
|
+
.listActivities({conversationUrl: conversation.url})
|
|
549
|
+
.then((activities) => {
|
|
550
|
+
assert.isArray(activities);
|
|
551
|
+
assert.lengthOf(activities, 2);
|
|
552
|
+
}));
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
describe('#listThreads()', () => {
|
|
556
|
+
let webex2;
|
|
557
|
+
|
|
558
|
+
before('connect mccoy to mercury', () => {
|
|
559
|
+
webex2 = new WebexCore({
|
|
560
|
+
credentials: {
|
|
561
|
+
authorization: mccoy.token,
|
|
562
|
+
},
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
return webex2.internal.mercury.connect();
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
after(() => webex2 && webex2.internal.mercury.disconnect());
|
|
569
|
+
|
|
570
|
+
let conversation;
|
|
571
|
+
let parent;
|
|
572
|
+
|
|
573
|
+
before('create conversation', () =>
|
|
574
|
+
webex.internal.conversation.create({participants}).then((c) => {
|
|
575
|
+
conversation = c;
|
|
576
|
+
assert.lengthOf(conversation.participants.items, 3);
|
|
577
|
+
|
|
578
|
+
return webex2.internal.conversation
|
|
579
|
+
.post(conversation, {displayName: 'first message'})
|
|
580
|
+
.then((parentActivity) => {
|
|
581
|
+
parent = parentActivity;
|
|
582
|
+
});
|
|
583
|
+
})
|
|
584
|
+
);
|
|
585
|
+
|
|
586
|
+
it('retrieves threads()', () =>
|
|
587
|
+
webex2.internal.conversation
|
|
588
|
+
.post(conversation, 'thread1', {
|
|
589
|
+
parentActivityId: parent.id,
|
|
590
|
+
activityType: 'reply',
|
|
591
|
+
})
|
|
592
|
+
.then(() => webex2.internal.conversation.listThreads())
|
|
593
|
+
.then((thread) => {
|
|
594
|
+
assert.equal(thread.length, 1);
|
|
595
|
+
const firstThread = thread[0];
|
|
596
|
+
|
|
597
|
+
assert.equal(firstThread.childType, 'reply');
|
|
598
|
+
assert.equal(firstThread.parentActivityId, parent.id);
|
|
599
|
+
assert.equal(firstThread.conversationId, conversation.id);
|
|
600
|
+
assert.equal(firstThread.childActivities.length, 1);
|
|
601
|
+
|
|
602
|
+
const childActivity = firstThread.childActivities[0];
|
|
603
|
+
|
|
604
|
+
assert.equal(childActivity.objectType, 'activity');
|
|
605
|
+
assert.equal(childActivity.object.displayName, 'thread1');
|
|
606
|
+
}));
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
describe('#listMentions()', () => {
|
|
610
|
+
let webex2;
|
|
611
|
+
|
|
612
|
+
before('connect mccoy to mercury', () => {
|
|
613
|
+
webex2 = new WebexCore({
|
|
614
|
+
credentials: {
|
|
615
|
+
authorization: mccoy.token,
|
|
616
|
+
},
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
return webex2.internal.mercury.connect();
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
after(() => webex2 && webex2.internal.mercury.disconnect());
|
|
623
|
+
|
|
624
|
+
let conversation;
|
|
625
|
+
|
|
626
|
+
before('create conversation', () =>
|
|
627
|
+
webex.internal.conversation.create({participants}).then((c) => {
|
|
628
|
+
conversation = c;
|
|
629
|
+
assert.lengthOf(conversation.participants.items, 3);
|
|
630
|
+
})
|
|
631
|
+
);
|
|
632
|
+
|
|
633
|
+
it('retrieves activities in which the current user was mentioned', () =>
|
|
634
|
+
webex2.internal.conversation
|
|
635
|
+
.post(conversation, {
|
|
636
|
+
displayName: 'Green blooded hobgloblin',
|
|
637
|
+
content: `<webex-mention data-object-type="person" data-object-id="${spock.id}">Green blooded hobgloblin</webex-mention>`,
|
|
638
|
+
mentions: {
|
|
639
|
+
items: [
|
|
640
|
+
{
|
|
641
|
+
id: `${spock.id}`,
|
|
642
|
+
objectType: 'person',
|
|
643
|
+
},
|
|
644
|
+
],
|
|
645
|
+
},
|
|
646
|
+
})
|
|
647
|
+
.then((activity) =>
|
|
648
|
+
webex.internal.conversation
|
|
649
|
+
.listMentions({sinceDate: Date.parse(activity.published) - 1})
|
|
650
|
+
.then((mentions) => {
|
|
651
|
+
assert.lengthOf(mentions, 1);
|
|
652
|
+
assert.equal(mentions[0].url, activity.url);
|
|
653
|
+
})
|
|
654
|
+
));
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
// TODO: add testing for bulk_activities_fetch() with clusters later
|
|
658
|
+
describe('#bulkActivitiesFetch()', () => {
|
|
659
|
+
let jenny, maria, dan, convo1, convo2, euConvo1;
|
|
660
|
+
let webex3;
|
|
661
|
+
|
|
662
|
+
before('create tests users and connect one to mercury', () =>
|
|
663
|
+
testUsers.create({count: 4}).then((users) => {
|
|
664
|
+
[jenny, maria, dan] = users;
|
|
665
|
+
|
|
666
|
+
webex3 = new WebexCore({
|
|
667
|
+
credentials: {
|
|
668
|
+
authorization: jenny.token,
|
|
669
|
+
},
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
return webex3.internal.mercury.connect();
|
|
673
|
+
})
|
|
674
|
+
);
|
|
675
|
+
|
|
676
|
+
after(() => webex3 && webex3.internal.mercury.disconnect());
|
|
677
|
+
|
|
678
|
+
before('create conversation 1', () =>
|
|
679
|
+
webex3.internal.conversation.create({participants: [jenny, maria]}).then((c1) => {
|
|
680
|
+
convo1 = c1;
|
|
681
|
+
})
|
|
682
|
+
);
|
|
683
|
+
|
|
684
|
+
before('create conversation 2', () =>
|
|
685
|
+
webex3.internal.conversation.create({participants: [jenny, dan]}).then((c2) => {
|
|
686
|
+
convo2 = c2;
|
|
687
|
+
})
|
|
688
|
+
);
|
|
689
|
+
|
|
690
|
+
before('create conversations in EU cluster', () =>
|
|
691
|
+
suluEU.webex.internal.conversation
|
|
692
|
+
.create({
|
|
693
|
+
displayName: 'eu test 1',
|
|
694
|
+
participants: [jenny, suluEU, dan],
|
|
695
|
+
})
|
|
696
|
+
.then((c) => {
|
|
697
|
+
euConvo1 = c;
|
|
698
|
+
})
|
|
699
|
+
);
|
|
700
|
+
|
|
701
|
+
before('add comments to convo1, and check post requests successfully went through', () =>
|
|
702
|
+
webex3.internal.conversation
|
|
703
|
+
.post(convo1, {displayName: 'BAGELS (O)'})
|
|
704
|
+
.then((c1) => {
|
|
705
|
+
assert.equal(c1.object.displayName, 'BAGELS (O)');
|
|
706
|
+
|
|
707
|
+
return webex3.internal.conversation.post(convo1, {displayName: 'Cream Cheese'});
|
|
708
|
+
})
|
|
709
|
+
.then((c2) => {
|
|
710
|
+
assert.equal(c2.object.displayName, 'Cream Cheese');
|
|
711
|
+
})
|
|
712
|
+
);
|
|
713
|
+
|
|
714
|
+
before('add comments to convo2, and check post requests successfully went through', () =>
|
|
715
|
+
webex3.internal.conversation
|
|
716
|
+
.post(convo2, {displayName: 'Want to head to lunch soon?'})
|
|
717
|
+
.then((c1) => {
|
|
718
|
+
assert.equal(c1.object.displayName, 'Want to head to lunch soon?');
|
|
719
|
+
|
|
720
|
+
return webex3.internal.conversation.post(convo2, {displayName: 'Sure :)'});
|
|
721
|
+
})
|
|
722
|
+
.then((c2) => {
|
|
723
|
+
assert.equal(c2.object.displayName, 'Sure :)');
|
|
724
|
+
|
|
725
|
+
return webex3.internal.conversation.post(convo2, {displayName: 'where?'});
|
|
726
|
+
})
|
|
727
|
+
.then((c3) => {
|
|
728
|
+
assert.equal(c3.object.displayName, 'where?');
|
|
729
|
+
|
|
730
|
+
return webex3.internal.conversation.post(convo2, {displayName: 'Meekong Bar!'});
|
|
731
|
+
})
|
|
732
|
+
.then((c4) => {
|
|
733
|
+
assert.equal(c4.object.displayName, 'Meekong Bar!');
|
|
734
|
+
})
|
|
735
|
+
);
|
|
736
|
+
|
|
737
|
+
before('add comments to euConvo1, and check post requests successfully went through', () =>
|
|
738
|
+
suluEU.webex.internal.conversation.post(euConvo1, {displayName: 'Hello'}).then((c1) => {
|
|
739
|
+
assert.equal(c1.object.displayName, 'Hello');
|
|
740
|
+
})
|
|
741
|
+
);
|
|
742
|
+
|
|
743
|
+
it('retrieves activities from a single conversation', () =>
|
|
744
|
+
webex3.internal.conversation
|
|
745
|
+
.listActivities({conversationUrl: convo1.url})
|
|
746
|
+
.then((convoActivities) => {
|
|
747
|
+
const activityURLs = [];
|
|
748
|
+
const expectedActivities = [];
|
|
749
|
+
|
|
750
|
+
convoActivities.forEach((a) => {
|
|
751
|
+
if (a.verb === 'post') {
|
|
752
|
+
activityURLs.push(a.url);
|
|
753
|
+
expectedActivities.push(a);
|
|
754
|
+
}
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
return webex3.internal.conversation
|
|
758
|
+
.bulkActivitiesFetch(activityURLs)
|
|
759
|
+
.then((bulkFetchedActivities) => {
|
|
760
|
+
assert.lengthOf(bulkFetchedActivities, expectedActivities.length);
|
|
761
|
+
assert.equal(
|
|
762
|
+
bulkFetchedActivities[0].object.displayName,
|
|
763
|
+
expectedActivities[0].object.displayName
|
|
764
|
+
);
|
|
765
|
+
assert.equal(
|
|
766
|
+
bulkFetchedActivities[1].object.displayName,
|
|
767
|
+
expectedActivities[1].object.displayName
|
|
768
|
+
);
|
|
769
|
+
});
|
|
770
|
+
}));
|
|
771
|
+
|
|
772
|
+
it('retrieves activities from multiple conversations', () => {
|
|
773
|
+
const activityURLs = [];
|
|
774
|
+
const expectedActivities = [];
|
|
775
|
+
|
|
776
|
+
return webex3.internal.conversation
|
|
777
|
+
.listActivities({conversationUrl: convo1.url})
|
|
778
|
+
.then((convo1Activities) => {
|
|
779
|
+
// gets all post activity urls from convo1
|
|
780
|
+
convo1Activities.forEach((a1) => {
|
|
781
|
+
if (a1.verb === 'post') {
|
|
782
|
+
activityURLs.push(a1.url);
|
|
783
|
+
expectedActivities.push(a1);
|
|
784
|
+
}
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
return webex3.internal.conversation.listActivities({conversationUrl: convo2.url});
|
|
788
|
+
})
|
|
789
|
+
.then((convo2Activities) => {
|
|
790
|
+
// gets activity urls of only comment 3 and 4 from convo2
|
|
791
|
+
[3, 4].forEach((i) => {
|
|
792
|
+
activityURLs.push(convo2Activities[i].url);
|
|
793
|
+
expectedActivities.push(convo2Activities[i]);
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
return webex3.internal.conversation
|
|
797
|
+
.bulkActivitiesFetch(activityURLs)
|
|
798
|
+
.then((bulkFetchedActivities) => {
|
|
799
|
+
assert.lengthOf(bulkFetchedActivities, expectedActivities.length);
|
|
800
|
+
assert.equal(
|
|
801
|
+
bulkFetchedActivities[0].object.displayName,
|
|
802
|
+
expectedActivities[0].object.displayName
|
|
803
|
+
);
|
|
804
|
+
assert.equal(
|
|
805
|
+
bulkFetchedActivities[1].object.displayName,
|
|
806
|
+
expectedActivities[1].object.displayName
|
|
807
|
+
);
|
|
808
|
+
assert.equal(
|
|
809
|
+
bulkFetchedActivities[2].object.displayName,
|
|
810
|
+
expectedActivities[2].object.displayName
|
|
811
|
+
);
|
|
812
|
+
assert.equal(
|
|
813
|
+
bulkFetchedActivities[3].object.displayName,
|
|
814
|
+
expectedActivities[3].object.displayName
|
|
815
|
+
);
|
|
816
|
+
});
|
|
817
|
+
});
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
it('given a activity url that does not exist, should return []', () => {
|
|
821
|
+
const mockURL =
|
|
822
|
+
'https://conversation-intb.ciscospark.com/conversation/api/v1/activities/6d8c7c90-a770-11e9-bcfb-6616ead99ac3';
|
|
823
|
+
|
|
824
|
+
webex3.internal.conversation
|
|
825
|
+
.bulkActivitiesFetch([mockURL])
|
|
826
|
+
.then((bulkFetchedActivities) => {
|
|
827
|
+
assert.equal(bulkFetchedActivities, []);
|
|
828
|
+
});
|
|
829
|
+
});
|
|
830
|
+
|
|
831
|
+
it('retrieves activities from multiple conversations passing in base convo url', () => {
|
|
832
|
+
const activityURLs = [];
|
|
833
|
+
const expectedActivities = [];
|
|
834
|
+
|
|
835
|
+
return webex3.internal.conversation
|
|
836
|
+
.listActivities({conversationUrl: convo1.url})
|
|
837
|
+
.then((convo1Activities) => {
|
|
838
|
+
// gets all post activity urls from convo1
|
|
839
|
+
convo1Activities.forEach((a1) => {
|
|
840
|
+
if (a1.verb === 'post') {
|
|
841
|
+
activityURLs.push(a1.url);
|
|
842
|
+
expectedActivities.push(a1);
|
|
843
|
+
}
|
|
844
|
+
});
|
|
845
|
+
|
|
846
|
+
return webex3.internal.conversation.listActivities({conversationUrl: convo2.url});
|
|
847
|
+
})
|
|
848
|
+
.then((convo2Activities) => {
|
|
849
|
+
// gets activity urls of only comment 3 and 4 from convo2
|
|
850
|
+
[3, 4].forEach((i) => {
|
|
851
|
+
activityURLs.push(convo2Activities[i].url);
|
|
852
|
+
expectedActivities.push(convo2Activities[i]);
|
|
853
|
+
});
|
|
854
|
+
|
|
855
|
+
return webex3.internal.conversation
|
|
856
|
+
.bulkActivitiesFetch(activityURLs, undefined, {url: process.env.CONVERSATION_SERVICE})
|
|
857
|
+
.then((bulkFetchedActivities) => {
|
|
858
|
+
assert.lengthOf(bulkFetchedActivities, expectedActivities.length);
|
|
859
|
+
assert.equal(
|
|
860
|
+
bulkFetchedActivities[0].object.displayName,
|
|
861
|
+
expectedActivities[0].object.displayName
|
|
862
|
+
);
|
|
863
|
+
assert.equal(
|
|
864
|
+
bulkFetchedActivities[1].object.displayName,
|
|
865
|
+
expectedActivities[1].object.displayName
|
|
866
|
+
);
|
|
867
|
+
assert.equal(
|
|
868
|
+
bulkFetchedActivities[2].object.displayName,
|
|
869
|
+
expectedActivities[2].object.displayName
|
|
870
|
+
);
|
|
871
|
+
assert.equal(
|
|
872
|
+
bulkFetchedActivities[3].object.displayName,
|
|
873
|
+
expectedActivities[3].object.displayName
|
|
874
|
+
);
|
|
875
|
+
});
|
|
876
|
+
});
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
it('retrieves activities from conversations passing in base convo url from another cluster', () => {
|
|
880
|
+
const activityURLs = [];
|
|
881
|
+
const expectedActivities = [];
|
|
882
|
+
|
|
883
|
+
return webex3.internal.conversation
|
|
884
|
+
.listActivities({conversationUrl: euConvo1.url})
|
|
885
|
+
.then((euConvo1Activities) => {
|
|
886
|
+
const convoUrlRegex = /(.*)\/activities/;
|
|
887
|
+
|
|
888
|
+
activityURLs.push(euConvo1Activities[1].url);
|
|
889
|
+
expectedActivities.push(euConvo1Activities[1]);
|
|
890
|
+
const match = convoUrlRegex.exec(euConvo1Activities[1].url);
|
|
891
|
+
const convoUrl = match[1];
|
|
892
|
+
|
|
893
|
+
return webex3.internal.conversation.bulkActivitiesFetch(activityURLs, {url: convoUrl});
|
|
894
|
+
})
|
|
895
|
+
.then((bulkFetchedActivities) => {
|
|
896
|
+
assert.lengthOf(bulkFetchedActivities, 1);
|
|
897
|
+
assert.equal(
|
|
898
|
+
bulkFetchedActivities[0].object.displayName,
|
|
899
|
+
expectedActivities[0].object.displayName
|
|
900
|
+
);
|
|
901
|
+
});
|
|
902
|
+
});
|
|
903
|
+
});
|
|
904
|
+
|
|
905
|
+
describe('#listParentActivityIds', () => {
|
|
906
|
+
let conversation, parent;
|
|
907
|
+
|
|
908
|
+
beforeEach('create conversation with activity', () =>
|
|
909
|
+
webex.internal.conversation
|
|
910
|
+
.create({participants})
|
|
911
|
+
.then((c) => {
|
|
912
|
+
conversation = c;
|
|
913
|
+
|
|
914
|
+
return webex.internal.conversation.post(conversation, {displayName: 'first message'});
|
|
915
|
+
})
|
|
916
|
+
.then((parentAct) => {
|
|
917
|
+
parent = parentAct;
|
|
918
|
+
})
|
|
919
|
+
);
|
|
920
|
+
|
|
921
|
+
it('retrieves parent IDs for thread parents()', () =>
|
|
922
|
+
webex.internal.conversation
|
|
923
|
+
.post(
|
|
924
|
+
conversation,
|
|
925
|
+
{displayName: 'first thread reply'},
|
|
926
|
+
{
|
|
927
|
+
parentActivityId: parent.id,
|
|
928
|
+
activityType: 'reply',
|
|
929
|
+
}
|
|
930
|
+
)
|
|
931
|
+
.then(({parent: parentObj} = {}) => {
|
|
932
|
+
assert.equal(parentObj.type, 'reply');
|
|
933
|
+
assert.equal(parentObj.id, parent.id);
|
|
934
|
+
|
|
935
|
+
return webex.internal.conversation.listParentActivityIds(conversation.url, {
|
|
936
|
+
activityType: 'reply',
|
|
937
|
+
});
|
|
938
|
+
})
|
|
939
|
+
.then(({reply}) => {
|
|
940
|
+
assert.include(reply, parent.id);
|
|
941
|
+
}));
|
|
942
|
+
|
|
943
|
+
it('retrieves parent IDs for edits', () =>
|
|
944
|
+
webex.internal.conversation
|
|
945
|
+
.post(conversation, 'edited', {
|
|
946
|
+
parent: {
|
|
947
|
+
id: parent.id,
|
|
948
|
+
type: 'edit',
|
|
949
|
+
},
|
|
950
|
+
})
|
|
951
|
+
.then((edit) => {
|
|
952
|
+
assert.equal(edit.parent.type, 'edit');
|
|
953
|
+
assert.equal(edit.parent.id, parent.id);
|
|
954
|
+
|
|
955
|
+
return webex.internal.conversation.listParentActivityIds(conversation.url, {
|
|
956
|
+
activityType: 'edit',
|
|
957
|
+
});
|
|
958
|
+
})
|
|
959
|
+
.then(({edit}) => {
|
|
960
|
+
assert.include(edit, parent.id);
|
|
961
|
+
}));
|
|
962
|
+
|
|
963
|
+
it('retrieves parent IDs for reactions', () =>
|
|
964
|
+
webex.internal.conversation
|
|
965
|
+
.addReaction(conversation, 'heart', parent)
|
|
966
|
+
.then((reaction) => {
|
|
967
|
+
assert.equal(reaction.parent.type, 'reaction');
|
|
968
|
+
assert.equal(reaction.parent.id, parent.id);
|
|
969
|
+
|
|
970
|
+
return webex.internal.conversation.listParentActivityIds(conversation.url, {
|
|
971
|
+
activityType: 'reaction',
|
|
972
|
+
});
|
|
973
|
+
})
|
|
974
|
+
.then(({reaction}) => {
|
|
975
|
+
assert.include(reaction, parent.id);
|
|
976
|
+
}));
|
|
977
|
+
});
|
|
978
|
+
|
|
979
|
+
describe('#listChildActivitiesByParentId()', () => {
|
|
980
|
+
let conversation, parent;
|
|
981
|
+
let replies;
|
|
982
|
+
|
|
983
|
+
before('create conversation with thread replies', () =>
|
|
984
|
+
webex.internal.conversation
|
|
985
|
+
.create({participants})
|
|
986
|
+
.then((c) => {
|
|
987
|
+
conversation = c;
|
|
988
|
+
|
|
989
|
+
return webex.internal.conversation.post(conversation, {displayName: 'first message'});
|
|
990
|
+
})
|
|
991
|
+
.then((parentAct) => {
|
|
992
|
+
parent = parentAct;
|
|
993
|
+
|
|
994
|
+
const messages = ['thread 1', 'thread 2', 'thread 3'];
|
|
995
|
+
|
|
996
|
+
return Promise.all(
|
|
997
|
+
messages.map((msg) =>
|
|
998
|
+
webex.internal.conversation.post(conversation, msg, {
|
|
999
|
+
parentActivityId: parent.id,
|
|
1000
|
+
activityType: 'reply',
|
|
1001
|
+
})
|
|
1002
|
+
)
|
|
1003
|
+
);
|
|
1004
|
+
})
|
|
1005
|
+
.then((repliesArr) => {
|
|
1006
|
+
replies = repliesArr;
|
|
1007
|
+
})
|
|
1008
|
+
);
|
|
1009
|
+
|
|
1010
|
+
it('retrieves thread reply activities for a given parent', () =>
|
|
1011
|
+
webex.internal.conversation
|
|
1012
|
+
.listChildActivitiesByParentId(conversation.url, parent.id, 'reply')
|
|
1013
|
+
.then((response) => {
|
|
1014
|
+
const {items} = response.body;
|
|
1015
|
+
|
|
1016
|
+
items.forEach((threadAct) => {
|
|
1017
|
+
assert.include(
|
|
1018
|
+
replies.map((reply) => reply.id),
|
|
1019
|
+
threadAct.id
|
|
1020
|
+
);
|
|
1021
|
+
});
|
|
1022
|
+
}));
|
|
1023
|
+
});
|
|
1024
|
+
|
|
1025
|
+
describe('#_listActivitiesThreadOrdered', () => {
|
|
1026
|
+
let conversation, firstParentBatch, secondParentBatch, getOlder, jumpToActivity;
|
|
1027
|
+
|
|
1028
|
+
const minActivities = 10;
|
|
1029
|
+
const displayNames = [
|
|
1030
|
+
'first message',
|
|
1031
|
+
'second message',
|
|
1032
|
+
'third message',
|
|
1033
|
+
'fourth message',
|
|
1034
|
+
'fifth message',
|
|
1035
|
+
'sixth message',
|
|
1036
|
+
'seventh message',
|
|
1037
|
+
'eighth message',
|
|
1038
|
+
'ninth message',
|
|
1039
|
+
];
|
|
1040
|
+
|
|
1041
|
+
const initializeGenerator = () =>
|
|
1042
|
+
webex.internal.conversation.listActivitiesThreadOrdered({
|
|
1043
|
+
conversationUrl: conversation.url,
|
|
1044
|
+
minActivities,
|
|
1045
|
+
});
|
|
1046
|
+
|
|
1047
|
+
before(() =>
|
|
1048
|
+
webex.internal.conversation
|
|
1049
|
+
.create({participants})
|
|
1050
|
+
.then((c) => {
|
|
1051
|
+
conversation = c;
|
|
1052
|
+
|
|
1053
|
+
return c;
|
|
1054
|
+
})
|
|
1055
|
+
.then((c) => Promise.all(displayNames.slice(0, 5).map(postMessage(webex, c))))
|
|
1056
|
+
.then((parents) => {
|
|
1057
|
+
firstParentBatch = parents;
|
|
1058
|
+
|
|
1059
|
+
return Promise.all(createThreadObjs(parents).map(postReply(webex, conversation)));
|
|
1060
|
+
})
|
|
1061
|
+
.then(() => Promise.all(displayNames.slice(4).map(postMessage(webex, conversation))))
|
|
1062
|
+
.then((parents) => {
|
|
1063
|
+
secondParentBatch = parents;
|
|
1064
|
+
|
|
1065
|
+
return Promise.all(createThreadObjs(parents).map(postReply(webex, conversation)));
|
|
1066
|
+
})
|
|
1067
|
+
);
|
|
1068
|
+
|
|
1069
|
+
beforeEach(() => {
|
|
1070
|
+
const funcs = initializeGenerator();
|
|
1071
|
+
|
|
1072
|
+
getOlder = funcs.getOlder;
|
|
1073
|
+
jumpToActivity = funcs.jumpToActivity;
|
|
1074
|
+
});
|
|
1075
|
+
|
|
1076
|
+
it('should return more than or exactly N minimum activities', () =>
|
|
1077
|
+
getOlder().then(({value}) => {
|
|
1078
|
+
assert.isAtLeast(value.length, minActivities);
|
|
1079
|
+
}));
|
|
1080
|
+
|
|
1081
|
+
it('should return edit activity ID as activity ID when an activity has been edited', () => {
|
|
1082
|
+
const lastParent = secondParentBatch[secondParentBatch.length - 1];
|
|
1083
|
+
|
|
1084
|
+
const message = {
|
|
1085
|
+
displayName: 'edited',
|
|
1086
|
+
content: 'edited',
|
|
1087
|
+
};
|
|
1088
|
+
|
|
1089
|
+
const editingActivity = Object.assign(
|
|
1090
|
+
{
|
|
1091
|
+
parent: {
|
|
1092
|
+
id: lastParent.id,
|
|
1093
|
+
type: 'edit',
|
|
1094
|
+
},
|
|
1095
|
+
},
|
|
1096
|
+
{
|
|
1097
|
+
object: message,
|
|
1098
|
+
}
|
|
1099
|
+
);
|
|
1100
|
+
|
|
1101
|
+
return webex.internal.conversation
|
|
1102
|
+
.post(conversation, message, editingActivity)
|
|
1103
|
+
.then(() => getOlder())
|
|
1104
|
+
.then(({value}) => {
|
|
1105
|
+
const activities = value.map((act) => act.activity);
|
|
1106
|
+
const editedAct = find(activities, (act) => act.editParent);
|
|
1107
|
+
|
|
1108
|
+
assert.equal(editedAct.editParent.id, lastParent.id);
|
|
1109
|
+
assert.notEqual(editedAct.id, lastParent.id);
|
|
1110
|
+
});
|
|
1111
|
+
});
|
|
1112
|
+
|
|
1113
|
+
it('should return activities in thread order', () =>
|
|
1114
|
+
getOlder().then((data) => {
|
|
1115
|
+
const {value} = data;
|
|
1116
|
+
const oldestAct = value[0].activity;
|
|
1117
|
+
const newestAct = value[value.length - 1].activity;
|
|
1118
|
+
|
|
1119
|
+
const oldestThreadIx = findIndex(value, ['activity.parent.type', 'reply']);
|
|
1120
|
+
const oldestParent = value[oldestThreadIx - 1].activity;
|
|
1121
|
+
|
|
1122
|
+
assert.isTrue(oldestAct.published < newestAct.published);
|
|
1123
|
+
|
|
1124
|
+
assert.doesNotHaveAnyKeys(oldestParent, 'parentActivityId');
|
|
1125
|
+
assert.isTrue(oldestParent.object.objectType === 'comment');
|
|
1126
|
+
}));
|
|
1127
|
+
|
|
1128
|
+
it('should return next batch when getOlder is called a second time', () => {
|
|
1129
|
+
let firstBatch;
|
|
1130
|
+
|
|
1131
|
+
return getOlder()
|
|
1132
|
+
.then(({value}) => {
|
|
1133
|
+
firstBatch = value;
|
|
1134
|
+
|
|
1135
|
+
return getOlder();
|
|
1136
|
+
})
|
|
1137
|
+
.then(({value}) => {
|
|
1138
|
+
const secondBatch = value;
|
|
1139
|
+
|
|
1140
|
+
const oldestRootInFirstBatch = find(firstBatch, [
|
|
1141
|
+
'activity.object.objectType',
|
|
1142
|
+
'comment',
|
|
1143
|
+
]).activity;
|
|
1144
|
+
const newestRootInSecondBatch = findLast(secondBatch, [
|
|
1145
|
+
'activity.object.objectType',
|
|
1146
|
+
'comment',
|
|
1147
|
+
]).activity;
|
|
1148
|
+
|
|
1149
|
+
assert.isTrue(oldestRootInFirstBatch.published > newestRootInSecondBatch.published);
|
|
1150
|
+
});
|
|
1151
|
+
});
|
|
1152
|
+
|
|
1153
|
+
it('should return done as true when no more activities can be fetched', () => {
|
|
1154
|
+
const {getOlder: getOlderWithLargeMin} =
|
|
1155
|
+
webex.internal.conversation.listActivitiesThreadOrdered({
|
|
1156
|
+
conversationId: conversation.id,
|
|
1157
|
+
minActivities: 50,
|
|
1158
|
+
});
|
|
1159
|
+
|
|
1160
|
+
return getOlderWithLargeMin().then(({done}) => {
|
|
1161
|
+
assert.isTrue(done);
|
|
1162
|
+
});
|
|
1163
|
+
});
|
|
1164
|
+
|
|
1165
|
+
describe('jumpToActivity()', () => {
|
|
1166
|
+
let _listActivitiesThreadOrderedSpy;
|
|
1167
|
+
|
|
1168
|
+
beforeEach(() => {
|
|
1169
|
+
_listActivitiesThreadOrderedSpy = sinon.spy(
|
|
1170
|
+
webex.internal.conversation,
|
|
1171
|
+
'_listActivitiesThreadOrdered'
|
|
1172
|
+
);
|
|
1173
|
+
});
|
|
1174
|
+
|
|
1175
|
+
afterEach(() => {
|
|
1176
|
+
webex.internal.conversation._listActivitiesThreadOrdered.restore();
|
|
1177
|
+
});
|
|
1178
|
+
|
|
1179
|
+
it('should return searched-for activity with surrounding activities when jumpToActivity is called with an activity', () => {
|
|
1180
|
+
const search = firstParentBatch[firstParentBatch.length - 1];
|
|
1181
|
+
|
|
1182
|
+
return jumpToActivity(search).then(({value}) => {
|
|
1183
|
+
const searchedForActivityIx = findIndex(value, ['id', search.id]);
|
|
1184
|
+
|
|
1185
|
+
assert.isFalse(searchedForActivityIx === -1);
|
|
1186
|
+
assert.isTrue(searchedForActivityIx > 0);
|
|
1187
|
+
assert.isTrue(searchedForActivityIx < value.length);
|
|
1188
|
+
});
|
|
1189
|
+
});
|
|
1190
|
+
|
|
1191
|
+
it('should return all activities in a space when jumping to an activity in a space with less activities than the asked-for activities limit', () =>
|
|
1192
|
+
webex.internal.conversation
|
|
1193
|
+
.create({participants: [scott.id]})
|
|
1194
|
+
.then((c) =>
|
|
1195
|
+
webex.internal.conversation
|
|
1196
|
+
.post(c, {displayName: 'first message'})
|
|
1197
|
+
.then((m) =>
|
|
1198
|
+
webex.internal.conversation
|
|
1199
|
+
.listActivities({conversationUrl: c.url})
|
|
1200
|
+
.then((acts) => jumpToActivity(m).then(() => acts.length))
|
|
1201
|
+
)
|
|
1202
|
+
)
|
|
1203
|
+
.then((actCount) => {
|
|
1204
|
+
assert.isTrue(actCount < minActivities);
|
|
1205
|
+
}));
|
|
1206
|
+
|
|
1207
|
+
it('should return all activities in a space when jumping to an activity in a space with more activities than the asked-for activities limit', () =>
|
|
1208
|
+
webex.internal.conversation
|
|
1209
|
+
.create({participants: [scott.id]})
|
|
1210
|
+
.then((c) => {
|
|
1211
|
+
const $posts = [];
|
|
1212
|
+
|
|
1213
|
+
// eslint-disable-next-line no-plusplus
|
|
1214
|
+
for (let i = 0; i < 15; i++) {
|
|
1215
|
+
$posts.push(webex.internal.conversation.post(c, {displayName: `message ${i}`}));
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
return Promise.all($posts).then(() =>
|
|
1219
|
+
webex.internal.conversation.post(c, {displayName: 'message last'})
|
|
1220
|
+
);
|
|
1221
|
+
})
|
|
1222
|
+
.then((lastPost) => jumpToActivity(lastPost))
|
|
1223
|
+
.then(({value: acts}) => {
|
|
1224
|
+
assert.isAtLeast(acts.length, minActivities);
|
|
1225
|
+
|
|
1226
|
+
const firstAct = acts[0].activity;
|
|
1227
|
+
|
|
1228
|
+
assert.notEqual(firstAct.verb, 'create');
|
|
1229
|
+
}));
|
|
1230
|
+
|
|
1231
|
+
it('should re-initialize _listActivitiesThreadOrdered when jumpToActivity is called with a new URL', () => {
|
|
1232
|
+
let conversation2, msg;
|
|
1233
|
+
|
|
1234
|
+
return webex.internal.conversation
|
|
1235
|
+
.create({participants: [scott.id]})
|
|
1236
|
+
.then((c) => {
|
|
1237
|
+
conversation2 = c;
|
|
1238
|
+
|
|
1239
|
+
return webex.internal.conversation.post(conversation2, {
|
|
1240
|
+
displayName: 'first message',
|
|
1241
|
+
});
|
|
1242
|
+
})
|
|
1243
|
+
.then((m) => {
|
|
1244
|
+
msg = m;
|
|
1245
|
+
|
|
1246
|
+
return jumpToActivity(msg);
|
|
1247
|
+
})
|
|
1248
|
+
.then(() => {
|
|
1249
|
+
assert.isTrue(_listActivitiesThreadOrderedSpy.args[0][0].url === conversation2.url);
|
|
1250
|
+
});
|
|
1251
|
+
});
|
|
1252
|
+
});
|
|
1253
|
+
});
|
|
1254
|
+
});
|
|
1255
|
+
});
|