@tellescope/sdk 0.0.94 → 0.0.97
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/lib/cjs/enduser.d.ts +24 -0
- package/lib/cjs/enduser.d.ts.map +1 -1
- package/lib/cjs/sdk.d.ts +24 -0
- package/lib/cjs/sdk.d.ts.map +1 -1
- package/lib/cjs/sdk.js +1 -0
- package/lib/cjs/sdk.js.map +1 -1
- package/lib/cjs/session.d.ts +3 -0
- package/lib/cjs/session.d.ts.map +1 -1
- package/lib/cjs/session.js +11 -7
- package/lib/cjs/session.js.map +1 -1
- package/lib/cjs/tests/socket_tests.d.ts.map +1 -1
- package/lib/cjs/tests/socket_tests.js +244 -128
- package/lib/cjs/tests/socket_tests.js.map +1 -1
- package/lib/cjs/tests/tests.d.ts.map +1 -1
- package/lib/cjs/tests/tests.js +89 -215
- package/lib/cjs/tests/tests.js.map +1 -1
- package/lib/cjs/tests/webhooks_tests.js +4 -4
- package/lib/cjs/tests/webhooks_tests.js.map +1 -1
- package/lib/esm/enduser.d.ts +24 -1
- package/lib/esm/enduser.d.ts.map +1 -1
- package/lib/esm/sdk.d.ts +24 -0
- package/lib/esm/sdk.d.ts.map +1 -1
- package/lib/esm/sdk.js +1 -0
- package/lib/esm/sdk.js.map +1 -1
- package/lib/esm/session.d.ts +3 -1
- package/lib/esm/session.d.ts.map +1 -1
- package/lib/esm/session.js +11 -7
- package/lib/esm/session.js.map +1 -1
- package/lib/esm/tests/socket_tests.d.ts.map +1 -1
- package/lib/esm/tests/socket_tests.js +244 -128
- package/lib/esm/tests/socket_tests.js.map +1 -1
- package/lib/esm/tests/tests.d.ts.map +1 -1
- package/lib/esm/tests/tests.js +89 -215
- package/lib/esm/tests/tests.js.map +1 -1
- package/lib/esm/tests/webhooks_tests.js +4 -4
- package/lib/esm/tests/webhooks_tests.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/src/sdk.ts +1 -0
- package/src/session.ts +11 -7
- package/src/tests/socket_tests.ts +184 -63
- package/src/tests/tests.ts +35 -149
- package/src/tests/webhooks_tests.ts +4 -5
|
@@ -23,17 +23,20 @@ export const get_sha256 = (s='') => createHash('sha256').update(s).digest('hex')
|
|
|
23
23
|
|
|
24
24
|
const VERBOSE = true
|
|
25
25
|
|
|
26
|
-
const AWAIT_SOCKET_DURATION =
|
|
26
|
+
const AWAIT_SOCKET_DURATION = 250 // 25ms was generally passing for Redis, 1000ms should be upper limit of performance
|
|
27
27
|
|
|
28
28
|
const host = process.env.TEST_URL || 'http://localhost:8080'
|
|
29
29
|
const [email, password] = [process.env.TEST_EMAIL, process.env.TEST_PASSWORD]
|
|
30
30
|
const [email2, password2] = [process.env.TEST_EMAIL_2, process.env.TEST_PASSWORD_2]
|
|
31
|
+
const [nonAdminEmail, nonAdminPassword] = [process.env.NON_ADMIN_EMAIL, process.env.NON_ADMIN_PASSWORD]
|
|
31
32
|
const businessId = '60398b1131a295e64f084ff6'
|
|
32
33
|
|
|
33
34
|
const user1 = new Session({ host, enableSocketLogging: VERBOSE })
|
|
34
35
|
const user2 = new Session({ host, enableSocketLogging: VERBOSE })
|
|
36
|
+
const sdkNonAdmin = new Session({ host })
|
|
37
|
+
|
|
35
38
|
const enduserSDK = new EnduserSession({ host, businessId, enableSocketLogging: VERBOSE })
|
|
36
|
-
if (!(email && password && email2 && password2)) {
|
|
39
|
+
if (!(email && password && email2 && password2 && nonAdminEmail && nonAdminPassword)) {
|
|
37
40
|
console.error("Set TEST_EMAIL and TEST_PASSWORD")
|
|
38
41
|
process.exit(1)
|
|
39
42
|
}
|
|
@@ -42,7 +45,7 @@ if (!(email && password && email2 && password2)) {
|
|
|
42
45
|
const basic_tests = async () => {
|
|
43
46
|
const socket_events: Indexable[] = []
|
|
44
47
|
|
|
45
|
-
user2.
|
|
48
|
+
user2.handle_events({
|
|
46
49
|
'created-endusers': es => socket_events.push(es),
|
|
47
50
|
'updated-endusers': es => socket_events.push(es),
|
|
48
51
|
'deleted-endusers': es => socket_events.push(es),
|
|
@@ -68,52 +71,37 @@ const basic_tests = async () => {
|
|
|
68
71
|
|
|
69
72
|
const access_tests = async () => {
|
|
70
73
|
const user1Events: Indexable[] = []
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
// const user2Deletions: string[] = []
|
|
74
|
+
const nonAdminEvents: Indexable[] = []
|
|
75
|
+
const enduserEvents: Indexable[] = []
|
|
74
76
|
|
|
75
|
-
user1.handle_events({
|
|
76
|
-
|
|
77
|
-
// 'updated-chat_rooms': rs => user1Events.push(...rs), sent message will create update event as cached messagepreview/sender updated
|
|
78
|
-
// 'deleted-chat_rooms': rs => user1Events.push(...rs),
|
|
79
|
-
})
|
|
80
|
-
user2.handle_events({
|
|
81
|
-
'created-chat_rooms': rs => user2Events.push(...rs),
|
|
82
|
-
// 'updated-chat_rooms': rs => user2Events.push(...rs),
|
|
83
|
-
// 'deleted-chat_rooms': rs => user2Events.push(...rs),
|
|
84
|
-
})
|
|
77
|
+
user1.handle_events({ 'created-chat_rooms': rs => user1Events.push(...rs) })
|
|
78
|
+
sdkNonAdmin.handle_events({ 'created-chat_rooms': rs => nonAdminEvents.push(...rs) })
|
|
85
79
|
|
|
86
80
|
const user1Id = user1.userInfo.id
|
|
87
|
-
const user2Id =
|
|
81
|
+
const user2Id = sdkNonAdmin.userInfo.id
|
|
88
82
|
|
|
89
83
|
const room = await user1.api.chat_rooms.createOne({ type: 'internal', userIds: [user1Id] })
|
|
90
84
|
const sharedRoom = await user1.api.chat_rooms.createOne({ type: 'internal', userIds: [user1Id, user2Id] })
|
|
91
85
|
await wait(undefined, AWAIT_SOCKET_DURATION)
|
|
92
86
|
|
|
93
|
-
assert(user1Events.length ===
|
|
94
|
-
assert(
|
|
95
|
-
|
|
96
|
-
user1.removeAllSocketListeners('created-chat_rooms')
|
|
97
|
-
user1.removeAllSocketListeners('update-chat_rooms')
|
|
98
|
-
user1.removeAllSocketListeners('deleted-chat_rooms')
|
|
99
|
-
user2.removeAllSocketListeners('created-chat_rooms')
|
|
100
|
-
user2.removeAllSocketListeners('update-chat_rooms')
|
|
101
|
-
user2.removeAllSocketListeners('deleted-chat_rooms')
|
|
102
|
-
|
|
103
|
-
user1.subscribe({ [room.id]: 'chats' })
|
|
104
|
-
user2.subscribe({ [room.id]: 'chats' }) // connection should be rejected
|
|
105
|
-
user1.subscribe({ [sharedRoom.id]: 'chats' })
|
|
106
|
-
user2.subscribe({ [sharedRoom.id]: 'chats' })
|
|
87
|
+
assert(user1Events.length === 2, 'bad event distribution for filter', 'creator gets socket notifications')
|
|
88
|
+
assert(nonAdminEvents.length === 1 && sharedRoom.id === nonAdminEvents[0].id, 'bad event distribution for filter', 'verify filter socket push')
|
|
107
89
|
|
|
108
90
|
user1.handle_events({
|
|
91
|
+
'created-chat_rooms': rs => user1Events.push(...rs),
|
|
109
92
|
'created-chats': rs => user1Events.push(...rs),
|
|
93
|
+
'created-tickets': rs => user1Events.push(...rs),
|
|
94
|
+
'created-endusers': rs => user1Events.push(...rs),
|
|
110
95
|
'updated-chats': rs => user1Events.push(...rs),
|
|
111
96
|
'deleted-chats': rs => user1Events.push(...rs),
|
|
112
97
|
})
|
|
113
|
-
|
|
114
|
-
'created-
|
|
115
|
-
'
|
|
116
|
-
'
|
|
98
|
+
sdkNonAdmin.handle_events({
|
|
99
|
+
'created-chat_rooms': rs => nonAdminEvents.push(...rs),
|
|
100
|
+
'created-chats': rs => nonAdminEvents.push(...rs),
|
|
101
|
+
'created-tickets': rs => nonAdminEvents.push(...rs),
|
|
102
|
+
'created-endusers': rs => nonAdminEvents.push(...rs),
|
|
103
|
+
'updated-chats': rs => nonAdminEvents.push(...rs),
|
|
104
|
+
'deleted-chats': rs => nonAdminEvents.push(...rs),
|
|
117
105
|
})
|
|
118
106
|
await wait(undefined, AWAIT_SOCKET_DURATION)
|
|
119
107
|
|
|
@@ -121,18 +109,160 @@ const access_tests = async () => {
|
|
|
121
109
|
await user1.api.chats.createOne({ roomId: room.id, message: "Hello...", })
|
|
122
110
|
await wait(undefined, AWAIT_SOCKET_DURATION)
|
|
123
111
|
|
|
124
|
-
assert(user1Events.length ===
|
|
125
|
-
assert(
|
|
112
|
+
assert(user1Events.length === 4, 'bad chats self', 'chats to self')
|
|
113
|
+
assert(nonAdminEvents.length === 1, 'non-admin got chats', 'non admin doesnt get chats for unassigned room')
|
|
126
114
|
|
|
127
|
-
const sharedChat = await user1.api.chats.createOne({ roomId: sharedRoom.id, message: "Hello
|
|
128
|
-
const sharedChat2 = await
|
|
115
|
+
const sharedChat = await user1.api.chats.createOne({ roomId: sharedRoom.id, message: "Hello from admin on shared", })
|
|
116
|
+
const sharedChat2 = await sdkNonAdmin.api.chats.createOne({ roomId: sharedRoom.id, message: "Hello from nonadmin on shared", })
|
|
129
117
|
await wait(undefined, AWAIT_SOCKET_DURATION)
|
|
130
118
|
|
|
131
|
-
assert(user1Events.length ===
|
|
119
|
+
assert(user1Events.length === 6 && !!user1Events.find((r: any) => r?.id === sharedChat2.id), 'bad chats other', 'verify chat received')
|
|
120
|
+
assert(
|
|
121
|
+
nonAdminEvents.length === 3 && !!nonAdminEvents.find((e: any) => e.id === sharedChat.id),
|
|
122
|
+
'bad chats self, non-admin', 'push valid for non-admin default access'
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
const unassignedEnduser = await user1.api.endusers.createOne({ email: 'unassigned@tellescope.com' })
|
|
126
|
+
const assignedEnduser = await user1.api.endusers.createOne({ email: 'assigned@tellescope.com', assignedTo: [user2Id] })
|
|
127
|
+
await wait (undefined, AWAIT_SOCKET_DURATION)
|
|
128
|
+
|
|
129
|
+
assert(
|
|
130
|
+
!!user1Events.find(e => e.id === unassignedEnduser.id) && !!user1Events.find(e => e.id === assignedEnduser.id),
|
|
131
|
+
'admin did not get endusers',
|
|
132
|
+
'admin got assigned and unassigned endusers',
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
assert(
|
|
136
|
+
!nonAdminEvents.find(e => e.id === unassignedEnduser.id) && !!nonAdminEvents.find(e => e.id === assignedEnduser.id),
|
|
137
|
+
'non-admin got incorrect endusers',
|
|
138
|
+
'non-admin got assigned enduser',
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
await user1.api.endusers.set_password({ id: unassignedEnduser.id, password: 'enduserPassword!' })
|
|
142
|
+
await enduserSDK.authenticate(unassignedEnduser.email as string, 'enduserPassword!')
|
|
143
|
+
await enduserSDK.authenticate_socket()
|
|
144
|
+
|
|
145
|
+
enduserSDK.handle_events({
|
|
146
|
+
'created-chat_rooms': rs => enduserEvents.push(...rs),
|
|
147
|
+
'created-chats': rs => enduserEvents.push(...rs),
|
|
148
|
+
'created-tickets': rs => enduserEvents.push(...rs),
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
// test admin and enduser get messages
|
|
152
|
+
const roomUnassigned = await user1.api.chat_rooms.createOne({ enduserIds: [unassignedEnduser.id] })
|
|
153
|
+
// test non-admin user in userIds gets message
|
|
154
|
+
const roomUnassignedWithUser = await user1.api.chat_rooms.createOne({ enduserIds: [unassignedEnduser.id], userIds: [user2Id] })
|
|
155
|
+
// test non-admin user who is assigned to enduser gets messages
|
|
156
|
+
const roomAssigned = await user1.api.chat_rooms.createOne({ enduserIds: [assignedEnduser.id] })
|
|
157
|
+
await wait (undefined, AWAIT_SOCKET_DURATION)
|
|
158
|
+
|
|
159
|
+
assert((
|
|
160
|
+
!!user1Events.find(e => e.id === roomUnassigned.id)
|
|
161
|
+
&& !!user1Events.find(e => e.id === roomUnassignedWithUser.id)
|
|
162
|
+
&& !!user1Events.find(e => e.id === roomAssigned.id)
|
|
163
|
+
),
|
|
164
|
+
'enduser did not get chat rooms',
|
|
165
|
+
'enduser got chat rooms',
|
|
166
|
+
)
|
|
167
|
+
assert((
|
|
168
|
+
!nonAdminEvents.find(e => e.id === roomUnassigned.id) // shouldn't get as non-admin
|
|
169
|
+
&& !!nonAdminEvents.find(e => e.id === roomUnassignedWithUser.id) // gets for in room
|
|
170
|
+
&& !!nonAdminEvents.find(e => e.id === roomAssigned.id) // gets for enduser assignment
|
|
171
|
+
),
|
|
172
|
+
'non-admin did not get chat rooms',
|
|
173
|
+
'non-admin got chat rooms',
|
|
174
|
+
)
|
|
175
|
+
assert(
|
|
176
|
+
(
|
|
177
|
+
!!enduserEvents.find(e => e.id === roomUnassigned.id)
|
|
178
|
+
&& !!enduserEvents.find(e => e.id === roomUnassignedWithUser.id)
|
|
179
|
+
&& !enduserEvents.find(e => e.id === roomAssigned.id)
|
|
180
|
+
),
|
|
181
|
+
'enduser did not get chat rooms',
|
|
182
|
+
'enduser got chat rooms',
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
let userMessage = await user1.api.chats.createOne({ message: 'user unassigned', roomId: roomUnassigned.id })
|
|
186
|
+
let enduserMessage = await enduserSDK.api.chats.createOne({ message: 'enduseruser unassigned', roomId: roomUnassigned.id })
|
|
187
|
+
await wait (undefined, AWAIT_SOCKET_DURATION)
|
|
188
|
+
|
|
189
|
+
assert(
|
|
190
|
+
!!enduserEvents.find(e => e.id === userMessage.id),
|
|
191
|
+
'enduser did not get message',
|
|
192
|
+
'enduser got message from user',
|
|
193
|
+
)
|
|
132
194
|
assert(
|
|
133
|
-
|
|
134
|
-
'
|
|
195
|
+
!!user1Events.find(e => e.id === enduserMessage.id),
|
|
196
|
+
'user did not get message',
|
|
197
|
+
'user got message from enduser',
|
|
135
198
|
)
|
|
199
|
+
assert(
|
|
200
|
+
!nonAdminEvents.find(e => e.id === enduserMessage.id) && !nonAdminEvents.find(e => e.id === userMessage.id),
|
|
201
|
+
'non-admin got unexpected message',
|
|
202
|
+
'non-admin correctly did not get message from enduser or user',
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
userMessage = await user1.api.chats.createOne({ message: 'user unassigned with user', roomId: roomUnassignedWithUser.id })
|
|
207
|
+
enduserMessage = await enduserSDK.api.chats.createOne({ message: 'enduser unassigned with user', roomId: roomUnassignedWithUser.id })
|
|
208
|
+
let nonAdminMessage = await sdkNonAdmin.api.chats.createOne({ message: 'non-admin unassigned with non', roomId: roomUnassignedWithUser.id })
|
|
209
|
+
await wait (undefined, AWAIT_SOCKET_DURATION)
|
|
210
|
+
|
|
211
|
+
assert(
|
|
212
|
+
!!enduserEvents.find(e => e.id === userMessage.id) && !!enduserEvents.find(e => e.id === nonAdminMessage.id),
|
|
213
|
+
'enduser did not get message',
|
|
214
|
+
'enduser got message from user',
|
|
215
|
+
)
|
|
216
|
+
assert(
|
|
217
|
+
!!user1Events.find(e => e.id === enduserMessage.id) && !!user1Events.find(e => e.id === nonAdminMessage.id),
|
|
218
|
+
'user did not get messages',
|
|
219
|
+
'user got messages',
|
|
220
|
+
)
|
|
221
|
+
assert(
|
|
222
|
+
!!nonAdminEvents.find(e => e.id === enduserMessage.id) && !!nonAdminEvents.find(e => e.id === userMessage.id),
|
|
223
|
+
'non-admin didnt get messages',
|
|
224
|
+
'non-admin got message from user and enduser',
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
await user1.api.endusers.set_password({ id: assignedEnduser.id, password: 'enduserPassword!' })
|
|
229
|
+
await enduserSDK.authenticate(assignedEnduser.email as string, 'enduserPassword!')
|
|
230
|
+
await enduserSDK.authenticate_socket()
|
|
231
|
+
|
|
232
|
+
enduserSDK.handle_events({
|
|
233
|
+
'created-chats': rs => enduserEvents.push(...rs),
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
userMessage = await user1.api.chats.createOne({ message: 'user assigned', roomId: roomAssigned.id })
|
|
238
|
+
enduserMessage = await enduserSDK.api.chats.createOne({ message: 'enduser assigned', roomId: roomAssigned.id })
|
|
239
|
+
nonAdminMessage = await sdkNonAdmin.api.chats.createOne({ message: 'non-admin assigned', roomId: roomAssigned.id })
|
|
240
|
+
await wait (undefined, AWAIT_SOCKET_DURATION)
|
|
241
|
+
|
|
242
|
+
assert(
|
|
243
|
+
!!enduserEvents.find(e => e.id === userMessage.id) && !!enduserEvents.find(e => e.id === nonAdminMessage.id),
|
|
244
|
+
'enduser did not get messages',
|
|
245
|
+
'enduser got messages from users',
|
|
246
|
+
)
|
|
247
|
+
assert(
|
|
248
|
+
!!user1Events.find(e => e.id === enduserMessage.id) && !!user1Events.find(e => e.id === nonAdminMessage.id),
|
|
249
|
+
'user did not get messages',
|
|
250
|
+
'user got messages',
|
|
251
|
+
)
|
|
252
|
+
assert(
|
|
253
|
+
!!nonAdminEvents.find(e => e.id === enduserMessage.id) && !!nonAdminEvents.find(e => e.id === userMessage.id),
|
|
254
|
+
'non-admin didnt get messages',
|
|
255
|
+
'non-admin got message from user and enduser',
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
await Promise.all([
|
|
260
|
+
await user1.api.endusers.deleteOne(unassignedEnduser.id),
|
|
261
|
+
await user1.api.endusers.deleteOne(assignedEnduser.id),
|
|
262
|
+
await user1.api.chat_rooms.deleteOne(roomAssigned.id),
|
|
263
|
+
await user1.api.chat_rooms.deleteOne(roomUnassigned.id),
|
|
264
|
+
await user1.api.chat_rooms.deleteOne(roomUnassignedWithUser.id),
|
|
265
|
+
])
|
|
136
266
|
}
|
|
137
267
|
|
|
138
268
|
const enduser_tests = async () => {
|
|
@@ -160,30 +290,23 @@ const enduser_tests = async () => {
|
|
|
160
290
|
enduserIds: [enduser.id],
|
|
161
291
|
})
|
|
162
292
|
|
|
163
|
-
user1.subscribe({ [room.id]: 'chats' })
|
|
164
|
-
user1.subscribe({ tickets: 'tickets' })
|
|
165
|
-
enduserSDK.subscribe({
|
|
166
|
-
[room.id]: 'chats',
|
|
167
|
-
dontCache: 'chats', // prevents cacheing of otherwise identical-looking subscriptions for user1 and enduserSDK for chats
|
|
168
|
-
})
|
|
169
|
-
|
|
170
293
|
await wait(undefined, AWAIT_SOCKET_DURATION)
|
|
171
294
|
|
|
172
295
|
const messageToEnduser = await user1.api.chats.createOne({ roomId: room.id, message: "Hello!" })
|
|
173
296
|
const messageToUser = await enduserSDK.api.chats.createOne({ roomId: room.id, message: "Hello right back!" })
|
|
174
297
|
await wait(undefined, AWAIT_SOCKET_DURATION)
|
|
175
298
|
|
|
176
|
-
assert(
|
|
177
|
-
assert(
|
|
299
|
+
assert(!!userEvents.find(e => e.id === messageToUser.id), 'no message on socket for user', 'push message to user')
|
|
300
|
+
assert(!!enduserEvents.find(e => e.id === messageToEnduser.id), 'no message on socket for enduser', 'push message to enduser')
|
|
178
301
|
|
|
179
302
|
const unusedTicket = await user1.api.tickets.createOne({ enduserId: PLACEHOLDER_ID, title: "For Noone" }) // should not get pushed to enduser
|
|
180
303
|
const ticketForEnduser = await user1.api.tickets.createOne({ enduserId: enduser.id, title: "For enduser" })
|
|
181
304
|
const ticketFromEnduser = await enduserSDK.api.tickets.createOne({ enduserId: enduser.id, title: "By enduser" })
|
|
182
305
|
await wait(undefined, AWAIT_SOCKET_DURATION)
|
|
183
306
|
|
|
184
|
-
assert(
|
|
185
|
-
assert(
|
|
186
|
-
assert(enduserEvents
|
|
307
|
+
assert(!!userEvents.find(t => t.id === ticketFromEnduser.id), 'no ticket on socket for user', 'push ticket to user')
|
|
308
|
+
assert(!!enduserEvents.find(t => t.id === ticketForEnduser.id), 'no ticket on socket for enduser', 'push ticket to enduser')
|
|
309
|
+
assert(!enduserEvents.find(t => t.id === unusedTicket.id), 'enduser got an orgwide ticket', 'enduser does not receive org-wide ticket')
|
|
187
310
|
|
|
188
311
|
await user1.api.tickets.deleteOne(unusedTicket.id)
|
|
189
312
|
await user1.api.tickets.deleteOne(ticketForEnduser.id)
|
|
@@ -222,8 +345,6 @@ const deauthentication_tests = async (byTimeout=false) => {
|
|
|
222
345
|
|
|
223
346
|
const userEvents = [] as ChatMessage[]
|
|
224
347
|
const enduserEvents = [] as ChatMessage[]
|
|
225
|
-
user1.subscribe({ [room.id]: 'chats' })
|
|
226
|
-
enduserSDK.subscribe({ [room.id]: 'chats' })
|
|
227
348
|
user1.handle_events({ 'created-chats': rs => userEvents.push(...rs) })
|
|
228
349
|
enduserSDK.handle_events({ 'created-chats': rs => enduserEvents.push(...rs) })
|
|
229
350
|
await wait(undefined, AWAIT_SOCKET_DURATION)
|
|
@@ -233,9 +354,9 @@ const deauthentication_tests = async (byTimeout=false) => {
|
|
|
233
354
|
} else {
|
|
234
355
|
await wait(undefined, TEST_SESSION_DURATION * 1000 + SESSION_TIMEOUT_DELAY)
|
|
235
356
|
}
|
|
236
|
-
await user1.api.chats.createOne({ roomId: room.id, message: "Hello!" })
|
|
357
|
+
const badChatEnduser = await user1.api.chats.createOne({ roomId: room.id, message: "Hello!" })
|
|
237
358
|
await wait(undefined, AWAIT_SOCKET_DURATION)
|
|
238
|
-
assert(
|
|
359
|
+
assert(enduserEvents.find(c => c.id === badChatEnduser.id) === undefined, 'enduser got message after logout on socket', 'enduser logged out')
|
|
239
360
|
|
|
240
361
|
// re-authenticate enduser to send message to user
|
|
241
362
|
await enduserSDK.authenticate(enduser.email as string, 'enduserPassword!')
|
|
@@ -248,9 +369,9 @@ const deauthentication_tests = async (byTimeout=false) => {
|
|
|
248
369
|
} else {
|
|
249
370
|
await wait(undefined, AWAIT_SOCKET_DURATION)
|
|
250
371
|
}
|
|
251
|
-
await enduserSDK.api.chats.createOne({ roomId: room.id, message: "Hello right back!" })
|
|
372
|
+
const badChat = await enduserSDK.api.chats.createOne({ roomId: room.id, message: "Hello right back!" })
|
|
252
373
|
await wait(undefined, AWAIT_SOCKET_DURATION)
|
|
253
|
-
assert(
|
|
374
|
+
assert(userEvents.find(e => e.id === badChat.id) === undefined, 'user got message after logout', 'user logged out')
|
|
254
375
|
|
|
255
376
|
|
|
256
377
|
// must come before cleanup, so cleanup works
|
|
@@ -303,7 +424,7 @@ const calendar_events = async () => {
|
|
|
303
424
|
})
|
|
304
425
|
await wait(undefined, AWAIT_SOCKET_DURATION)
|
|
305
426
|
|
|
306
|
-
assert(userEvents.length ===
|
|
427
|
+
assert(userEvents.length === 1, 'creator push bad', 'calendar event gone to creator')
|
|
307
428
|
assert(enduserEvents.length === 1 && enduserEvents[0].id === event.id, 'enduser did not get calendar event', 'calendar event on create for attending enduser')
|
|
308
429
|
|
|
309
430
|
// cleanup
|
|
@@ -317,10 +438,11 @@ const calendar_events = async () => {
|
|
|
317
438
|
await user1.authenticate(email, password)
|
|
318
439
|
await user1.reset_db()
|
|
319
440
|
await user2.authenticate(email2, password2) // generate authToken + socket connection for API keyj
|
|
441
|
+
await sdkNonAdmin.authenticate(nonAdminEmail, nonAdminPassword)
|
|
320
442
|
|
|
321
443
|
await user1.connectSocket()
|
|
322
444
|
await user2.connectSocket()
|
|
323
|
-
|
|
445
|
+
await sdkNonAdmin.connectSocket()
|
|
324
446
|
|
|
325
447
|
await basic_tests()
|
|
326
448
|
await access_tests()
|
|
@@ -330,7 +452,6 @@ const calendar_events = async () => {
|
|
|
330
452
|
|
|
331
453
|
await deauthentication_tests() // should come last!
|
|
332
454
|
await deauthentication_tests(true) // should come last!
|
|
333
|
-
|
|
334
455
|
} catch(err) {
|
|
335
456
|
console.error(err)
|
|
336
457
|
}
|
package/src/tests/tests.ts
CHANGED
|
@@ -923,7 +923,7 @@ const chat_room_tests = async () => {
|
|
|
923
923
|
let roomWithMessage = await sdk.api.chat_rooms.getOne(room.id)
|
|
924
924
|
assert(roomWithMessage.numMessages === 1, 'num mesages no update', 'num messages on send message')
|
|
925
925
|
assert((roomWithMessage?.recentMessageSentAt ?? 0) > Date.now() - 1000, 'recent message timestamp bad', 'recent message timestamp')
|
|
926
|
-
assert(roomWithMessage?.infoForUser?.[userId]?.unreadCount ===
|
|
926
|
+
assert(roomWithMessage?.infoForUser?.[userId]?.unreadCount === undefined, 'bad unread count for user', 'unread count for user')
|
|
927
927
|
assert(roomWithMessage?.infoForUser?.[enduserSDK.userInfo.id]?.unreadCount === 1, 'bad unread count for enduser', 'unread count for enduser')
|
|
928
928
|
|
|
929
929
|
roomWithMessage = await sdk.api.chat_rooms.updateOne(roomWithMessage.id, { infoForUser: { [userId]: { unreadCount: 0 }}})
|
|
@@ -1389,141 +1389,7 @@ const calendar_events_tests = async () => {
|
|
|
1389
1389
|
|
|
1390
1390
|
const automation_events_tests = async () => {
|
|
1391
1391
|
log_header("Automation Events")
|
|
1392
|
-
|
|
1393
|
-
title: 'Form', fields: [{ title: 'Question 1', type: 'string' }]
|
|
1394
|
-
})
|
|
1395
|
-
|
|
1396
|
-
const state1 = "State 1", state2 = "State 2";
|
|
1397
|
-
const journey = await sdk.api.journeys.createOne({
|
|
1398
|
-
title: "Automations Test",
|
|
1399
|
-
defaultState: state1,
|
|
1400
|
-
states: [
|
|
1401
|
-
{ name: state1, priority: 'N/A' },
|
|
1402
|
-
{ name: state2, priority: 'N/A' },
|
|
1403
|
-
]
|
|
1404
|
-
})
|
|
1405
|
-
|
|
1406
|
-
await async_test(
|
|
1407
|
-
`enterState cannot match updateStateForJourney`,
|
|
1408
|
-
() => sdk.api.automation_steps.createOne({
|
|
1409
|
-
journeyId: journey.id,
|
|
1410
|
-
event: {
|
|
1411
|
-
type: "enterState",
|
|
1412
|
-
info: { state: state1, journeyId: journey.id }
|
|
1413
|
-
},
|
|
1414
|
-
action: {
|
|
1415
|
-
type: 'updateStateForJourney',
|
|
1416
|
-
info: { state: state1, journeyId: journey.id },
|
|
1417
|
-
},
|
|
1418
|
-
}),
|
|
1419
|
-
{ shouldError: true, onError: e => e.message === 'updateStateForJourney cannot have the same journey and state as the enterState event' }
|
|
1420
|
-
)
|
|
1421
|
-
await async_test(
|
|
1422
|
-
`leaveState cannot match updateStateForJourney`,
|
|
1423
|
-
() => sdk.api.automation_steps.createOne({
|
|
1424
|
-
journeyId: journey.id,
|
|
1425
|
-
event: {
|
|
1426
|
-
type: "leaveState",
|
|
1427
|
-
info: { state: state1, journeyId: journey.id }
|
|
1428
|
-
},
|
|
1429
|
-
action: {
|
|
1430
|
-
type: 'updateStateForJourney',
|
|
1431
|
-
info: { state: state1, journeyId: journey.id },
|
|
1432
|
-
},
|
|
1433
|
-
}),
|
|
1434
|
-
{ shouldError: true, onError: e => e.message === 'updateStateForJourney cannot have the same journey and state as the leaveState event' }
|
|
1435
|
-
)
|
|
1436
|
-
|
|
1437
|
-
const testAction: AutomationAction = {
|
|
1438
|
-
type: 'sendWebhook',
|
|
1439
|
-
info: { message: 'test' }
|
|
1440
|
-
}
|
|
1441
|
-
await sdk.api.automation_steps.createOne({
|
|
1442
|
-
journeyId: journey.id,
|
|
1443
|
-
event: {
|
|
1444
|
-
type: "enterState",
|
|
1445
|
-
info: { state: state1, journeyId: journey.id }
|
|
1446
|
-
},
|
|
1447
|
-
action: testAction,
|
|
1448
|
-
})
|
|
1449
|
-
await sdk.api.automation_steps.createOne({
|
|
1450
|
-
journeyId: journey.id,
|
|
1451
|
-
event: {
|
|
1452
|
-
type: "leaveState",
|
|
1453
|
-
info: { state: state1, journeyId: journey.id }
|
|
1454
|
-
},
|
|
1455
|
-
action: testAction,
|
|
1456
|
-
})
|
|
1457
|
-
await sdk.api.automation_steps.createOne({
|
|
1458
|
-
journeyId: journey.id,
|
|
1459
|
-
event: {
|
|
1460
|
-
type: "enterState",
|
|
1461
|
-
info: { state: state2, journeyId: journey.id }
|
|
1462
|
-
},
|
|
1463
|
-
action: testAction,
|
|
1464
|
-
})
|
|
1465
|
-
|
|
1466
|
-
await sdk.api.automation_steps.createOne({
|
|
1467
|
-
journeyId: journey.id,
|
|
1468
|
-
event: {
|
|
1469
|
-
type: "formResponse",
|
|
1470
|
-
info: { formId: form.id },
|
|
1471
|
-
},
|
|
1472
|
-
conditions: [
|
|
1473
|
-
{
|
|
1474
|
-
type: 'atJourneyState',
|
|
1475
|
-
info: { state: state2, journeyId: journey.id }
|
|
1476
|
-
}
|
|
1477
|
-
],
|
|
1478
|
-
action: testAction,
|
|
1479
|
-
})
|
|
1480
|
-
|
|
1481
|
-
await async_test(
|
|
1482
|
-
`Cannot insert duplicate event/action pair`,
|
|
1483
|
-
() => sdk.api.automation_steps.createOne({
|
|
1484
|
-
journeyId: journey.id,
|
|
1485
|
-
event: {
|
|
1486
|
-
type: "enterState",
|
|
1487
|
-
info: { state: state2, journeyId: journey.id }
|
|
1488
|
-
},
|
|
1489
|
-
action: testAction,
|
|
1490
|
-
}),
|
|
1491
|
-
{ shouldError: true, onError: e => e.message === "You cannot create two identical event automations" }
|
|
1492
|
-
)
|
|
1493
|
-
|
|
1494
|
-
// trigger a1 on create
|
|
1495
|
-
const enduser = await sdk.api.endusers.createOne({
|
|
1496
|
-
email: "automations@tellescope.com",
|
|
1497
|
-
journeys: { [journey.id]: journey.defaultState }
|
|
1498
|
-
})
|
|
1499
|
-
|
|
1500
|
-
// should NOT trigger while user not in state 2
|
|
1501
|
-
await sdk.api.form_responses.submit_form_response({
|
|
1502
|
-
accessCode: (await sdk.api.form_responses.prepare_form_response({ formId: form.id, enduserId: enduser.id })).accessCode,
|
|
1503
|
-
responses: ['Answer']
|
|
1504
|
-
})
|
|
1505
|
-
|
|
1506
|
-
// trigger a2 and a3 by leaving state 1 an going to state 2
|
|
1507
|
-
await sdk.api.endusers.updateOne(enduser.id, { journeys: { [journey.id]: state2 } })
|
|
1508
|
-
|
|
1509
|
-
// SHOULD trigger now that user is in state 2
|
|
1510
|
-
await sdk.api.form_responses.submit_form_response({
|
|
1511
|
-
accessCode: (await sdk.api.form_responses.prepare_form_response({ formId: form.id, enduserId: enduser.id })).accessCode,
|
|
1512
|
-
responses: ['Answer 2']
|
|
1513
|
-
})
|
|
1514
|
-
|
|
1515
|
-
await async_test(
|
|
1516
|
-
`Automation events triggered correctly`,
|
|
1517
|
-
() => sdk.api.automated_actions.getSome({ filter: { enduserId: enduser.id }}),
|
|
1518
|
-
{ onResult: es => es && es.length === 4 && es.filter(a => a.automationStepId === "ONE_TIME").length === 4 }
|
|
1519
|
-
)
|
|
1520
|
-
|
|
1521
|
-
// cleanup
|
|
1522
|
-
await Promise.all([
|
|
1523
|
-
sdk.api.journeys.deleteOne(journey.id), // automation events deleted as side effect
|
|
1524
|
-
sdk.api.endusers.deleteOne(enduser.id),
|
|
1525
|
-
sdk.api.forms.deleteOne(form.id),
|
|
1526
|
-
])
|
|
1392
|
+
console.warn("Need new test coverage for automation stemps")
|
|
1527
1393
|
}
|
|
1528
1394
|
|
|
1529
1395
|
const form_response_tests = async () => {
|
|
@@ -1543,19 +1409,19 @@ const form_response_tests = async () => {
|
|
|
1543
1409
|
intakeField: stringIntakeField
|
|
1544
1410
|
}]
|
|
1545
1411
|
})
|
|
1546
|
-
await sdk.api.automation_steps.createOne({
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
})
|
|
1412
|
+
// await sdk.api.automation_steps.createOne({
|
|
1413
|
+
// event: { type: "formResponse", info: { formId: form.id } },
|
|
1414
|
+
// action: { type: 'sendWebhook', info: { message: 'test' } },
|
|
1415
|
+
// })
|
|
1550
1416
|
|
|
1551
1417
|
const { accessCode } = await sdk.api.form_responses.prepare_form_response({ formId: form.id, enduserId: enduser.id })
|
|
1552
1418
|
await sdk.api.form_responses.submit_form_response({ accessCode, responses: [stringResponse] })
|
|
1553
1419
|
|
|
1554
|
-
const [triggeredAutomation] = await sdk.api.automated_actions.getSome()
|
|
1420
|
+
// const [triggeredAutomation] = await sdk.api.automated_actions.getSome()
|
|
1555
1421
|
const enduserWithUpdate = await sdk.api.endusers.getOne(enduser.id)
|
|
1556
1422
|
const recordedResponse = await sdk.api.form_responses.getOne({ accessCode })
|
|
1557
1423
|
|
|
1558
|
-
assert(triggeredAutomation?.event?.type === 'formResponse', 'no form response event', 'form response event triggered')
|
|
1424
|
+
// assert(triggeredAutomation?.event?.type === 'formResponse', 'no form response event', 'form response event triggered')
|
|
1559
1425
|
assert(enduserWithUpdate?.fields?.[stringIntakeField] === stringResponse, 'no enduser update', 'enduser updated')
|
|
1560
1426
|
assert(
|
|
1561
1427
|
recordedResponse?.responses?.length === 1 && recordedResponse.responses[0]?.[stringTitle] === stringResponse,
|
|
@@ -1622,19 +1488,19 @@ const notifications_tests = async () => {
|
|
|
1622
1488
|
const chat = await sdk.api.chats.createOne({ message: 'test', roomId: room.id, })
|
|
1623
1489
|
const ticket = await sdk.api.tickets.createOne({ title: 'Ticket for notification', owner: sdkNonAdmin.userInfo.id })
|
|
1624
1490
|
|
|
1625
|
-
await wait(undefined,
|
|
1491
|
+
await wait(undefined, 250) // notifications may be created in background
|
|
1626
1492
|
|
|
1627
1493
|
// neither should throw error
|
|
1628
|
-
const
|
|
1629
|
-
const chatNotifications = await sdk.api.user_notifications.getSome({ filter: { type: '
|
|
1494
|
+
const ticketNotifications = await sdk.api.user_notifications.getSome({ filter: { type: 'newTicket' } })
|
|
1495
|
+
const chatNotifications = await sdk.api.user_notifications.getSome({ filter: { type: 'newTeamChatMessage' } })
|
|
1630
1496
|
|
|
1631
|
-
assert(!!
|
|
1497
|
+
assert(!!ticketNotifications.find(n => n.relatedRecords?.find(r => r.id === ticket.id)), 'No ticket notification', 'Got notification for new new ticket')
|
|
1632
1498
|
assert(!!chatNotifications.find(notification => notification.relatedRecords?.find(r => r.id === chat.id)), 'No chat notification', 'Got notification for new chat')
|
|
1633
1499
|
|
|
1634
1500
|
await Promise.all([
|
|
1635
1501
|
sdk.api.chat_rooms.deleteOne(room.id),
|
|
1636
1502
|
sdk.api.tickets.deleteOne(ticket.id),
|
|
1637
|
-
sdk.api.user_notifications.deleteOne(
|
|
1503
|
+
sdk.api.user_notifications.deleteOne(ticketNotifications.find(n => n.relatedRecords?.find(r => r.id === ticket.id))!.id),
|
|
1638
1504
|
...chatNotifications.map(n =>
|
|
1639
1505
|
sdk.api.user_notifications.deleteOne(n.id),
|
|
1640
1506
|
),
|
|
@@ -1793,8 +1659,27 @@ const role_based_access_tests = async () => {
|
|
|
1793
1659
|
sdk.api.sms_messages.deleteOne(sms.id),
|
|
1794
1660
|
sdk.api.calendar_events.deleteOne(calendarEvent.id),
|
|
1795
1661
|
sdk.api.chat_rooms.deleteOne(chatRoom.id),
|
|
1796
|
-
|
|
1797
|
-
|
|
1662
|
+
])
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
const status_update_tests = async () => {
|
|
1666
|
+
log_header("Enduser Status Updates")
|
|
1667
|
+
|
|
1668
|
+
const journey = await sdk.api.journeys.createOne({ title: 'test' })
|
|
1669
|
+
const enduser = await sdk.api.endusers.createOne({ email: 'delete@tellescope.com' })
|
|
1670
|
+
const status = await sdk.api.enduser_status_updates.createOne({ enduserId: enduser.id, journeyId: journey.id, status: "Working"})
|
|
1671
|
+
|
|
1672
|
+
// status update on enduser is a side effect
|
|
1673
|
+
await wait(undefined, 100)
|
|
1674
|
+
await async_test(
|
|
1675
|
+
`status update`, () => sdk.api.endusers.getOne(enduser.id), {
|
|
1676
|
+
onResult: e => e.journeys?.[journey.id] === status.status
|
|
1677
|
+
},
|
|
1678
|
+
)
|
|
1679
|
+
|
|
1680
|
+
await Promise.all([
|
|
1681
|
+
sdk.api.journeys.deleteOne(journey.id), // status deleted as side effect
|
|
1682
|
+
sdk.api.endusers.deleteOne(enduser.id), // status deleted as side effect
|
|
1798
1683
|
])
|
|
1799
1684
|
}
|
|
1800
1685
|
|
|
@@ -1822,6 +1707,7 @@ const tests: { [K in keyof ClientModelForName]: () => void } = {
|
|
|
1822
1707
|
automation_steps: automation_events_tests,
|
|
1823
1708
|
sequence_automations: NO_TEST,
|
|
1824
1709
|
automated_actions: NO_TEST,
|
|
1710
|
+
enduser_status_updates: status_update_tests,
|
|
1825
1711
|
user_logs: NO_TEST,
|
|
1826
1712
|
user_notifications: notifications_tests,
|
|
1827
1713
|
};
|
|
@@ -42,7 +42,7 @@ const app = express()
|
|
|
42
42
|
app.use(bodyParser.urlencoded({ extended: true, limit: '25mb' }))
|
|
43
43
|
app.use(bodyParser.json({ limit: "25mb" }))
|
|
44
44
|
|
|
45
|
-
const PORT =
|
|
45
|
+
const PORT = 3999
|
|
46
46
|
const TEST_SECRET = "this is a test secret for verifying integrity of web hooks"
|
|
47
47
|
const webhookEndpoint = '/handle-webhook'
|
|
48
48
|
const webhookURL = `http://127.0.0.1:${PORT}${webhookEndpoint}`
|
|
@@ -98,7 +98,7 @@ const check_next_webhook = async (evaluate: (hook: WebhookCall) => boolean, name
|
|
|
98
98
|
if (noHookExpected) {
|
|
99
99
|
assert(!event, error, name)
|
|
100
100
|
} else {
|
|
101
|
-
assert(!!event, 'did not get hook', 'got hook')
|
|
101
|
+
assert(!!event, error || 'did not get hook', name || 'got hook')
|
|
102
102
|
}
|
|
103
103
|
if (!event) return // ensure webhookIndex not incremented
|
|
104
104
|
|
|
@@ -190,7 +190,7 @@ const meetings_tests = async (isSubscribed: boolean) => {
|
|
|
190
190
|
await sdk.api.endusers.deleteOne(enduser.id)
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
const AUTOMATION_POLLING_DELAY_MS =
|
|
193
|
+
const AUTOMATION_POLLING_DELAY_MS = 3000 - CHECK_WEBHOOK_DELAY_MS
|
|
194
194
|
const test_automation_webhooks = async () => {
|
|
195
195
|
log_header("Automation Events")
|
|
196
196
|
const state1 = "State 1", state2 = "State 2";
|
|
@@ -221,12 +221,11 @@ const test_automation_webhooks = async () => {
|
|
|
221
221
|
|
|
222
222
|
await check_next_webhook(
|
|
223
223
|
({ message }) => message === testMessage,
|
|
224
|
-
'Automation webhook error',
|
|
225
224
|
'Automation webhook received',
|
|
225
|
+
'Automation webhook error',
|
|
226
226
|
true
|
|
227
227
|
)
|
|
228
228
|
|
|
229
|
-
|
|
230
229
|
// cleanup
|
|
231
230
|
await sdk.api.journeys.deleteOne(journey.id) // automation events deleted as side effect
|
|
232
231
|
await sdk.api.endusers.deleteOne(enduser.id)
|