@chat21/chat21-web-widget 5.1.33 → 5.1.34-rc1

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.
Files changed (201) hide show
  1. package/.angular-mcp-cache/package.json +1 -0
  2. package/.cursor/angular18-accessibility-auditor-skill.md +442 -0
  3. package/.cursor/mcp.json +15 -0
  4. package/.github/workflows/docker-community-push-latest.yml +23 -13
  5. package/.github/workflows/docker-image-tag-community-tag-push.yml +22 -12
  6. package/.github/workflows/playwright.yml +27 -0
  7. package/CHANGELOG.md +130 -6
  8. package/Dockerfile +4 -5
  9. package/angular.json +24 -4
  10. package/docs/changelog/this-branch.md +36 -0
  11. package/env.sample +3 -2
  12. package/mocks/voice-websocket-mock/server.cjs +245 -0
  13. package/nginx.conf +22 -2
  14. package/package.json +10 -3
  15. package/playwright.config.ts +41 -0
  16. package/src/app/app.component.html +2 -2
  17. package/src/app/app.component.scss +25 -14
  18. package/src/app/app.component.spec.ts +21 -6
  19. package/src/app/app.component.ts +10 -9
  20. package/src/app/app.module.ts +15 -0
  21. package/src/app/component/conversation-detail/conversation/conversation.component.html +25 -11
  22. package/src/app/component/conversation-detail/conversation/conversation.component.scss +40 -2
  23. package/src/app/component/conversation-detail/conversation/conversation.component.spec.ts +644 -75
  24. package/src/app/component/conversation-detail/conversation/conversation.component.ts +100 -14
  25. package/src/app/component/conversation-detail/conversation-audio-recorder/conversation-audio-recorder.component.html +25 -13
  26. package/src/app/component/conversation-detail/conversation-audio-recorder/conversation-audio-recorder.component.spec.ts +123 -5
  27. package/src/app/component/conversation-detail/conversation-audio-recorder/conversation-audio-recorder.component.ts +1 -0
  28. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.html +23 -10
  29. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.scss +33 -2
  30. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.spec.ts +242 -149
  31. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.ts +8 -6
  32. package/src/app/component/conversation-detail/conversation-emojii/conversation-emojii.component.spec.ts +53 -3
  33. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.html +200 -96
  34. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.scss +211 -6
  35. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.spec.ts +452 -78
  36. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts +291 -76
  37. package/src/app/component/conversation-detail/conversation-header/conversation-header.component.html +113 -53
  38. package/src/app/component/conversation-detail/conversation-header/conversation-header.component.scss +12 -4
  39. package/src/app/component/conversation-detail/conversation-header/conversation-header.component.spec.ts +274 -29
  40. package/src/app/component/conversation-detail/conversation-internal-frame/conversation-internal-frame.component.html +23 -9
  41. package/src/app/component/conversation-detail/conversation-internal-frame/conversation-internal-frame.component.spec.ts +80 -8
  42. package/src/app/component/conversation-detail/conversation-preview/conversation-preview.component.html +29 -23
  43. package/src/app/component/conversation-detail/conversation-preview/conversation-preview.component.spec.ts +185 -16
  44. package/src/app/component/conversation-detail/conversation-preview/conversation-preview.component.ts +34 -14
  45. package/src/app/component/conversation-detail/stream-audio-spectrum/stream-audio-spectrum.component.html +46 -0
  46. package/src/app/component/conversation-detail/stream-audio-spectrum/stream-audio-spectrum.component.scss +83 -0
  47. package/src/app/component/conversation-detail/stream-audio-spectrum/stream-audio-spectrum.component.ts +192 -0
  48. package/src/app/component/error-alert/error-alert.component.spec.ts +65 -5
  49. package/src/app/component/eyeeye-catcher-card/eyeeye-catcher-card.component.html +16 -7
  50. package/src/app/component/eyeeye-catcher-card/eyeeye-catcher-card.component.scss +21 -0
  51. package/src/app/component/eyeeye-catcher-card/eyeeye-catcher-card.component.spec.ts +89 -7
  52. package/src/app/component/form/form-builder/form-builder.component.html +1 -1
  53. package/src/app/component/form/form-builder/form-builder.component.spec.ts +163 -21
  54. package/src/app/component/form/inputs/form-checkbox/form-checkbox.component.html +8 -4
  55. package/src/app/component/form/inputs/form-checkbox/form-checkbox.component.scss +10 -5
  56. package/src/app/component/form/inputs/form-checkbox/form-checkbox.component.spec.ts +90 -16
  57. package/src/app/component/form/inputs/form-checkbox/form-checkbox.component.ts +26 -0
  58. package/src/app/component/form/inputs/form-label/form-label.component.spec.ts +45 -11
  59. package/src/app/component/form/inputs/form-radio-button/form-radio-button.component.spec.ts +24 -6
  60. package/src/app/component/form/inputs/form-select/form-select.component.spec.ts +14 -5
  61. package/src/app/component/form/inputs/form-text/form-text.component.html +14 -12
  62. package/src/app/component/form/inputs/form-text/form-text.component.scss +11 -1
  63. package/src/app/component/form/inputs/form-text/form-text.component.spec.ts +113 -17
  64. package/src/app/component/form/inputs/form-text/form-text.component.ts +35 -3
  65. package/src/app/component/form/inputs/form-textarea/form-textarea.component.html +13 -11
  66. package/src/app/component/form/inputs/form-textarea/form-textarea.component.scss +6 -5
  67. package/src/app/component/form/inputs/form-textarea/form-textarea.component.spec.ts +149 -13
  68. package/src/app/component/form/inputs/form-textarea/form-textarea.component.ts +26 -0
  69. package/src/app/component/form/prechat-form/prechat-form.component.html +14 -11
  70. package/src/app/component/form/prechat-form/prechat-form.component.spec.ts +102 -10
  71. package/src/app/component/form/prechat-form/prechat-form.component.ts +8 -1
  72. package/src/app/component/form/prechat-form-test-mock.ts +35 -0
  73. package/src/app/component/home/home.component.html +38 -31
  74. package/src/app/component/home/home.component.scss +4 -2
  75. package/src/app/component/home/home.component.spec.ts +226 -11
  76. package/src/app/component/home-conversations/home-conversations.component.html +30 -26
  77. package/src/app/component/home-conversations/home-conversations.component.scss +3 -0
  78. package/src/app/component/home-conversations/home-conversations.component.spec.ts +212 -36
  79. package/src/app/component/last-message/last-message.component.html +15 -9
  80. package/src/app/component/last-message/last-message.component.scss +16 -2
  81. package/src/app/component/last-message/last-message.component.spec.ts +204 -23
  82. package/src/app/component/last-message/last-message.component.ts +4 -1
  83. package/src/app/component/launcher-button/launcher-button.component.html +8 -13
  84. package/src/app/component/launcher-button/launcher-button.component.spec.ts +104 -8
  85. package/src/app/component/list-all-conversations/list-all-conversations.component.html +12 -17
  86. package/src/app/component/list-all-conversations/list-all-conversations.component.scss +2 -0
  87. package/src/app/component/list-conversations/list-conversations.component.html +22 -22
  88. package/src/app/component/menu-options/menu-options.component.html +30 -20
  89. package/src/app/component/menu-options/menu-options.component.spec.ts +125 -9
  90. package/src/app/component/message/audio/audio.component.html +13 -15
  91. package/src/app/component/message/audio/audio.component.spec.ts +140 -5
  92. package/src/app/component/message/audio/audio.component.ts +1 -5
  93. package/src/app/component/message/audio-sync/audio-sync.component.html +18 -0
  94. package/src/app/component/message/audio-sync/audio-sync.component.scss +65 -0
  95. package/src/app/component/message/audio-sync/audio-sync.component.spec.ts +103 -0
  96. package/src/app/component/message/audio-sync/audio-sync.component.ts +643 -0
  97. package/src/app/component/message/avatar/avatar.component.html +2 -2
  98. package/src/app/component/message/avatar/avatar.component.spec.ts +99 -7
  99. package/src/app/component/message/bubble-message/bubble-message.component.html +43 -51
  100. package/src/app/component/message/bubble-message/bubble-message.component.scss +59 -1
  101. package/src/app/component/message/bubble-message/bubble-message.component.spec.ts +154 -57
  102. package/src/app/component/message/bubble-message/bubble-message.component.ts +152 -109
  103. package/src/app/component/message/buttons/action-button/action-button.component.html +3 -4
  104. package/src/app/component/message/buttons/action-button/action-button.component.spec.ts +49 -5
  105. package/src/app/component/message/buttons/link-button/link-button.component.scss +5 -8
  106. package/src/app/component/message/buttons/link-button/link-button.component.spec.ts +50 -5
  107. package/src/app/component/message/buttons/text-button/text-button.component.spec.ts +44 -5
  108. package/src/app/component/message/carousel/carousel.component.html +29 -16
  109. package/src/app/component/message/carousel/carousel.component.scss +20 -8
  110. package/src/app/component/message/carousel/carousel.component.spec.ts +80 -3
  111. package/src/app/component/message/carousel/carousel.component.ts +16 -0
  112. package/src/app/component/message/frame/frame.component.html +9 -4
  113. package/src/app/component/message/frame/frame.component.spec.ts +34 -15
  114. package/src/app/component/message/frame/frame.component.ts +7 -2
  115. package/src/app/component/message/html/html.component.html +1 -1
  116. package/src/app/component/message/html/html.component.scss +1 -1
  117. package/src/app/component/message/html/html.component.spec.ts +24 -7
  118. package/src/app/component/message/image/image.component.html +12 -10
  119. package/src/app/component/message/image/image.component.scss +16 -0
  120. package/src/app/component/message/image/image.component.spec.ts +101 -15
  121. package/src/app/component/message/image/image.component.ts +90 -51
  122. package/src/app/component/message/info-message/info-message.component.spec.ts +26 -14
  123. package/src/app/component/message/json-sources/json-sources.component.html +38 -0
  124. package/src/app/component/message/json-sources/json-sources.component.scss +201 -0
  125. package/src/app/component/message/json-sources/json-sources.component.ts +89 -0
  126. package/src/app/component/message/like-unlike/like-unlike.component.html +7 -9
  127. package/src/app/component/message/like-unlike/like-unlike.component.spec.ts +31 -3
  128. package/src/app/component/message/return-receipt/return-receipt.component.spec.ts +38 -17
  129. package/src/app/component/message/text/text.component.html +3 -3
  130. package/src/app/component/message/text/text.component.scss +80 -86
  131. package/src/app/component/message/text/text.component.spec.ts +106 -13
  132. package/src/app/component/message-attachment/message-attachment.component.spec.ts +134 -13
  133. package/src/app/component/selection-department/selection-department.component.html +21 -23
  134. package/src/app/component/selection-department/selection-department.component.spec.ts +159 -14
  135. package/src/app/component/selection-department/selection-department.component.ts +8 -1
  136. package/src/app/component/send-button/send-button.component.html +5 -13
  137. package/src/app/component/send-button/send-button.component.spec.ts +2 -2
  138. package/src/app/component/star-rating-widget/star-rating-widget.component.html +51 -81
  139. package/src/app/directives/tooltip.directive.spec.ts +8 -4
  140. package/src/app/modals/confirm-close/confirm-close.component.html +20 -8
  141. package/src/app/modals/confirm-close/confirm-close.component.scss +3 -0
  142. package/src/app/modals/confirm-close/confirm-close.component.spec.ts +13 -4
  143. package/src/app/modals/confirm-close/confirm-close.component.ts +8 -1
  144. package/src/app/pipe/html-entites-encode.pipe.spec.ts +35 -2
  145. package/src/app/pipe/marked.pipe.spec.ts +38 -2
  146. package/src/app/pipe/marked.pipe.ts +51 -41
  147. package/src/app/providers/app-config.service.ts +4 -2
  148. package/src/app/providers/brand.service.spec.ts +23 -2
  149. package/src/app/providers/brand.service.ts +1 -1
  150. package/src/app/providers/global-settings.service.spec.ts +1009 -14
  151. package/src/app/providers/global-settings.service.ts +82 -2
  152. package/src/app/providers/json-sources-parser.service.ts +175 -0
  153. package/src/app/providers/translator.service.ts +26 -6
  154. package/src/app/providers/tts-audio-playback-coordinator.service.spec.ts +117 -0
  155. package/src/app/providers/tts-audio-playback-coordinator.service.ts +109 -0
  156. package/src/app/providers/url-preview.service.ts +82 -0
  157. package/src/app/providers/voice/STT&TTS/openai-voice.config.ts +12 -0
  158. package/src/app/providers/voice/STT&TTS/openai-voice.provider.ts +171 -0
  159. package/src/app/providers/voice/STT&TTS/speech-provider.abstract.ts +39 -0
  160. package/src/app/providers/voice/audio.types.ts +40 -0
  161. package/src/app/providers/voice/vad.service.spec.ts +28 -0
  162. package/src/app/providers/voice/vad.service.ts +70 -0
  163. package/src/app/providers/voice/voice-streaming.service.spec.ts +23 -0
  164. package/src/app/providers/voice/voice-streaming.service.ts +702 -0
  165. package/src/app/providers/voice/voice-streaming.types.ts +112 -0
  166. package/src/app/providers/voice/voice.service.spec.ts +227 -0
  167. package/src/app/providers/voice/voice.service.ts +973 -0
  168. package/src/app/sass/_variables.scss +3 -0
  169. package/src/app/sass/animations.scss +19 -1
  170. package/src/app/shims/onnxruntime-web-wasm.ts +4 -0
  171. package/src/app/utils/globals.ts +21 -1
  172. package/src/app/utils/json-sources-utils.ts +27 -0
  173. package/src/app/utils/url-utils.ts +98 -0
  174. package/src/app/utils/utils-resources.ts +1 -1
  175. package/src/assets/i18n/en.json +106 -99
  176. package/src/assets/i18n/es.json +107 -100
  177. package/src/assets/i18n/fr.json +107 -100
  178. package/src/assets/i18n/it.json +107 -98
  179. package/src/assets/onnx/ort-wasm-simd-threaded.mjs +59 -0
  180. package/src/assets/onnx/ort-wasm-simd-threaded.wasm +0 -0
  181. package/src/assets/sounds/keyboard.mp3 +0 -0
  182. package/src/assets/twp/chatbot-panel.html +3 -1
  183. package/src/assets/twp/index-dev.html +18 -0
  184. package/src/assets/twp/tiledesk_widget_files/widget-css-override-example.css +14 -0
  185. package/src/assets/vad/silero_vad_legacy.onnx +0 -0
  186. package/src/assets/vad/vad.worklet.bundle.min.js +1 -0
  187. package/src/chat21-core/models/message.ts +2 -1
  188. package/src/chat21-core/providers/chat-manager.spec.ts +72 -0
  189. package/src/chat21-core/providers/firebase/firebase-conversation-handler.ts +3 -2
  190. package/src/chat21-core/providers/mqtt/mqtt-conversation-handler.ts +12 -0
  191. package/src/chat21-core/providers/scripts/script.service.spec.ts +12 -2
  192. package/src/chat21-core/providers/tiledesk/tiledesk-requests.service.ts +1 -1
  193. package/src/chat21-core/utils/constants.ts +4 -0
  194. package/src/chat21-core/utils/utils-message.ts +45 -6
  195. package/src/chat21-core/utils/utils.ts +5 -2
  196. package/src/widget-config-template.json +4 -1
  197. package/src/widget-config.json +4 -1
  198. package/tests/widget-form-rich.spec.ts +67 -0
  199. package/tests/widget-index-dev-settings.spec.ts +52 -0
  200. package/tests/widget-twp-iframe.spec.ts +39 -0
  201. package/tsconfig.json +5 -0
@@ -6,9 +6,11 @@ import {
6
6
  MESSAGE_TYPE_MINE,
7
7
  MESSAGE_TYPE_OTHERS,
8
8
  MAX_WIDTH_IMAGES,
9
+ MIN_WIDTH_IMAGES,
9
10
  INFO_MESSAGE_TYPE,
10
11
  CHANNEL_TYPE,
11
- MESSAGE_TYPE_PRIVATE
12
+ MESSAGE_TYPE_PRIVATE,
13
+ TYPE_MSG_URL_PREVIEW
12
14
  } from '../../chat21-core/utils/constants';
13
15
  /** */
14
16
  export function isCarousel(message: any) {
@@ -48,6 +50,20 @@ export function isAudio(message: any) {
48
50
  return false;
49
51
  }
50
52
 
53
+ export function isJsonSources(message: any) {
54
+ if (message && message.type && message.type === 'url_preview') {
55
+ return true;
56
+ }
57
+ return false;
58
+ }
59
+
60
+ export function isAudioTTS(message: any) {
61
+ if (message && message.type && message.type === 'tts' && message.metadata && message.metadata.src && message.metadata.type.includes('audio') ) {
62
+ return true;
63
+ }
64
+ return false;
65
+ }
66
+
51
67
  /** */
52
68
  export function isInfo(message: any) {
53
69
  if (message && message.attributes && (message.attributes.subtype === 'info' || message.attributes.subtype === 'info/support')) {
@@ -91,10 +107,19 @@ export function isSameSender(messages, senderId, index):boolean{
91
107
  }
92
108
 
93
109
  export function isLastMessage(messages, idMessage):boolean {
94
- if (idMessage === messages[messages.length - 1].uid) {
95
- return true;
96
- }
97
- return false;
110
+ // url_preview messages are auxiliary (citations card): they must not "steal"
111
+ // last-message status from the preceding interactive message, otherwise its
112
+ // text/action buttons would disappear as soon as a url_preview arrives.
113
+ const interactive = (messages || []).filter((m: any) => !isUrlPreviewMessage(m));
114
+ const last = interactive[interactive.length - 1] || messages[messages.length - 1];
115
+ return !!last && idMessage === last.uid;
116
+ }
117
+
118
+ function isUrlPreviewMessage(m: any): boolean {
119
+ if (!m) return false;
120
+ return m.type === TYPE_MSG_URL_PREVIEW
121
+ || m.metadata?.type === TYPE_MSG_URL_PREVIEW
122
+ || m.attributes?.type === TYPE_MSG_URL_PREVIEW;
98
123
  }
99
124
 
100
125
  export function isFirstMessage(messages, senderId, index):boolean{
@@ -314,7 +339,21 @@ export function commandToMessage(msg: MessageModel, conversation: ConversationMo
314
339
  message.type = msg['type']
315
340
  message.isSender = isSender(message.sender, currentUserId)
316
341
  message.attributes = { ...conversation.attributes, ...msg['attributes']}
317
-
318
342
 
319
343
  return message as MessageModel
320
344
  }
345
+
346
+ export function calcImageSize(metadata: any): { width: number; height: number } {
347
+ const size = { width: metadata.width, height: metadata.height };
348
+ if (!metadata.width) return size;
349
+ if (metadata.width <= 55) {
350
+ const ratio = metadata.width / metadata.height;
351
+ size.width = MIN_WIDTH_IMAGES;
352
+ size.height = MIN_WIDTH_IMAGES / ratio;
353
+ } else if (metadata.width > MAX_WIDTH_IMAGES) {
354
+ const ratio = metadata.width / metadata.height;
355
+ size.width = MAX_WIDTH_IMAGES;
356
+ size.height = MAX_WIDTH_IMAGES / ratio;
357
+ }
358
+ return size;
359
+ }
@@ -773,6 +773,11 @@ export function isAllowedUrlInText(text: string, allowedUrls: string[]) {
773
773
  return nonWhitelistedDomains.length === 0;
774
774
  }
775
775
 
776
+ // function extractUrls(text: string): string[] {
777
+ // const urlRegex = /https?:\/\/[^\s]+/g;
778
+ // return text.match(urlRegex) || [];
779
+ // }
780
+
776
781
  function extractUrls(text: string): string[] {
777
782
  // Rileva URL con o senza protocollo (http/https)
778
783
  const urlRegex = /\b((https?:\/\/)?(www\.)?[a-z0-9.-]+\.[a-z]{2,})(\/[^\s]*)?/gi;
@@ -787,5 +792,3 @@ function extractUrls(text: string): string[] {
787
792
  }
788
793
 
789
794
 
790
-
791
-
@@ -24,5 +24,8 @@
24
24
  "dashboardUrl": "${DASHBOARD_URL}",
25
25
  "authPersistence": "${AUTH_PERSISTENCE}",
26
26
  "enbedJs": "${ENBED_JS}",
27
- "brandSrc": "${BRAND_SRC}"
27
+ "brandSrc": "${BRAND_SRC}",
28
+ "closeChatInConversation": "${CLOSE_CHAT_IN_CONVERSATION}",
29
+ "voiceProxyWsUrl": "${VOICE_PROXY_WS_URL}",
30
+ "voiceProxyApiBaseUrl": "${VOICE_PROXY_API_BASE_URL}"
28
31
  }
@@ -24,6 +24,9 @@
24
24
  "dashboardUrl": "http://localhost:4500/",
25
25
  "authPersistence": "LOCAL",
26
26
  "enbedJs": true,
27
- "brandSrc": "${BRAND_SRC}"
27
+ "brandSrc": "${BRAND_SRC}",
28
+ "voiceProxyWsUrl": "wss://localhost:3000/speech/ws/voice",
29
+ "voiceProxyApiBaseUrl": "https://localhost:3000/speech/api",
30
+ "closeChatInConversation": false
28
31
 
29
32
  }
@@ -0,0 +1,67 @@
1
+ import { test, expect, type Page } from '@playwright/test';
2
+
3
+ const BASE_QUERY =
4
+ 'tiledesk_projectid=65c5f17ab4e95a0013a0181a&tiledesk_isLogEnabled=true&tiledesk_open=true';
5
+
6
+ function widgetFrame(page: Page) {
7
+ return page.frameLocator('#tiledeskiframe');
8
+ }
9
+
10
+ test.describe('Widget TWP — form / testi / allegati / reparti', () => {
11
+ test.beforeEach(({ page }) => {
12
+ page.setDefaultNavigationTimeout(120_000);
13
+ });
14
+
15
+ test('dopo nuova conversazione compare conversazione, prechat o selezione reparto', async ({ page }) => {
16
+ await page.goto(`/assets/twp/index.html?${BASE_QUERY}`);
17
+ await expect(page.locator('#tiledeskiframe')).toBeAttached({ timeout: 120_000 });
18
+ const w = widgetFrame(page);
19
+ await w.locator('#c21-app-list-conversations .c21-button-primary').first().click({ timeout: 120_000 });
20
+ await expect(
21
+ w.locator('chat-conversation, chat-selection-department, chat-prechat-form').first(),
22
+ ).toBeVisible({ timeout: 120_000 });
23
+ });
24
+
25
+ test('se compare la modale reparti, elenco pulsanti e click impostano flusso', async ({ page }) => {
26
+ await page.goto(`/assets/twp/index.html?${BASE_QUERY}`);
27
+ const w = widgetFrame(page);
28
+ await w.locator('#c21-app-list-conversations .c21-button-primary').first().click({ timeout: 120_000 });
29
+ const panel = w.locator('#chat21-selection-department');
30
+ try {
31
+ await panel.waitFor({ state: 'visible', timeout: 25_000 });
32
+ } catch {
33
+ test.skip();
34
+ }
35
+ await expect(panel).toHaveAttribute('role', 'dialog');
36
+ const deptButtons = panel.locator('.c21-button-department');
37
+ await expect(deptButtons.first()).toBeVisible();
38
+ const count = await deptButtons.count();
39
+ expect(count).toBeGreaterThan(0);
40
+ await deptButtons.first().click();
41
+ await expect(w.locator('chat-conversation').first()).toBeAttached({ timeout: 120_000 });
42
+ });
43
+
44
+ test('con prechat attivato da URL può comparire textarea o form (best-effort)', async ({ page }) => {
45
+ await page.goto(`/assets/twp/index.html?${BASE_QUERY}&tiledesk_preChatForm=true`);
46
+ const w = widgetFrame(page);
47
+ await w.locator('#c21-app-list-conversations .c21-button-primary').first().click({ timeout: 120_000 });
48
+ const prechat = w.locator('chat-prechat-form');
49
+ const textarea = w.locator('textarea#c21-prechat-notes, textarea.form-control, chat-form-textarea textarea');
50
+ await expect(prechat.or(textarea.first())).toBeVisible({ timeout: 120_000 });
51
+ });
52
+
53
+ test('messaggio in conversazione: area testo o bubble visibile nel frame', async ({ page }) => {
54
+ await page.goto(`/assets/twp/index.html?${BASE_QUERY}`);
55
+ const w = widgetFrame(page);
56
+ await w.locator('#c21-app-list-conversations .c21-button-primary').first().click({ timeout: 120_000 });
57
+ await expect(
58
+ w.locator('chat-conversation, chat-prechat-form, chat-selection-department').first(),
59
+ ).toBeVisible({ timeout: 120_000 });
60
+ const conv = w.locator('chat-conversation');
61
+ if (await conv.isVisible().catch(() => false)) {
62
+ await expect(
63
+ conv.locator('.message_innerhtml, chat-text, textarea, [contenteditable]').first(),
64
+ ).toBeVisible({ timeout: 60_000 });
65
+ }
66
+ });
67
+ });
@@ -0,0 +1,52 @@
1
+ import { test, expect } from '@playwright/test';
2
+
3
+ /**
4
+ * Pagina dev: campi testo + pulsante "Test this setting" chiamano onClick* e scrivono su window.tiledeskSettings.
5
+ * Verifica che i valori fake restino coerenti con quanto impostato nel codice inline della pagina.
6
+ */
7
+ test.describe('index-dev.html tiledeskSettings da input', () => {
8
+ test.beforeEach(({ page }) => {
9
+ page.setDefaultNavigationTimeout(120_000);
10
+ });
11
+
12
+ test('marginX / marginY / welcomeTitle aggiornano window.tiledeskSettings', async ({ page }) => {
13
+ await page.goto(
14
+ 'http://127.0.0.1:4203/assets/twp/index-dev.html?tiledesk_projectid=65c5f17ab4e95a0013a0181a&tiledesk_isLogEnabled=true',
15
+ );
16
+ const out = await page.evaluate(() => {
17
+ const mx = document.querySelector('#marginX') as HTMLInputElement;
18
+ const my = document.querySelector('#marginY') as HTMLInputElement;
19
+ const wt = document.querySelector('#welcomeTitle') as HTMLInputElement;
20
+ mx.value = '11px';
21
+ my.value = '22px';
22
+ wt.value = 'Titolo fake';
23
+ (window as any).onClickMarginX();
24
+ (window as any).onClickMarginY();
25
+ (window as any).onClickWelcomeTitle();
26
+ const s = (window as any).tiledeskSettings;
27
+ return { marginX: s.marginX, marginY: s.marginY, welcomeTitle: s.welcomeTitle };
28
+ });
29
+ expect(out.marginX).toBe('11px');
30
+ expect(out.marginY).toBe('22px');
31
+ expect(out.welcomeTitle).toBe('Titolo fake');
32
+ });
33
+
34
+ test('calloutTitle / widgetTitle / departmentID aggiornano tiledeskSettings', async ({ page }) => {
35
+ await page.goto(
36
+ 'http://127.0.0.1:4203/assets/twp/index-dev.html?tiledesk_projectid=65c5f17ab4e95a0013a0181a&tiledesk_isLogEnabled=true',
37
+ );
38
+ const out = await page.evaluate(() => {
39
+ (document.querySelector('#calloutTitle') as HTMLInputElement).value = 'Callout FAKE';
40
+ (document.querySelector('#widgetTitle') as HTMLInputElement).value = 'Widget FAKE';
41
+ (document.querySelector('#departmentID') as HTMLInputElement).value = 'dep-xyz';
42
+ (window as any).onClickCalloutTitle();
43
+ (window as any).onClickWidgetTitle();
44
+ (window as any).onClickDepartmentId();
45
+ const s = (window as any).tiledeskSettings;
46
+ return { calloutTitle: s.calloutTitle, widgetTitle: s.widgetTitle, departmentID: s.departmentID };
47
+ });
48
+ expect(out.calloutTitle).toBe('Callout FAKE');
49
+ expect(out.widgetTitle).toBe('Widget FAKE');
50
+ expect(out.departmentID).toBe('dep-xyz');
51
+ });
52
+ });
@@ -0,0 +1,39 @@
1
+ import { test, expect, type Page } from '@playwright/test';
2
+
3
+ /**
4
+ * Pagina host: `src/assets/twp/index.html` carica `launch.js` e crea `#tiledeskiframe`
5
+ * (vedi `src/launch.js`). L’app Angular gira nel frame; `tiledesk_open=true` viene letto
6
+ * dal parent via `GlobalSettingsService` (`tiledesk_open` → `globals.isOpen`).
7
+ */
8
+ const TWP_QUERY =
9
+ 'tiledesk_projectid=65c5f17ab4e95a0013a0181a&tiledesk_isLogEnabled=true&tiledesk_open=true';
10
+
11
+ function widgetFrame(page: Page) {
12
+ return page.frameLocator('#tiledeskiframe');
13
+ }
14
+
15
+ test.describe('Widget TWP (host + iframe)', () => {
16
+ test.beforeEach(({ page }) => {
17
+ page.setDefaultNavigationTimeout(120_000);
18
+ });
19
+
20
+ test('mostra home e lista conversazioni nel frame con widget già aperto', async ({ page }) => {
21
+ await page.goto(`/assets/twp/index.html?${TWP_QUERY}`);
22
+ await expect(page.locator('#tiledeskiframe')).toBeAttached({ timeout: 120_000 });
23
+ const w = widgetFrame(page);
24
+ await expect(w.locator('#chat21-home-component')).toBeVisible({ timeout: 120_000 });
25
+ await expect(w.locator('#c21-app-list-conversations')).toBeVisible();
26
+ });
27
+
28
+ test('click su CTA primaria apre conversazione, reparto o prechat', async ({ page }) => {
29
+ await page.goto(`/assets/twp/index.html?${TWP_QUERY}`);
30
+ await expect(page.locator('#tiledeskiframe')).toBeAttached({ timeout: 120_000 });
31
+ const w = widgetFrame(page);
32
+ const primary = w.locator('#c21-app-list-conversations .c21-button-primary').first();
33
+ await expect(primary).toBeVisible({ timeout: 120_000 });
34
+ await primary.click();
35
+ await expect(
36
+ w.locator('chat-conversation, chat-selection-department, chat-prechat-form').first(),
37
+ ).toBeVisible({ timeout: 120_000 });
38
+ });
39
+ });
package/tsconfig.json CHANGED
@@ -23,6 +23,11 @@
23
23
  "dom"
24
24
  ],
25
25
  "resolveJsonModule": true,
26
+ "paths": {
27
+ "onnxruntime-web/wasm": [
28
+ "src/app/shims/onnxruntime-web-wasm.ts"
29
+ ]
30
+ }
26
31
  },
27
32
  "skipLibCheck": true,
28
33
  "angularCompilerOptions": {