@meetelise/chat 1.59.0 → 1.59.2
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/dist/src/WebComponent/Scheduler/tour-scheduler.d.ts +4 -0
- package/dist/src/WebComponent/actions/call-us-window.d.ts +5 -0
- package/dist/src/WebComponent/actions/email-us-window.d.ts +5 -0
- package/dist/src/WebComponent/me-chat.d.ts +15 -9
- package/dist/src/WebComponent/pubnub-chat.d.ts +14 -0
- package/package.json +1 -1
- package/public/dist/index.js +5594 -5573
- package/src/WebComponent/Scheduler/tour-scheduler.ts +27 -0
- package/src/WebComponent/actions/call-us-window.ts +22 -0
- package/src/WebComponent/actions/email-us-window.ts +22 -0
- package/src/WebComponent/me-chat.ts +89 -136
- package/src/WebComponent/me-select.ts +1 -1
- package/src/WebComponent/pubnub-chat-styles.ts +12 -0
- package/src/WebComponent/pubnub-chat.ts +186 -7
- package/src/chatKeyboard.test.ts +430 -0
- package/src/disclaimers.ts +36 -3
- package/src/meChatAutoOpen.test.ts +143 -0
- package/src/pubnub-chat.test.ts +184 -0
package/src/pubnub-chat.test.ts
CHANGED
|
@@ -250,3 +250,187 @@ it("keeps a photo carousel and its arrows inside the message bubble", async () =
|
|
|
250
250
|
expect(centreY(next)).to.be.closeTo(centreY(photo), 1);
|
|
251
251
|
expect(media.shadowRoot?.textContent).not.to.contain("Living Room");
|
|
252
252
|
});
|
|
253
|
+
|
|
254
|
+
const announcerText = (chat: PubnubChat): string =>
|
|
255
|
+
(chat.shadowRoot?.querySelector("#reply-announcer")?.textContent ?? "")
|
|
256
|
+
.replace(/\s+/g, " ")
|
|
257
|
+
.trim();
|
|
258
|
+
|
|
259
|
+
const streamedReply = (
|
|
260
|
+
chunks: string[],
|
|
261
|
+
done: boolean,
|
|
262
|
+
timestamp: number
|
|
263
|
+
): SimpleTextChatMessage => ({
|
|
264
|
+
timestamp,
|
|
265
|
+
message: chunks.join(""),
|
|
266
|
+
isLeadMessage: false,
|
|
267
|
+
chunks: chunks.map((text, order) => ({
|
|
268
|
+
text,
|
|
269
|
+
order,
|
|
270
|
+
isDone: done && order === chunks.length - 1,
|
|
271
|
+
})),
|
|
272
|
+
type: "text",
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it("announces a streamed reply once, after it finishes", async () => {
|
|
276
|
+
const { chat } = await createScrollableChat();
|
|
277
|
+
const list = chat.shadowRoot?.querySelector("#message-thread-list");
|
|
278
|
+
const region = chat.shadowRoot?.querySelector("#reply-announcer");
|
|
279
|
+
if (!region) throw new Error("Expected the reply announcer");
|
|
280
|
+
|
|
281
|
+
expect(list?.getAttribute("role")).to.equal(null);
|
|
282
|
+
expect(list?.hasAttribute("aria-live")).to.equal(false);
|
|
283
|
+
expect(region.getAttribute("role")).to.equal("status");
|
|
284
|
+
expect(region.getAttribute("aria-live")).to.equal("polite");
|
|
285
|
+
expect(region.getAttribute("aria-atomic")).to.equal("true");
|
|
286
|
+
|
|
287
|
+
const seen: string[] = [];
|
|
288
|
+
const note = (): void => {
|
|
289
|
+
const text = announcerText(chat);
|
|
290
|
+
if (seen[seen.length - 1] !== text) seen.push(text);
|
|
291
|
+
};
|
|
292
|
+
note();
|
|
293
|
+
|
|
294
|
+
const chunks = ["The maple ", "studio is ", "available now."];
|
|
295
|
+
for (let i = 1; i <= chunks.length; i++) {
|
|
296
|
+
const partial = chunks.slice(0, i);
|
|
297
|
+
const done = i === chunks.length;
|
|
298
|
+
chat.messages = [streamedReply(partial, done, 100)];
|
|
299
|
+
await waitForRender(chat);
|
|
300
|
+
note();
|
|
301
|
+
if (!done) {
|
|
302
|
+
expect(announcerText(chat)).to.equal("");
|
|
303
|
+
expect(
|
|
304
|
+
chat.shadowRoot
|
|
305
|
+
?.querySelector('[role="article"]')
|
|
306
|
+
?.getAttribute("aria-label")
|
|
307
|
+
).to.equal(`Elise: ${partial.join("")}`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
expect(seen).to.deep.equal(["", "Elise: The maple studio is available now."]);
|
|
312
|
+
|
|
313
|
+
// Redrawing the finished reply must not speak it again.
|
|
314
|
+
chat.messages = [...chat.messages];
|
|
315
|
+
await waitForRender(chat);
|
|
316
|
+
note();
|
|
317
|
+
expect(seen).to.deep.equal(["", "Elise: The maple studio is available now."]);
|
|
318
|
+
|
|
319
|
+
const followUp = ["Ask ", "about parking."];
|
|
320
|
+
for (let i = 1; i <= followUp.length; i++) {
|
|
321
|
+
const partial = followUp.slice(0, i);
|
|
322
|
+
chat.messages = [
|
|
323
|
+
chat.messages[0],
|
|
324
|
+
streamedReply(partial, i === followUp.length, 200),
|
|
325
|
+
];
|
|
326
|
+
await waitForRender(chat);
|
|
327
|
+
note();
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
expect(announcerText(chat)).to.equal("Elise: Ask about parking.");
|
|
331
|
+
expect(seen).to.deep.equal([
|
|
332
|
+
"",
|
|
333
|
+
"Elise: The maple studio is available now.",
|
|
334
|
+
"Elise: Ask about parking.",
|
|
335
|
+
]);
|
|
336
|
+
|
|
337
|
+
chat.messages = [
|
|
338
|
+
...chat.messages,
|
|
339
|
+
{
|
|
340
|
+
timestamp: 300,
|
|
341
|
+
message: "Thanks",
|
|
342
|
+
isLeadMessage: true,
|
|
343
|
+
chunks: [{ text: "Thanks", order: 0, isDone: true }],
|
|
344
|
+
type: "text",
|
|
345
|
+
},
|
|
346
|
+
];
|
|
347
|
+
await waitForRender(chat);
|
|
348
|
+
note();
|
|
349
|
+
expect(seen).to.deep.equal([
|
|
350
|
+
"",
|
|
351
|
+
"Elise: The maple studio is available now.",
|
|
352
|
+
"Elise: Ask about parking.",
|
|
353
|
+
]);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it("announces a later reply when it repeats the previous text", async () => {
|
|
357
|
+
const { chat } = await createScrollableChat();
|
|
358
|
+
chat.messages = [streamedReply(["Ok"], false, 100)];
|
|
359
|
+
await waitForRender(chat);
|
|
360
|
+
|
|
361
|
+
chat.messages = [streamedReply(["Ok"], true, 100)];
|
|
362
|
+
await waitForRender(chat);
|
|
363
|
+
const first = announcerText(chat);
|
|
364
|
+
|
|
365
|
+
chat.messages = [...chat.messages, streamedReply(["Ok"], true, 200)];
|
|
366
|
+
await waitForRender(chat);
|
|
367
|
+
const second = announcerText(chat);
|
|
368
|
+
|
|
369
|
+
expect(first).to.equal("Elise: Ok");
|
|
370
|
+
expect(second.replace(/\u200b/g, "")).to.equal("Elise: Ok");
|
|
371
|
+
expect(second).to.not.equal(first);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it("does not announce replies already on screen when the chat connects", async () => {
|
|
375
|
+
const chat = document.createElement("pubnub-chat") as PubnubChat;
|
|
376
|
+
chat.buildingSlug = "test-building";
|
|
377
|
+
chat.orgSlug = "test-org";
|
|
378
|
+
chat.building = {
|
|
379
|
+
id: 1,
|
|
380
|
+
orgId: 1,
|
|
381
|
+
name: "Test Building",
|
|
382
|
+
welcomeMessage: null,
|
|
383
|
+
state: "NY",
|
|
384
|
+
country: "US",
|
|
385
|
+
customAdditionalDisclaimer: null,
|
|
386
|
+
userFirstName: "Emily",
|
|
387
|
+
} as BuildingWebchatView;
|
|
388
|
+
chat.myPubnub = {
|
|
389
|
+
simpleChatMessages: [completedMessage("Already in the thread.")],
|
|
390
|
+
addChatListener: () => undefined,
|
|
391
|
+
} as unknown as PubnubChat["myPubnub"];
|
|
392
|
+
document.body.appendChild(chat);
|
|
393
|
+
await waitForRender(chat);
|
|
394
|
+
|
|
395
|
+
expect(announcerText(chat)).to.equal("");
|
|
396
|
+
expect(
|
|
397
|
+
chat.shadowRoot
|
|
398
|
+
?.querySelector('[role="article"]')
|
|
399
|
+
?.getAttribute("aria-label")
|
|
400
|
+
).to.equal("Emily: Already in the thread.");
|
|
401
|
+
|
|
402
|
+
chat.messages = [
|
|
403
|
+
...chat.messages,
|
|
404
|
+
streamedReply(["A new reply after connect."], true, 200),
|
|
405
|
+
];
|
|
406
|
+
await waitForRender(chat);
|
|
407
|
+
|
|
408
|
+
expect(announcerText(chat)).to.equal("Emily: A new reply after connect.");
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
it("keeps every widget's message list out of the live region", async () => {
|
|
412
|
+
for (const widgetType of ["default", "healthcare", "utilities"] as const) {
|
|
413
|
+
const chat = document.createElement("pubnub-chat") as PubnubChat;
|
|
414
|
+
chat.buildingSlug = "test-building";
|
|
415
|
+
chat.orgSlug = "test-org";
|
|
416
|
+
chat.widgetType = widgetType;
|
|
417
|
+
chat.building = {
|
|
418
|
+
id: 1,
|
|
419
|
+
orgId: 1,
|
|
420
|
+
name: "Test Building",
|
|
421
|
+
welcomeMessage: "Welcome",
|
|
422
|
+
state: "NY",
|
|
423
|
+
country: "US",
|
|
424
|
+
customAdditionalDisclaimer: null,
|
|
425
|
+
} as BuildingWebchatView;
|
|
426
|
+
document.body.appendChild(chat);
|
|
427
|
+
await waitForRender(chat);
|
|
428
|
+
|
|
429
|
+
const list = chat.shadowRoot?.querySelector("#message-thread-list");
|
|
430
|
+
const region = chat.shadowRoot?.querySelector("#reply-announcer");
|
|
431
|
+
expect(list?.getAttribute("role")).to.equal(null);
|
|
432
|
+
expect(list?.hasAttribute("aria-live")).to.equal(false);
|
|
433
|
+
expect(region?.getAttribute("aria-live")).to.equal("polite");
|
|
434
|
+
chat.remove();
|
|
435
|
+
}
|
|
436
|
+
});
|