@servicetitan/titan-chatbot-ui-cypress 3.0.1 → 3.1.1

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 (178) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +3 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/mocks/chatbot-api-client.mock.d.ts +0 -1
  7. package/dist/mocks/chatbot-api-client.mock.d.ts.map +1 -1
  8. package/dist/mocks/chatbot-api-client.mock.js +0 -6
  9. package/dist/mocks/chatbot-api-client.mock.js.map +1 -1
  10. package/dist/tests/index.d.ts +30 -0
  11. package/dist/tests/index.d.ts.map +1 -0
  12. package/dist/tests/index.js +30 -0
  13. package/dist/tests/index.js.map +1 -0
  14. package/dist/tests/titan-chat-ui/chat-error.shared-tests.d.ts +3 -0
  15. package/dist/tests/titan-chat-ui/chat-error.shared-tests.d.ts.map +1 -0
  16. package/dist/tests/titan-chat-ui/chat-error.shared-tests.js +138 -0
  17. package/dist/tests/titan-chat-ui/chat-error.shared-tests.js.map +1 -0
  18. package/dist/tests/titan-chat-ui/chat-input-file.shared-tests.d.ts +7 -0
  19. package/dist/tests/titan-chat-ui/chat-input-file.shared-tests.d.ts.map +1 -0
  20. package/dist/tests/titan-chat-ui/chat-input-file.shared-tests.js +123 -0
  21. package/dist/tests/titan-chat-ui/chat-input-file.shared-tests.js.map +1 -0
  22. package/dist/tests/titan-chat-ui/chat-input.shared-tests.d.ts +3 -0
  23. package/dist/tests/titan-chat-ui/chat-input.shared-tests.d.ts.map +1 -0
  24. package/dist/tests/titan-chat-ui/chat-input.shared-tests.js +71 -0
  25. package/dist/tests/titan-chat-ui/chat-input.shared-tests.js.map +1 -0
  26. package/dist/tests/titan-chat-ui/chat-log.shared-tests.d.ts +9 -0
  27. package/dist/tests/titan-chat-ui/chat-log.shared-tests.d.ts.map +1 -0
  28. package/dist/tests/titan-chat-ui/chat-log.shared-tests.js +73 -0
  29. package/dist/tests/titan-chat-ui/chat-log.shared-tests.js.map +1 -0
  30. package/dist/tests/titan-chat-ui/chat-messages.shared-tests.d.ts +8 -0
  31. package/dist/tests/titan-chat-ui/chat-messages.shared-tests.d.ts.map +1 -0
  32. package/dist/tests/titan-chat-ui/chat-messages.shared-tests.js +118 -0
  33. package/dist/tests/titan-chat-ui/chat-messages.shared-tests.js.map +1 -0
  34. package/dist/tests/titan-chat-ui/chat-notifications.shared-tests.d.ts +3 -0
  35. package/dist/tests/titan-chat-ui/chat-notifications.shared-tests.d.ts.map +1 -0
  36. package/dist/tests/titan-chat-ui/chat-notifications.shared-tests.js +110 -0
  37. package/dist/tests/titan-chat-ui/chat-notifications.shared-tests.js.map +1 -0
  38. package/dist/tests/titan-chat-ui/chat-timer.shared-tests.d.ts +3 -0
  39. package/dist/tests/titan-chat-ui/chat-timer.shared-tests.d.ts.map +1 -0
  40. package/dist/tests/titan-chat-ui/chat-timer.shared-tests.js +76 -0
  41. package/dist/tests/titan-chat-ui/chat-timer.shared-tests.js.map +1 -0
  42. package/dist/tests/titan-chat-ui/chat.shared-tests.d.ts +9 -0
  43. package/dist/tests/titan-chat-ui/chat.shared-tests.d.ts.map +1 -0
  44. package/dist/tests/titan-chat-ui/chat.shared-tests.js +111 -0
  45. package/dist/tests/titan-chat-ui/chat.shared-tests.js.map +1 -0
  46. package/dist/tests/titan-chat-ui/message-agent.shared-tests.d.ts +27 -0
  47. package/dist/tests/titan-chat-ui/message-agent.shared-tests.d.ts.map +1 -0
  48. package/dist/tests/titan-chat-ui/message-agent.shared-tests.js +67 -0
  49. package/dist/tests/titan-chat-ui/message-agent.shared-tests.js.map +1 -0
  50. package/dist/tests/titan-chat-ui/message-content-file.shared-tests.d.ts +10 -0
  51. package/dist/tests/titan-chat-ui/message-content-file.shared-tests.d.ts.map +1 -0
  52. package/dist/tests/titan-chat-ui/message-content-file.shared-tests.js +88 -0
  53. package/dist/tests/titan-chat-ui/message-content-file.shared-tests.js.map +1 -0
  54. package/dist/tests/titan-chat-ui/message-system.shared-tests.d.ts +16 -0
  55. package/dist/tests/titan-chat-ui/message-system.shared-tests.d.ts.map +1 -0
  56. package/dist/tests/titan-chat-ui/message-system.shared-tests.js +65 -0
  57. package/dist/tests/titan-chat-ui/message-system.shared-tests.js.map +1 -0
  58. package/dist/tests/titan-chat-ui/message-timeout.shared-tests.d.ts +8 -0
  59. package/dist/tests/titan-chat-ui/message-timeout.shared-tests.d.ts.map +1 -0
  60. package/dist/tests/titan-chat-ui/message-timeout.shared-tests.js +63 -0
  61. package/dist/tests/titan-chat-ui/message-timeout.shared-tests.js.map +1 -0
  62. package/dist/tests/titan-chat-ui/message-typing.shared-tests.d.ts +12 -0
  63. package/dist/tests/titan-chat-ui/message-typing.shared-tests.d.ts.map +1 -0
  64. package/dist/tests/titan-chat-ui/message-typing.shared-tests.js +46 -0
  65. package/dist/tests/titan-chat-ui/message-typing.shared-tests.js.map +1 -0
  66. package/dist/tests/titan-chat-ui/message-user.shared-tests.d.ts +10 -0
  67. package/dist/tests/titan-chat-ui/message-user.shared-tests.d.ts.map +1 -0
  68. package/dist/tests/titan-chat-ui/message-user.shared-tests.js +64 -0
  69. package/dist/tests/titan-chat-ui/message-user.shared-tests.js.map +1 -0
  70. package/dist/tests/titan-chatbot-ui/chatbot-filters.shared-tests.d.ts +7 -0
  71. package/dist/tests/titan-chatbot-ui/chatbot-filters.shared-tests.d.ts.map +1 -0
  72. package/dist/tests/titan-chatbot-ui/chatbot-filters.shared-tests.js +118 -0
  73. package/dist/tests/titan-chatbot-ui/chatbot-filters.shared-tests.js.map +1 -0
  74. package/dist/tests/titan-chatbot-ui/chatbot-help-center.shared-tests.d.ts +9 -0
  75. package/dist/tests/titan-chatbot-ui/chatbot-help-center.shared-tests.d.ts.map +1 -0
  76. package/dist/tests/titan-chatbot-ui/chatbot-help-center.shared-tests.js +162 -0
  77. package/dist/tests/titan-chatbot-ui/chatbot-help-center.shared-tests.js.map +1 -0
  78. package/dist/tests/titan-chatbot-ui/chatbot-links.shared-tests.d.ts +15 -0
  79. package/dist/tests/titan-chatbot-ui/chatbot-links.shared-tests.d.ts.map +1 -0
  80. package/dist/tests/titan-chatbot-ui/chatbot-links.shared-tests.js +123 -0
  81. package/dist/tests/titan-chatbot-ui/chatbot-links.shared-tests.js.map +1 -0
  82. package/dist/tests/titan-chatbot-ui/chatbot-live.shared-tests.d.ts +9 -0
  83. package/dist/tests/titan-chatbot-ui/chatbot-live.shared-tests.d.ts.map +1 -0
  84. package/dist/tests/titan-chatbot-ui/chatbot-live.shared-tests.js +84 -0
  85. package/dist/tests/titan-chatbot-ui/chatbot-live.shared-tests.js.map +1 -0
  86. package/dist/tests/titan-chatbot-ui/chatbot-message-answer-readonly.shared-tests.d.ts +8 -0
  87. package/dist/tests/titan-chatbot-ui/chatbot-message-answer-readonly.shared-tests.d.ts.map +1 -0
  88. package/dist/tests/titan-chatbot-ui/chatbot-message-answer-readonly.shared-tests.js +142 -0
  89. package/dist/tests/titan-chatbot-ui/chatbot-message-answer-readonly.shared-tests.js.map +1 -0
  90. package/dist/tests/titan-chatbot-ui/chatbot-message-answer.shared-tests.d.ts +8 -0
  91. package/dist/tests/titan-chatbot-ui/chatbot-message-answer.shared-tests.d.ts.map +1 -0
  92. package/dist/tests/titan-chatbot-ui/chatbot-message-answer.shared-tests.js +105 -0
  93. package/dist/tests/titan-chatbot-ui/chatbot-message-answer.shared-tests.js.map +1 -0
  94. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-form-guardrail.shared-tests.d.ts +3 -0
  95. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-form-guardrail.shared-tests.d.ts.map +1 -0
  96. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-form-guardrail.shared-tests.js +86 -0
  97. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-form-guardrail.shared-tests.js.map +1 -0
  98. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-form.shared-tests.d.ts +3 -0
  99. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-form.shared-tests.d.ts.map +1 -0
  100. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-form.shared-tests.js +143 -0
  101. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-form.shared-tests.js.map +1 -0
  102. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-popover.shared-tests.d.ts +8 -0
  103. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-popover.shared-tests.d.ts.map +1 -0
  104. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-popover.shared-tests.js +200 -0
  105. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-popover.shared-tests.js.map +1 -0
  106. package/dist/tests/titan-chatbot-ui/chatbot-message-typing.shared-tests.d.ts +11 -0
  107. package/dist/tests/titan-chatbot-ui/chatbot-message-typing.shared-tests.d.ts.map +1 -0
  108. package/dist/tests/titan-chatbot-ui/chatbot-message-typing.shared-tests.js +81 -0
  109. package/dist/tests/titan-chatbot-ui/chatbot-message-typing.shared-tests.js.map +1 -0
  110. package/dist/tests/titan-chatbot-ui/chatbot-restart-dialog.shared-tests.d.ts +8 -0
  111. package/dist/tests/titan-chatbot-ui/chatbot-restart-dialog.shared-tests.d.ts.map +1 -0
  112. package/dist/tests/titan-chatbot-ui/chatbot-restart-dialog.shared-tests.js +60 -0
  113. package/dist/tests/titan-chatbot-ui/chatbot-restart-dialog.shared-tests.js.map +1 -0
  114. package/dist/tests/titan-chatbot-ui/chatbot-restart-link.shared-tests.d.ts +8 -0
  115. package/dist/tests/titan-chatbot-ui/chatbot-restart-link.shared-tests.d.ts.map +1 -0
  116. package/dist/tests/titan-chatbot-ui/chatbot-restart-link.shared-tests.js +77 -0
  117. package/dist/tests/titan-chatbot-ui/chatbot-restart-link.shared-tests.js.map +1 -0
  118. package/dist/tests/titan-chatbot-ui/chatbot-session-feedback-modal.shared-tests.d.ts +7 -0
  119. package/dist/tests/titan-chatbot-ui/chatbot-session-feedback-modal.shared-tests.d.ts.map +1 -0
  120. package/dist/tests/titan-chatbot-ui/chatbot-session-feedback-modal.shared-tests.js +130 -0
  121. package/dist/tests/titan-chatbot-ui/chatbot-session-feedback-modal.shared-tests.js.map +1 -0
  122. package/dist/tests/titan-chatbot-ui/chatbot-titan-chatbot.shared-tests.d.ts +9 -0
  123. package/dist/tests/titan-chatbot-ui/chatbot-titan-chatbot.shared-tests.d.ts.map +1 -0
  124. package/dist/tests/titan-chatbot-ui/chatbot-titan-chatbot.shared-tests.js +157 -0
  125. package/dist/tests/titan-chatbot-ui/chatbot-titan-chatbot.shared-tests.js.map +1 -0
  126. package/dist/tests/titan-chatbot-ui/chatbot.shared-tests.d.ts +9 -0
  127. package/dist/tests/titan-chatbot-ui/chatbot.shared-tests.d.ts.map +1 -0
  128. package/dist/tests/titan-chatbot-ui/chatbot.shared-tests.js +114 -0
  129. package/dist/tests/titan-chatbot-ui/chatbot.shared-tests.js.map +1 -0
  130. package/dist/utils/chat-ui-selectors.d.ts +12 -0
  131. package/dist/utils/chat-ui-selectors.d.ts.map +1 -1
  132. package/dist/utils/chat-ui-selectors.js +24 -0
  133. package/dist/utils/chat-ui-selectors.js.map +1 -1
  134. package/dist/utils/test-utils-chatbot.d.ts +5 -0
  135. package/dist/utils/test-utils-chatbot.d.ts.map +1 -0
  136. package/dist/utils/test-utils-chatbot.js +55 -0
  137. package/dist/utils/test-utils-chatbot.js.map +1 -0
  138. package/dist/utils/test-utils.d.ts +6 -0
  139. package/dist/utils/test-utils.d.ts.map +1 -0
  140. package/dist/utils/test-utils.js +38 -0
  141. package/dist/utils/test-utils.js.map +1 -0
  142. package/package.json +10 -5
  143. package/src/index.ts +3 -0
  144. package/src/mocks/chatbot-api-client.mock.ts +0 -1
  145. package/src/tests/index.ts +30 -0
  146. package/src/tests/titan-chat-ui/chat-error.shared-tests.tsx +185 -0
  147. package/src/tests/titan-chat-ui/chat-input-file.shared-tests.tsx +182 -0
  148. package/src/tests/titan-chat-ui/chat-input.shared-tests.tsx +99 -0
  149. package/src/tests/titan-chat-ui/chat-log.shared-tests.tsx +117 -0
  150. package/src/tests/titan-chat-ui/chat-messages.shared-tests.tsx +156 -0
  151. package/src/tests/titan-chat-ui/chat-notifications.shared-tests.tsx +153 -0
  152. package/src/tests/titan-chat-ui/chat-timer.shared-tests.tsx +106 -0
  153. package/src/tests/titan-chat-ui/chat.shared-tests.tsx +158 -0
  154. package/src/tests/titan-chat-ui/message-agent.shared-tests.tsx +170 -0
  155. package/src/tests/titan-chat-ui/message-content-file.shared-tests.tsx +139 -0
  156. package/src/tests/titan-chat-ui/message-system.shared-tests.tsx +147 -0
  157. package/src/tests/titan-chat-ui/message-timeout.shared-tests.tsx +117 -0
  158. package/src/tests/titan-chat-ui/message-typing.shared-tests.tsx +92 -0
  159. package/src/tests/titan-chat-ui/message-user.shared-tests.tsx +138 -0
  160. package/src/tests/titan-chatbot-ui/chatbot-filters.shared-tests.tsx +164 -0
  161. package/src/tests/titan-chatbot-ui/chatbot-help-center.shared-tests.tsx +225 -0
  162. package/src/tests/titan-chatbot-ui/chatbot-links.shared-tests.tsx +189 -0
  163. package/src/tests/titan-chatbot-ui/chatbot-live.shared-tests.tsx +127 -0
  164. package/src/tests/titan-chatbot-ui/chatbot-message-answer-readonly.shared-tests.tsx +187 -0
  165. package/src/tests/titan-chatbot-ui/chatbot-message-answer.shared-tests.tsx +144 -0
  166. package/src/tests/titan-chatbot-ui/chatbot-message-feedback-form-guardrail.shared-tests.tsx +127 -0
  167. package/src/tests/titan-chatbot-ui/chatbot-message-feedback-form.shared-tests.tsx +198 -0
  168. package/src/tests/titan-chatbot-ui/chatbot-message-feedback-popover.shared-tests.tsx +285 -0
  169. package/src/tests/titan-chatbot-ui/chatbot-message-typing.shared-tests.tsx +112 -0
  170. package/src/tests/titan-chatbot-ui/chatbot-restart-dialog.shared-tests.tsx +91 -0
  171. package/src/tests/titan-chatbot-ui/chatbot-restart-link.shared-tests.tsx +116 -0
  172. package/src/tests/titan-chatbot-ui/chatbot-session-feedback-modal.shared-tests.tsx +182 -0
  173. package/src/tests/titan-chatbot-ui/chatbot-titan-chatbot.shared-tests.tsx +221 -0
  174. package/src/tests/titan-chatbot-ui/chatbot.shared-tests.tsx +158 -0
  175. package/src/utils/chat-ui-selectors.ts +24 -0
  176. package/src/utils/test-utils-chatbot.tsx +73 -0
  177. package/src/utils/test-utils.tsx +52 -0
  178. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,225 @@
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 axios from 'axios';
18
+ import { mount } from 'cypress/react';
19
+ import { FC, ReactElement, useMemo } from 'react';
20
+ import { CypressMocks } from '../..';
21
+ import { ChatUiSelectors } from '../../utils/chat-ui-selectors';
22
+
23
+ const ChatbotBaseUrl = 'https://chatbot-api.example.com/base/url';
24
+
25
+ const initializeHelpCenterChatbotContainer = () => {
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
+ interface IChatbotProps {
56
+ className?: string;
57
+ customizations?: ChatbotCustomizations;
58
+ }
59
+
60
+ export function runChatbotHelpCenterSharedTests(
61
+ ChatbotComponent: FC<IChatbotProps>,
62
+ wrapperComponent?: (component: ReactElement) => ReactElement
63
+ ) {
64
+ let container: Container;
65
+ let log: CypressMocks.LogMock;
66
+ let apiClientSettings: ApiClientHelpCenter.IChatbotClientSettingsHelpCenter;
67
+ let apiClient: ApiClientHelpCenter.ChatbotApiClient;
68
+ let uiStore: ChatbotUiStore;
69
+ let uiBackendStore: ChatbotUiBackendStore;
70
+
71
+ beforeEach(() => {
72
+ container = initializeHelpCenterChatbotContainer();
73
+ log = container.get<CypressMocks.LogMock>(Log);
74
+ apiClientSettings =
75
+ container.get<ApiClientHelpCenter.IChatbotClientSettingsHelpCenter>(
76
+ CHATBOT_CLIENT_SETTINGS
77
+ );
78
+ apiClient = container.get<ApiClientHelpCenter.ChatbotApiClient>(CHATBOT_API_CLIENT);
79
+ uiStore = container.get<ChatbotUiStore>(CHATBOT_UI_STORE_TOKEN);
80
+ uiBackendStore = container.get<ChatbotUiBackendStore>(CHATBOT_UI_BACKEND_STORE_TOKEN);
81
+ cy.viewport(550, 800);
82
+ cy.clock(Date.parse('2023-10-01T00:00:00Z'));
83
+ });
84
+
85
+ const render = () => {
86
+ const ChatbotWrapper: FC = () => {
87
+ const customizationContext = useMemo<ChatbotCustomizations>(
88
+ () => ({
89
+ filters: { enabled: true },
90
+ feedback: { title: 'TITLE' },
91
+ }),
92
+ []
93
+ );
94
+
95
+ const component = (
96
+ <ChatbotComponent
97
+ className="h-100vh max-h-100vh of-x-hidden"
98
+ customizations={customizationContext}
99
+ />
100
+ );
101
+
102
+ const wrappedComponent = wrapperComponent ? wrapperComponent(component) : component;
103
+
104
+ return (
105
+ <Provider
106
+ singletons={[
107
+ {
108
+ provide: Log,
109
+ useValue: log,
110
+ },
111
+ {
112
+ provide: CHATBOT_CLIENT_SETTINGS,
113
+ useValue: apiClientSettings,
114
+ },
115
+ { provide: CHATBOT_API_CLIENT, useValue: apiClient },
116
+ {
117
+ provide: CHATBOT_UI_STORE_TOKEN,
118
+ useValue: uiStore,
119
+ },
120
+ {
121
+ provide: CHATBOT_UI_BACKEND_STORE_TOKEN,
122
+ useValue: uiBackendStore,
123
+ },
124
+ ]}
125
+ >
126
+ {wrappedComponent}
127
+ </Provider>
128
+ );
129
+ };
130
+ cy.spy(uiStore, 'run').as('runSpy');
131
+ mount(<ChatbotWrapper />);
132
+ return cy.wrap(
133
+ new Promise(resolve => {
134
+ cy.get('@runSpy')
135
+ .should('have.been.calledOnce')
136
+ .then((invocation: any) => {
137
+ const initPromise = invocation.firstCall.returnValue as ReturnType<
138
+ IChatbotUiStore['run']
139
+ >;
140
+ initPromise.then(resolve);
141
+ });
142
+ })
143
+ );
144
+ };
145
+
146
+ it('should render the chatbot with help center API', () => {
147
+ const sessionMock = CypressMocks.HC.CreateSession;
148
+ const messageMock = CypressMocks.HC.SendUserMessage;
149
+ const messageFeedbackMock = CypressMocks.HC.MessageFeedback;
150
+ const sessionFeedbackMock = CypressMocks.HC.SessionFeedback;
151
+
152
+ const aliasFilterOptions = CypressMocks.HC.interceptFilterOptions(ChatbotBaseUrl);
153
+ const aliasCreateSession = sessionMock.intercept(ChatbotBaseUrl);
154
+ const aliasSendUserMessage = messageMock.intercept(ChatbotBaseUrl);
155
+ const aliasMessageFeedback = messageFeedbackMock.intercept(ChatbotBaseUrl);
156
+ const aliasSessionFeedback = sessionFeedbackMock.intercept(ChatbotBaseUrl);
157
+
158
+ render().then(() => {
159
+ // Expect filters were loaded using the Help Center API
160
+ cy.wait(aliasFilterOptions).then(interception => {
161
+ // Check options were loaded correctly
162
+ expect(interception.request.url).to.equal(
163
+ `${ChatbotBaseUrl}/api/Chat/filter-options`
164
+ );
165
+ expect(interception.response?.body).to.an('object');
166
+ expect(interception.response?.body?.sources).to.an('array');
167
+ expect(interception.response?.body?.contentTypes).to.an('array');
168
+ expect(interception.response?.body?.productAreas).to.an('array');
169
+ expect(interception.response?.statusCode).to.equal(200);
170
+ });
171
+
172
+ // Ask the bot a question
173
+ cy.log('Sending message...');
174
+ ChatUiSelectors.chatInput.type(`${messageMock.request.text}{enter}`, { delay: 0 });
175
+
176
+ // Check that the session was created
177
+ cy.wait(aliasCreateSession).then(interception => {
178
+ expect(interception.request.url).to.equal(
179
+ `${ChatbotBaseUrl}/api/Chat/create-session`
180
+ );
181
+ expect(interception.request.body).to.deep.equal(sessionMock.request);
182
+ expect(interception.response?.body).to.deep.equal(sessionMock.response);
183
+ expect(interception.response?.statusCode).to.equal(200);
184
+ });
185
+
186
+ // Check the user message is sent
187
+ cy.wait(aliasSendUserMessage).then(interception => {
188
+ expect(interception.request.url).to.equal(
189
+ `${ChatbotBaseUrl}/api/Chat/user-message`
190
+ );
191
+ expect(interception.request.body).to.deep.equal(messageMock.request);
192
+ expect(interception.response?.body).to.deep.equal(messageMock.response);
193
+ expect(interception.response?.statusCode).to.equal(200);
194
+ });
195
+
196
+ // Send session feedback (manually)
197
+ cy.log('Sending session feedback...');
198
+ uiStore.sendSessionFeedback(
199
+ new Models.Feedback({
200
+ sessionId: sessionMock.response.id,
201
+ description: 'Good answer!',
202
+ rating: Models.FeedbackRatings.ThumbsUp,
203
+ })
204
+ );
205
+ cy.wait(aliasSessionFeedback).then(interception => {
206
+ expect(interception.request.url).to.equal(
207
+ `${ChatbotBaseUrl}/api/Chat/session-feedback?sessionId=${sessionMock.response.id}`
208
+ );
209
+ expect(interception.request.body).to.deep.equal(sessionFeedbackMock.request);
210
+ expect(interception.response?.statusCode).to.equal(200);
211
+ });
212
+
213
+ // Check the feedback is sent with thumbs up
214
+ cy.log('Sending message feedback...');
215
+ ChatUiSelectors.chatbotMessageFeedbackThumbsUp.scrollIntoView().click({ force: true });
216
+ cy.wait(aliasMessageFeedback).then(interception => {
217
+ expect(interception.request.url).to.equal(
218
+ `${ChatbotBaseUrl}/api/Chat/bot-message-feedback?sessionId=${messageMock.response.sessionId}&botMessageId=${messageMock.response.id}`
219
+ );
220
+ expect(interception.request.body).to.deep.equal(messageFeedbackMock.request);
221
+ expect(interception.response?.statusCode).to.equal(200);
222
+ });
223
+ });
224
+ });
225
+ }
@@ -0,0 +1,189 @@
1
+ import { Container } from '@servicetitan/react-ioc';
2
+ import { CHATBOT_API_CLIENT, Models, ModelsMocks } from '@servicetitan/titan-chatbot-api';
3
+ import { FC, ReactElement } from 'react';
4
+ import { CypressMocks, testInitContainerChatbot, testRenderWrapperChatbot } from '../..';
5
+ import { ChatUiSelectors } from '../../utils/chat-ui-selectors';
6
+
7
+ interface IChatbotLinksProps {
8
+ seeMoreLabel?: string;
9
+ seeLessLabel?: string;
10
+ links?: Models.ScoredUrl[];
11
+ onToggle?: () => void;
12
+ linkProps?: {
13
+ primary?: boolean;
14
+ className?: string;
15
+ };
16
+ }
17
+
18
+ export function runChatbotLinksSharedTests(
19
+ ChatbotLinksComponent: FC<IChatbotLinksProps>,
20
+ wrapperComponent?: (component: ReactElement) => ReactElement
21
+ ) {
22
+ let container: Container;
23
+ let api: CypressMocks.ChatbotApiClientMock;
24
+
25
+ const mockApiClient = () => {
26
+ api.postSession = cy.stub().resolves(ModelsMocks.mockSession());
27
+ api.getOptions = cy.stub().resolves(ModelsMocks.mockFrontendModel());
28
+ };
29
+
30
+ beforeEach(() => {
31
+ container = testInitContainerChatbot();
32
+ api = container.get<CypressMocks.ChatbotApiClientMock>(CHATBOT_API_CLIENT);
33
+ mockApiClient();
34
+ cy.viewport(550, 800);
35
+ });
36
+
37
+ const render = (
38
+ props: {
39
+ seeMoreLabel?: string;
40
+ seeLessLabel?: string;
41
+ links?: Models.ScoredUrl[];
42
+ onToggle?: () => void;
43
+ linkProps?: {
44
+ primary?: boolean;
45
+ className?: string;
46
+ };
47
+ } = {},
48
+ onAfterInit?: () => void
49
+ ) => {
50
+ const defaultProps = {
51
+ seeMoreLabel: 'See more',
52
+ seeLessLabel: 'See less',
53
+ links: ModelsMocks.mockScoredUrls(),
54
+ ...props,
55
+ };
56
+
57
+ return cy.wrap(null).then(() => {
58
+ const component = <ChatbotLinksComponent {...defaultProps} />;
59
+ const wrappedComponent = wrapperComponent ? wrapperComponent(component) : component;
60
+
61
+ return testRenderWrapperChatbot(container, wrappedComponent, onAfterInit);
62
+ });
63
+ };
64
+
65
+ it('should render component with links when links are provided', () => {
66
+ render();
67
+
68
+ ChatUiSelectors.chatbotLinksMore.should('be.visible');
69
+ ChatUiSelectors.chatbotLinksMore.should('contain.text', 'See more');
70
+ ChatUiSelectors.chatbotLinksLink.should('not.be.visible');
71
+ });
72
+
73
+ it('should not render anything when no links are provided', () => {
74
+ render({ links: [] });
75
+
76
+ ChatUiSelectors.chatbotLinksMore.should('not.exist');
77
+ ChatUiSelectors.chatbotLinksCollapsible.should('not.exist');
78
+ });
79
+
80
+ it('should toggle collapsible when clicking the toggle button', () => {
81
+ render();
82
+
83
+ // Initially collapsed
84
+ ChatUiSelectors.chatbotLinksMore.should('contain.text', 'See more');
85
+ ChatUiSelectors.chatbotLinksLink.should('not.be.visible');
86
+
87
+ // Click to expand
88
+ ChatUiSelectors.chatbotLinksMore.click();
89
+
90
+ ChatUiSelectors.chatbotLinksMore.should('contain.text', 'See less');
91
+ ChatUiSelectors.chatbotLinksLink.should('be.visible');
92
+
93
+ // Click to collapse
94
+ ChatUiSelectors.chatbotLinksMore.click();
95
+
96
+ ChatUiSelectors.chatbotLinksMore.should('contain.text', 'See more');
97
+ ChatUiSelectors.chatbotLinksLink.should('not.be.visible');
98
+ });
99
+
100
+ it('should render all links when expanded', () => {
101
+ const testLinks = [
102
+ ModelsMocks.mockScoredUrl({ url: 'https://test1.com', title: 'Test Link 1' }),
103
+ ModelsMocks.mockScoredUrl({ url: 'https://test2.com', title: 'Test Link 2' }),
104
+ ModelsMocks.mockScoredUrl({ url: 'https://test3.com', title: 'Test Link 3' }),
105
+ ];
106
+
107
+ render({ links: testLinks });
108
+
109
+ // Expand the links
110
+ ChatUiSelectors.chatbotLinksMore.click();
111
+
112
+ // Check that all links are rendered
113
+ ChatUiSelectors.chatbotLinksLink.should('have.length', 3);
114
+ ChatUiSelectors.chatbotLinksLink.eq(0).should('contain.text', 'Test Link 1');
115
+ ChatUiSelectors.chatbotLinksLink.eq(1).should('contain.text', 'Test Link 2');
116
+ ChatUiSelectors.chatbotLinksLink.eq(2).should('contain.text', 'Test Link 3');
117
+ });
118
+
119
+ it('should render link with url as text when title is not provided', () => {
120
+ const testLinks = [
121
+ ModelsMocks.mockScoredUrl({ url: 'https://test-no-title.com', title: undefined }),
122
+ ];
123
+
124
+ render({ links: testLinks });
125
+
126
+ // Expand the links
127
+ ChatUiSelectors.chatbotLinksMore.click();
128
+
129
+ ChatUiSelectors.chatbotLinksLink.should('contain.text', 'https://test-no-title.com');
130
+ });
131
+
132
+ it('should set correct href and target attributes on links', () => {
133
+ const testLinks = [
134
+ ModelsMocks.mockScoredUrl({ url: 'https://external-link.com', title: 'External Link' }),
135
+ ];
136
+
137
+ render({ links: testLinks });
138
+
139
+ // Expand the links
140
+ ChatUiSelectors.chatbotLinksMore.click();
141
+
142
+ ChatUiSelectors.chatbotLinksLink
143
+ .should('have.attr', 'href', 'https://external-link.com')
144
+ .and('have.attr', 'target', '_blank');
145
+ });
146
+
147
+ it('should call onToggle callback with delay when toggling', () => {
148
+ const onToggleSpy = cy.stub().as('onToggle');
149
+
150
+ render({ onToggle: onToggleSpy });
151
+
152
+ ChatUiSelectors.chatbotLinksMore.click();
153
+
154
+ // Callback should not be called immediately
155
+ cy.get('@onToggle').should('not.have.been.called');
156
+
157
+ // Wait for the 200ms delay
158
+ cy.wait(250);
159
+ cy.get('@onToggle').should('have.been.calledOnce');
160
+ });
161
+
162
+ it('should use custom labels when provided', () => {
163
+ render({
164
+ seeMoreLabel: 'Show links',
165
+ seeLessLabel: 'Hide links',
166
+ });
167
+
168
+ ChatUiSelectors.chatbotLinksMore.should('contain.text', 'Show links');
169
+
170
+ ChatUiSelectors.chatbotLinksMore.click();
171
+ ChatUiSelectors.chatbotLinksMore.should('contain.text', 'Hide links');
172
+ });
173
+
174
+ it('should apply custom link props when provided', () => {
175
+ const testLinks = [ModelsMocks.mockScoredUrl({ url: 'https://test.com', title: 'Test' })];
176
+
177
+ render({
178
+ links: testLinks,
179
+ linkProps: {
180
+ className: 'custom-link-class',
181
+ },
182
+ });
183
+
184
+ // Expand the links
185
+ ChatUiSelectors.chatbotLinksMore.click();
186
+
187
+ ChatUiSelectors.chatbotLinksLink.should('have.class', 'custom-link-class');
188
+ });
189
+ }
@@ -0,0 +1,127 @@
1
+ import { 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
+ Models,
11
+ ModelsMocks,
12
+ } from '@servicetitan/titan-chatbot-api';
13
+ import { mount } from 'cypress/react';
14
+ import { FC, ReactElement, useMemo } from 'react';
15
+ import { CypressMocks, testInitContainerChatbot } from '../..';
16
+ import { ChatUiSelectors } from '../../utils/chat-ui-selectors';
17
+
18
+ interface IChatbotProps {
19
+ className?: string;
20
+ customizations?: ChatbotCustomizations;
21
+ }
22
+
23
+ export function runChatbotLiveSharedTests(
24
+ ChatbotComponent: FC<IChatbotProps>,
25
+ wrapperComponent?: (component: ReactElement) => ReactElement
26
+ ) {
27
+ let container: Container;
28
+ let log: CypressMocks.LogMock;
29
+ let api: CypressMocks.ChatbotApiClientMock;
30
+ let uiStore: ChatbotUiStore;
31
+ let uiBackendStore: ChatbotUiBackendStore;
32
+
33
+ const mockApi = () => {
34
+ api.postSession = cy.stub().resolves(ModelsMocks.mockSession());
35
+ api.getOptions = cy.stub().resolves(ModelsMocks.mockFrontendModel());
36
+ };
37
+
38
+ beforeEach(() => {
39
+ cy.intercept('GET', 'https://fonts.gstatic.com/**', {
40
+ statusCode: 200,
41
+ body: new ArrayBuffer(0),
42
+ headers: {
43
+ 'Content-Type': 'font/woff2',
44
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
45
+ },
46
+ });
47
+ container = testInitContainerChatbot();
48
+ log = container.get<CypressMocks.LogMock>(Log);
49
+ api = container.get<CypressMocks.ChatbotApiClientMock>(CHATBOT_API_CLIENT);
50
+ uiStore = container.get<ChatbotUiStore>(CHATBOT_UI_STORE_TOKEN);
51
+ uiBackendStore = container.get<ChatbotUiBackendStore>(CHATBOT_UI_BACKEND_STORE_TOKEN);
52
+ mockApi();
53
+ cy.viewport(550, 800);
54
+ });
55
+
56
+ const mockAskBotApi = (answer: string) => {
57
+ api.postMessage = cy.stub().as('askBot').resolves(
58
+ ModelsMocks.mockBotMessage({
59
+ answer,
60
+ })
61
+ );
62
+ api.postFeedback = cy
63
+ .stub()
64
+ .as('askBotFeedback')
65
+ .resolves(
66
+ ModelsMocks.mockFeedback({
67
+ rating: Models.FeedbackRatings.ThumbsUp,
68
+ })
69
+ );
70
+ };
71
+
72
+ const render = () => {
73
+ const ChatbotWrapper: FC = () => {
74
+ const customizationContext = useMemo<ChatbotCustomizations>(
75
+ () => ({
76
+ filters: { enabled: true },
77
+ feedback: { title: 'TITLE' },
78
+ }),
79
+ []
80
+ );
81
+
82
+ const component = (
83
+ <ChatbotComponent
84
+ className="h-100vh max-h-100vh of-x-hidden"
85
+ customizations={customizationContext}
86
+ />
87
+ );
88
+
89
+ const wrappedComponent = wrapperComponent ? wrapperComponent(component) : component;
90
+
91
+ return (
92
+ <Provider
93
+ singletons={[
94
+ {
95
+ provide: Log,
96
+ useValue: log,
97
+ },
98
+ { provide: CHATBOT_API_CLIENT, useValue: api },
99
+ {
100
+ provide: CHATBOT_UI_STORE_TOKEN,
101
+ useValue: uiStore,
102
+ },
103
+ {
104
+ provide: CHATBOT_UI_BACKEND_STORE_TOKEN,
105
+ useValue: uiBackendStore,
106
+ },
107
+ ]}
108
+ >
109
+ {wrappedComponent}
110
+ </Provider>
111
+ );
112
+ };
113
+ mount(<ChatbotWrapper />);
114
+ };
115
+
116
+ const ask = (message: string) => {
117
+ ChatUiSelectors.chatInput.type(`${message}{enter}`, { delay: 0 });
118
+ };
119
+
120
+ it.skip('should render the chatbot component', () => {
121
+ mockAskBotApi("Hello! I'm chatbot mocked response!!!");
122
+ render();
123
+ ask('Hello!');
124
+ ChatUiSelectors.chatbotMessageFeedbackThumbsUp.should('be.visible').click();
125
+ cy.get('@askBotFeedback').should('have.been.calledOnce');
126
+ });
127
+ }