@servicetitan/titan-chatbot-ui-cypress 3.1.0 → 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 (173) hide show
  1. package/CHANGELOG.md +12 -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/tests/index.d.ts +30 -0
  7. package/dist/tests/index.d.ts.map +1 -0
  8. package/dist/tests/index.js +30 -0
  9. package/dist/tests/index.js.map +1 -0
  10. package/dist/tests/titan-chat-ui/chat-error.shared-tests.d.ts +3 -0
  11. package/dist/tests/titan-chat-ui/chat-error.shared-tests.d.ts.map +1 -0
  12. package/dist/tests/titan-chat-ui/chat-error.shared-tests.js +138 -0
  13. package/dist/tests/titan-chat-ui/chat-error.shared-tests.js.map +1 -0
  14. package/dist/tests/titan-chat-ui/chat-input-file.shared-tests.d.ts +7 -0
  15. package/dist/tests/titan-chat-ui/chat-input-file.shared-tests.d.ts.map +1 -0
  16. package/dist/tests/titan-chat-ui/chat-input-file.shared-tests.js +123 -0
  17. package/dist/tests/titan-chat-ui/chat-input-file.shared-tests.js.map +1 -0
  18. package/dist/tests/titan-chat-ui/chat-input.shared-tests.d.ts +3 -0
  19. package/dist/tests/titan-chat-ui/chat-input.shared-tests.d.ts.map +1 -0
  20. package/dist/tests/titan-chat-ui/chat-input.shared-tests.js +71 -0
  21. package/dist/tests/titan-chat-ui/chat-input.shared-tests.js.map +1 -0
  22. package/dist/tests/titan-chat-ui/chat-log.shared-tests.d.ts +9 -0
  23. package/dist/tests/titan-chat-ui/chat-log.shared-tests.d.ts.map +1 -0
  24. package/dist/tests/titan-chat-ui/chat-log.shared-tests.js +73 -0
  25. package/dist/tests/titan-chat-ui/chat-log.shared-tests.js.map +1 -0
  26. package/dist/tests/titan-chat-ui/chat-messages.shared-tests.d.ts +8 -0
  27. package/dist/tests/titan-chat-ui/chat-messages.shared-tests.d.ts.map +1 -0
  28. package/dist/tests/titan-chat-ui/chat-messages.shared-tests.js +118 -0
  29. package/dist/tests/titan-chat-ui/chat-messages.shared-tests.js.map +1 -0
  30. package/dist/tests/titan-chat-ui/chat-notifications.shared-tests.d.ts +3 -0
  31. package/dist/tests/titan-chat-ui/chat-notifications.shared-tests.d.ts.map +1 -0
  32. package/dist/tests/titan-chat-ui/chat-notifications.shared-tests.js +110 -0
  33. package/dist/tests/titan-chat-ui/chat-notifications.shared-tests.js.map +1 -0
  34. package/dist/tests/titan-chat-ui/chat-timer.shared-tests.d.ts +3 -0
  35. package/dist/tests/titan-chat-ui/chat-timer.shared-tests.d.ts.map +1 -0
  36. package/dist/tests/titan-chat-ui/chat-timer.shared-tests.js +76 -0
  37. package/dist/tests/titan-chat-ui/chat-timer.shared-tests.js.map +1 -0
  38. package/dist/tests/titan-chat-ui/chat.shared-tests.d.ts +9 -0
  39. package/dist/tests/titan-chat-ui/chat.shared-tests.d.ts.map +1 -0
  40. package/dist/tests/titan-chat-ui/chat.shared-tests.js +111 -0
  41. package/dist/tests/titan-chat-ui/chat.shared-tests.js.map +1 -0
  42. package/dist/tests/titan-chat-ui/message-agent.shared-tests.d.ts +27 -0
  43. package/dist/tests/titan-chat-ui/message-agent.shared-tests.d.ts.map +1 -0
  44. package/dist/tests/titan-chat-ui/message-agent.shared-tests.js +67 -0
  45. package/dist/tests/titan-chat-ui/message-agent.shared-tests.js.map +1 -0
  46. package/dist/tests/titan-chat-ui/message-content-file.shared-tests.d.ts +10 -0
  47. package/dist/tests/titan-chat-ui/message-content-file.shared-tests.d.ts.map +1 -0
  48. package/dist/tests/titan-chat-ui/message-content-file.shared-tests.js +88 -0
  49. package/dist/tests/titan-chat-ui/message-content-file.shared-tests.js.map +1 -0
  50. package/dist/tests/titan-chat-ui/message-system.shared-tests.d.ts +16 -0
  51. package/dist/tests/titan-chat-ui/message-system.shared-tests.d.ts.map +1 -0
  52. package/dist/tests/titan-chat-ui/message-system.shared-tests.js +65 -0
  53. package/dist/tests/titan-chat-ui/message-system.shared-tests.js.map +1 -0
  54. package/dist/tests/titan-chat-ui/message-timeout.shared-tests.d.ts +8 -0
  55. package/dist/tests/titan-chat-ui/message-timeout.shared-tests.d.ts.map +1 -0
  56. package/dist/tests/titan-chat-ui/message-timeout.shared-tests.js +63 -0
  57. package/dist/tests/titan-chat-ui/message-timeout.shared-tests.js.map +1 -0
  58. package/dist/tests/titan-chat-ui/message-typing.shared-tests.d.ts +12 -0
  59. package/dist/tests/titan-chat-ui/message-typing.shared-tests.d.ts.map +1 -0
  60. package/dist/tests/titan-chat-ui/message-typing.shared-tests.js +46 -0
  61. package/dist/tests/titan-chat-ui/message-typing.shared-tests.js.map +1 -0
  62. package/dist/tests/titan-chat-ui/message-user.shared-tests.d.ts +10 -0
  63. package/dist/tests/titan-chat-ui/message-user.shared-tests.d.ts.map +1 -0
  64. package/dist/tests/titan-chat-ui/message-user.shared-tests.js +64 -0
  65. package/dist/tests/titan-chat-ui/message-user.shared-tests.js.map +1 -0
  66. package/dist/tests/titan-chatbot-ui/chatbot-filters.shared-tests.d.ts +7 -0
  67. package/dist/tests/titan-chatbot-ui/chatbot-filters.shared-tests.d.ts.map +1 -0
  68. package/dist/tests/titan-chatbot-ui/chatbot-filters.shared-tests.js +118 -0
  69. package/dist/tests/titan-chatbot-ui/chatbot-filters.shared-tests.js.map +1 -0
  70. package/dist/tests/titan-chatbot-ui/chatbot-help-center.shared-tests.d.ts +9 -0
  71. package/dist/tests/titan-chatbot-ui/chatbot-help-center.shared-tests.d.ts.map +1 -0
  72. package/dist/tests/titan-chatbot-ui/chatbot-help-center.shared-tests.js +162 -0
  73. package/dist/tests/titan-chatbot-ui/chatbot-help-center.shared-tests.js.map +1 -0
  74. package/dist/tests/titan-chatbot-ui/chatbot-links.shared-tests.d.ts +15 -0
  75. package/dist/tests/titan-chatbot-ui/chatbot-links.shared-tests.d.ts.map +1 -0
  76. package/dist/tests/titan-chatbot-ui/chatbot-links.shared-tests.js +123 -0
  77. package/dist/tests/titan-chatbot-ui/chatbot-links.shared-tests.js.map +1 -0
  78. package/dist/tests/titan-chatbot-ui/chatbot-live.shared-tests.d.ts +9 -0
  79. package/dist/tests/titan-chatbot-ui/chatbot-live.shared-tests.d.ts.map +1 -0
  80. package/dist/tests/titan-chatbot-ui/chatbot-live.shared-tests.js +84 -0
  81. package/dist/tests/titan-chatbot-ui/chatbot-live.shared-tests.js.map +1 -0
  82. package/dist/tests/titan-chatbot-ui/chatbot-message-answer-readonly.shared-tests.d.ts +8 -0
  83. package/dist/tests/titan-chatbot-ui/chatbot-message-answer-readonly.shared-tests.d.ts.map +1 -0
  84. package/dist/tests/titan-chatbot-ui/chatbot-message-answer-readonly.shared-tests.js +142 -0
  85. package/dist/tests/titan-chatbot-ui/chatbot-message-answer-readonly.shared-tests.js.map +1 -0
  86. package/dist/tests/titan-chatbot-ui/chatbot-message-answer.shared-tests.d.ts +8 -0
  87. package/dist/tests/titan-chatbot-ui/chatbot-message-answer.shared-tests.d.ts.map +1 -0
  88. package/dist/tests/titan-chatbot-ui/chatbot-message-answer.shared-tests.js +105 -0
  89. package/dist/tests/titan-chatbot-ui/chatbot-message-answer.shared-tests.js.map +1 -0
  90. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-form-guardrail.shared-tests.d.ts +3 -0
  91. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-form-guardrail.shared-tests.d.ts.map +1 -0
  92. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-form-guardrail.shared-tests.js +86 -0
  93. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-form-guardrail.shared-tests.js.map +1 -0
  94. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-form.shared-tests.d.ts +3 -0
  95. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-form.shared-tests.d.ts.map +1 -0
  96. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-form.shared-tests.js +143 -0
  97. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-form.shared-tests.js.map +1 -0
  98. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-popover.shared-tests.d.ts +8 -0
  99. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-popover.shared-tests.d.ts.map +1 -0
  100. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-popover.shared-tests.js +200 -0
  101. package/dist/tests/titan-chatbot-ui/chatbot-message-feedback-popover.shared-tests.js.map +1 -0
  102. package/dist/tests/titan-chatbot-ui/chatbot-message-typing.shared-tests.d.ts +11 -0
  103. package/dist/tests/titan-chatbot-ui/chatbot-message-typing.shared-tests.d.ts.map +1 -0
  104. package/dist/tests/titan-chatbot-ui/chatbot-message-typing.shared-tests.js +81 -0
  105. package/dist/tests/titan-chatbot-ui/chatbot-message-typing.shared-tests.js.map +1 -0
  106. package/dist/tests/titan-chatbot-ui/chatbot-restart-dialog.shared-tests.d.ts +8 -0
  107. package/dist/tests/titan-chatbot-ui/chatbot-restart-dialog.shared-tests.d.ts.map +1 -0
  108. package/dist/tests/titan-chatbot-ui/chatbot-restart-dialog.shared-tests.js +60 -0
  109. package/dist/tests/titan-chatbot-ui/chatbot-restart-dialog.shared-tests.js.map +1 -0
  110. package/dist/tests/titan-chatbot-ui/chatbot-restart-link.shared-tests.d.ts +8 -0
  111. package/dist/tests/titan-chatbot-ui/chatbot-restart-link.shared-tests.d.ts.map +1 -0
  112. package/dist/tests/titan-chatbot-ui/chatbot-restart-link.shared-tests.js +77 -0
  113. package/dist/tests/titan-chatbot-ui/chatbot-restart-link.shared-tests.js.map +1 -0
  114. package/dist/tests/titan-chatbot-ui/chatbot-session-feedback-modal.shared-tests.d.ts +7 -0
  115. package/dist/tests/titan-chatbot-ui/chatbot-session-feedback-modal.shared-tests.d.ts.map +1 -0
  116. package/dist/tests/titan-chatbot-ui/chatbot-session-feedback-modal.shared-tests.js +130 -0
  117. package/dist/tests/titan-chatbot-ui/chatbot-session-feedback-modal.shared-tests.js.map +1 -0
  118. package/dist/tests/titan-chatbot-ui/chatbot-titan-chatbot.shared-tests.d.ts +9 -0
  119. package/dist/tests/titan-chatbot-ui/chatbot-titan-chatbot.shared-tests.d.ts.map +1 -0
  120. package/dist/tests/titan-chatbot-ui/chatbot-titan-chatbot.shared-tests.js +157 -0
  121. package/dist/tests/titan-chatbot-ui/chatbot-titan-chatbot.shared-tests.js.map +1 -0
  122. package/dist/tests/titan-chatbot-ui/chatbot.shared-tests.d.ts +9 -0
  123. package/dist/tests/titan-chatbot-ui/chatbot.shared-tests.d.ts.map +1 -0
  124. package/dist/tests/titan-chatbot-ui/chatbot.shared-tests.js +114 -0
  125. package/dist/tests/titan-chatbot-ui/chatbot.shared-tests.js.map +1 -0
  126. package/dist/utils/chat-ui-selectors.d.ts +12 -0
  127. package/dist/utils/chat-ui-selectors.d.ts.map +1 -1
  128. package/dist/utils/chat-ui-selectors.js +24 -0
  129. package/dist/utils/chat-ui-selectors.js.map +1 -1
  130. package/dist/utils/test-utils-chatbot.d.ts +5 -0
  131. package/dist/utils/test-utils-chatbot.d.ts.map +1 -0
  132. package/dist/utils/test-utils-chatbot.js +55 -0
  133. package/dist/utils/test-utils-chatbot.js.map +1 -0
  134. package/dist/utils/test-utils.d.ts +6 -0
  135. package/dist/utils/test-utils.d.ts.map +1 -0
  136. package/dist/utils/test-utils.js +38 -0
  137. package/dist/utils/test-utils.js.map +1 -0
  138. package/package.json +10 -5
  139. package/src/index.ts +3 -0
  140. package/src/tests/index.ts +30 -0
  141. package/src/tests/titan-chat-ui/chat-error.shared-tests.tsx +185 -0
  142. package/src/tests/titan-chat-ui/chat-input-file.shared-tests.tsx +182 -0
  143. package/src/tests/titan-chat-ui/chat-input.shared-tests.tsx +99 -0
  144. package/src/tests/titan-chat-ui/chat-log.shared-tests.tsx +117 -0
  145. package/src/tests/titan-chat-ui/chat-messages.shared-tests.tsx +156 -0
  146. package/src/tests/titan-chat-ui/chat-notifications.shared-tests.tsx +153 -0
  147. package/src/tests/titan-chat-ui/chat-timer.shared-tests.tsx +106 -0
  148. package/src/tests/titan-chat-ui/chat.shared-tests.tsx +158 -0
  149. package/src/tests/titan-chat-ui/message-agent.shared-tests.tsx +170 -0
  150. package/src/tests/titan-chat-ui/message-content-file.shared-tests.tsx +139 -0
  151. package/src/tests/titan-chat-ui/message-system.shared-tests.tsx +147 -0
  152. package/src/tests/titan-chat-ui/message-timeout.shared-tests.tsx +117 -0
  153. package/src/tests/titan-chat-ui/message-typing.shared-tests.tsx +92 -0
  154. package/src/tests/titan-chat-ui/message-user.shared-tests.tsx +138 -0
  155. package/src/tests/titan-chatbot-ui/chatbot-filters.shared-tests.tsx +164 -0
  156. package/src/tests/titan-chatbot-ui/chatbot-help-center.shared-tests.tsx +225 -0
  157. package/src/tests/titan-chatbot-ui/chatbot-links.shared-tests.tsx +189 -0
  158. package/src/tests/titan-chatbot-ui/chatbot-live.shared-tests.tsx +127 -0
  159. package/src/tests/titan-chatbot-ui/chatbot-message-answer-readonly.shared-tests.tsx +187 -0
  160. package/src/tests/titan-chatbot-ui/chatbot-message-answer.shared-tests.tsx +144 -0
  161. package/src/tests/titan-chatbot-ui/chatbot-message-feedback-form-guardrail.shared-tests.tsx +127 -0
  162. package/src/tests/titan-chatbot-ui/chatbot-message-feedback-form.shared-tests.tsx +198 -0
  163. package/src/tests/titan-chatbot-ui/chatbot-message-feedback-popover.shared-tests.tsx +285 -0
  164. package/src/tests/titan-chatbot-ui/chatbot-message-typing.shared-tests.tsx +112 -0
  165. package/src/tests/titan-chatbot-ui/chatbot-restart-dialog.shared-tests.tsx +91 -0
  166. package/src/tests/titan-chatbot-ui/chatbot-restart-link.shared-tests.tsx +116 -0
  167. package/src/tests/titan-chatbot-ui/chatbot-session-feedback-modal.shared-tests.tsx +182 -0
  168. package/src/tests/titan-chatbot-ui/chatbot-titan-chatbot.shared-tests.tsx +221 -0
  169. package/src/tests/titan-chatbot-ui/chatbot.shared-tests.tsx +158 -0
  170. package/src/utils/chat-ui-selectors.ts +24 -0
  171. package/src/utils/test-utils-chatbot.tsx +73 -0
  172. package/src/utils/test-utils.tsx +52 -0
  173. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,138 @@
1
+ import { Container } from '@servicetitan/react-ioc';
2
+ import {
3
+ CHAT_UI_BACKEND_STORE_TOKEN,
4
+ CHAT_UI_STORE_TOKEN,
5
+ ChatUiBackendEchoStore,
6
+ IChatUiBackendStore,
7
+ IChatUiStore,
8
+ } from '@servicetitan/titan-chat-ui-common';
9
+ import { FC, ReactNode } from 'react';
10
+ import { ChatUiSelectors } from '../../utils/chat-ui-selectors';
11
+ import { testInitContainer, testRenderWrapper } from '../../utils/test-utils';
12
+
13
+ interface MessageUserProps {
14
+ children?: ReactNode;
15
+ messageFooter?: ReactNode;
16
+ isError?: boolean;
17
+ className?: string;
18
+ }
19
+
20
+ export function runMessageUserSharedTests(
21
+ MessageUserComponent: FC<MessageUserProps>,
22
+ TextComponent: FC<any>
23
+ ) {
24
+ let container: Container;
25
+ let chatUiStore: IChatUiStore;
26
+ let chatUiBackendStore: IChatUiBackendStore;
27
+
28
+ beforeEach(() => {
29
+ container = testInitContainer();
30
+ chatUiStore = container.get<IChatUiStore>(CHAT_UI_STORE_TOKEN);
31
+ chatUiBackendStore = container.get<ChatUiBackendEchoStore>(CHAT_UI_BACKEND_STORE_TOKEN);
32
+ cy.viewport(800, 800);
33
+ });
34
+
35
+ const render = (
36
+ children?: ReactNode,
37
+ messageFooter?: ReactNode,
38
+ isError?: boolean,
39
+ className?: string,
40
+ onAfterInit?: () => void
41
+ ) =>
42
+ cy.wrap(null).then(() =>
43
+ testRenderWrapper(
44
+ chatUiStore,
45
+ chatUiBackendStore,
46
+ <MessageUserComponent
47
+ messageFooter={messageFooter}
48
+ isError={isError}
49
+ className={className}
50
+ >
51
+ {children}
52
+ </MessageUserComponent>,
53
+ onAfterInit
54
+ )
55
+ );
56
+
57
+ it('should render user message with basic content', () => {
58
+ render(<TextComponent data-cy="content">message user content</TextComponent>);
59
+
60
+ ChatUiSelectors.chatMessageUser.should('be.visible');
61
+ ChatUiSelectors.chatMessageContent
62
+ .should('be.visible')
63
+ .should('contain.text', 'message user content');
64
+ });
65
+
66
+ it('should render user message with long text content', () => {
67
+ const longText = 'message user content '.repeat(100).trim();
68
+ render(<TextComponent data-cy="content">{longText}</TextComponent>);
69
+
70
+ ChatUiSelectors.chatMessageContent.should('be.visible').should('contain.text', longText);
71
+ });
72
+
73
+ it('should render user message with footer', () => {
74
+ render(
75
+ <TextComponent data-cy="content">message user content</TextComponent>,
76
+ <TextComponent>message user footer</TextComponent>
77
+ );
78
+
79
+ ChatUiSelectors.chatMessageFooter.should('be.visible');
80
+ ChatUiSelectors.chatMessageFooter.should('contain.text', 'message user footer');
81
+ });
82
+
83
+ it('should render user message with error state', () => {
84
+ render(
85
+ <TextComponent data-cy="content">error message content</TextComponent>,
86
+ undefined,
87
+ true
88
+ );
89
+
90
+ ChatUiSelectors.chatMessageUser.should('be.visible');
91
+ ChatUiSelectors.chatMessageContent.should('be.visible');
92
+ });
93
+
94
+ it('should render user message with custom className', () => {
95
+ render(
96
+ <TextComponent data-cy="content">message content</TextComponent>,
97
+ undefined,
98
+ false,
99
+ 'custom-message-class'
100
+ );
101
+
102
+ ChatUiSelectors.chatMessageUser.should('be.visible');
103
+ ChatUiSelectors.chatMessageUser.should('have.class', 'custom-message-class');
104
+ });
105
+
106
+ it('should not render footer when messageFooter is not provided', () => {
107
+ render(<TextComponent data-cy="content">message without footer</TextComponent>);
108
+
109
+ ChatUiSelectors.chatMessageUser.should('be.visible');
110
+ ChatUiSelectors.chatMessageFooter.should('not.exist');
111
+ });
112
+
113
+ it('should have proper data-cy attributes for testing', () => {
114
+ render(<TextComponent data-cy="content">test message</TextComponent>);
115
+
116
+ ChatUiSelectors.chatMessageUser.should('have.attr', 'data-cy', 'titan-chat-message-user');
117
+ ChatUiSelectors.chatMessageContent.should(
118
+ 'have.attr',
119
+ 'data-cy',
120
+ 'titan-chat-message-content'
121
+ );
122
+ });
123
+
124
+ it('should render both content and footer when both are provided', () => {
125
+ render(
126
+ <TextComponent data-cy="content">message content</TextComponent>,
127
+ <TextComponent data-cy="footer">message footer</TextComponent>
128
+ );
129
+
130
+ ChatUiSelectors.chatMessageUser.should('be.visible');
131
+ ChatUiSelectors.chatMessageContent
132
+ .should('be.visible')
133
+ .should('contain.text', 'message content');
134
+ ChatUiSelectors.chatMessageFooter
135
+ .should('be.visible')
136
+ .should('contain.text', 'message footer');
137
+ });
138
+ }
@@ -0,0 +1,164 @@
1
+ import { Container } from '@servicetitan/react-ioc';
2
+ import {
3
+ CHATBOT_API_CLIENT,
4
+ CHATBOT_UI_STORE_TOKEN,
5
+ ChatbotUiStore,
6
+ IChatbotUiStore,
7
+ ModelsMocks,
8
+ } from '@servicetitan/titan-chatbot-api';
9
+ import { FC, ReactElement } from 'react';
10
+ import { CypressMocks, testInitContainerChatbot, testRenderWrapperChatbot } from '../..';
11
+ import { ChatUiSelectors } from '../../utils/chat-ui-selectors';
12
+
13
+ interface IChatFiltersProps {
14
+ className?: string;
15
+ }
16
+
17
+ export function runChatbotFiltersSharedTests(
18
+ ChatFiltersComponent: FC<IChatFiltersProps>,
19
+ wrapperComponent?: (component: ReactElement) => ReactElement
20
+ ) {
21
+ let container: Container;
22
+ let api: CypressMocks.ChatbotApiClientMock;
23
+ let chatbotUiStore: IChatbotUiStore;
24
+
25
+ const filter = (index: number) => ChatUiSelectors.chatbotFilterButton.eq(index);
26
+ const filterOptions = (index: number) =>
27
+ ChatUiSelectors.chatbotFilterOptions.then($options =>
28
+ ChatUiSelectors.chatbotFilterOptions.eq($options.length === 1 ? 0 : index)
29
+ );
30
+ const filterContent = (index: number) => {
31
+ const selector = `[data-cy="${ChatUiSelectors.cy.chatbotFilterContent}"], [data-anvil-component="Popover"]`;
32
+ return cy
33
+ .get(selector)
34
+ .then($options => cy.get(selector).eq($options.length === 1 ? 0 : index));
35
+ };
36
+
37
+ const mockApiClient = () => {
38
+ api.postSession = cy.stub().resolves(ModelsMocks.mockSession());
39
+ api.getOptions = cy.stub().resolves(ModelsMocks.mockFrontendModel());
40
+ };
41
+
42
+ beforeEach(() => {
43
+ container = testInitContainerChatbot();
44
+ api = container.get<CypressMocks.ChatbotApiClientMock>(CHATBOT_API_CLIENT);
45
+ chatbotUiStore = container.get<ChatbotUiStore>(CHATBOT_UI_STORE_TOKEN);
46
+ mockApiClient();
47
+ cy.viewport(550, 800);
48
+ });
49
+
50
+ const render = (className?: string, onAfterInit?: () => void) => {
51
+ return cy.wrap(null).then(() => {
52
+ const component = (
53
+ <div
54
+ style={{
55
+ position: 'absolute',
56
+ bottom: '2rem',
57
+ left: '2rem',
58
+ width: 'calc(100% - 4rem)',
59
+ }}
60
+ >
61
+ <ChatFiltersComponent className={className} />
62
+ </div>
63
+ );
64
+ const wrappedComponent = wrapperComponent ? wrapperComponent(component) : component;
65
+
66
+ return testRenderWrapperChatbot(container, wrappedComponent, onAfterInit);
67
+ });
68
+ };
69
+
70
+ it('should render filters container when filters are available', () => {
71
+ render().then(() => {
72
+ chatbotUiStore.setFilters(ModelsMocks.mockFrontendModel());
73
+ });
74
+
75
+ ChatUiSelectors.chatbotFilters.should('be.visible');
76
+ ChatUiSelectors.chatbotFilterButton.should('have.length', 1);
77
+ });
78
+
79
+ it('should not render anything when no filters are available', () => {
80
+ render().then(() => {
81
+ chatbotUiStore.setFilters(ModelsMocks.mockFrontendModelEmpty());
82
+ });
83
+
84
+ ChatUiSelectors.chatbotFilters.should('not.exist');
85
+ });
86
+
87
+ it('should apply custom className to filters container', () => {
88
+ const customClass = 'custom-filters-class';
89
+
90
+ render(customClass).then(() => {
91
+ chatbotUiStore.setFilters(ModelsMocks.mockFrontendModel());
92
+ });
93
+
94
+ ChatUiSelectors.chatbotFilters.should('have.class', customClass);
95
+ });
96
+
97
+ it('should cascade filters 1', () => {
98
+ render().then(() => {
99
+ chatbotUiStore.setFilters(ModelsMocks.mockFrontendModel());
100
+ });
101
+
102
+ filter(0).click();
103
+ filterOptions(0).within(() => {
104
+ cy.contains('Knowledge Base').should('be.visible');
105
+ cy.contains('Jarvis').should('be.visible').click();
106
+ });
107
+
108
+ ChatUiSelectors.chatbotFilterButton.should('have.length', 2);
109
+ filter(0).should('contain.text', 'Sources');
110
+ filter(1).should('contain.text', 'Content Types').click();
111
+ filterOptions(1).within(() => {
112
+ cy.contains('Xxx').should('be.visible').click();
113
+ cy.contains('Yyy').should('be.visible').click();
114
+ cy.contains('Release Notes').should('be.visible').click();
115
+ });
116
+
117
+ ChatUiSelectors.chatbotFilterButton.should('have.length', 2);
118
+ filter(0).should('contain.text', 'Sources1');
119
+ filter(1).should('contain.text', 'Content Types3');
120
+ });
121
+
122
+ it('should cascade filters 2', () => {
123
+ render().then(() => {
124
+ chatbotUiStore.setFilters(ModelsMocks.mockFrontendModel());
125
+ });
126
+
127
+ filter(0).click();
128
+ filterOptions(0).within(() => {
129
+ cy.contains('Knowledge Base').should('be.visible').click();
130
+ cy.contains('Jarvis').should('be.visible').click();
131
+ });
132
+
133
+ ChatUiSelectors.chatbotFilterButton.should('have.length', 3);
134
+ filter(0).should('contain.text', 'Sources');
135
+ filter(1).should('contain.text', 'Content Types').click();
136
+ filter(2).should('contain.text', 'Product Areas');
137
+ filterOptions(1).within(() => {
138
+ cy.contains('Xxx').should('be.visible').click();
139
+ cy.contains('Yyy').should('be.visible').click();
140
+ cy.contains('FAQ').should('be.visible').click();
141
+ cy.contains('How To').should('be.visible').click();
142
+ cy.contains('Release Notes').should('be.visible').click();
143
+ });
144
+
145
+ filter(2).should('contain.text', 'Product Areas').click();
146
+ filterOptions(2).within(() => {
147
+ cy.contains('Call Booking').should('be.visible').click();
148
+ cy.contains('Marketing').should('be.visible').click();
149
+ cy.contains('Marketing Pro').should('be.visible').click();
150
+ });
151
+
152
+ ChatUiSelectors.chatbotFilterButton.should('have.length', 3);
153
+ filter(0).should('contain.text', 'Sources2');
154
+ filter(1).should('contain.text', 'Content Types5');
155
+ filter(2).should('contain.text', 'Product Areas3');
156
+
157
+ filter(0).click();
158
+ filterContent(0).within(() => {
159
+ ChatUiSelectors.chatbotFilterNone.click();
160
+ });
161
+
162
+ ChatUiSelectors.chatbotFilterButton.should('have.length', 1);
163
+ });
164
+ }
@@ -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
+ }