@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,127 @@
1
+ import { Container, Provider, useDependencies } from '@servicetitan/react-ioc';
2
+ import {
3
+ CHATBOT_API_CLIENT,
4
+ MessageFeedbackGuardrailStore,
5
+ ModelsMocks,
6
+ } from '@servicetitan/titan-chatbot-api';
7
+ import { FC, ReactElement } from 'react';
8
+ import { CypressMocks, testInitContainerChatbot, testRenderWrapperChatbot } from '../..';
9
+ import { ChatUiSelectors } from '../../utils/chat-ui-selectors';
10
+
11
+ export function runChatbotMessageFeedbackFormGuardrailSharedTests(
12
+ ChatbotMessageFeedbackFormGuardrailComponent: FC,
13
+ wrapperComponent?: (component: ReactElement) => ReactElement
14
+ ) {
15
+ let container: Container;
16
+ let api: CypressMocks.ChatbotApiClientMock;
17
+ let messageFeedbackGuardrailStore: MessageFeedbackGuardrailStore;
18
+
19
+ const mockApiClient = () => {
20
+ api.postSession = cy.stub().resolves(ModelsMocks.mockSession());
21
+ api.getOptions = cy.stub().resolves(ModelsMocks.mockFrontendModel());
22
+ };
23
+
24
+ beforeEach(() => {
25
+ container = testInitContainerChatbot();
26
+ container.bind(MessageFeedbackGuardrailStore).toSelf().inSingletonScope();
27
+ api = container.get<CypressMocks.ChatbotApiClientMock>(CHATBOT_API_CLIENT);
28
+ messageFeedbackGuardrailStore = container.get(MessageFeedbackGuardrailStore);
29
+ mockApiClient();
30
+ cy.viewport(550, 800);
31
+ });
32
+
33
+ const getFormError = () => cy.get('[data-anvil-component="Banner"]');
34
+ const checkValid = () => {
35
+ cy.getCy('validator').click();
36
+ getFormError().should('not.exist');
37
+ };
38
+ const checkInvalid = () => {
39
+ cy.getCy('validator').click();
40
+ getFormError().should('be.visible');
41
+ };
42
+
43
+ const render = (onAfterInit?: () => void) => {
44
+ return cy.wrap(null).then(() => {
45
+ const Validator: FC = () => {
46
+ const [formStore] = useDependencies(MessageFeedbackGuardrailStore);
47
+ return (
48
+ <button
49
+ className="m-t-3"
50
+ data-cy="validator"
51
+ onClick={() => formStore.formState.validate()}
52
+ >
53
+ Validate
54
+ </button>
55
+ );
56
+ };
57
+
58
+ const component = (
59
+ <Provider
60
+ singletons={[
61
+ {
62
+ provide: MessageFeedbackGuardrailStore,
63
+ useValue: messageFeedbackGuardrailStore,
64
+ },
65
+ ]}
66
+ >
67
+ <ChatbotMessageFeedbackFormGuardrailComponent />
68
+ <Validator />
69
+ </Provider>
70
+ );
71
+
72
+ const wrappedComponent = wrapperComponent ? wrapperComponent(component) : component;
73
+
74
+ return testRenderWrapperChatbot(container, wrappedComponent, onAfterInit);
75
+ });
76
+ };
77
+
78
+ it('should render form', () => {
79
+ render();
80
+
81
+ ChatUiSelectors.chatbotMessageFeedback.should('be.visible');
82
+ ChatUiSelectors.chatbotMessageFeedbackLinkUrl.should('be.visible');
83
+ ChatUiSelectors.chatbotMessageFeedbackOtherComment.should('be.visible');
84
+ checkInvalid();
85
+ getFormError().find('.Banner__title').should('contain.text', 'Form Incomplete');
86
+ getFormError()
87
+ .find('ul > li')
88
+ .should('contain.text', 'At least one input must be provided.');
89
+
90
+ ChatUiSelectors.chatbotMessageFeedbackLinkUrl.type('https://example.com');
91
+ checkValid();
92
+
93
+ ChatUiSelectors.chatbotMessageFeedbackLinkUrl.clear();
94
+ checkInvalid();
95
+
96
+ ChatUiSelectors.chatbotMessageFeedbackOtherComment.type('Test comment');
97
+ checkValid();
98
+ });
99
+
100
+ it('should validate form when both fields are filled', () => {
101
+ render();
102
+
103
+ ChatUiSelectors.chatbotMessageFeedbackLinkUrl.type('https://example.com');
104
+ ChatUiSelectors.chatbotMessageFeedbackOtherComment.type('Additional feedback comment');
105
+ checkValid();
106
+ });
107
+
108
+ it('should show error when form is submitted empty', () => {
109
+ render();
110
+
111
+ checkInvalid();
112
+ getFormError().should('be.visible');
113
+ getFormError().find('.Banner__title').should('contain.text', 'Form Incomplete');
114
+ });
115
+
116
+ it('should clear validation error when valid input is provided', () => {
117
+ render();
118
+
119
+ // First show the error
120
+ checkInvalid();
121
+ getFormError().should('be.visible');
122
+
123
+ // Then provide valid input
124
+ ChatUiSelectors.chatbotMessageFeedbackLinkUrl.type('https://valid-url.com');
125
+ checkValid();
126
+ });
127
+ }
@@ -0,0 +1,198 @@
1
+ import { Container, Provider, useDependencies } from '@servicetitan/react-ioc';
2
+ import {
3
+ CHATBOT_API_CLIENT,
4
+ CHATBOT_UI_STORE_TOKEN,
5
+ ChatbotUiStore,
6
+ IChatbotUiStore,
7
+ MessageFeedbackStore,
8
+ ModelsMocks,
9
+ } from '@servicetitan/titan-chatbot-api';
10
+ import { FC, ReactElement } from 'react';
11
+ import { CypressMocks, testInitContainerChatbot, testRenderWrapperChatbot } from '../..';
12
+ import { ChatUiSelectors } from '../../utils/chat-ui-selectors';
13
+
14
+ export function runChatbotMessageFeedbackFormSharedTests(
15
+ ChatbotMessageFeedbackFormComponent: FC,
16
+ wrapperComponent?: (component: ReactElement) => ReactElement
17
+ ) {
18
+ let container: Container;
19
+ let api: CypressMocks.ChatbotApiClientMock;
20
+ let chatbotUiStore: IChatbotUiStore;
21
+ let messageFeedbackStore: MessageFeedbackStore;
22
+
23
+ const mockApiClient = () => {
24
+ api.postSession = cy.stub().resolves(ModelsMocks.mockSession());
25
+ api.getOptions = cy.stub().resolves(ModelsMocks.mockFrontendModel());
26
+ };
27
+
28
+ beforeEach(() => {
29
+ container = testInitContainerChatbot();
30
+ container.bind<MessageFeedbackStore>(MessageFeedbackStore).toSelf().inSingletonScope();
31
+ api = container.get<CypressMocks.ChatbotApiClientMock>(CHATBOT_API_CLIENT);
32
+ chatbotUiStore = container.get<ChatbotUiStore>(CHATBOT_UI_STORE_TOKEN);
33
+ messageFeedbackStore = container.get<MessageFeedbackStore>(MessageFeedbackStore);
34
+ mockApiClient();
35
+ cy.viewport(550, 800);
36
+ });
37
+
38
+ const getFormError = () =>
39
+ ChatUiSelectors.chatbotMessageFeedback.find(
40
+ '.FormField__errorText,[class^="_error-container"]'
41
+ );
42
+ const checkValid = () => {
43
+ cy.getCy('validator').click();
44
+ getFormError().should('not.exist');
45
+ };
46
+ const checkInvalid = () => {
47
+ cy.getCy('validator').click();
48
+ getFormError().should('be.visible');
49
+ };
50
+
51
+ const render = (onAfterInit?: () => void) => {
52
+ return cy.wrap(null).then(() => {
53
+ const Validator: FC = () => {
54
+ const [formStore] = useDependencies(MessageFeedbackStore);
55
+ return (
56
+ <button
57
+ style={{ marginTop: '20px' }}
58
+ data-cy="validator"
59
+ onClick={() => formStore.formState.validate()}
60
+ >
61
+ Validate
62
+ </button>
63
+ );
64
+ };
65
+
66
+ const component = (
67
+ <Provider
68
+ singletons={[
69
+ {
70
+ provide: MessageFeedbackStore,
71
+ useValue: messageFeedbackStore,
72
+ },
73
+ ]}
74
+ >
75
+ <ChatbotMessageFeedbackFormComponent />
76
+ <Validator />
77
+ </Provider>
78
+ );
79
+
80
+ const wrappedComponent = wrapperComponent ? wrapperComponent(component) : component;
81
+
82
+ return testRenderWrapperChatbot(container, wrappedComponent, onAfterInit);
83
+ });
84
+ };
85
+
86
+ it('should render default state external', () => {
87
+ render();
88
+ cy.clock(Date.parse('2023-10-01T00:00:00Z'));
89
+
90
+ // Default render
91
+ ChatUiSelectors.chatbotMessageFeedback.should('be.visible');
92
+ ChatUiSelectors.chatbotMessageFeedbackUnrelated.should('be.visible');
93
+ ChatUiSelectors.chatbotMessageFeedbackUnclear.should('be.visible');
94
+ ChatUiSelectors.chatbotMessageFeedbackNotFull.should('be.visible');
95
+ ChatUiSelectors.chatbotMessageFeedbackIncorrect.should('be.visible');
96
+ ChatUiSelectors.chatbotMessageFeedbackOther.should('be.visible');
97
+ ChatUiSelectors.chatbotMessageFeedbackOtherComment.should('not.exist');
98
+ checkValid();
99
+
100
+ // Click 'other' and check comment textarea
101
+ ChatUiSelectors.chatbotMessageFeedbackOther.parent().find('input').click({ force: true });
102
+ ChatUiSelectors.chatbotMessageFeedbackOtherComment
103
+ .should('be.visible')
104
+ .type('Test comment');
105
+ getFormError().should('not.exist');
106
+ checkValid();
107
+
108
+ ChatUiSelectors.chatbotMessageFeedbackOtherComment.clear().blur();
109
+ getFormError().should('be.visible').should('contain.text', 'Enter details.');
110
+ checkInvalid();
111
+ });
112
+
113
+ it('should render default state internal', () => {
114
+ render(() => {
115
+ chatbotUiStore.customizations.feedback = {
116
+ isCommentAlwaysRequired: true,
117
+ };
118
+ });
119
+ cy.clock(Date.parse('2023-10-01T00:00:00Z'));
120
+
121
+ // Default render
122
+ ChatUiSelectors.chatbotMessageFeedback.should('be.visible');
123
+ ChatUiSelectors.chatbotMessageFeedbackUnrelated.should('be.visible');
124
+ ChatUiSelectors.chatbotMessageFeedbackUnclear.should('be.visible');
125
+ ChatUiSelectors.chatbotMessageFeedbackNotFull.should('be.visible');
126
+ ChatUiSelectors.chatbotMessageFeedbackIncorrect.should('be.visible');
127
+ ChatUiSelectors.chatbotMessageFeedbackOther.should('be.visible');
128
+ ChatUiSelectors.chatbotMessageFeedbackOtherComment.should('be.visible');
129
+ checkInvalid();
130
+
131
+ // Don't click 'other' and check comment textarea: should be mandatory
132
+ ChatUiSelectors.chatbotMessageFeedbackOtherComment.focus().blur();
133
+ getFormError().should('be.visible').should('contain.text', 'Enter details.');
134
+ checkInvalid();
135
+
136
+ ChatUiSelectors.chatbotMessageFeedbackOtherComment.type('Test comment');
137
+ checkValid();
138
+ });
139
+
140
+ it('should validate form when selecting feedback option without other', () => {
141
+ render();
142
+ cy.clock(Date.parse('2023-10-01T00:00:00Z'));
143
+
144
+ ChatUiSelectors.chatbotMessageFeedbackUnrelated
145
+ .parent()
146
+ .find('input')
147
+ .click({ force: true });
148
+ checkValid();
149
+
150
+ ChatUiSelectors.chatbotMessageFeedbackUnclear.parent().find('input').click({ force: true });
151
+ checkValid();
152
+
153
+ ChatUiSelectors.chatbotMessageFeedbackIncorrect
154
+ .parent()
155
+ .find('input')
156
+ .click({ force: true });
157
+ checkValid();
158
+ });
159
+
160
+ it('should handle multiple selection changes', () => {
161
+ render();
162
+ cy.clock(Date.parse('2023-10-01T00:00:00Z'));
163
+
164
+ // First select a standard option
165
+ ChatUiSelectors.chatbotMessageFeedbackUnrelated
166
+ .parent()
167
+ .find('input')
168
+ .click({ force: true });
169
+ checkValid();
170
+
171
+ // Then switch to 'other' option
172
+ ChatUiSelectors.chatbotMessageFeedbackOther.parent().find('input').click({ force: true });
173
+ ChatUiSelectors.chatbotMessageFeedbackOtherComment.should('be.visible');
174
+
175
+ // Should be invalid without comment
176
+ ChatUiSelectors.chatbotMessageFeedbackOtherComment.focus().blur();
177
+ getFormError().should('be.visible').should('contain.text', 'Enter details.');
178
+ checkInvalid();
179
+
180
+ // Add comment and validate
181
+ ChatUiSelectors.chatbotMessageFeedbackOtherComment.type('Custom feedback');
182
+ checkValid();
183
+ });
184
+
185
+ it('should show error when other is selected but comment is cleared', () => {
186
+ render();
187
+ cy.clock(Date.parse('2023-10-01T00:00:00Z'));
188
+
189
+ ChatUiSelectors.chatbotMessageFeedbackOther.parent().find('input').click({ force: true });
190
+ ChatUiSelectors.chatbotMessageFeedbackOtherComment.type('Initial comment');
191
+ checkValid();
192
+
193
+ // Clear the comment
194
+ ChatUiSelectors.chatbotMessageFeedbackOtherComment.clear().blur();
195
+ getFormError().should('be.visible').should('contain.text', 'Enter details.');
196
+ checkInvalid();
197
+ });
198
+ }
@@ -0,0 +1,285 @@
1
+ import { Container } from '@servicetitan/react-ioc';
2
+ import {
3
+ CHATBOT_API_CLIENT,
4
+ CHATBOT_UI_STORE_TOKEN,
5
+ ChatbotUiStore,
6
+ IChatbotUiStore,
7
+ MessageFeedbackGuardrailStore,
8
+ MessageFeedbackStore,
9
+ Models,
10
+ ModelsMocks,
11
+ } from '@servicetitan/titan-chatbot-api';
12
+ import { FC, ReactElement } from 'react';
13
+ import { CypressMocks, testInitContainerChatbot, testRenderWrapperChatbot } from '../..';
14
+ import { ChatUiSelectors } from '../../utils/chat-ui-selectors';
15
+
16
+ interface IChatbotMessageFeedbackPopoverProps {
17
+ botMessage: Models.IBotMessage;
18
+ }
19
+
20
+ export function runChatbotMessageFeedbackPopoverSharedTests(
21
+ ChatbotMessageFeedbackPopoverComponent: FC<IChatbotMessageFeedbackPopoverProps>,
22
+ wrapperComponent?: (component: ReactElement) => ReactElement
23
+ ) {
24
+ let container: Container;
25
+ let api: CypressMocks.ChatbotApiClientMock;
26
+ let chatbotUiStore: IChatbotUiStore;
27
+
28
+ const mockApiClient = () => {
29
+ api.postSession = cy.stub().resolves(ModelsMocks.mockSession());
30
+ api.getOptions = cy.stub().resolves(ModelsMocks.mockFrontendModel());
31
+ api.postFeedback = cy.stub().resolves(ModelsMocks.mockFeedback());
32
+ };
33
+
34
+ beforeEach(() => {
35
+ container = testInitContainerChatbot();
36
+ container.bind(MessageFeedbackStore).toSelf().inSingletonScope();
37
+ container.bind(MessageFeedbackGuardrailStore).toSelf().inSingletonScope();
38
+ api = container.get<CypressMocks.ChatbotApiClientMock>(CHATBOT_API_CLIENT);
39
+ chatbotUiStore = container.get<ChatbotUiStore>(CHATBOT_UI_STORE_TOKEN);
40
+ mockApiClient();
41
+ cy.viewport(550, 800);
42
+ });
43
+
44
+ const render = (botMessage: Models.IBotMessage, onAfterInit?: () => void) => {
45
+ return cy.wrap(null).then(() => {
46
+ const component = <ChatbotMessageFeedbackPopoverComponent botMessage={botMessage} />;
47
+ const wrappedComponent = wrapperComponent ? wrapperComponent(component) : component;
48
+
49
+ return testRenderWrapperChatbot(container, wrappedComponent, onAfterInit);
50
+ });
51
+ };
52
+
53
+ it('should render feedback component for regular bot message', () => {
54
+ const botMessage = ModelsMocks.mockBotMessage({
55
+ answer: 'Test answer',
56
+ isGuardrailed: false,
57
+ });
58
+
59
+ render(botMessage, () => {
60
+ chatbotUiStore.customizations.feedback = { title: 'Rate this answer' };
61
+ });
62
+
63
+ // Should show feedback title
64
+ cy.contains('Rate this answer').should('be.visible');
65
+
66
+ // Should show thumbs up button
67
+ ChatUiSelectors.chatbotMessageFeedbackThumbsUp.should('be.visible');
68
+
69
+ // Should show thumbs down button
70
+ ChatUiSelectors.chatbotMessageFeedbackThumbsDown.should('be.visible');
71
+ });
72
+
73
+ it('should render feedback component for guardrail bot message', () => {
74
+ const botMessage = ModelsMocks.mockBotMessage({
75
+ answer: 'Guardrail response',
76
+ isGuardrailed: true,
77
+ });
78
+
79
+ render(botMessage, () => {
80
+ chatbotUiStore.customizations.feedback = { title: 'Rate this answer' };
81
+ });
82
+
83
+ // Should not show feedback title for guardrail
84
+ cy.contains('Rate this answer').should('not.exist');
85
+
86
+ // Should not show thumbs up button for guardrail
87
+ ChatUiSelectors.chatbotMessageFeedbackThumbsUp.should('not.exist');
88
+
89
+ // Should show "Provide correct answer" link
90
+ ChatUiSelectors.chatbotMessageFeedbackProvideAnswer.should('be.visible');
91
+ ChatUiSelectors.chatbotMessageFeedbackProvideAnswer.should(
92
+ 'contain.text',
93
+ 'Provide correct answer'
94
+ );
95
+ });
96
+
97
+ it('should handle thumbs up feedback submission', () => {
98
+ const botMessage = ModelsMocks.mockBotMessage({
99
+ answer: 'Test answer',
100
+ isGuardrailed: false,
101
+ });
102
+
103
+ render(botMessage, () => {
104
+ chatbotUiStore.sendMessageFeedback = cy.stub().resolves();
105
+ });
106
+
107
+ ChatUiSelectors.chatbotMessageFeedbackThumbsUp.click();
108
+
109
+ // Should show success state
110
+ ChatUiSelectors.chatbotMessageFeedbackSuccess.should('be.visible');
111
+ ChatUiSelectors.chatbotMessageFeedbackSuccess.should(
112
+ 'contain.text',
113
+ 'Thanks for your feedback.'
114
+ );
115
+ });
116
+
117
+ it('should handle failed feedback submission', () => {
118
+ const botMessage = ModelsMocks.mockBotMessage({
119
+ answer: 'Test answer',
120
+ isGuardrailed: false,
121
+ });
122
+
123
+ render(botMessage, () => {
124
+ chatbotUiStore.sendMessageFeedback = cy.stub().rejects(new Error('API Error'));
125
+ });
126
+
127
+ ChatUiSelectors.chatbotMessageFeedbackThumbsUp.click();
128
+
129
+ // Should show failure state
130
+ ChatUiSelectors.chatbotMessageFeedbackFailed.should('be.visible');
131
+ ChatUiSelectors.chatbotMessageFeedbackFailed.should(
132
+ 'contain.text',
133
+ 'Failed to send feedback.'
134
+ );
135
+ });
136
+
137
+ it('should open feedback form popover when thumbs down is clicked', () => {
138
+ const botMessage = ModelsMocks.mockBotMessage({
139
+ answer: 'Test answer',
140
+ isGuardrailed: false,
141
+ });
142
+
143
+ render(botMessage);
144
+
145
+ ChatUiSelectors.chatbotMessageFeedbackThumbsDown.click();
146
+
147
+ // Should show popover with form
148
+ cy.contains("Why didn't this answer solve your problem?").should('be.visible');
149
+ ChatUiSelectors.chatbotMessageFeedback.should('be.visible');
150
+ ChatUiSelectors.chatbotMessageFeedbackSubmit.should('be.visible').and('be.disabled');
151
+ });
152
+
153
+ it('should open guardrail feedback form when provide answer link is clicked', () => {
154
+ const botMessage = ModelsMocks.mockBotMessage({
155
+ answer: 'Guardrail response',
156
+ isGuardrailed: true,
157
+ });
158
+
159
+ render(botMessage);
160
+
161
+ ChatUiSelectors.chatbotMessageFeedbackProvideAnswer.click();
162
+
163
+ // Should show popover with guardrail form
164
+ cy.contains('Provide correct answer').should('be.visible');
165
+ ChatUiSelectors.chatbotMessageFeedback.should('be.visible');
166
+ ChatUiSelectors.chatbotMessageFeedbackSubmit.should('be.visible').and('be.disabled');
167
+ });
168
+
169
+ it('should enable submit button when regular feedback form is valid', () => {
170
+ const botMessage = ModelsMocks.mockBotMessage({
171
+ answer: 'Test answer',
172
+ isGuardrailed: false,
173
+ });
174
+
175
+ render(botMessage);
176
+
177
+ ChatUiSelectors.chatbotMessageFeedbackThumbsDown.click();
178
+
179
+ // Select a feedback option
180
+ ChatUiSelectors.chatbotMessageFeedbackUnrelated
181
+ .parent()
182
+ .find('input')
183
+ .click({ force: true });
184
+
185
+ // Submit button should be enabled
186
+ ChatUiSelectors.chatbotMessageFeedbackSubmit.should('be.enabled');
187
+ });
188
+
189
+ it('should enable submit button when guardrail feedback form is valid', () => {
190
+ const botMessage = ModelsMocks.mockBotMessage({
191
+ answer: 'Guardrail response',
192
+ isGuardrailed: true,
193
+ });
194
+
195
+ render(botMessage);
196
+
197
+ ChatUiSelectors.chatbotMessageFeedbackProvideAnswer.click();
198
+
199
+ // Fill in the URL field
200
+ ChatUiSelectors.chatbotMessageFeedbackLinkUrl.type('https://example.com');
201
+
202
+ // Submit button should be enabled
203
+ ChatUiSelectors.chatbotMessageFeedbackSubmit.should('be.enabled');
204
+ });
205
+
206
+ it('should submit feedback form successfully', () => {
207
+ const botMessage = ModelsMocks.mockBotMessage({
208
+ answer: 'Test answer',
209
+ isGuardrailed: false,
210
+ });
211
+
212
+ render(botMessage, () => {
213
+ chatbotUiStore.sendMessageFeedback = cy.stub().resolves();
214
+ });
215
+
216
+ ChatUiSelectors.chatbotMessageFeedbackThumbsDown.click();
217
+ ChatUiSelectors.chatbotMessageFeedbackUnrelated
218
+ .parent()
219
+ .find('input')
220
+ .click({ force: true });
221
+ ChatUiSelectors.chatbotMessageFeedbackSubmit.click();
222
+
223
+ // Should show success state
224
+ ChatUiSelectors.chatbotMessageFeedbackSuccess.should('be.visible');
225
+ });
226
+
227
+ it('should submit guardrail feedback form successfully', () => {
228
+ const botMessage = ModelsMocks.mockBotMessage({
229
+ answer: 'Guardrail response',
230
+ isGuardrailed: true,
231
+ });
232
+
233
+ render(botMessage, () => {
234
+ chatbotUiStore.sendMessageFeedback = cy.stub().resolves();
235
+ });
236
+
237
+ ChatUiSelectors.chatbotMessageFeedbackProvideAnswer.click();
238
+ ChatUiSelectors.chatbotMessageFeedbackLinkUrl.type('https://example.com');
239
+ ChatUiSelectors.chatbotMessageFeedbackSubmit.click();
240
+
241
+ // Should show success state
242
+ ChatUiSelectors.chatbotMessageFeedbackSuccess.should('be.visible');
243
+ });
244
+
245
+ it('should handle form validation errors', () => {
246
+ const botMessage = ModelsMocks.mockBotMessage({
247
+ answer: 'Test answer',
248
+ isGuardrailed: false,
249
+ });
250
+
251
+ render(botMessage);
252
+
253
+ ChatUiSelectors.chatbotMessageFeedbackThumbsDown.click();
254
+
255
+ // Try to submit without selecting feedback
256
+ ChatUiSelectors.chatbotMessageFeedbackSubmit.should('be.disabled');
257
+
258
+ // Select "Other" which requires comment
259
+ ChatUiSelectors.chatbotMessageFeedbackOther.parent().find('input').click({ force: true });
260
+
261
+ // Add comment
262
+ ChatUiSelectors.chatbotMessageFeedbackOtherComment.type('Custom feedback');
263
+
264
+ // Submit button should be enabled
265
+ ChatUiSelectors.chatbotMessageFeedbackSubmit.should('be.enabled');
266
+ });
267
+
268
+ it('should not show title when feedback customization title is not set', () => {
269
+ const botMessage = ModelsMocks.mockBotMessage({
270
+ answer: 'Test answer',
271
+ isGuardrailed: false,
272
+ });
273
+
274
+ render(botMessage, () => {
275
+ chatbotUiStore.customizations.feedback = {};
276
+ });
277
+
278
+ // Should not show any title
279
+ cy.contains('Rate this answer').should('not.exist');
280
+
281
+ // But should still show feedback buttons
282
+ ChatUiSelectors.chatbotMessageFeedbackThumbsUp.should('be.visible');
283
+ ChatUiSelectors.chatbotMessageFeedbackThumbsDown.should('be.visible');
284
+ });
285
+ }