@servicetitan/titan-chatbot-ui 3.0.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.
Files changed (226) hide show
  1. package/CHANGELOG.md +142 -0
  2. package/README.md +15 -0
  3. package/dist/components/chatbot/__tests-cy__/chatbot-help-center.test.d.ts +2 -0
  4. package/dist/components/chatbot/__tests-cy__/chatbot-help-center.test.d.ts.map +1 -0
  5. package/dist/components/chatbot/__tests-cy__/chatbot-help-center.test.js +160 -0
  6. package/dist/components/chatbot/__tests-cy__/chatbot-help-center.test.js.map +1 -0
  7. package/dist/components/chatbot/__tests-cy__/chatbot-live.test.d.ts +2 -0
  8. package/dist/components/chatbot/__tests-cy__/chatbot-live.test.d.ts.map +1 -0
  9. package/dist/components/chatbot/__tests-cy__/chatbot-live.test.js +90 -0
  10. package/dist/components/chatbot/__tests-cy__/chatbot-live.test.js.map +1 -0
  11. package/dist/components/chatbot/__tests-cy__/chatbot-titan-chatbot.test.d.ts +2 -0
  12. package/dist/components/chatbot/__tests-cy__/chatbot-titan-chatbot.test.d.ts.map +1 -0
  13. package/dist/components/chatbot/__tests-cy__/chatbot-titan-chatbot.test.js +155 -0
  14. package/dist/components/chatbot/__tests-cy__/chatbot-titan-chatbot.test.js.map +1 -0
  15. package/dist/components/chatbot/__tests-cy__/chatbot.test.d.ts +2 -0
  16. package/dist/components/chatbot/__tests-cy__/chatbot.test.d.ts.map +1 -0
  17. package/dist/components/chatbot/__tests-cy__/chatbot.test.js +139 -0
  18. package/dist/components/chatbot/__tests-cy__/chatbot.test.js.map +1 -0
  19. package/dist/components/chatbot/chatbot-to-chat-provider-adapter.d.ts +6 -0
  20. package/dist/components/chatbot/chatbot-to-chat-provider-adapter.d.ts.map +1 -0
  21. package/dist/components/chatbot/chatbot-to-chat-provider-adapter.js +21 -0
  22. package/dist/components/chatbot/chatbot-to-chat-provider-adapter.js.map +1 -0
  23. package/dist/components/chatbot/chatbot.d.ts +9 -0
  24. package/dist/components/chatbot/chatbot.d.ts.map +1 -0
  25. package/dist/components/chatbot/chatbot.js +68 -0
  26. package/dist/components/chatbot/chatbot.js.map +1 -0
  27. package/dist/components/chatbot/dialog/chatbot-restart-dialog.d.ts +6 -0
  28. package/dist/components/chatbot/dialog/chatbot-restart-dialog.d.ts.map +1 -0
  29. package/dist/components/chatbot/dialog/chatbot-restart-dialog.js +20 -0
  30. package/dist/components/chatbot/dialog/chatbot-restart-dialog.js.map +1 -0
  31. package/dist/components/chatbot/dialog/chatbot-restart-link.d.ts +4 -0
  32. package/dist/components/chatbot/dialog/chatbot-restart-link.d.ts.map +1 -0
  33. package/dist/components/chatbot/dialog/chatbot-restart-link.js +13 -0
  34. package/dist/components/chatbot/dialog/chatbot-restart-link.js.map +1 -0
  35. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-form-guardrail.test.d.ts +2 -0
  36. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-form-guardrail.test.d.ts.map +1 -0
  37. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-form-guardrail.test.js +65 -0
  38. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-form-guardrail.test.js.map +1 -0
  39. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-form.test.d.ts +2 -0
  40. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-form.test.d.ts.map +1 -0
  41. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-form.test.js +100 -0
  42. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-form.test.js.map +1 -0
  43. package/dist/components/chatbot/feedback/chatbot-message-feedback-form-guardrail.d.ts +3 -0
  44. package/dist/components/chatbot/feedback/chatbot-message-feedback-form-guardrail.d.ts.map +1 -0
  45. package/dist/components/chatbot/feedback/chatbot-message-feedback-form-guardrail.js +13 -0
  46. package/dist/components/chatbot/feedback/chatbot-message-feedback-form-guardrail.js.map +1 -0
  47. package/dist/components/chatbot/feedback/chatbot-message-feedback-form.d.ts +3 -0
  48. package/dist/components/chatbot/feedback/chatbot-message-feedback-form.d.ts.map +1 -0
  49. package/dist/components/chatbot/feedback/chatbot-message-feedback-form.js +12 -0
  50. package/dist/components/chatbot/feedback/chatbot-message-feedback-form.js.map +1 -0
  51. package/dist/components/chatbot/feedback/chatbot-message-feedback-form.module.less +15 -0
  52. package/dist/components/chatbot/feedback/chatbot-message-feedback-popover.d.ts +9 -0
  53. package/dist/components/chatbot/feedback/chatbot-message-feedback-popover.d.ts.map +1 -0
  54. package/dist/components/chatbot/feedback/chatbot-message-feedback-popover.js +60 -0
  55. package/dist/components/chatbot/feedback/chatbot-message-feedback-popover.js.map +1 -0
  56. package/dist/components/chatbot/feedback/chatbot-message-feedback-popover.module.less +10 -0
  57. package/dist/components/chatbot/feedback/chatbot-message-feedback.d.ts +9 -0
  58. package/dist/components/chatbot/feedback/chatbot-message-feedback.d.ts.map +1 -0
  59. package/dist/components/chatbot/feedback/chatbot-message-feedback.js +17 -0
  60. package/dist/components/chatbot/feedback/chatbot-message-feedback.js.map +1 -0
  61. package/dist/components/chatbot/feedback/chatbot-session-feedback-link.d.ts +4 -0
  62. package/dist/components/chatbot/feedback/chatbot-session-feedback-link.d.ts.map +1 -0
  63. package/dist/components/chatbot/feedback/chatbot-session-feedback-link.js +16 -0
  64. package/dist/components/chatbot/feedback/chatbot-session-feedback-link.js.map +1 -0
  65. package/dist/components/chatbot/feedback/chatbot-session-feedback-modal.d.ts +5 -0
  66. package/dist/components/chatbot/feedback/chatbot-session-feedback-modal.d.ts.map +1 -0
  67. package/dist/components/chatbot/feedback/chatbot-session-feedback-modal.js +24 -0
  68. package/dist/components/chatbot/feedback/chatbot-session-feedback-modal.js.map +1 -0
  69. package/dist/components/chatbot/filters/chatbot-filter.d.ts +8 -0
  70. package/dist/components/chatbot/filters/chatbot-filter.d.ts.map +1 -0
  71. package/dist/components/chatbot/filters/chatbot-filter.js +61 -0
  72. package/dist/components/chatbot/filters/chatbot-filter.js.map +1 -0
  73. package/dist/components/chatbot/filters/chatbot-filter.module.css +19 -0
  74. package/dist/components/chatbot/filters/chatbot-filters.d.ts +5 -0
  75. package/dist/components/chatbot/filters/chatbot-filters.d.ts.map +1 -0
  76. package/dist/components/chatbot/filters/chatbot-filters.js +11 -0
  77. package/dist/components/chatbot/filters/chatbot-filters.js.map +1 -0
  78. package/dist/components/chatbot/messages/__tests-cy__/chatbot-message-answer.test.d.ts +2 -0
  79. package/dist/components/chatbot/messages/__tests-cy__/chatbot-message-answer.test.d.ts.map +1 -0
  80. package/dist/components/chatbot/messages/__tests-cy__/chatbot-message-answer.test.js +85 -0
  81. package/dist/components/chatbot/messages/__tests-cy__/chatbot-message-answer.test.js.map +1 -0
  82. package/dist/components/chatbot/messages/__tests-cy__/chatbot-message-typing.test.d.ts +2 -0
  83. package/dist/components/chatbot/messages/__tests-cy__/chatbot-message-typing.test.d.ts.map +1 -0
  84. package/dist/components/chatbot/messages/__tests-cy__/chatbot-message-typing.test.js +57 -0
  85. package/dist/components/chatbot/messages/__tests-cy__/chatbot-message-typing.test.js.map +1 -0
  86. package/dist/components/chatbot/messages/chatbot-links.d.ts +15 -0
  87. package/dist/components/chatbot/messages/chatbot-links.d.ts.map +1 -0
  88. package/dist/components/chatbot/messages/chatbot-links.js +21 -0
  89. package/dist/components/chatbot/messages/chatbot-links.js.map +1 -0
  90. package/dist/components/chatbot/messages/chatbot-links.module.less +22 -0
  91. package/dist/components/chatbot/messages/chatbot-message-agent-footer.d.ts +8 -0
  92. package/dist/components/chatbot/messages/chatbot-message-agent-footer.d.ts.map +1 -0
  93. package/dist/components/chatbot/messages/chatbot-message-agent-footer.js +13 -0
  94. package/dist/components/chatbot/messages/chatbot-message-agent-footer.js.map +1 -0
  95. package/dist/components/chatbot/messages/chatbot-message-answer-readonly.d.ts +6 -0
  96. package/dist/components/chatbot/messages/chatbot-message-answer-readonly.d.ts.map +1 -0
  97. package/dist/components/chatbot/messages/chatbot-message-answer-readonly.js +17 -0
  98. package/dist/components/chatbot/messages/chatbot-message-answer-readonly.js.map +1 -0
  99. package/dist/components/chatbot/messages/chatbot-message-answer.d.ts +6 -0
  100. package/dist/components/chatbot/messages/chatbot-message-answer.d.ts.map +1 -0
  101. package/dist/components/chatbot/messages/chatbot-message-answer.js +29 -0
  102. package/dist/components/chatbot/messages/chatbot-message-answer.js.map +1 -0
  103. package/dist/components/chatbot/messages/chatbot-message-answer.module.less +3 -0
  104. package/dist/components/chatbot/messages/chatbot-message-timeout.d.ts +6 -0
  105. package/dist/components/chatbot/messages/chatbot-message-timeout.d.ts.map +1 -0
  106. package/dist/components/chatbot/messages/chatbot-message-timeout.js +17 -0
  107. package/dist/components/chatbot/messages/chatbot-message-timeout.js.map +1 -0
  108. package/dist/components/chatbot/messages/chatbot-message-typing.d.ts +8 -0
  109. package/dist/components/chatbot/messages/chatbot-message-typing.d.ts.map +1 -0
  110. package/dist/components/chatbot/messages/chatbot-message-typing.js +27 -0
  111. package/dist/components/chatbot/messages/chatbot-message-typing.js.map +1 -0
  112. package/dist/components/chatbot/messages/chatbot-message-welcome.d.ts +3 -0
  113. package/dist/components/chatbot/messages/chatbot-message-welcome.d.ts.map +1 -0
  114. package/dist/components/chatbot/messages/chatbot-message-welcome.js +4 -0
  115. package/dist/components/chatbot/messages/chatbot-message-welcome.js.map +1 -0
  116. package/dist/components/chatbot/templates/chatbot-message-template-agent-readonly.d.ts +6 -0
  117. package/dist/components/chatbot/templates/chatbot-message-template-agent-readonly.d.ts.map +1 -0
  118. package/dist/components/chatbot/templates/chatbot-message-template-agent-readonly.js +12 -0
  119. package/dist/components/chatbot/templates/chatbot-message-template-agent-readonly.js.map +1 -0
  120. package/dist/components/chatbot/templates/chatbot-message-template-agent.d.ts +6 -0
  121. package/dist/components/chatbot/templates/chatbot-message-template-agent.d.ts.map +1 -0
  122. package/dist/components/chatbot/templates/chatbot-message-template-agent.js +10 -0
  123. package/dist/components/chatbot/templates/chatbot-message-template-agent.js.map +1 -0
  124. package/dist/components/chatbot/templates/chatbot-message-template-user-readonly.d.ts +6 -0
  125. package/dist/components/chatbot/templates/chatbot-message-template-user-readonly.d.ts.map +1 -0
  126. package/dist/components/chatbot/templates/chatbot-message-template-user-readonly.js +7 -0
  127. package/dist/components/chatbot/templates/chatbot-message-template-user-readonly.js.map +1 -0
  128. package/dist/index.d.ts +6 -0
  129. package/dist/index.d.ts.map +1 -0
  130. package/dist/index.js +6 -0
  131. package/dist/index.js.map +1 -0
  132. package/dist/stores/__tests__/message-feedback-guardrail.store.test.d.ts +2 -0
  133. package/dist/stores/__tests__/message-feedback-guardrail.store.test.d.ts.map +1 -0
  134. package/dist/stores/__tests__/message-feedback-guardrail.store.test.js +49 -0
  135. package/dist/stores/__tests__/message-feedback-guardrail.store.test.js.map +1 -0
  136. package/dist/stores/__tests__/message-feedback.store.test.d.ts +2 -0
  137. package/dist/stores/__tests__/message-feedback.store.test.d.ts.map +1 -0
  138. package/dist/stores/__tests__/message-feedback.store.test.js +114 -0
  139. package/dist/stores/__tests__/message-feedback.store.test.js.map +1 -0
  140. package/dist/stores/__tests__/session-feedback.store.test.d.ts +2 -0
  141. package/dist/stores/__tests__/session-feedback.store.test.d.ts.map +1 -0
  142. package/dist/stores/__tests__/session-feedback.store.test.js +39 -0
  143. package/dist/stores/__tests__/session-feedback.store.test.js.map +1 -0
  144. package/dist/stores/message-feedback-base.store.d.ts +8 -0
  145. package/dist/stores/message-feedback-base.store.d.ts.map +1 -0
  146. package/dist/stores/message-feedback-base.store.js +2 -0
  147. package/dist/stores/message-feedback-base.store.js.map +1 -0
  148. package/dist/stores/message-feedback-guardrail.store.d.ts +16 -0
  149. package/dist/stores/message-feedback-guardrail.store.d.ts.map +1 -0
  150. package/dist/stores/message-feedback-guardrail.store.js +85 -0
  151. package/dist/stores/message-feedback-guardrail.store.js.map +1 -0
  152. package/dist/stores/message-feedback.store.d.ts +23 -0
  153. package/dist/stores/message-feedback.store.d.ts.map +1 -0
  154. package/dist/stores/message-feedback.store.js +145 -0
  155. package/dist/stores/message-feedback.store.js.map +1 -0
  156. package/dist/stores/session-feedback.store.d.ts +15 -0
  157. package/dist/stores/session-feedback.store.d.ts.map +1 -0
  158. package/dist/stores/session-feedback.store.js +75 -0
  159. package/dist/stores/session-feedback.store.js.map +1 -0
  160. package/dist/utils/__tests__/axios-utils.test.d.ts +2 -0
  161. package/dist/utils/__tests__/axios-utils.test.d.ts.map +1 -0
  162. package/dist/utils/__tests__/axios-utils.test.js +33 -0
  163. package/dist/utils/__tests__/axios-utils.test.js.map +1 -0
  164. package/dist/utils/axios-utils.d.ts +5 -0
  165. package/dist/utils/axios-utils.d.ts.map +1 -0
  166. package/dist/utils/axios-utils.js +23 -0
  167. package/dist/utils/axios-utils.js.map +1 -0
  168. package/dist/utils/test-utils.d.ts +5 -0
  169. package/dist/utils/test-utils.d.ts.map +1 -0
  170. package/dist/utils/test-utils.js +17 -0
  171. package/dist/utils/test-utils.js.map +1 -0
  172. package/package.json +59 -0
  173. package/src/components/chatbot/__tests-cy__/chatbot-help-center.test.tsx +210 -0
  174. package/src/components/chatbot/__tests-cy__/chatbot-live.test.tsx +120 -0
  175. package/src/components/chatbot/__tests-cy__/chatbot-titan-chatbot.test.tsx +206 -0
  176. package/src/components/chatbot/__tests-cy__/chatbot.test.tsx +181 -0
  177. package/src/components/chatbot/chatbot-to-chat-provider-adapter.tsx +36 -0
  178. package/src/components/chatbot/chatbot.tsx +95 -0
  179. package/src/components/chatbot/dialog/chatbot-restart-dialog.tsx +36 -0
  180. package/src/components/chatbot/dialog/chatbot-restart-link.tsx +26 -0
  181. package/src/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-form-guardrail.test.tsx +89 -0
  182. package/src/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-form.test.tsx +131 -0
  183. package/src/components/chatbot/feedback/chatbot-message-feedback-form-guardrail.tsx +35 -0
  184. package/src/components/chatbot/feedback/chatbot-message-feedback-form.module.less +15 -0
  185. package/src/components/chatbot/feedback/chatbot-message-feedback-form.module.less.d.ts +4 -0
  186. package/src/components/chatbot/feedback/chatbot-message-feedback-form.tsx +65 -0
  187. package/src/components/chatbot/feedback/chatbot-message-feedback-popover.module.less +10 -0
  188. package/src/components/chatbot/feedback/chatbot-message-feedback-popover.module.less.d.ts +4 -0
  189. package/src/components/chatbot/feedback/chatbot-message-feedback-popover.tsx +200 -0
  190. package/src/components/chatbot/feedback/chatbot-message-feedback.tsx +27 -0
  191. package/src/components/chatbot/feedback/chatbot-session-feedback-link.tsx +29 -0
  192. package/src/components/chatbot/feedback/chatbot-session-feedback-modal.tsx +96 -0
  193. package/src/components/chatbot/filters/chatbot-filter.module.css +19 -0
  194. package/src/components/chatbot/filters/chatbot-filter.module.css.d.ts +5 -0
  195. package/src/components/chatbot/filters/chatbot-filter.tsx +160 -0
  196. package/src/components/chatbot/filters/chatbot-filters.tsx +17 -0
  197. package/src/components/chatbot/messages/__tests-cy__/chatbot-message-answer.test.tsx +110 -0
  198. package/src/components/chatbot/messages/__tests-cy__/chatbot-message-typing.test.tsx +71 -0
  199. package/src/components/chatbot/messages/chatbot-links.module.less +22 -0
  200. package/src/components/chatbot/messages/chatbot-links.module.less.d.ts +4 -0
  201. package/src/components/chatbot/messages/chatbot-links.tsx +76 -0
  202. package/src/components/chatbot/messages/chatbot-message-agent-footer.tsx +35 -0
  203. package/src/components/chatbot/messages/chatbot-message-answer-readonly.tsx +39 -0
  204. package/src/components/chatbot/messages/chatbot-message-answer.module.less +3 -0
  205. package/src/components/chatbot/messages/chatbot-message-answer.module.less.d.ts +3 -0
  206. package/src/components/chatbot/messages/chatbot-message-answer.tsx +55 -0
  207. package/src/components/chatbot/messages/chatbot-message-timeout.tsx +20 -0
  208. package/src/components/chatbot/messages/chatbot-message-typing.tsx +39 -0
  209. package/src/components/chatbot/messages/chatbot-message-welcome.tsx +16 -0
  210. package/src/components/chatbot/templates/chatbot-message-template-agent-readonly.tsx +25 -0
  211. package/src/components/chatbot/templates/chatbot-message-template-agent.tsx +25 -0
  212. package/src/components/chatbot/templates/chatbot-message-template-user-readonly.tsx +16 -0
  213. package/src/cypress.d.ts +10 -0
  214. package/src/index.ts +5 -0
  215. package/src/stores/__tests__/message-feedback-guardrail.store.test.ts +61 -0
  216. package/src/stores/__tests__/message-feedback.store.test.ts +121 -0
  217. package/src/stores/__tests__/session-feedback.store.test.ts +47 -0
  218. package/src/stores/message-feedback-base.store.ts +8 -0
  219. package/src/stores/message-feedback-guardrail.store.ts +60 -0
  220. package/src/stores/message-feedback.store.ts +113 -0
  221. package/src/stores/session-feedback.store.ts +44 -0
  222. package/src/utils/__tests__/axios-utils.test.ts +40 -0
  223. package/src/utils/axios-utils.ts +25 -0
  224. package/src/utils/test-utils.ts +22 -0
  225. package/tsconfig.json +25 -0
  226. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,210 @@
1
+ import { ILog, Log } from '@servicetitan/log-service';
2
+ import { Container, Provider } from '@servicetitan/react-ioc';
3
+ import {
4
+ ApiClientHelpCenter,
5
+ CHATBOT_API_CLIENT,
6
+ CHATBOT_CLIENT_SETTINGS,
7
+ CHATBOT_UI_BACKEND_STORE_TOKEN,
8
+ CHATBOT_UI_STORE_TOKEN,
9
+ ChatbotCustomizations,
10
+ ChatbotUiBackendStore,
11
+ ChatbotUiStore,
12
+ IChatbotApiClient,
13
+ IChatbotUiBackendStore,
14
+ IChatbotUiStore,
15
+ Models,
16
+ } from '@servicetitan/titan-chatbot-api';
17
+ import { ChatUiSelectors, CypressMocks } from '@servicetitan/titan-chatbot-ui-cypress';
18
+ import axios from 'axios';
19
+ import { mount } from 'cypress/react';
20
+ import { FC, useMemo } from 'react';
21
+ import { Chatbot } from '../chatbot';
22
+
23
+ const ChatbotBaseUrl = 'https://chatbot-api.example.com/base/url';
24
+
25
+ const initContainer = () => {
26
+ const rootContainer = new Container();
27
+ const container = new Container();
28
+ container.parent = rootContainer;
29
+ container.bind<ILog>(Log).to(CypressMocks.LogMock).inSingletonScope();
30
+ container.bind<IChatbotUiStore>(CHATBOT_UI_STORE_TOKEN).to(ChatbotUiStore).inSingletonScope();
31
+ container
32
+ .bind<IChatbotUiBackendStore>(CHATBOT_UI_BACKEND_STORE_TOKEN)
33
+ .to(ChatbotUiBackendStore)
34
+ .inSingletonScope();
35
+
36
+ // Set up Helpcenter API client
37
+ const clientSettings: ApiClientHelpCenter.IChatbotClientSettingsHelpCenter = {
38
+ area: 'FloatingChat',
39
+ instance: 'STapp',
40
+ constructorParametersFactory: () => ({
41
+ baseUrl: ChatbotBaseUrl,
42
+ axiosInstance: axios.create(),
43
+ }),
44
+ };
45
+ container
46
+ .bind<ApiClientHelpCenter.IChatbotClientSettingsHelpCenter>(CHATBOT_CLIENT_SETTINGS)
47
+ .toConstantValue(clientSettings);
48
+ container
49
+ .bind<IChatbotApiClient>(CHATBOT_API_CLIENT)
50
+ .to(ApiClientHelpCenter.ChatbotApiClient)
51
+ .inSingletonScope();
52
+ return container;
53
+ };
54
+
55
+ describe('[Chatbot with Help Center API]', () => {
56
+ let container: Container;
57
+ let log: CypressMocks.LogMock;
58
+ let apiClientSettings: ApiClientHelpCenter.IChatbotClientSettingsHelpCenter;
59
+ let apiClient: ApiClientHelpCenter.ChatbotApiClient;
60
+ let uiStore: ChatbotUiStore;
61
+ let uiBackendStore: ChatbotUiBackendStore;
62
+
63
+ beforeEach(() => {
64
+ container = initContainer();
65
+ log = container.get<CypressMocks.LogMock>(Log);
66
+ apiClientSettings =
67
+ container.get<ApiClientHelpCenter.IChatbotClientSettingsHelpCenter>(
68
+ CHATBOT_CLIENT_SETTINGS
69
+ );
70
+ apiClient = container.get<ApiClientHelpCenter.ChatbotApiClient>(CHATBOT_API_CLIENT);
71
+ uiStore = container.get<ChatbotUiStore>(CHATBOT_UI_STORE_TOKEN);
72
+ uiBackendStore = container.get<ChatbotUiBackendStore>(CHATBOT_UI_BACKEND_STORE_TOKEN);
73
+ cy.viewport(550, 800);
74
+ cy.clock(Date.parse('2023-10-01T00:00:00Z'));
75
+ });
76
+
77
+ const render = () => {
78
+ const ChatbotWrapper: FC = () => {
79
+ const customizationContext = useMemo<ChatbotCustomizations>(
80
+ () => ({
81
+ filters: { enabled: true },
82
+ feedback: { title: 'TITLE' },
83
+ }),
84
+ []
85
+ );
86
+ return (
87
+ <Provider
88
+ singletons={[
89
+ {
90
+ provide: Log,
91
+ useValue: log,
92
+ },
93
+ {
94
+ provide: CHATBOT_CLIENT_SETTINGS,
95
+ useValue: apiClientSettings,
96
+ },
97
+ { provide: CHATBOT_API_CLIENT, useValue: apiClient },
98
+ {
99
+ provide: CHATBOT_UI_STORE_TOKEN,
100
+ useValue: uiStore,
101
+ },
102
+ {
103
+ provide: CHATBOT_UI_BACKEND_STORE_TOKEN,
104
+ useValue: uiBackendStore,
105
+ },
106
+ ]}
107
+ >
108
+ <Chatbot
109
+ className="h-100vh max-h-100vh of-x-hidden"
110
+ customizations={customizationContext}
111
+ />
112
+ </Provider>
113
+ );
114
+ };
115
+ cy.spy(uiStore, 'run').as('runSpy');
116
+ mount(<ChatbotWrapper />);
117
+ return cy.wrap(
118
+ new Promise(resolve => {
119
+ cy.get('@runSpy')
120
+ .should('have.been.calledOnce')
121
+ .then((invocation: any) => {
122
+ const initPromise = invocation.firstCall.returnValue as ReturnType<
123
+ IChatbotUiStore['run']
124
+ >;
125
+ initPromise.then(resolve);
126
+ });
127
+ })
128
+ );
129
+ };
130
+
131
+ it('should render the chatbot with help center API', () => {
132
+ const sessionMock = CypressMocks.HC.CreateSession;
133
+ const messageMock = CypressMocks.HC.SendUserMessage;
134
+ const messageFeedbackMock = CypressMocks.HC.MessageFeedback;
135
+ const sessionFeedbackMock = CypressMocks.HC.SessionFeedback;
136
+
137
+ const aliasFilterOptions = CypressMocks.HC.interceptFilterOptions(ChatbotBaseUrl);
138
+ const aliasCreateSession = sessionMock.intercept(ChatbotBaseUrl);
139
+ const aliasSendUserMessage = messageMock.intercept(ChatbotBaseUrl);
140
+ const aliasMessageFeedback = messageFeedbackMock.intercept(ChatbotBaseUrl);
141
+ const aliasSessionFeedback = sessionFeedbackMock.intercept(ChatbotBaseUrl);
142
+
143
+ render().then(() => {
144
+ // Expect filters were loaded using the Help Center API
145
+ cy.wait(aliasFilterOptions).then(interception => {
146
+ // Check options were loaded correctly
147
+ expect(interception.request.url).to.equal(
148
+ `${ChatbotBaseUrl}/api/Chat/filter-options`
149
+ );
150
+ expect(interception.response?.body).to.an('object');
151
+ expect(interception.response?.body?.sources).to.an('array');
152
+ expect(interception.response?.body?.contentTypes).to.an('array');
153
+ expect(interception.response?.body?.productAreas).to.an('array');
154
+ expect(interception.response?.statusCode).to.equal(200);
155
+ });
156
+
157
+ // Ask the bot a question
158
+ cy.log('Sending message...');
159
+ ChatUiSelectors.chatInput.type(`${messageMock.request.text}{enter}`, { delay: 0 });
160
+
161
+ // Check that the session was created
162
+ cy.wait(aliasCreateSession).then(interception => {
163
+ expect(interception.request.url).to.equal(
164
+ `${ChatbotBaseUrl}/api/Chat/create-session`
165
+ );
166
+ expect(interception.request.body).to.deep.equal(sessionMock.request);
167
+ expect(interception.response?.body).to.deep.equal(sessionMock.response);
168
+ expect(interception.response?.statusCode).to.equal(200);
169
+ });
170
+
171
+ // Check the user message is sent
172
+ cy.wait(aliasSendUserMessage).then(interception => {
173
+ expect(interception.request.url).to.equal(
174
+ `${ChatbotBaseUrl}/api/Chat/user-message`
175
+ );
176
+ expect(interception.request.body).to.deep.equal(messageMock.request);
177
+ expect(interception.response?.body).to.deep.equal(messageMock.response);
178
+ expect(interception.response?.statusCode).to.equal(200);
179
+ });
180
+
181
+ // Send session feedback (manually)
182
+ cy.log('Sending session feedback...');
183
+ uiStore.sendSessionFeedback(
184
+ new Models.Feedback({
185
+ sessionId: sessionMock.response.id,
186
+ description: 'Good answer!',
187
+ rating: Models.FeedbackRatings.ThumbsUp,
188
+ })
189
+ );
190
+ cy.wait(aliasSessionFeedback).then(interception => {
191
+ expect(interception.request.url).to.equal(
192
+ `${ChatbotBaseUrl}/api/Chat/session-feedback?sessionId=${sessionMock.response.id}`
193
+ );
194
+ expect(interception.request.body).to.deep.equal(sessionFeedbackMock.request);
195
+ expect(interception.response?.statusCode).to.equal(200);
196
+ });
197
+
198
+ // Check the feedback is sent with thumbs up
199
+ cy.log('Sending message feedback...');
200
+ ChatUiSelectors.chatbotMessageFeedbackThumbsUp.scrollIntoView().click({ force: true });
201
+ cy.wait(aliasMessageFeedback).then(interception => {
202
+ expect(interception.request.url).to.equal(
203
+ `${ChatbotBaseUrl}/api/Chat/bot-message-feedback?sessionId=${messageMock.response.sessionId}&botMessageId=${messageMock.response.id}`
204
+ );
205
+ expect(interception.request.body).to.deep.equal(messageFeedbackMock.request);
206
+ expect(interception.response?.statusCode).to.equal(200);
207
+ });
208
+ });
209
+ });
210
+ });
@@ -0,0 +1,120 @@
1
+ import { ILog, Log } from '@servicetitan/log-service';
2
+ import { Container, Provider } from '@servicetitan/react-ioc';
3
+ import {
4
+ CHATBOT_API_CLIENT,
5
+ CHATBOT_UI_BACKEND_STORE_TOKEN,
6
+ CHATBOT_UI_STORE_TOKEN,
7
+ ChatbotCustomizations,
8
+ ChatbotUiBackendStore,
9
+ ChatbotUiStore,
10
+ IChatbotApiClient,
11
+ IChatbotUiBackendStore,
12
+ IChatbotUiStore,
13
+ ModelsMocks,
14
+ } from '@servicetitan/titan-chatbot-api';
15
+ import { CypressMocks } from '@servicetitan/titan-chatbot-ui-cypress';
16
+ import { mount } from 'cypress/react';
17
+ import { FC, useMemo } from 'react';
18
+ import { Chatbot } from '../chatbot';
19
+
20
+ const initContainer = () => {
21
+ const rootContainer = new Container();
22
+ const container = new Container();
23
+ container.parent = rootContainer;
24
+ container.bind<ILog>(Log).to(CypressMocks.LogMock).inSingletonScope();
25
+ container
26
+ .bind<IChatbotApiClient>(CHATBOT_API_CLIENT)
27
+ .to(CypressMocks.ChatbotApiClientMock)
28
+ .inSingletonScope();
29
+ container.bind<IChatbotUiStore>(CHATBOT_UI_STORE_TOKEN).to(ChatbotUiStore).inSingletonScope();
30
+ container
31
+ .bind<IChatbotUiBackendStore>(CHATBOT_UI_BACKEND_STORE_TOKEN)
32
+ .to(ChatbotUiBackendStore)
33
+ .inSingletonScope();
34
+ return container;
35
+ };
36
+
37
+ /**
38
+ * The test is for internal purposes only.
39
+ */
40
+ describe.skip('[Chatbot]', () => {
41
+ let container: Container;
42
+ let log: CypressMocks.LogMock;
43
+ let api: CypressMocks.ChatbotApiClientMock;
44
+ let uiStore: ChatbotUiStore;
45
+ let uiBackendStore: ChatbotUiBackendStore;
46
+
47
+ const mockApi = () => {
48
+ api.postSession = cy.stub().resolves(ModelsMocks.mockSession());
49
+ api.getOptions = cy.stub().resolves(ModelsMocks.mockFrontendModel());
50
+ };
51
+
52
+ beforeEach(() => {
53
+ cy.intercept('GET', 'https://fonts.gstatic.com/**', {
54
+ statusCode: 200,
55
+ body: new ArrayBuffer(0),
56
+ headers: {
57
+ 'Content-Type': 'font/woff2',
58
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
59
+ },
60
+ });
61
+ container = initContainer();
62
+ log = container.get<CypressMocks.LogMock>(Log);
63
+ api = container.get<CypressMocks.ChatbotApiClientMock>(CHATBOT_API_CLIENT);
64
+ uiStore = container.get<ChatbotUiStore>(CHATBOT_UI_STORE_TOKEN);
65
+ uiBackendStore = container.get<ChatbotUiBackendStore>(CHATBOT_UI_BACKEND_STORE_TOKEN);
66
+ mockApi();
67
+ cy.viewport(550, 800);
68
+ });
69
+
70
+ const mockAskBotApi = (answer: string) => {
71
+ api.postMessage = cy.stub().as('askBot').resolves(
72
+ ModelsMocks.mockBotMessage({
73
+ answer,
74
+ })
75
+ );
76
+ return '@askBot';
77
+ };
78
+
79
+ const render = () => {
80
+ const ChatbotWrapper: FC = () => {
81
+ const customizationContext = useMemo<ChatbotCustomizations>(
82
+ () => ({
83
+ filters: { enabled: true },
84
+ feedback: { title: 'TITLE' },
85
+ }),
86
+ []
87
+ );
88
+ return (
89
+ <Provider
90
+ singletons={[
91
+ {
92
+ provide: Log,
93
+ useValue: log,
94
+ },
95
+ { provide: CHATBOT_API_CLIENT, useValue: api },
96
+ {
97
+ provide: CHATBOT_UI_STORE_TOKEN,
98
+ useValue: uiStore,
99
+ },
100
+ {
101
+ provide: CHATBOT_UI_BACKEND_STORE_TOKEN,
102
+ useValue: uiBackendStore,
103
+ },
104
+ ]}
105
+ >
106
+ <Chatbot
107
+ className="h-100vh max-h-100vh of-x-hidden"
108
+ customizations={customizationContext}
109
+ />
110
+ </Provider>
111
+ );
112
+ };
113
+ mount(<ChatbotWrapper />);
114
+ };
115
+
116
+ it('should render the chatbot component', () => {
117
+ mockAskBotApi("Hello! I'm chatbot mocked response!!!");
118
+ render();
119
+ });
120
+ });
@@ -0,0 +1,206 @@
1
+ import { ILog, Log } from '@servicetitan/log-service';
2
+ import { Container, Provider } from '@servicetitan/react-ioc';
3
+ import {
4
+ ApiClientTitanChat,
5
+ CHATBOT_API_CLIENT,
6
+ CHATBOT_CLIENT_SETTINGS,
7
+ CHATBOT_UI_BACKEND_STORE_TOKEN,
8
+ CHATBOT_UI_STORE_TOKEN,
9
+ ChatbotCustomizations,
10
+ ChatbotUiBackendStore,
11
+ ChatbotUiStore,
12
+ IChatbotApiClient,
13
+ IChatbotUiBackendStore,
14
+ IChatbotUiStore,
15
+ Models,
16
+ } from '@servicetitan/titan-chatbot-api';
17
+ import { ChatUiSelectors, CypressMocks } from '@servicetitan/titan-chatbot-ui-cypress';
18
+ import { mount } from 'cypress/react';
19
+ import { FC, useMemo } from 'react';
20
+ import { Chatbot } from '../chatbot';
21
+
22
+ const ChatbotBaseUrl = 'https://chatbot-api.example.com/base/url';
23
+ const ChatbotVersion = 2;
24
+
25
+ const initContainer = () => {
26
+ const rootContainer = new Container();
27
+ const container = new Container();
28
+ container.parent = rootContainer;
29
+ container.bind<ILog>(Log).to(CypressMocks.LogMock).inSingletonScope();
30
+ container.bind<IChatbotUiStore>(CHATBOT_UI_STORE_TOKEN).to(ChatbotUiStore).inSingletonScope();
31
+ container
32
+ .bind<IChatbotUiBackendStore>(CHATBOT_UI_BACKEND_STORE_TOKEN)
33
+ .to(ChatbotUiBackendStore)
34
+ .inSingletonScope();
35
+
36
+ // Set up Helpcenter API client
37
+ const clientSettings: ApiClientTitanChat.IChatbotClientSettingsTitanChat = {
38
+ clientId: 'TitanChatClientId',
39
+ version: String(ChatbotVersion),
40
+ constructorParametersFactory: () => ({
41
+ baseUrl: ChatbotBaseUrl,
42
+ }),
43
+ };
44
+ container
45
+ .bind<ApiClientTitanChat.IChatbotClientSettingsTitanChat>(CHATBOT_CLIENT_SETTINGS)
46
+ .toConstantValue(clientSettings);
47
+ container
48
+ .bind<IChatbotApiClient>(CHATBOT_API_CLIENT)
49
+ .to(ApiClientTitanChat.ChatbotApiClient)
50
+ .inSingletonScope();
51
+ return container;
52
+ };
53
+
54
+ describe('[Chatbot with Titan Chat API]', () => {
55
+ let container: Container;
56
+ let log: CypressMocks.LogMock;
57
+ let apiClientSettings: ApiClientTitanChat.IChatbotClientSettingsTitanChat;
58
+ let apiClient: ApiClientTitanChat.ChatbotApiClient;
59
+ let uiStore: ChatbotUiStore;
60
+ let uiBackendStore: ChatbotUiBackendStore;
61
+
62
+ beforeEach(() => {
63
+ container = initContainer();
64
+ log = container.get<CypressMocks.LogMock>(Log);
65
+ apiClientSettings =
66
+ container.get<ApiClientTitanChat.IChatbotClientSettingsTitanChat>(
67
+ CHATBOT_CLIENT_SETTINGS
68
+ );
69
+ apiClient = container.get<ApiClientTitanChat.ChatbotApiClient>(CHATBOT_API_CLIENT);
70
+ uiStore = container.get<ChatbotUiStore>(CHATBOT_UI_STORE_TOKEN);
71
+ uiBackendStore = container.get<ChatbotUiBackendStore>(CHATBOT_UI_BACKEND_STORE_TOKEN);
72
+ cy.viewport(550, 800);
73
+ cy.clock(Date.parse('2023-10-01T00:00:00Z'));
74
+ });
75
+
76
+ const render = () => {
77
+ const ChatbotWrapper: FC = () => {
78
+ const customizationContext = useMemo<ChatbotCustomizations>(
79
+ () => ({
80
+ filters: { enabled: true },
81
+ feedback: { title: 'TITLE' },
82
+ }),
83
+ []
84
+ );
85
+ return (
86
+ <Provider
87
+ singletons={[
88
+ {
89
+ provide: Log,
90
+ useValue: log,
91
+ },
92
+ {
93
+ provide: CHATBOT_CLIENT_SETTINGS,
94
+ useValue: apiClientSettings,
95
+ },
96
+ { provide: CHATBOT_API_CLIENT, useValue: apiClient },
97
+ {
98
+ provide: CHATBOT_UI_STORE_TOKEN,
99
+ useValue: uiStore,
100
+ },
101
+ {
102
+ provide: CHATBOT_UI_BACKEND_STORE_TOKEN,
103
+ useValue: uiBackendStore,
104
+ },
105
+ ]}
106
+ >
107
+ <Chatbot
108
+ className="h-100vh max-h-100vh of-x-hidden"
109
+ customizations={customizationContext}
110
+ />
111
+ </Provider>
112
+ );
113
+ };
114
+ cy.spy(uiStore, 'run').as('runSpy');
115
+ mount(<ChatbotWrapper />);
116
+ return cy.wrap(
117
+ new Promise(resolve => {
118
+ cy.get('@runSpy')
119
+ .should('have.been.calledOnce')
120
+ .then((invocation: any) => {
121
+ const initPromise = invocation.firstCall.returnValue as ReturnType<
122
+ IChatbotUiStore['run']
123
+ >;
124
+ initPromise.then(resolve);
125
+ });
126
+ })
127
+ );
128
+ };
129
+
130
+ it('should render the chatbot with titan chat API', () => {
131
+ const optionsMock = CypressMocks.TC.Options;
132
+ const sessionMock = CypressMocks.TC.SessionPost;
133
+ const messageMock = CypressMocks.TC.MessagePost;
134
+ const messageFeedbackMock = CypressMocks.TC.MessageFeedbackPost;
135
+ const sessionFeedbackMock = CypressMocks.TC.SessionFeedbackPost;
136
+
137
+ const aliasOptions = optionsMock.intercept(ChatbotBaseUrl, ChatbotVersion);
138
+ const aliasSession = sessionMock.intercept(ChatbotBaseUrl, ChatbotVersion);
139
+ const aliasMessage = messageMock.intercept(ChatbotBaseUrl, ChatbotVersion);
140
+ const { aliasPostMessage, aliasPostSession } = CypressMocks.TC.interceptFeedback(
141
+ ChatbotBaseUrl,
142
+ ChatbotVersion
143
+ );
144
+
145
+ render().then(() => {
146
+ cy.log('Getting options...');
147
+ cy.wait(aliasOptions).then(interception => {
148
+ expect(interception.request.url).to.equal(
149
+ `${ChatbotBaseUrl}/api/v${ChatbotVersion}/options`
150
+ );
151
+ expect(interception.response?.statusCode).to.equal(200);
152
+ expect(interception.response?.body).to.deep.equal(optionsMock.response);
153
+ });
154
+
155
+ // Ask the bot a question
156
+ cy.log('Sending message...');
157
+ ChatUiSelectors.chatInput.type(`${messageMock.request.question}{enter}`, { delay: 0 });
158
+
159
+ // Check that the session was created
160
+ cy.wait(aliasSession).then(interception => {
161
+ expect(interception.request.url).to.equal(
162
+ `${ChatbotBaseUrl}/api/v${ChatbotVersion}/session`
163
+ );
164
+ expect(interception.request.body).to.deep.equal(sessionMock.request);
165
+ expect(interception.response?.body).to.deep.equal(sessionMock.response);
166
+ expect(interception.response?.statusCode).to.equal(200);
167
+ });
168
+
169
+ // Check the user message is sent
170
+ cy.wait(aliasMessage).then(interception => {
171
+ expect(interception.request.url).to.equal(
172
+ `${ChatbotBaseUrl}/api/v${ChatbotVersion}/message`
173
+ );
174
+ expect(interception.request.body).to.deep.equal(messageMock.request);
175
+ expect(interception.response?.body).to.deep.equal(messageMock.response);
176
+ expect(interception.response?.statusCode).to.equal(200);
177
+ });
178
+
179
+ cy.tick(100);
180
+ // Send session feedback (manually)
181
+ cy.log('Sending session feedback...');
182
+ uiStore.sendSessionFeedback(new Models.Feedback(sessionFeedbackMock.request));
183
+ cy.wait(aliasPostSession).then(interception => {
184
+ expect(interception.request.url).to.equal(
185
+ `${ChatbotBaseUrl}/api/v${ChatbotVersion}/feedback`
186
+ );
187
+ expect(interception.request.body).to.deep.equal(sessionFeedbackMock.request);
188
+ expect(interception.response?.body).to.deep.equal(sessionFeedbackMock.response);
189
+ expect(interception.response?.statusCode).to.equal(200);
190
+ });
191
+
192
+ cy.tick(100);
193
+ // Check the feedback is sent with thumbs up
194
+ cy.log('Sending message feedback...');
195
+ ChatUiSelectors.chatbotMessageFeedbackThumbsUp.scrollIntoView().click({ force: true });
196
+ cy.wait(aliasPostMessage).then(interception => {
197
+ expect(interception.request.url).to.equal(
198
+ `${ChatbotBaseUrl}/api/v${ChatbotVersion}/feedback`
199
+ );
200
+ expect(interception.request.body).to.deep.equal(messageFeedbackMock.request);
201
+ expect(interception.response?.body).to.deep.equal(messageFeedbackMock.response);
202
+ expect(interception.response?.statusCode).to.equal(200);
203
+ });
204
+ });
205
+ });
206
+ });