@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
@@ -1,26 +1,1021 @@
1
- import { Globals } from './../utils/globals';
2
1
  import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
3
- import { TestBed, inject } from '@angular/core/testing';
2
+ import { Injectable } from '@angular/core';
3
+ import { TestBed } from '@angular/core/testing';
4
4
  import { AppStorageService } from '../../chat21-core/providers/abstract/app-storage.service';
5
+ import { LoggerInstance } from '../../chat21-core/providers/logger/loggerInstance';
6
+ import { LoggerService } from '../../chat21-core/providers/abstract/logger.service';
7
+ import { convertColorToRGBA } from '../utils/utils';
8
+ import { Globals } from '../utils/globals';
5
9
  import { AppConfigService } from './app-config.service';
6
-
7
10
  import { GlobalSettingsService } from './global-settings.service';
8
11
 
12
+ const noopLogger: LoggerService = {
13
+ setLoggerConfig: () => {},
14
+ getLoggerConfig: () => ({ isLogEnabled: false, logLevel: 0 }),
15
+ debug: () => {},
16
+ info: () => {},
17
+ log: () => {},
18
+ warn: () => {},
19
+ error: () => {},
20
+ } as LoggerService;
21
+
22
+ @Injectable()
23
+ class AppStorageStub extends AppStorageService {
24
+ initialize(): void {}
25
+ getItem(): any {
26
+ return null;
27
+ }
28
+ setItem(): void {}
29
+ getItemWithoutProjectID(): any {
30
+ return null;
31
+ }
32
+ setItemWithoutProjectID(): void {}
33
+ removeItem(): void {}
34
+ clear(): void {}
35
+ }
36
+
37
+ function fakeWindowWithSettings(
38
+ tiledeskSettings: Record<string, unknown>,
39
+ href = 'https://host.example/page',
40
+ ): Record<string, unknown> {
41
+ return {
42
+ tiledesk: { getBaseLocation: () => 'https://cdn.example/w/' },
43
+ tiledeskSettings,
44
+ location: { href },
45
+ };
46
+ }
47
+
48
+ function fakeWindowUrlOnly(href: string): Record<string, unknown> {
49
+ return { location: { href } };
50
+ }
51
+
52
+ function newGlobalsWithContext(windowContext: Record<string, unknown>): Globals {
53
+ const g = new Globals();
54
+ g.initDefafultParameters();
55
+ g.windowContext = windowContext as any;
56
+ return g;
57
+ }
58
+
9
59
  describe('GlobalSettingsService', () => {
10
60
  beforeEach(() => {
61
+ LoggerInstance.setInstance(noopLogger);
11
62
  TestBed.configureTestingModule({
12
- imports: [],
13
- providers: [
63
+ providers: [
14
64
  GlobalSettingsService,
15
- AppStorageService,
16
- AppConfigService,
17
- Globals,
18
- provideHttpClient(withInterceptorsFromDi())
19
- ]
20
- });
65
+ { provide: AppStorageService, useClass: AppStorageStub },
66
+ {
67
+ provide: AppConfigService,
68
+ useValue: {
69
+ getConfig: () => ({
70
+ firebaseConfig: { tenant: 'cfg-tenant' },
71
+ logLevel: 'Error',
72
+ authPersistence: 'LOCAL',
73
+ apiUrl: 'https://api.example/',
74
+ }),
75
+ },
76
+ },
77
+ provideHttpClient(withInterceptorsFromDi()),
78
+ ],
79
+ });
80
+ });
81
+
82
+ it('should be created', () => {
83
+ expect(TestBed.inject(GlobalSettingsService)).toBeTruthy();
84
+ });
85
+
86
+ describe('setVariablesFromSettings (tiledeskSettings → Globals)', () => {
87
+ const service = () => TestBed.inject(GlobalSettingsService);
88
+
89
+ it('tenant, recipientId, widgetTitle, userEmail, userFullname', () => {
90
+ const g = newGlobalsWithContext(
91
+ fakeWindowWithSettings({
92
+ tenant: 't-1',
93
+ recipientId: 'r-1',
94
+ widgetTitle: 'WT',
95
+ userEmail: 'a@b.c',
96
+ userFullname: 'Full Name',
97
+ }),
98
+ );
99
+ service().setVariablesFromSettings(g);
100
+ expect(g.tenant).toBe('t-1');
101
+ expect(g.recipientId).toBe('r-1');
102
+ expect(g.widgetTitle).toBe('WT');
103
+ expect(g.userEmail).toBe('a@b.c');
104
+ expect(g.userFullname).toBe('Full Name');
105
+ });
106
+
107
+ it('preChatForm, channelType, lang, align', () => {
108
+ const g = newGlobalsWithContext(
109
+ fakeWindowWithSettings({
110
+ preChatForm: true,
111
+ channelType: 'whatsapp',
112
+ lang: 'it',
113
+ align: 'left',
114
+ }),
115
+ );
116
+ service().setVariablesFromSettings(g);
117
+ expect(g.preChatForm).toBe(true);
118
+ expect(g.channelType).toBe('whatsapp');
119
+ expect(g.lang).toBe('it');
120
+ expect(g.align).toBe('left');
121
+ });
122
+
123
+ it('isOpen e open aggiornano isOpen', () => {
124
+ const g1 = newGlobalsWithContext(fakeWindowWithSettings({ isOpen: true }));
125
+ service().setVariablesFromSettings(g1);
126
+ expect(g1.isOpen).toBe(true);
127
+ const g2 = newGlobalsWithContext(fakeWindowWithSettings({ open: true }));
128
+ service().setVariablesFromSettings(g2);
129
+ expect(g2.isOpen).toBe(true);
130
+ });
131
+
132
+ it('margin e launcher', () => {
133
+ const g = newGlobalsWithContext(
134
+ fakeWindowWithSettings({
135
+ marginX: '1px',
136
+ marginY: '2px',
137
+ mobileMarginX: '3px',
138
+ mobileMarginY: '4px',
139
+ launcherWidth: '50px',
140
+ launcherHeight: '51px',
141
+ baloonImage: 'https://x/svg',
142
+ baloonShape: '12%',
143
+ calloutTimer: 9,
144
+ }),
145
+ );
146
+ service().setVariablesFromSettings(g);
147
+ expect(g.marginX).toBe('1px');
148
+ expect(g.marginY).toBe('2px');
149
+ expect(g.mobileMarginX).toBe('3px');
150
+ expect(g.mobileMarginY).toBe('4px');
151
+ expect(g.launcherWidth).toBe('50px');
152
+ expect(g.launcherHeight).toBe('51px');
153
+ expect(g.baloonImage).toBe('https://x/svg');
154
+ expect(g.baloonShape).toBe('12%');
155
+ expect(g.calloutTimer).toBe(9 as any);
156
+ });
157
+
158
+ it('calloutTitle, calloutMsg, fullscreenMode, header flags', () => {
159
+ const g = newGlobalsWithContext(
160
+ fakeWindowWithSettings({
161
+ calloutTitle: 'CT',
162
+ calloutMsg: 'CM',
163
+ fullscreenMode: true,
164
+ hideHeaderCloseButton: true,
165
+ hideHeaderConversation: true,
166
+ }),
167
+ );
168
+ service().setVariablesFromSettings(g);
169
+ expect(g.calloutTitle).toBe('CT');
170
+ expect(g.calloutMsg).toBe('CM');
171
+ expect(g.fullscreenMode).toBe(true);
172
+ expect(g.hideHeaderCloseButton).toBe(true);
173
+ expect(g.hideHeaderConversation).toBe(true);
174
+ });
175
+
176
+ it('themeColor, themeColorOpacity, themeForegroundColor', () => {
177
+ const g = newGlobalsWithContext(
178
+ fakeWindowWithSettings({
179
+ themeColor: '#ff0000',
180
+ themeColorOpacity: 77,
181
+ themeForegroundColor: '#00ff00',
182
+ }),
183
+ );
184
+ service().setVariablesFromSettings(g);
185
+ expect(g.themeColor).toBe(convertColorToRGBA('#ff0000', 100));
186
+ expect(g.bubbleSentBackground).toBe(convertColorToRGBA('#ff0000', 100));
187
+ expect(g.themeColorOpacity).toBe(77);
188
+ expect(g.themeForegroundColor).toBe(convertColorToRGBA('#00ff00', 100));
189
+ });
190
+
191
+ it('allowTranscriptDownload, startFromHome, logoChat, welcome', () => {
192
+ const g = newGlobalsWithContext(
193
+ fakeWindowWithSettings({
194
+ allowTranscriptDownload: true,
195
+ startFromHome: false,
196
+ logoChat: 'https://logo',
197
+ welcomeTitle: 'WTi',
198
+ welcomeMsg: 'WMi',
199
+ }),
200
+ );
201
+ service().setVariablesFromSettings(g);
202
+ expect(g.allowTranscriptDownload).toBe(true);
203
+ expect(g.startFromHome).toBe(false);
204
+ expect(g.logoChat).toBe('https://logo');
205
+ expect(g.welcomeTitle).toBe('WTi');
206
+ expect(g.welcomeMsg).toBe('WMi');
207
+ });
208
+
209
+ it('autoStart, startHidden, isShown, filter e show agenti', () => {
210
+ const g = newGlobalsWithContext(
211
+ fakeWindowWithSettings({
212
+ autoStart: true,
213
+ startHidden: true,
214
+ isShown: false,
215
+ filterByRequester: true,
216
+ showWaitTime: true,
217
+ showAvailableAgents: false,
218
+ showLogoutOption: true,
219
+ }),
220
+ );
221
+ service().setVariablesFromSettings(g);
222
+ expect(g.autoStart).toBe(true);
223
+ expect(g.startHidden).toBe(true);
224
+ expect(g.isShown).toBe(false);
225
+ expect(g.filterByRequester).toBe(true);
226
+ expect(g.showWaitTime).toBe(true);
227
+ expect(g.showAvailableAgents).toBe(false);
228
+ expect(g.showLogoutOption).toBe(true);
229
+ });
230
+
231
+ it('customAttributes, showAllConversations, dynamicWaitTimeReply', () => {
232
+ const attrs = { k: 1 };
233
+ const g = newGlobalsWithContext(
234
+ fakeWindowWithSettings({
235
+ customAttributes: attrs,
236
+ showAllConversations: true,
237
+ dynamicWaitTimeReply: false,
238
+ }),
239
+ );
240
+ service().setVariablesFromSettings(g);
241
+ expect(g.customAttributes).toEqual(attrs);
242
+ expect(g.showAllConversations).toBe(true);
243
+ expect(g.dynamicWaitTimeReply).toBe(false);
244
+ });
245
+
246
+ it('soundEnabled, openExternalLinkButton, menu flags, isLogEnabled', () => {
247
+ const g = newGlobalsWithContext(
248
+ fakeWindowWithSettings({
249
+ soundEnabled: false,
250
+ openExternalLinkButton: false,
251
+ hideCloseConversationOptionMenu: true,
252
+ hideHeaderConversationOptionsMenu: true,
253
+ hideSettings: true,
254
+ isLogEnabled: true,
255
+ }),
256
+ );
257
+ service().setVariablesFromSettings(g);
258
+ expect(g.soundEnabled).toBe(false);
259
+ expect(g.openExternalLinkButton).toBe(false);
260
+ expect(g.hideCloseConversationOptionMenu).toBe(true);
261
+ expect(g.hideHeaderConversationOptionsMenu).toBe(true);
262
+ expect(g.hideSettings).toBe(true);
263
+ expect(g.isLogEnabled).toBe(true);
264
+ });
265
+
266
+ it('preChatFormJson (array JSON)', () => {
267
+ const form = [{ name: 'userFullname', type: 'text' }];
268
+ const g = newGlobalsWithContext(fakeWindowWithSettings({ preChatFormJson: form }));
269
+ service().setVariablesFromSettings(g);
270
+ expect(g.preChatFormJson).toEqual(form as any);
271
+ });
272
+
273
+ it('bubble colors (sent background / text / received)', () => {
274
+ const g = newGlobalsWithContext(
275
+ fakeWindowWithSettings({
276
+ bubbleSentBackground: '#111111',
277
+ bubbleSentTextColor: '#222222',
278
+ bubbleReceivedBackground: '#333333',
279
+ bubbleReceivedTextColor: '#444444',
280
+ }),
281
+ );
282
+ service().setVariablesFromSettings(g);
283
+ expect(g.bubbleSentBackground).toBe(convertColorToRGBA('#111111', 100));
284
+ expect(g.bubbleSentTextColor).toBe(convertColorToRGBA('#222222', 100));
285
+ expect(g.bubbleReceivedBackground).toBe(convertColorToRGBA('#333333', 100));
286
+ expect(g.bubbleReceivedTextColor).toBe(convertColorToRGBA('#444444', 100));
287
+ });
288
+
289
+ it('fontSize, fontFamily (append), fontFamilySource', () => {
290
+ const g = newGlobalsWithContext(
291
+ fakeWindowWithSettings({
292
+ fontSize: '2em',
293
+ fontFamily: 'Arial',
294
+ fontFamilySource: 'https://fonts.googleapis.com/css?family=Arial',
295
+ }),
296
+ );
297
+ const baseFf = g.fontFamily;
298
+ service().setVariablesFromSettings(g);
299
+ expect(g.fontSize).toBe('2em');
300
+ expect(g.fontFamily).toBe('Arial,' + baseFf);
301
+ expect(g.fontFamilySource).toBe('https://fonts.googleapis.com/css?family=Arial');
302
+ });
303
+
304
+ it('button colors e dimensioni', () => {
305
+ const g = newGlobalsWithContext(
306
+ fakeWindowWithSettings({
307
+ buttonFontSize: '20px',
308
+ buttonBackgroundColor: '#abcdef',
309
+ buttonTextColor: '#111111',
310
+ buttonHoverBackgroundColor: '#222222',
311
+ buttonHoverTextColor: '#333333',
312
+ }),
313
+ );
314
+ service().setVariablesFromSettings(g);
315
+ expect(g.buttonFontSize).toBe('20px');
316
+ expect(g.buttonBackgroundColor).toBe(convertColorToRGBA('#abcdef', 100));
317
+ expect(g.buttonTextColor).toBe(convertColorToRGBA('#111111', 100));
318
+ expect(g.buttonHoverBackgroundColor).toBe(convertColorToRGBA('#222222', 100));
319
+ expect(g.buttonHoverTextColor).toBe(convertColorToRGBA('#333333', 100));
320
+ });
321
+
322
+ it('singleConversation, restartConversation, nativeRating, typingLocation', () => {
323
+ const g = newGlobalsWithContext(
324
+ fakeWindowWithSettings({
325
+ singleConversation: true,
326
+ restartConversation: true,
327
+ nativeRating: false,
328
+ typingLocation: 'header',
329
+ }),
330
+ );
331
+ service().setVariablesFromSettings(g);
332
+ expect(g.singleConversation).toBe(true);
333
+ expect(g.restartConversation).toBe(true);
334
+ expect(g.nativeRating).toBe(false);
335
+ expect(g.typingLocation).toBe('header');
336
+ });
337
+
338
+ it('showInfoMessage (stringa CSV) e allowReopen aggiunge CHAT_CLOSED', () => {
339
+ const g = newGlobalsWithContext(
340
+ fakeWindowWithSettings({
341
+ showInfoMessage: ' A , B ',
342
+ allowReopen: true,
343
+ }),
344
+ );
345
+ service().setVariablesFromSettings(g);
346
+ expect(g.allowReopen).toBe(true);
347
+ expect(g.showInfoMessage).toEqual(['A', 'B', 'CHAT_CLOSED']);
348
+ });
349
+
350
+ it('participants, whatsapp, telegram, messangerPageTitle, fileUploadAccept, disconnetTime', () => {
351
+ const g = newGlobalsWithContext(
352
+ fakeWindowWithSettings({
353
+ participants: ' a , b ',
354
+ whatsappNumber: '+39000',
355
+ telegramUsername: '@u',
356
+ messangerPageTitle: 'T',
357
+ fileUploadAccept: '.pdf',
358
+ disconnetTime: 120,
359
+ }),
360
+ );
361
+ service().setVariablesFromSettings(g);
362
+ expect(g.participants).toEqual(['a', 'b']);
363
+ expect(g.whatsappNumber).toBe('+39000');
364
+ expect(g.telegramUsername).toBe('@u');
365
+ expect(g.messangerPageTitle).toBe('T');
366
+ expect(g.fileUploadAccept).toBe('.pdf');
367
+ expect(g.disconnetTime).toBe(120);
368
+ });
369
+
370
+ it('displayOnDesktop/Mobile e onPageChangeVisibility', () => {
371
+ const g = newGlobalsWithContext(
372
+ fakeWindowWithSettings({
373
+ displayOnDesktop: true,
374
+ displayOnMobile: false,
375
+ onPageChangeVisibilityDesktop: 'last',
376
+ onPageChangeVisibilityMobile: 'close',
377
+ }),
378
+ );
379
+ service().setVariablesFromSettings(g);
380
+ expect(g.displayOnDesktop).toBe(true);
381
+ expect(g.displayOnMobile).toBe(false);
382
+ expect(g.onPageChangeVisibilityDesktop).toBe('last');
383
+ expect(g.onPageChangeVisibilityMobile).toBe('close');
384
+ });
385
+
386
+ it('footer attachment/emoji/audio e size', () => {
387
+ const g = newGlobalsWithContext(
388
+ fakeWindowWithSettings({
389
+ showAttachmentFooterButton: true,
390
+ showEmojiFooterButton: false,
391
+ showAudioRecorderFooterButton: true,
392
+ size: 'max',
393
+ }),
394
+ );
395
+ service().setVariablesFromSettings(g);
396
+ expect(g.showAttachmentFooterButton).toBe(true);
397
+ expect(g.showEmojiFooterButton).toBe(false);
398
+ expect(g.showAudioRecorderFooterButton).toBe(true);
399
+ expect(g.size).toBe('max');
400
+ });
401
+ });
402
+
403
+ describe('setVariablesFromUrlParameters (query tiledesk_* → Globals)', () => {
404
+ const service = () => TestBed.inject(GlobalSettingsService);
405
+ const q = (pairs: Record<string, string>) => {
406
+ const qs = Object.entries(pairs)
407
+ .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
408
+ .join('&');
409
+ return `https://host.example/app?${qs}`;
410
+ };
411
+
412
+ it('tenant, recipientId, widgetTitle, userEmail, userFullname, channelType, lang', () => {
413
+ const href = q({
414
+ tiledesk_tenant: 't-url',
415
+ tiledesk_recipientId: 'rec-url',
416
+ tiledesk_widgetTitle: 'W-url',
417
+ tiledesk_userEmail: 'e@mail.it',
418
+ tiledesk_userFullname: 'Nome',
419
+ tiledesk_channelType: 'group',
420
+ tiledesk_lang: 'de',
421
+ });
422
+ const g = newGlobalsWithContext(fakeWindowUrlOnly(href));
423
+ service().setVariablesFromUrlParameters(g);
424
+ expect(g.tenant).toBe('t-url');
425
+ expect(g.recipientId).toBe('rec-url');
426
+ expect(g.widgetTitle).toBe('W-url');
427
+ expect(g.userEmail).toBe('e@mail.it');
428
+ expect(g.userFullname).toBe('Nome');
429
+ expect(g.channelType).toBe('group');
430
+ expect(g.lang).toBe('de');
431
+ });
432
+
433
+ it('calloutTimer, align, margini, launcher, baloon', () => {
434
+ const href = q({
435
+ tiledesk_calloutTimer: '15',
436
+ tiledesk_align: 'right',
437
+ tiledesk_marginX: '10px',
438
+ tiledesk_marginY: '11px',
439
+ tiledesk_mobileMarginX: '12px',
440
+ tiledesk_mobileMarginY: '13px',
441
+ tiledesk_launcherWidth: '60px',
442
+ tiledesk_launcherHeight: '61px',
443
+ tiledesk_baloonImage: 'https://i.svg',
444
+ tiledesk_baloonShape: '40%',
445
+ });
446
+ const g = newGlobalsWithContext(fakeWindowUrlOnly(href));
447
+ service().setVariablesFromUrlParameters(g);
448
+ expect(g.calloutTimer).toBe(15);
449
+ expect(g.align).toBe('right');
450
+ expect(g.marginX).toBe('10px');
451
+ expect(g.marginY).toBe('11px');
452
+ expect(g.mobileMarginX).toBe('12px');
453
+ expect(g.mobileMarginY).toBe('13px');
454
+ expect(g.launcherWidth).toBe('60px');
455
+ expect(g.launcherHeight).toBe('61px');
456
+ expect(g.baloonImage).toBe('https://i.svg');
457
+ expect(g.baloonShape).toBe('40%');
458
+ });
459
+
460
+ it('welcomeMsg, calloutTitle, calloutMsg, hide header flags', () => {
461
+ const href = q({
462
+ tiledesk_welcomeMsg: 'WM-url',
463
+ tiledesk_calloutTitle: 'CT-url',
464
+ tiledesk_calloutMsg: 'CM-url',
465
+ tiledesk_hideHeaderCloseButton: 'true',
466
+ tiledesk_hideHeaderConversation: 'false',
467
+ });
468
+ const g = newGlobalsWithContext(fakeWindowUrlOnly(href));
469
+ service().setVariablesFromUrlParameters(g);
470
+ expect(g.welcomeMsg).toBe('WM-url');
471
+ expect(g.calloutTitle).toBe('CT-url');
472
+ expect(g.calloutMsg).toBe('CM-url');
473
+ expect(g.hideHeaderCloseButton).toBe(true);
474
+ expect(g.hideHeaderConversation).toBe(false);
475
+ });
476
+
477
+ it('themeColor, themeColorOpacity, themeForegroundColor (effetti colore)', () => {
478
+ const href = q({
479
+ tiledesk_themeColor: '#aa0000',
480
+ tiledesk_themeColorOpacity: '88',
481
+ tiledesk_themeForegroundColor: '#00aa00',
482
+ });
483
+ const g = newGlobalsWithContext(fakeWindowUrlOnly(href));
484
+ service().setVariablesFromUrlParameters(g);
485
+ expect(g.themeColor).toBe(convertColorToRGBA('#aa0000', 100));
486
+ expect(g.themeColorOpacity).toBe(88);
487
+ expect(g.themeForegroundColor).toBe(convertColorToRGBA('#00aa00', 100));
488
+ expect(g.bubbleSentTextColor).toBe(convertColorToRGBA('#00aa00', 100));
489
+ });
490
+
491
+ it('logoChat, welcomeTitle, autoStart, startHidden, isShown, isLogEnabled', () => {
492
+ const href = q({
493
+ tiledesk_logoChat: 'https://l.png',
494
+ tiledesk_welcomeTitle: 'WT-u',
495
+ tiledesk_autoStart: 'true',
496
+ tiledesk_startHidden: 'true',
497
+ tiledesk_isShown: 'false',
498
+ tiledesk_isLogEnabled: 'true',
499
+ });
500
+ const g = newGlobalsWithContext(fakeWindowUrlOnly(href));
501
+ service().setVariablesFromUrlParameters(g);
502
+ expect(g.logoChat).toBe('https://l.png');
503
+ expect(g.welcomeTitle).toBe('WT-u');
504
+ expect(g.autoStart).toBe(true);
505
+ expect(g.startHidden).toBe(true);
506
+ expect(g.isShown).toBe(false);
507
+ expect(g.isLogEnabled).toBe(true);
508
+ });
509
+
510
+ it('filterByRequester, showWaitTime, showAvailableAgents, showLogoutOption, preChatForm', () => {
511
+ const href = q({
512
+ tiledesk_filterByRequester: 'true',
513
+ tiledesk_showWaitTime: 'false',
514
+ tiledesk_showAvailableAgents: 'true',
515
+ tiledesk_showLogoutOption: 'false',
516
+ tiledesk_preChatForm: 'true',
517
+ });
518
+ const g = newGlobalsWithContext(fakeWindowUrlOnly(href));
519
+ service().setVariablesFromUrlParameters(g);
520
+ expect(g.filterByRequester).toBe(true);
521
+ expect(g.showWaitTime).toBe(false);
522
+ expect(g.showAvailableAgents).toBe(true);
523
+ expect(g.showLogoutOption).toBe(false);
524
+ expect(g.preChatForm).toBe(true);
525
+ });
526
+
527
+ it('isOpen e open (URL)', () => {
528
+ const g1 = newGlobalsWithContext(fakeWindowUrlOnly(q({ tiledesk_isOpen: 'true' })));
529
+ service().setVariablesFromUrlParameters(g1);
530
+ expect(g1.isOpen).toBe(true);
531
+ const g2 = newGlobalsWithContext(fakeWindowUrlOnly(q({ tiledesk_open: 'true' })));
532
+ service().setVariablesFromUrlParameters(g2);
533
+ expect(g2.isOpen).toBe(true);
534
+ });
535
+
536
+ it('allowTranscriptDownload, startFromHome, fullscreenMode, customAttributes', () => {
537
+ const href = q({
538
+ tiledesk_allowTranscriptDownload: 'true',
539
+ tiledesk_startFromHome: 'false',
540
+ tiledesk_fullscreenMode: 'true',
541
+ tiledesk_customAttributes: JSON.stringify({ z: 2 }),
542
+ });
543
+ const g = newGlobalsWithContext(fakeWindowUrlOnly(href));
544
+ service().setVariablesFromUrlParameters(g);
545
+ expect(g.allowTranscriptDownload).toBe(true);
546
+ expect(g.startFromHome).toBe(false);
547
+ expect(g.fullscreenMode).toBe(true);
548
+ expect(g.customAttributes).toEqual({ z: 2 });
549
+ });
550
+
551
+ it('departmentID, persistence, showAllConversations, jwt', () => {
552
+ const href = q({
553
+ tiledesk_departmentID: 'dep-99',
554
+ tiledesk_persistence: 'session',
555
+ tiledesk_showAllConversations: 'true',
556
+ tiledesk_jwt: 'abc.jwt.token',
557
+ });
558
+ const g = newGlobalsWithContext(fakeWindowUrlOnly(href));
559
+ service().setVariablesFromUrlParameters(g);
560
+ expect(g.departmentID).toBe('dep-99');
561
+ expect(g.persistence).toBe('session');
562
+ expect(g.showAllConversations).toBe(true);
563
+ expect(g.jwt).toBe('abc.jwt.token');
564
+ });
565
+
566
+ it('dynamicWaitTimeReply, soundEnabled, link e menu hide flags', () => {
567
+ const href = q({
568
+ tiledesk_dynamicWaitTimeReply: 'false',
569
+ tiledesk_soundEnabled: 'true',
570
+ tiledesk_openExternalLinkButton: 'false',
571
+ tiledesk_hideHeaderConversationOptionsMenu: 'true',
572
+ tiledesk_hideCloseConversationOptionMenu: 'true',
573
+ tiledesk_hideSettings: 'false',
574
+ });
575
+ const g = newGlobalsWithContext(fakeWindowUrlOnly(href));
576
+ service().setVariablesFromUrlParameters(g);
577
+ expect(g.dynamicWaitTimeReply).toBe(false);
578
+ expect(g.soundEnabled).toBe(true);
579
+ expect(g.openExternalLinkButton).toBe(false);
580
+ expect(g.hideHeaderConversationOptionsMenu).toBe(true);
581
+ expect(g.hideCloseConversationOptionMenu).toBe(true);
582
+ expect(g.hideSettings).toBe(false);
583
+ });
584
+
585
+ it('logLevel e preChatFormJson (JSON)', () => {
586
+ const href = q({
587
+ tiledesk_logLevel: 'Debug',
588
+ tiledesk_preChatFormJson: JSON.stringify([{ name: 'x', type: 'text' }]),
589
+ });
590
+ const g = newGlobalsWithContext(fakeWindowUrlOnly(href));
591
+ service().setVariablesFromUrlParameters(g);
592
+ expect(g.logLevel).toBe('Debug');
593
+ expect(g.preChatFormJson).toEqual([{ name: 'x', type: 'text' }] as any);
594
+ });
595
+
596
+ it('bubble URL (sent/received) e font', () => {
597
+ const href = q({
598
+ tiledesk_bubbleSentBackground: '#123456',
599
+ tiledesk_bubbleSentTextColor: '#654321',
600
+ tiledesk_bubbleReceivedBackground: '#abcdef',
601
+ tiledesk_bubbleReceivedTextColor: '#fedcba',
602
+ tiledesk_fontSize: '1.1em',
603
+ tiledesk_fontFamily: 'Georgia',
604
+ tiledesk_buttonFontSize: '13px',
605
+ });
606
+ const g = newGlobalsWithContext(fakeWindowUrlOnly(href));
607
+ service().setVariablesFromUrlParameters(g);
608
+ expect(g.bubbleSentBackground).toBe(convertColorToRGBA('#123456', 100));
609
+ expect(g.bubbleSentTextColor).toBe(convertColorToRGBA('#654321', 100));
610
+ expect(g.bubbleReceivedBackground).toBe(convertColorToRGBA('#abcdef', 100));
611
+ expect(g.bubbleReceivedTextColor).toBe(convertColorToRGBA('#fedcba', 100));
612
+ expect(g.fontSize).toBe('1.1em');
613
+ expect(g.fontFamily).toBe('Georgia');
614
+ expect(g.buttonFontSize).toBe('13px');
615
+ });
616
+
617
+ it('button colors da URL', () => {
618
+ const href = q({
619
+ tiledesk_buttonBackgroundColor: '#112233',
620
+ tiledesk_buttonTextColor: '#445566',
621
+ tiledesk_buttonHoverBackgroundColor: '#778899',
622
+ tiledesk_buttonHoverTextColor: '#aabbcc',
623
+ });
624
+ const g = newGlobalsWithContext(fakeWindowUrlOnly(href));
625
+ service().setVariablesFromUrlParameters(g);
626
+ expect(g.buttonBackgroundColor).toBe(convertColorToRGBA('#112233', 100));
627
+ expect(g.buttonTextColor).toBe(convertColorToRGBA('#445566', 100));
628
+ expect(g.buttonHoverBackgroundColor).toBe(convertColorToRGBA('#778899', 100));
629
+ expect(g.buttonHoverTextColor).toBe(convertColorToRGBA('#aabbcc', 100));
630
+ });
631
+
632
+ it('singleConversation, restartConversation, nativeRating, typingLocation', () => {
633
+ const href = q({
634
+ tiledesk_singleConversation: 'true',
635
+ tiledesk_restartConversation: 'false',
636
+ tiledesk_nativeRating: 'true',
637
+ tiledesk_typingLocation: 'content',
638
+ });
639
+ const g = newGlobalsWithContext(fakeWindowUrlOnly(href));
640
+ service().setVariablesFromUrlParameters(g);
641
+ expect(g.singleConversation).toBe(true);
642
+ expect(g.restartConversation).toBe(false);
643
+ expect(g.nativeRating).toBe(true);
644
+ expect(g.typingLocation).toBe('content');
645
+ });
646
+
647
+ it('showInfoMessage, allowReopen, participants, fileUploadAccept, disconnetTime', () => {
648
+ const href = q({
649
+ tiledesk_showInfoMessage: 'X, Y',
650
+ tiledesk_allowReopen: 'true',
651
+ tiledesk_participants: 'p1, p2',
652
+ tiledesk_fileUploadAccept: 'image/*',
653
+ tiledesk_disconnetTime: '45',
654
+ });
655
+ const g = newGlobalsWithContext(fakeWindowUrlOnly(href));
656
+ service().setVariablesFromUrlParameters(g);
657
+ expect(g.allowReopen).toBe(true);
658
+ expect(g.showInfoMessage).toEqual(['X', 'Y', 'CHAT_CLOSED']);
659
+ expect(g.participants).toEqual(['p1', 'p2']);
660
+ expect(g.fileUploadAccept).toBe('image/*');
661
+ expect(g.disconnetTime).toBe(45);
662
+ });
663
+
664
+ it('hiddenMessage, td_draft (dev), footer buttons, size', () => {
665
+ const href = q({
666
+ tiledesk_hiddenMessage: 'hidden-text',
667
+ td_draft: 'true',
668
+ tiledesk_showAttachmentFooterButton: 'true',
669
+ tiledesk_showEmojiFooterButton: 'false',
670
+ tiledesk_size: 'min',
671
+ });
672
+ const g = newGlobalsWithContext(fakeWindowUrlOnly(href));
673
+ service().setVariablesFromUrlParameters(g);
674
+ expect(g.hiddenMessage).toBe('hidden-text');
675
+ expect(g.isDevMode).toBe(true);
676
+ expect(g.showAttachmentFooterButton).toBe(true);
677
+ expect(g.showEmojiFooterButton).toBe(false);
678
+ expect(g.size).toBe('min');
679
+ });
680
+ });
681
+
682
+ describe('setMainParametersFromSettings (departmentID, persistence, …)', () => {
683
+ it('legge departmentID, persistence, filterByRequester, showAllConversations da tiledeskSettings', () => {
684
+ const svc = TestBed.inject(GlobalSettingsService);
685
+ const g = new Globals();
686
+ g.initDefafultParameters();
687
+ g.windowContext = {
688
+ tiledesk: { getBaseLocation: () => 'https://x/' },
689
+ tiledeskSettings: {
690
+ departmentID: 'd-ext',
691
+ persistence: 'none',
692
+ filterByRequester: true,
693
+ showAllConversations: false,
694
+ },
695
+ } as any;
696
+ svc.globals = g;
697
+ svc.setMainParametersFromSettings(g);
698
+ expect(g.departmentID).toBe('d-ext');
699
+ expect(g.persistence).toBe('none');
700
+ expect(g.filterByRequester).toBe(true);
701
+ expect(g.showAllConversations).toBe(false);
702
+ });
21
703
  });
22
704
 
23
- it('should be created', inject([GlobalSettingsService], (service: GlobalSettingsService) => {
24
- expect(service).toBeTruthy();
25
- }));
705
+ /**
706
+ * Allineato a `tests/widget-index-dev-settings.spec.ts` e agli `onClick*` di
707
+ * `src/assets/twp/index-dev.html` (stessi nomi chiave su `window.tiledeskSettings`).
708
+ */
709
+ describe('index-dev.html: tiledeskSettings → Globals', () => {
710
+ const settingsSvc = () => TestBed.inject(GlobalSettingsService);
711
+
712
+ it('Playwright — marginX, marginY, welcomeTitle, calloutTitle, widgetTitle', () => {
713
+ const g = newGlobalsWithContext(
714
+ fakeWindowWithSettings({
715
+ marginX: '11px',
716
+ marginY: '22px',
717
+ welcomeTitle: 'Titolo fake',
718
+ calloutTitle: 'Callout FAKE',
719
+ widgetTitle: 'Widget FAKE',
720
+ }),
721
+ );
722
+ settingsSvc().setVariablesFromSettings(g);
723
+ expect(g.marginX).toBe('11px');
724
+ expect(g.marginY).toBe('22px');
725
+ expect(g.welcomeTitle).toBe('Titolo fake');
726
+ expect(g.calloutTitle).toBe('Callout FAKE');
727
+ expect(g.widgetTitle).toBe('Widget FAKE');
728
+ });
729
+
730
+ it('Playwright — departmentID (setMainParametersFromSettings, come bottone index-dev)', () => {
731
+ const svc = TestBed.inject(GlobalSettingsService);
732
+ const g = new Globals();
733
+ g.initDefafultParameters();
734
+ g.windowContext = {
735
+ tiledesk: { getBaseLocation: () => 'https://cdn/' },
736
+ tiledeskSettings: { departmentID: 'dep-xyz' },
737
+ } as any;
738
+ svc.globals = g;
739
+ svc.setMainParametersFromSettings(g);
740
+ expect(g.departmentID).toBe('dep-xyz');
741
+ });
742
+
743
+ it('index-dev — posizione: size, fullscreenMode, align, margini mobile', () => {
744
+ const g = newGlobalsWithContext(
745
+ fakeWindowWithSettings({
746
+ size: 'max',
747
+ fullscreenMode: true,
748
+ align: 'left',
749
+ mobileMarginX: '5px',
750
+ mobileMarginY: '6px',
751
+ }),
752
+ );
753
+ settingsSvc().setVariablesFromSettings(g);
754
+ expect(g.size).toBe('max');
755
+ expect(g.fullscreenMode).toBe(true);
756
+ expect(g.align).toBe('left');
757
+ expect(g.mobileMarginX).toBe('5px');
758
+ expect(g.mobileMarginY).toBe('6px');
759
+ });
760
+
761
+ it('index-dev — disconnetTime, startFromHome, open, preChatForm, calloutTimer', () => {
762
+ const g = newGlobalsWithContext(
763
+ fakeWindowWithSettings({
764
+ disconnetTime: 120,
765
+ startFromHome: false,
766
+ open: true,
767
+ preChatForm: true,
768
+ calloutTimer: 8,
769
+ }),
770
+ );
771
+ settingsSvc().setVariablesFromSettings(g);
772
+ expect(g.disconnetTime).toBe(120);
773
+ expect(g.startFromHome).toBe(false);
774
+ expect(g.isOpen).toBe(true);
775
+ expect(g.preChatForm).toBe(true);
776
+ expect(g.calloutTimer).toBe(8 as any);
777
+ });
778
+
779
+ it('index-dev — calloutMsg, welcomeMsg, logoChat, lang', () => {
780
+ const g = newGlobalsWithContext(
781
+ fakeWindowWithSettings({
782
+ calloutMsg: 'Msg callout',
783
+ welcomeMsg: 'Benvenuto',
784
+ logoChat: 'https://cdn.example/logo.png',
785
+ lang: 'de',
786
+ }),
787
+ );
788
+ settingsSvc().setVariablesFromSettings(g);
789
+ expect(g.calloutMsg).toBe('Msg callout');
790
+ expect(g.welcomeMsg).toBe('Benvenuto');
791
+ expect(g.logoChat).toBe('https://cdn.example/logo.png');
792
+ expect(g.lang).toBe('de');
793
+ });
794
+
795
+ it('index-dev — singleConversation, hideSettings, nativeRating', () => {
796
+ const g = newGlobalsWithContext(
797
+ fakeWindowWithSettings({
798
+ singleConversation: true,
799
+ hideSettings: true,
800
+ nativeRating: false,
801
+ }),
802
+ );
803
+ settingsSvc().setVariablesFromSettings(g);
804
+ expect(g.singleConversation).toBe(true);
805
+ expect(g.hideSettings).toBe(true);
806
+ expect(g.nativeRating).toBe(false);
807
+ });
808
+
809
+ it('index-dev — restart: la pagina usa chiave `restart`, il widget legge `restartConversation`', () => {
810
+ const gWrong = newGlobalsWithContext(fakeWindowWithSettings({ restart: true }));
811
+ settingsSvc().setVariablesFromSettings(gWrong);
812
+ expect(gWrong.restartConversation).toBe(false);
813
+
814
+ const gOk = newGlobalsWithContext(fakeWindowWithSettings({ restartConversation: true }));
815
+ settingsSvc().setVariablesFromSettings(gOk);
816
+ expect(gOk.restartConversation).toBe(true);
817
+ });
818
+
819
+ it('index-dev — colori tema e opacità (themeColor, themeColorOpacity, themeForegroundColor)', () => {
820
+ const g = newGlobalsWithContext(
821
+ fakeWindowWithSettings({
822
+ themeColor: '#2a6ac1',
823
+ themeColorOpacity: 80,
824
+ themeForegroundColor: '#ffffff',
825
+ }),
826
+ );
827
+ settingsSvc().setVariablesFromSettings(g);
828
+ expect(g.themeColor).toBe(convertColorToRGBA('#2a6ac1', 100));
829
+ expect(g.themeColorOpacity).toBe(80);
830
+ expect(g.themeForegroundColor).toBe(convertColorToRGBA('#ffffff', 100));
831
+ });
832
+
833
+ it('index-dev — onClickColor: bubble e pulsanti (stringhe hex come in pagina)', () => {
834
+ const g = newGlobalsWithContext(
835
+ fakeWindowWithSettings({
836
+ bubbleSentBackground: '#123456',
837
+ bubbleSentTextColor: '#abcdef',
838
+ bubbleReceivedBackground: '#f0f0f0',
839
+ bubbleReceivedTextColor: '#111111',
840
+ buttonBackgroundColor: '#222222',
841
+ buttonTextColor: '#333333',
842
+ buttonHoverBackgroundColor: '#444444',
843
+ buttonHoverTextColor: '#555555',
844
+ }),
845
+ );
846
+ settingsSvc().setVariablesFromSettings(g);
847
+ expect(g.bubbleSentBackground).toBe(convertColorToRGBA('#123456', 100));
848
+ expect(g.bubbleSentTextColor).toBe(convertColorToRGBA('#abcdef', 100));
849
+ expect(g.bubbleReceivedBackground).toBe(convertColorToRGBA('#f0f0f0', 100));
850
+ expect(g.bubbleReceivedTextColor).toBe(convertColorToRGBA('#111111', 100));
851
+ expect(g.buttonBackgroundColor).toBe(convertColorToRGBA('#222222', 100));
852
+ expect(g.buttonTextColor).toBe(convertColorToRGBA('#333333', 100));
853
+ expect(g.buttonHoverBackgroundColor).toBe(convertColorToRGBA('#444444', 100));
854
+ expect(g.buttonHoverTextColor).toBe(convertColorToRGBA('#555555', 100));
855
+ });
856
+
857
+ it('index-dev — autoStart, startHidden, launcher (valore già con px come dopo onClick)', () => {
858
+ const g = newGlobalsWithContext(
859
+ fakeWindowWithSettings({
860
+ autoStart: true,
861
+ startHidden: false,
862
+ launcherWidth: '72px',
863
+ launcherHeight: '72px',
864
+ }),
865
+ );
866
+ settingsSvc().setVariablesFromSettings(g);
867
+ expect(g.autoStart).toBe(true);
868
+ expect(g.startHidden).toBe(false);
869
+ expect(g.launcherWidth).toBe('72px');
870
+ expect(g.launcherHeight).toBe('72px');
871
+ });
872
+
873
+ it('index-dev — persistence (main) e showWaitTime / showAvailableAgents / showAllConversations (settings)', () => {
874
+ const svc = TestBed.inject(GlobalSettingsService);
875
+ const g = new Globals();
876
+ g.initDefafultParameters();
877
+ g.windowContext = {
878
+ tiledesk: { getBaseLocation: () => 'https://cdn/' },
879
+ tiledeskSettings: {
880
+ persistence: 'session',
881
+ showWaitTime: false,
882
+ showAvailableAgents: true,
883
+ showAllConversations: true,
884
+ },
885
+ } as any;
886
+ svc.globals = g;
887
+ svc.setMainParametersFromSettings(g);
888
+ svc.setVariablesFromSettings(g);
889
+ expect(g.persistence).toBe('session');
890
+ expect(g.showWaitTime).toBe(false);
891
+ expect(g.showAvailableAgents).toBe(true);
892
+ expect(g.showAllConversations).toBe(true);
893
+ });
894
+
895
+ it('index-dev — baloonImage, baloonShape, dynamicWaitTimeReply, openExternalLinkButton, isLogEnabled', () => {
896
+ const g = newGlobalsWithContext(
897
+ fakeWindowWithSettings({
898
+ baloonImage: 'https://cdn/b.svg',
899
+ baloonShape: '10px 10px 10px 10px',
900
+ dynamicWaitTimeReply: false,
901
+ openExternalLinkButton: true,
902
+ isLogEnabled: true,
903
+ }),
904
+ );
905
+ settingsSvc().setVariablesFromSettings(g);
906
+ expect(g.baloonImage).toBe('https://cdn/b.svg');
907
+ expect(g.baloonShape).toBe('10px 10px 10px 10px');
908
+ expect(g.dynamicWaitTimeReply).toBe(false);
909
+ expect(g.openExternalLinkButton).toBe(true);
910
+ expect(g.isLogEnabled).toBe(true);
911
+ });
912
+
913
+ it('index-dev — canali social: whatsappNumber, messangerPageTitle, telegramUsername', () => {
914
+ const g = newGlobalsWithContext(
915
+ fakeWindowWithSettings({
916
+ whatsappNumber: '+39333111222',
917
+ messangerPageTitle: 'Pagina',
918
+ telegramUsername: '@bot',
919
+ }),
920
+ );
921
+ settingsSvc().setVariablesFromSettings(g);
922
+ expect(g.whatsappNumber).toBe('+39333111222');
923
+ expect(g.messangerPageTitle).toBe('Pagina');
924
+ expect(g.telegramUsername).toBe('@bot');
925
+ });
926
+
927
+ it('index-dev — header conversazione: hide*, allowTranscriptDownload, allowReopen', () => {
928
+ const g = newGlobalsWithContext(
929
+ fakeWindowWithSettings({
930
+ hideHeaderConversation: true,
931
+ hideHeaderCloseButton: true,
932
+ hideHeaderConversationOptionsMenu: true,
933
+ hideCloseConversationOptionMenu: false,
934
+ allowTranscriptDownload: true,
935
+ allowReopen: true,
936
+ }),
937
+ );
938
+ settingsSvc().setVariablesFromSettings(g);
939
+ expect(g.hideHeaderConversation).toBe(true);
940
+ expect(g.hideHeaderCloseButton).toBe(true);
941
+ expect(g.hideHeaderConversationOptionsMenu).toBe(true);
942
+ expect(g.hideCloseConversationOptionMenu).toBe(false);
943
+ expect(g.allowTranscriptDownload).toBe(true);
944
+ expect(g.allowReopen).toBe(true);
945
+ expect(g.showInfoMessage).toContain('CHAT_CLOSED');
946
+ });
947
+
948
+ it('index-dev — recipientId, soundEnabled, typingLocation', () => {
949
+ const g = newGlobalsWithContext(
950
+ fakeWindowWithSettings({
951
+ recipientId: 'agent-42',
952
+ soundEnabled: false,
953
+ typingLocation: 'header',
954
+ }),
955
+ );
956
+ settingsSvc().setVariablesFromSettings(g);
957
+ expect(g.recipientId).toBe('agent-42');
958
+ expect(g.soundEnabled).toBe(false);
959
+ expect(g.typingLocation).toBe('header');
960
+ });
961
+
962
+ it('index-dev — customAttributes (oggetto dopo JSON.parse in pagina)', () => {
963
+ const attrs = { source: 'index-dev', n: 1 };
964
+ const g = newGlobalsWithContext(fakeWindowWithSettings({ customAttributes: attrs }));
965
+ settingsSvc().setVariablesFromSettings(g);
966
+ expect(g.customAttributes).toEqual(attrs);
967
+ });
968
+
969
+ it('index-dev — showInfoMessage e participants come stringhe CSV (textarea)', () => {
970
+ const g = newGlobalsWithContext(
971
+ fakeWindowWithSettings({
972
+ showInfoMessage: ' MEMBER_JOINED_GROUP , CHAT_CLOSED ',
973
+ participants: ' id1 , id2 ',
974
+ }),
975
+ );
976
+ settingsSvc().setVariablesFromSettings(g);
977
+ expect(g.showInfoMessage).toEqual(['MEMBER_JOINED_GROUP', 'CHAT_CLOSED']);
978
+ expect(g.participants).toEqual(['id1', 'id2']);
979
+ });
980
+
981
+ it('index-dev — fileUploadAccept e footer attachment/emoji/audio', () => {
982
+ const g = newGlobalsWithContext(
983
+ fakeWindowWithSettings({
984
+ fileUploadAccept: 'image/png,.pdf',
985
+ showAttachmentFooterButton: true,
986
+ showEmojiFooterButton: false,
987
+ showAudioRecorderFooterButton: true,
988
+ }),
989
+ );
990
+ settingsSvc().setVariablesFromSettings(g);
991
+ expect(g.fileUploadAccept).toBe('image/png,.pdf');
992
+ expect(g.showAttachmentFooterButton).toBe(true);
993
+ expect(g.showEmojiFooterButton).toBe(false);
994
+ expect(g.showAudioRecorderFooterButton).toBe(true);
995
+ });
996
+
997
+ it('index-dev — fontSize, fontFamily + fontFamilySource, buttonFontSize', () => {
998
+ const g = newGlobalsWithContext(
999
+ fakeWindowWithSettings({
1000
+ fontSize: '1.6em',
1001
+ fontFamily: 'Lato',
1002
+ fontFamilySource: 'https://fonts.googleapis.com/css?family=Lato',
1003
+ buttonFontSize: '18px',
1004
+ }),
1005
+ );
1006
+ const baseFf = g.fontFamily;
1007
+ settingsSvc().setVariablesFromSettings(g);
1008
+ expect(g.fontSize).toBe('1.6em');
1009
+ expect(g.fontFamily).toBe('Lato,' + baseFf);
1010
+ expect(g.fontFamilySource).toBe('https://fonts.googleapis.com/css?family=Lato');
1011
+ expect(g.buttonFontSize).toBe('18px');
1012
+ });
1013
+
1014
+ it('index-dev — logLevel su tiledeskSettings non è letto da setVariablesFromSettings (solo URL / init)', () => {
1015
+ const g = newGlobalsWithContext(fakeWindowWithSettings({ logLevel: 'Debug' }));
1016
+ const before = g.logLevel;
1017
+ settingsSvc().setVariablesFromSettings(g);
1018
+ expect(g.logLevel).toBe(before);
1019
+ });
1020
+ });
26
1021
  });