@nyaruka/temba-components 0.136.1 → 0.137.0
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/CHANGELOG.md +10 -0
- package/demo/components/webchat/example.html +2 -2
- package/dist/temba-components.js +487 -551
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/display/Chat.js +123 -44
- package/out-tsc/src/display/Chat.js.map +1 -1
- package/out-tsc/src/events/eventRenderers.js +442 -0
- package/out-tsc/src/events/eventRenderers.js.map +1 -0
- package/out-tsc/src/flow/Editor.js +3 -2
- package/out-tsc/src/flow/Editor.js.map +1 -1
- package/out-tsc/src/flow/NodeEditor.js +0 -1
- package/out-tsc/src/flow/NodeEditor.js.map +1 -1
- package/out-tsc/src/list/ShortcutList.js +1 -1
- package/out-tsc/src/list/ShortcutList.js.map +1 -1
- package/out-tsc/src/live/ContactChat.js +12 -321
- package/out-tsc/src/live/ContactChat.js.map +1 -1
- package/out-tsc/src/simulator/Simulator.js +428 -571
- package/out-tsc/src/simulator/Simulator.js.map +1 -1
- package/out-tsc/test/temba-simulator.test.js +51 -32
- package/out-tsc/test/temba-simulator.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/contacts/chat-failure.png +0 -0
- package/screenshots/truth/contacts/chat-for-archived-contact.png +0 -0
- package/screenshots/truth/contacts/chat-for-blocked-contact.png +0 -0
- package/screenshots/truth/contacts/chat-for-stopped-contact.png +0 -0
- package/screenshots/truth/contacts/chat-sends-attachments-only.png +0 -0
- package/screenshots/truth/contacts/chat-sends-text-and-attachments.png +0 -0
- package/screenshots/truth/contacts/chat-sends-text-only.png +0 -0
- package/screenshots/truth/nodes/split_by_llm_categorize/editor/feedback-categorization.png +0 -0
- package/screenshots/truth/simulator/after-message-sent.png +0 -0
- package/screenshots/truth/simulator/after-reset.png +0 -0
- package/screenshots/truth/simulator/attachment-menu.png +0 -0
- package/screenshots/truth/simulator/context-expanded.png +0 -0
- package/screenshots/truth/simulator/context-explorer-open.png +0 -0
- package/screenshots/truth/simulator/event-info.png +0 -0
- package/screenshots/truth/simulator/image-attachment.png +0 -0
- package/screenshots/truth/simulator/open-initial.png +0 -0
- package/screenshots/truth/simulator/quick-replies.png +0 -0
- package/src/display/Chat.ts +123 -44
- package/src/events/eventRenderers.ts +527 -0
- package/src/flow/Editor.ts +3 -2
- package/src/flow/NodeEditor.ts +0 -1
- package/src/list/ShortcutList.ts +1 -1
- package/src/live/ContactChat.ts +17 -376
- package/src/simulator/Simulator.ts +487 -612
- package/test/temba-simulator.test.ts +64 -34
|
@@ -48,7 +48,7 @@ const openSimulator = async (simulator: Simulator) => {
|
|
|
48
48
|
tab.dispatchEvent(new CustomEvent('temba-button-clicked', { bubbles: true }));
|
|
49
49
|
|
|
50
50
|
await simulator.updateComplete;
|
|
51
|
-
// brief delay for async API
|
|
51
|
+
// brief delay for async API response processing
|
|
52
52
|
await delay(50);
|
|
53
53
|
};
|
|
54
54
|
|
|
@@ -148,16 +148,33 @@ const getSimulatorClip = (
|
|
|
148
148
|
|
|
149
149
|
const frameBounds = phoneFrame.getBoundingClientRect();
|
|
150
150
|
|
|
151
|
-
//
|
|
151
|
+
// clip to just the phone frame area
|
|
152
152
|
const padding = 10;
|
|
153
|
+
|
|
153
154
|
return {
|
|
154
155
|
x: frameBounds.x - padding,
|
|
155
156
|
y: frameBounds.y - padding,
|
|
156
|
-
|
|
157
|
+
// only add padding to the left to avoid capturing option pane on right
|
|
158
|
+
width: frameBounds.width + padding,
|
|
157
159
|
height: frameBounds.height + padding * 2
|
|
158
160
|
};
|
|
159
161
|
};
|
|
160
162
|
|
|
163
|
+
// helper to get message count from chat component
|
|
164
|
+
const getMessageCount = (simulator: Simulator): number => {
|
|
165
|
+
const chat = simulator.shadowRoot.querySelector('temba-chat') as any;
|
|
166
|
+
if (!chat) {
|
|
167
|
+
return 0;
|
|
168
|
+
}
|
|
169
|
+
// check how many messages are in the chat component
|
|
170
|
+
// the chat component stores messages in its internal state
|
|
171
|
+
return (
|
|
172
|
+
chat.messageGroups?.reduce((total: number, group: any) => {
|
|
173
|
+
return total + (group.messages?.length || 0);
|
|
174
|
+
}, 0) || 0
|
|
175
|
+
);
|
|
176
|
+
};
|
|
177
|
+
|
|
161
178
|
// mock responses for simulation endpoints
|
|
162
179
|
const mockSimulatorStart = () => {
|
|
163
180
|
const response = {
|
|
@@ -340,8 +357,6 @@ describe('temba-simulator', () => {
|
|
|
340
357
|
mockSimulatorStart();
|
|
341
358
|
|
|
342
359
|
const simulator: Simulator = await createSimulator();
|
|
343
|
-
// ensure consistent size for screenshot
|
|
344
|
-
simulator.size = 'medium';
|
|
345
360
|
await simulator.updateComplete;
|
|
346
361
|
await openSimulator(simulator);
|
|
347
362
|
|
|
@@ -354,9 +369,9 @@ describe('temba-simulator', () => {
|
|
|
354
369
|
const phoneScreen = simulator.shadowRoot.querySelector('.phone-screen');
|
|
355
370
|
expect(phoneScreen).to.exist;
|
|
356
371
|
|
|
357
|
-
// verify initial message is displayed
|
|
358
|
-
const
|
|
359
|
-
expect(
|
|
372
|
+
// verify initial message is displayed via chat component
|
|
373
|
+
const messageCount = getMessageCount(simulator);
|
|
374
|
+
expect(messageCount).to.be.greaterThan(0);
|
|
360
375
|
|
|
361
376
|
await assertScreenshot(
|
|
362
377
|
'simulator/open-initial',
|
|
@@ -368,13 +383,11 @@ describe('temba-simulator', () => {
|
|
|
368
383
|
mockSimulatorStart();
|
|
369
384
|
|
|
370
385
|
const simulator: Simulator = await createSimulator();
|
|
371
|
-
simulator.size = 'medium';
|
|
372
386
|
await simulator.updateComplete;
|
|
373
387
|
await openSimulator(simulator);
|
|
374
388
|
|
|
375
389
|
// count initial messages
|
|
376
|
-
|
|
377
|
-
const initialCount = messages.length;
|
|
390
|
+
const initialCount = getMessageCount(simulator);
|
|
378
391
|
|
|
379
392
|
// mock the resume response
|
|
380
393
|
mockSimulatorResume('Thanks for your message!');
|
|
@@ -396,13 +409,23 @@ describe('temba-simulator', () => {
|
|
|
396
409
|
});
|
|
397
410
|
input.dispatchEvent(enterEvent);
|
|
398
411
|
|
|
412
|
+
// wait for the message to be sent and response to come back
|
|
413
|
+
await waitForCondition(
|
|
414
|
+
() => getMessageCount(simulator) > initialCount,
|
|
415
|
+
40,
|
|
416
|
+
50
|
|
417
|
+
);
|
|
418
|
+
|
|
399
419
|
await simulator.updateComplete;
|
|
400
|
-
//
|
|
401
|
-
|
|
420
|
+
// wait for chat component to update
|
|
421
|
+
const chat = simulator.shadowRoot.querySelector('temba-chat') as any;
|
|
422
|
+
if (chat) {
|
|
423
|
+
await chat.updateComplete;
|
|
424
|
+
}
|
|
402
425
|
|
|
403
426
|
// verify we have more messages than before
|
|
404
|
-
|
|
405
|
-
expect(
|
|
427
|
+
const newCount = getMessageCount(simulator);
|
|
428
|
+
expect(newCount).to.be.greaterThan(initialCount);
|
|
406
429
|
|
|
407
430
|
// ensure DOM is settled
|
|
408
431
|
await simulator.updateComplete;
|
|
@@ -417,7 +440,6 @@ describe('temba-simulator', () => {
|
|
|
417
440
|
mockSimulatorStart();
|
|
418
441
|
|
|
419
442
|
const simulator: Simulator = await createSimulator();
|
|
420
|
-
simulator.size = 'medium';
|
|
421
443
|
await simulator.updateComplete;
|
|
422
444
|
await openSimulator(simulator);
|
|
423
445
|
|
|
@@ -442,9 +464,10 @@ describe('temba-simulator', () => {
|
|
|
442
464
|
await waitForCondition(
|
|
443
465
|
() =>
|
|
444
466
|
simulator.shadowRoot.querySelectorAll('.quick-reply-btn').length > 0,
|
|
445
|
-
|
|
467
|
+
5000
|
|
446
468
|
);
|
|
447
469
|
await simulator.updateComplete;
|
|
470
|
+
await delay(100); // extra delay for rendering
|
|
448
471
|
|
|
449
472
|
// take screenshot with quick replies
|
|
450
473
|
await assertScreenshot(
|
|
@@ -457,7 +480,6 @@ describe('temba-simulator', () => {
|
|
|
457
480
|
mockSimulatorStart();
|
|
458
481
|
|
|
459
482
|
const simulator: Simulator = await createSimulator();
|
|
460
|
-
simulator.size = 'medium';
|
|
461
483
|
await simulator.updateComplete;
|
|
462
484
|
await openSimulator(simulator);
|
|
463
485
|
|
|
@@ -486,12 +508,14 @@ describe('temba-simulator', () => {
|
|
|
486
508
|
mockSimulatorStart();
|
|
487
509
|
|
|
488
510
|
const simulator: Simulator = await createSimulator();
|
|
489
|
-
simulator.size = 'medium';
|
|
490
511
|
await simulator.updateComplete;
|
|
491
512
|
// reset attachment indices for deterministic testing
|
|
492
513
|
simulator.resetAttachmentIndices();
|
|
493
514
|
await openSimulator(simulator);
|
|
494
515
|
|
|
516
|
+
// count initial messages
|
|
517
|
+
const initialCount = getMessageCount(simulator);
|
|
518
|
+
|
|
495
519
|
// mock the response for image attachment
|
|
496
520
|
mockSimulatorResume('Nice picture!');
|
|
497
521
|
|
|
@@ -509,14 +533,23 @@ describe('temba-simulator', () => {
|
|
|
509
533
|
expect(imageMenuItem).to.exist;
|
|
510
534
|
imageMenuItem.click();
|
|
511
535
|
|
|
512
|
-
|
|
536
|
+
// wait for the attachment to be sent and response to come back
|
|
537
|
+
await waitForCondition(
|
|
538
|
+
() => getMessageCount(simulator) > initialCount,
|
|
539
|
+
40,
|
|
540
|
+
50
|
|
541
|
+
);
|
|
542
|
+
|
|
513
543
|
await simulator.updateComplete;
|
|
544
|
+
// wait for chat component to update
|
|
545
|
+
const chat = simulator.shadowRoot.querySelector('temba-chat') as any;
|
|
546
|
+
if (chat) {
|
|
547
|
+
await chat.updateComplete;
|
|
548
|
+
}
|
|
514
549
|
|
|
515
|
-
// verify
|
|
516
|
-
const
|
|
517
|
-
|
|
518
|
-
);
|
|
519
|
-
expect(attachmentWrappers.length).to.be.greaterThan(0);
|
|
550
|
+
// verify message with attachment was added via chat component
|
|
551
|
+
const newCount = getMessageCount(simulator);
|
|
552
|
+
expect(newCount).to.be.greaterThan(initialCount);
|
|
520
553
|
|
|
521
554
|
await assertScreenshot(
|
|
522
555
|
'simulator/image-attachment',
|
|
@@ -674,7 +707,6 @@ describe('temba-simulator', () => {
|
|
|
674
707
|
mockSimulatorStart();
|
|
675
708
|
|
|
676
709
|
const simulator: Simulator = await createSimulator();
|
|
677
|
-
simulator.size = 'medium';
|
|
678
710
|
await simulator.updateComplete;
|
|
679
711
|
await openSimulator(simulator);
|
|
680
712
|
|
|
@@ -696,8 +728,7 @@ describe('temba-simulator', () => {
|
|
|
696
728
|
await simulator.updateComplete;
|
|
697
729
|
|
|
698
730
|
// verify we have multiple messages
|
|
699
|
-
|
|
700
|
-
const messageCountBefore = messages.length;
|
|
731
|
+
const messageCountBefore = getMessageCount(simulator);
|
|
701
732
|
expect(messageCountBefore).to.be.greaterThan(1);
|
|
702
733
|
|
|
703
734
|
// mock the start response for reset
|
|
@@ -717,8 +748,8 @@ describe('temba-simulator', () => {
|
|
|
717
748
|
await simulator.updateComplete;
|
|
718
749
|
|
|
719
750
|
// verify messages are reset - should go back to just initial message
|
|
720
|
-
|
|
721
|
-
expect(
|
|
751
|
+
const messageCountAfter = getMessageCount(simulator);
|
|
752
|
+
expect(messageCountAfter).to.be.lessThan(messageCountBefore);
|
|
722
753
|
|
|
723
754
|
await assertScreenshot(
|
|
724
755
|
'simulator/after-reset',
|
|
@@ -799,13 +830,12 @@ describe('temba-simulator', () => {
|
|
|
799
830
|
mockPOST(/\/flow\/simulate\/.*\//, responseWithEvents);
|
|
800
831
|
|
|
801
832
|
const simulator: Simulator = await createSimulator();
|
|
802
|
-
simulator.size = 'medium';
|
|
803
833
|
await simulator.updateComplete;
|
|
804
834
|
await openSimulator(simulator);
|
|
805
835
|
|
|
806
|
-
// verify
|
|
807
|
-
const
|
|
808
|
-
expect(
|
|
836
|
+
// verify events are displayed via chat component (field change + message = 2 events)
|
|
837
|
+
const messageCount = getMessageCount(simulator);
|
|
838
|
+
expect(messageCount).to.be.greaterThan(0);
|
|
809
839
|
|
|
810
840
|
await assertScreenshot('simulator/event-info', getSimulatorClip(simulator));
|
|
811
841
|
});
|