@quidgest/chatbot 0.5.1 → 0.5.3

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 (70) hide show
  1. package/README.md +1 -2
  2. package/dist/components/ChatBot/types.d.ts +3 -1
  3. package/dist/components/ChatBotInput/ChatBotInput.vue.d.ts +3 -3
  4. package/dist/components/ChatBotInput/__tests__/ChatBotInput.spec.d.ts +1 -0
  5. package/dist/components/ChatBotInput/index.d.ts +2 -2
  6. package/dist/components/ChatBotInput/types.d.ts +4 -4
  7. package/dist/components/ChatBotMessage/__tests__/ChatBotMessage.spec.d.ts +1 -0
  8. package/dist/components/ChatBotMessage/__tests__/ChatBotMessageButtons.spec.d.ts +1 -0
  9. package/dist/components/ChatBotMessage/types.d.ts +3 -2
  10. package/dist/components/ChatToolBar/__tests__/ChatToolBar.spec.d.ts +1 -0
  11. package/dist/components/FieldPreview/__tests__/FieldPreview.spec.d.ts +1 -0
  12. package/dist/components/MarkdownRender/__tests__/MarkdownRender.spec.d.ts +1 -0
  13. package/dist/components/PulseDots/__tests__/PulseDots.spec.d.ts +1 -0
  14. package/dist/composables/__tests__/useChatMessages.spec.d.ts +1 -0
  15. package/dist/composables/__tests__/useSSE.spec.d.ts +1 -0
  16. package/dist/composables/useChatMessages.d.ts +2 -1
  17. package/dist/composables/useSSE.d.ts +1 -2
  18. package/dist/composables/useTexts.d.ts +2 -0
  19. package/dist/index.js +16 -16
  20. package/dist/index.mjs +2924 -1770
  21. package/dist/style.css +1 -1
  22. package/dist/test/setup.d.ts +1 -0
  23. package/dist/utils/__tests__/parseFieldValue.spec.d.ts +1 -0
  24. package/package.json +27 -5
  25. package/src/assets/styles/preview-file.scss +70 -0
  26. package/src/assets/styles/styles.scss +190 -222
  27. package/src/components/ChatBot/ChatBot.vue +345 -368
  28. package/src/components/ChatBot/types.ts +35 -33
  29. package/src/components/ChatBotInput/ChatBotInput.vue +188 -190
  30. package/src/components/ChatBotInput/__tests__/ChatBotInput.spec.ts +279 -0
  31. package/src/components/ChatBotInput/__tests__/__snapshots__/ChatBotInput.spec.ts.snap +25 -0
  32. package/src/components/ChatBotInput/index.ts +2 -2
  33. package/src/components/ChatBotInput/types.ts +25 -25
  34. package/src/components/ChatBotMessage/ChatBotMessage.vue +159 -134
  35. package/src/components/ChatBotMessage/ChatBotMessageButtons.vue +179 -164
  36. package/src/components/ChatBotMessage/__tests__/ChatBotMessage.spec.ts +256 -0
  37. package/src/components/ChatBotMessage/__tests__/ChatBotMessageButtons.spec.ts +199 -0
  38. package/src/components/ChatBotMessage/__tests__/__snapshots__/ChatBotMessage.spec.ts.snap +35 -0
  39. package/src/components/ChatBotMessage/__tests__/__snapshots__/ChatBotMessageButtons.spec.ts.snap +25 -0
  40. package/src/components/ChatBotMessage/types.ts +54 -53
  41. package/src/components/ChatToolBar/ChatToolBar.vue +68 -64
  42. package/src/components/ChatToolBar/__tests__/ChatToolBar.spec.ts +118 -0
  43. package/src/components/ChatToolBar/__tests__/__snapshots__/ChatToolBar.spec.ts.snap +11 -0
  44. package/src/components/ChatToolBar/types.ts +12 -12
  45. package/src/components/FieldPreview/FieldPreview.vue +56 -58
  46. package/src/components/FieldPreview/__tests__/FieldPreview.spec.ts +72 -0
  47. package/src/components/FieldPreview/__tests__/__snapshots__/FieldPreview.spec.ts.snap +25 -0
  48. package/src/components/FieldPreview/field-preview.scss +26 -26
  49. package/src/components/FieldPreview/types.ts +5 -5
  50. package/src/components/MarkdownRender/MarkdownRender.vue +15 -15
  51. package/src/components/MarkdownRender/__tests__/MarkdownRender.spec.ts +68 -0
  52. package/src/components/MarkdownRender/__tests__/__snapshots__/MarkdownRender.spec.ts.snap +8 -0
  53. package/src/components/MarkdownRender/markdown-render.scss +19 -20
  54. package/src/components/MarkdownRender/types.ts +3 -3
  55. package/src/components/PulseDots/PulseDots.vue +17 -17
  56. package/src/components/PulseDots/__tests__/PulseDots.spec.ts +35 -0
  57. package/src/components/PulseDots/__tests__/__snapshots__/PulseDots.spec.ts.snap +7 -0
  58. package/src/components/PulseDots/__tests__/__snapshots__/pulse-dots.spec.ts.snap +7 -0
  59. package/src/components/PulseDots/pulse-dots.scss +24 -23
  60. package/src/composables/__tests__/useChatMessages.spec.ts +51 -0
  61. package/src/composables/__tests__/useSSE.spec.ts +132 -0
  62. package/src/composables/useChatApi.ts +128 -134
  63. package/src/composables/useChatMessages.ts +46 -48
  64. package/src/composables/useSSE.ts +75 -76
  65. package/src/composables/useTexts.ts +30 -30
  66. package/src/test/setup.ts +36 -0
  67. package/src/utils/__tests__/parseFieldValue.spec.ts +27 -0
  68. package/src/utils/parseFieldValue.ts +12 -0
  69. package/src/utils/helper.ts +0 -12
  70. /package/dist/utils/{helper.d.ts → parseFieldValue.d.ts} +0 -0
@@ -0,0 +1,199 @@
1
+ // Components
2
+ import { ChatBotMessageButtons } from '..'
3
+
4
+ // Utils
5
+ import { describe, expect, it, beforeEach, vi, afterEach } from 'vitest'
6
+ import { mount } from '@vue/test-utils'
7
+ import { useChatMessages } from '@/composables/useChatMessages'
8
+
9
+ // Types
10
+ import type { ChatBotMessageButtonsProps } from '..'
11
+
12
+ describe('ChatBotMessageButtons', () => {
13
+ const fixedDate = new Date('2025-01-01T11:47:00')
14
+ const { addChatMessage, clearMessages } = useChatMessages()
15
+
16
+ beforeEach(() => {
17
+ clearMessages()
18
+
19
+ vi.useFakeTimers()
20
+ vi.setSystemTime(fixedDate)
21
+ })
22
+
23
+ afterEach(() => {
24
+ vi.useRealTimers()
25
+ })
26
+
27
+ const props: ChatBotMessageButtonsProps = {
28
+ loading: false,
29
+ showButtons: true,
30
+ dateFormat: 'MM/DD/YYYY',
31
+ date: fixedDate
32
+ }
33
+
34
+ it('renders correctly with default props', () => {
35
+ const wrapper = mount(ChatBotMessageButtons, { props })
36
+
37
+ expect(wrapper.html()).toMatchSnapshot()
38
+ })
39
+
40
+ it('does not render buttons when showButtons is false', () => {
41
+ const wrapper = mount(ChatBotMessageButtons, {
42
+ props: { ...props, showButtons: false }
43
+ })
44
+
45
+ const buttons = wrapper.find('.q-chatbot__feedback-buttons')
46
+ expect(buttons.exists()).toBe(false)
47
+ })
48
+
49
+ it('sets loading state correctly to all buttons', () => {
50
+ const wrapper = mount(ChatBotMessageButtons, {
51
+ props: { ...props, loading: true }
52
+ })
53
+
54
+ const buttons = wrapper.findAll('q.-chatbot__feedback-buttons button')
55
+
56
+ buttons.forEach((button) => {
57
+ expect(button.attributes('disabled')).toBeDefined()
58
+ })
59
+ })
60
+
61
+ it('sets the hour date on the bottom of the component', () => {
62
+ const testDate = new Date('2024-01-01T12:00:00Z')
63
+ const wrapper = mount(ChatBotMessageButtons, {
64
+ props: {
65
+ ...props,
66
+ date: testDate
67
+ }
68
+ })
69
+
70
+ const dateElement = wrapper.find('.q-chatbot__sender')
71
+ expect(dateElement.text()).toBe('12:00')
72
+ })
73
+
74
+ it('emits the copy event when copy button is clicked', async () => {
75
+ const wrapper = mount(ChatBotMessageButtons, { props })
76
+ const copyButton = wrapper.find('.q-chatbot__copy-button')
77
+
78
+ await copyButton.trigger('click')
79
+
80
+ expect(wrapper.emitted()['copy-response']).toBeTruthy()
81
+ })
82
+
83
+ it('emits the apply-all event when apply all button is clicked', async () => {
84
+ // Add one message with fields to enable the button
85
+ const message = addChatMessage('Test message 1', 'bot')
86
+
87
+ message.fields = [
88
+ { name: 'field1', text: 'value1', type: 'text' },
89
+ { name: 'field2', text: 'value2', type: 'text' }
90
+ ]
91
+
92
+ const wrapper = mount(ChatBotMessageButtons, {
93
+ props: { ...props, showButtons: true }
94
+ })
95
+
96
+ const applyAllButton = wrapper.find('.q-chatbot__apply-all-button')
97
+ await applyAllButton.trigger('click')
98
+
99
+ expect(wrapper.emitted()['apply-all']).toBeTruthy()
100
+ })
101
+
102
+ it('does not emit apply-all if the button has already been clicked', async () => {
103
+ // Add one message with fields to enable the button
104
+ const message = addChatMessage('Test message 1', 'bot')
105
+
106
+ message.fields = [
107
+ { name: 'field1', text: 'value1', type: 'text' },
108
+ { name: 'field2', text: 'value2', type: 'text' }
109
+ ]
110
+
111
+ const wrapper = mount(ChatBotMessageButtons, {
112
+ props: { ...props, showButtons: true }
113
+ })
114
+
115
+ const applyAllButton = wrapper.find('.q-chatbot__apply-all-button')
116
+ await applyAllButton.trigger('click')
117
+ await applyAllButton.trigger('click') // Click again
118
+
119
+ expect(wrapper.emitted()['apply-all']).toBeTruthy()
120
+ expect(wrapper.emitted()['apply-all'].length).toBe(1) // Should only be emitted once
121
+ })
122
+
123
+ it('does not render apply all button if there is no message, and the message does not have fields', () => {
124
+ const wrapper = mount(ChatBotMessageButtons, {
125
+ props: { ...props, showButtons: true }
126
+ })
127
+
128
+ const applyAllButton = wrapper.find('.q-chatbot__apply-all-button')
129
+ expect(applyAllButton.exists()).toBe(false)
130
+ })
131
+
132
+ it('opens the dialog when clicking the thumbs up button', async () => {
133
+ const wrapper = mount(ChatBotMessageButtons, {
134
+ props: { ...props, showButtons: true }
135
+ })
136
+ const goodResponseButton = wrapper.find('.q-chatbot__good-response-button')
137
+ await goodResponseButton.trigger('click')
138
+
139
+ const dialog = wrapper.findComponent({ name: 'QDialog' })
140
+ expect(dialog.exists()).toBe(true)
141
+ })
142
+
143
+ it('opens the dialog when clicking the thumbs down button', async () => {
144
+ const wrapper = mount(ChatBotMessageButtons, {
145
+ props: { ...props, showButtons: true }
146
+ })
147
+ const badResponseButton = wrapper.find('.q-chatbot__bad-response-button')
148
+ await badResponseButton.trigger('click')
149
+
150
+ const dialog = wrapper.findComponent({ name: 'QDialog' })
151
+ expect(dialog.exists()).toBe(true)
152
+ })
153
+
154
+ it('emits submit-feedback event with comment when submitting feedback', async () => {
155
+ const wrapper = mount(ChatBotMessageButtons, {
156
+ props: { ...props, showButtons: true }
157
+ })
158
+ const goodResponseButton = wrapper.find('.q-chatbot__good-response-button')
159
+ await goodResponseButton.trigger('click')
160
+
161
+ const dialog = wrapper.findComponent({ name: 'QDialog' })
162
+ expect(dialog.exists()).toBe(true)
163
+
164
+ const commentInput = dialog.find('input')
165
+ expect(commentInput.exists()).toBe(true)
166
+ await commentInput.setValue('Great response!')
167
+
168
+ const overlay = wrapper.find('.q-overlay__content')
169
+ const submitButton = overlay.find('.q-chatbot__dialog-confirm-button')
170
+
171
+ expect(submitButton.exists()).toBe(true)
172
+ await submitButton.trigger('click')
173
+ expect(wrapper.emitted()['submit-feedback']).toBeTruthy()
174
+ expect(wrapper.emitted()['submit-feedback'][0]).toEqual([1, 'Great response!'])
175
+ })
176
+
177
+ it('uses a default date if no date prop is provided', () => {
178
+ const wrapper = mount(ChatBotMessageButtons, {
179
+ props: { ...props, date: undefined }
180
+ })
181
+
182
+ const dateElement = wrapper.find('.q-chatbot__sender')
183
+
184
+ // The default date is the current date, so we just check if it renders something
185
+ expect(dateElement.text().length).toBeGreaterThan(0)
186
+ })
187
+
188
+ it('uses the current data format if no dateFormat prop is provided', () => {
189
+ const wrapper = mount(ChatBotMessageButtons, {
190
+ props: { ...props, dateFormat: '' }
191
+ })
192
+
193
+ const dateElement = wrapper.find('.q-chatbot__sender')
194
+ const expectedFormat = fixedDate.toLocaleString()
195
+
196
+ // The date should be in the current locale format
197
+ expect(dateElement.text()).toBe(expectedFormat)
198
+ })
199
+ })
@@ -0,0 +1,35 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`ChatBotMessage > renders the component with default props 1`] = `
4
+ "<div class="q-chatbot__message-container"><span data-test="" type="img" alt="Sender Image" class="q-chatbot__profile"></span>
5
+ <div class="q-chatbot__message-wrapper">
6
+ <!--v-if-->
7
+ <div class="q-chatbot__message">
8
+ <div class="markdown-renderer q-chatbot__text">
9
+ <p>Hello, this is a test message.</p>
10
+ </div>
11
+ </div>
12
+ </div>
13
+ <!--teleport start-->
14
+ <transition-stub name="fade" appear="true" persisted="false" css="true">
15
+ <!--v-if-->
16
+ </transition-stub>
17
+ <transition-stub name="fade" appear="true" persisted="false" css="true">
18
+ <!--v-if-->
19
+ </transition-stub>
20
+ <!--teleport end-->
21
+ <!--v-if-->
22
+ <div class="q-chatbot__feedback-buttons">
23
+ <div class="q-button-group" role="group"><button type="button" class="q-button q-button--outlined q-button--primary q-button--borderless q-chatbot__good-response-button" title="Good response">
24
+ <!--v-if--><span class="q-button__content"><span data-test="thumb-up"></span> </span>
25
+ </button><button type="button" class="q-button q-button--outlined q-button--primary q-button--borderless q-chatbot__bad-response-button" title="Bad response">
26
+ <!--v-if--><span class="q-button__content"><span data-test="thumb-down"></span> </span>
27
+ </button><button type="button" class="q-button q-button--outlined q-button--primary q-button--borderless q-chatbot__copy-button" title="Copy response">
28
+ <!--v-if--><span class="q-button__content"><span data-test="copy-content"></span> </span>
29
+ </button>
30
+ <!--v-if-->
31
+ </div>
32
+ </div>
33
+ <div class="q-chatbot__sender">11:47</div>
34
+ </div>"
35
+ `;
@@ -0,0 +1,25 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`ChatBotMessageButtons > renders correctly with default props 1`] = `
4
+ "<!--teleport start-->
5
+ <transition-stub name="fade" appear="true" persisted="false" css="true">
6
+ <!--v-if-->
7
+ </transition-stub>
8
+ <transition-stub name="fade" appear="true" persisted="false" css="true">
9
+ <!--v-if-->
10
+ </transition-stub>
11
+ <!--teleport end-->
12
+ <!--v-if-->
13
+ <div class="q-chatbot__feedback-buttons">
14
+ <div class="q-button-group" role="group"><button type="button" class="q-button q-button--outlined q-button--primary q-button--borderless q-chatbot__good-response-button" title="Good response">
15
+ <!--v-if--><span class="q-button__content"><span data-test="thumb-up"></span> </span>
16
+ </button><button type="button" class="q-button q-button--outlined q-button--primary q-button--borderless q-chatbot__bad-response-button" title="Bad response">
17
+ <!--v-if--><span class="q-button__content"><span data-test="thumb-down"></span> </span>
18
+ </button><button type="button" class="q-button q-button--outlined q-button--primary q-button--borderless q-chatbot__copy-button" title="Copy response">
19
+ <!--v-if--><span class="q-button__content"><span data-test="copy-content"></span> </span>
20
+ </button>
21
+ <!--v-if-->
22
+ </div>
23
+ </div>
24
+ <div class="q-chatbot__sender">11:47</div>"
25
+ `;
@@ -1,70 +1,71 @@
1
- import { ChatBotMessageSender, FieldData } from '@/components/ChatBot/types'
1
+ import type { ChatBotMessageSender, FieldData } from '@/components/ChatBot/types'
2
+ import type { ChatBotFile } from '../ChatBotInput'
2
3
 
3
4
  export type ChatBotMessageProps = {
4
- /*
5
- * Sender of the message
6
- */
7
- sender?: ChatBotMessageSender
5
+ /*
6
+ * Sender of the message
7
+ */
8
+ sender?: ChatBotMessageSender
8
9
 
9
- /*
10
- * Message to be displayed
11
- */
12
- message?: string
10
+ /*
11
+ * Message to be displayed
12
+ */
13
+ message?: string
13
14
 
14
- /*
15
- * Date of when the message was sent
16
- */
17
- date?: Date
15
+ /*
16
+ * Date of when the message was sent
17
+ */
18
+ date?: Date
18
19
 
19
- /*
20
- * If the message is loading
21
- */
22
- loading?: boolean
20
+ /*
21
+ * If the message is loading
22
+ */
23
+ loading?: boolean
23
24
 
24
- /**
25
- * Project locale
26
- */
27
- dateFormat: string
25
+ /**
26
+ * Project locale
27
+ */
28
+ dateFormat: string
28
29
 
29
- /**
30
- * Image preview URL
31
- */
32
- imagePreviewUrl?: string
30
+ /**
31
+ * File Preview
32
+ */
33
+ file?: ChatBotFile
33
34
 
34
- /**
35
- * Default api endpoint
36
- */
37
- apiEndpoint: string
35
+ /**
36
+ * Default api endpoint
37
+ */
38
+ apiEndpoint: string
38
39
 
39
- /**
40
- * Session ID
41
- */
42
- sessionID?: string
40
+ /**
41
+ * Session ID
42
+ */
43
+ sessionID?: string
43
44
 
44
- /**
45
- * User image
46
- */
47
- userImage: string
45
+ /**
46
+ * User image
47
+ */
48
+ userImage: string
48
49
 
49
- /**
50
- * Chatbot image
51
- */
52
- chatbotImage: string
50
+ /**
51
+ * Chatbot image
52
+ */
53
+ chatbotImage: string
53
54
 
54
- /**
55
- * Flag to mark welcome messages
56
- */
57
- isWelcomeMessage?: boolean
55
+ /**
56
+ * Flag to mark welcome messages
57
+ */
58
+ isWelcomeMessage?: boolean
58
59
 
59
- /**
60
- * Additional fields for the message
61
- */
62
- fields?: FieldData[]
60
+ /**
61
+ * Additional fields for the message
62
+ */
63
+ fields?: FieldData[]
63
64
  }
64
65
 
65
66
  export type ChatBotMessageButtonsProps = {
66
- loading: boolean
67
- showButtons: boolean
68
- dateFormat: string
69
- date?: Date
67
+ loading: boolean
68
+ showButtons: boolean
69
+ dateFormat: string
70
+ date?: Date
70
71
  }
@@ -1,82 +1,86 @@
1
1
  <template>
2
- <div class="q-chatbot__tools">
3
- <div class="q-chatbot__tools__select">
4
- <q-select
5
- v-if="hasAgents"
6
- v-model="selectedChat"
7
- size="medium"
8
- :items="availableChats"
9
- @update:model-value="changeChat" />
10
- </div>
2
+ <div class="q-chatbot__tools">
3
+ <div class="q-chatbot__tools__select">
4
+ <q-select
5
+ v-if="hasAgents"
6
+ v-model="selectedChat"
7
+ class="q-chatbot__tools-select-input"
8
+ size="medium"
9
+ :items="availableChats"
10
+ @update:model-value="changeChat" />
11
+ </div>
11
12
 
12
- <q-button
13
- :title="clearChat"
14
- :disabled="props.disabled"
15
- borderless
16
- @click="clear">
17
- <q-icon icon="bin" />
18
- </q-button>
19
- </div>
13
+ <q-button
14
+ :title="clearChat"
15
+ :disabled="props.disabled"
16
+ class="q-chatbot__tools-clear"
17
+ borderless
18
+ @click="clear">
19
+ <q-icon icon="bin" />
20
+ </q-button>
21
+ </div>
20
22
  </template>
21
23
 
22
24
  <script setup lang="ts">
23
- import { useTexts } from '@/composables/useTexts'
24
- import { ChatToolBarProps } from './types'
25
- import { computed, ref, watch } from 'vue'
25
+ import { QButton, QSelect, QIcon } from '@quidgest/ui/components'
26
26
 
27
- const { clearChat } = useTexts()
27
+ import { useTexts } from '@/composables/useTexts'
28
+ import { ChatToolBarProps } from './types'
29
+ import { computed, ref, watch } from 'vue'
28
30
 
29
- const defaultChat = {
30
- key: '',
31
- value: 'Default Chat',
32
- formId: ''
33
- }
31
+ const props = withDefaults(defineProps<ChatToolBarProps>(), {
32
+ availableAgents: () => []
33
+ })
34
34
 
35
- const props = withDefaults(defineProps<ChatToolBarProps>(), {
36
- availableAgents: () => []
37
- })
35
+ const emit = defineEmits<{
36
+ (e: 'clear'): void
37
+ (e: 'change-chat', value: { key: string; formId: string }): void
38
+ }>()
38
39
 
39
- const emit = defineEmits<{
40
- (e: 'clear'): void
41
- (e: 'change-chat', value: { key: string; formId: string }): void
42
- }>()
40
+ const { clearChat } = useTexts()
43
41
 
44
- const hasAgents = computed(() => {
45
- return props.availableAgents && props.availableAgents.length > 0
46
- })
42
+ const defaultChat = {
43
+ key: '',
44
+ value: 'Default Chat',
45
+ formId: ''
46
+ }
47
47
 
48
- const selectedChat = ref(props.selectedAgentKey || defaultChat.key)
49
- watch(
50
- () => props.selectedAgentKey,
51
- (newValue) => {
52
- selectedChat.value = newValue || defaultChat.key
53
- }
54
- )
48
+ const hasAgents = computed(() => {
49
+ return props.availableAgents && props.availableAgents.length > 0
50
+ })
55
51
 
56
- const availableChats = computed(() => {
57
- const chats = props.availableAgents?.map((agent) => ({
58
- key: agent.key,
59
- value: agent.value,
60
- formId: agent.formId
61
- }))
52
+ const selectedChat = ref(props.selectedAgentKey || defaultChat.key)
53
+ watch(
54
+ () => props.selectedAgentKey,
55
+ (newValue) => {
56
+ selectedChat.value = newValue || defaultChat.key
57
+ }
58
+ )
62
59
 
63
- chats?.push(defaultChat)
64
- return chats || [defaultChat]
65
- })
60
+ const availableChats = computed(() => {
61
+ const chats = props.availableAgents?.map((agent) => ({
62
+ key: agent.key,
63
+ value: agent.value,
64
+ formId: agent.formId
65
+ }))
66
66
 
67
- function clear() {
68
- emit('clear')
69
- }
67
+ chats?.push(defaultChat)
68
+ return chats || [defaultChat]
69
+ })
70
70
 
71
- function changeChat(value: string) {
72
- const item = availableChats.value.find((chat) => chat.key === value)
73
- if (!item) return
71
+ function clear() {
72
+ emit('clear')
73
+ }
74
74
 
75
- if (item.key === defaultChat.key) {
76
- emit('change-chat', { key: '', formId: '' })
77
- return
78
- }
75
+ function changeChat(value: string) {
76
+ const item = availableChats.value.find((chat) => chat.key === value)
77
+ if (!item) return
79
78
 
80
- emit('change-chat', item)
81
- }
79
+ if (item.key === defaultChat.key) {
80
+ emit('change-chat', { key: '', formId: '' })
81
+ return
82
+ }
83
+
84
+ emit('change-chat', item)
85
+ }
82
86
  </script>
@@ -0,0 +1,118 @@
1
+ // Components
2
+ import { ChatToolBar } from '..'
3
+
4
+ // Utils
5
+ import { describe, it, expect } from 'vitest'
6
+ import { mount } from '@vue/test-utils'
7
+
8
+ // Types
9
+ import type { ChatToolBarProps } from '../'
10
+
11
+ describe('ChatToolBar', () => {
12
+ const props: ChatToolBarProps = {
13
+ disabled: false,
14
+ availableAgents: [],
15
+ selectedAgentKey: ''
16
+ }
17
+
18
+ it('should render the component', () => {
19
+ const wrapper = mount(ChatToolBar, { props })
20
+ expect(wrapper.html()).toMatchSnapshot()
21
+ })
22
+
23
+ it('should emit clear event when clear button is clicked', async () => {
24
+ const wrapper = mount(ChatToolBar, { props })
25
+ const button = wrapper.find('.q-chatbot__tools-clear')
26
+
27
+ await button.trigger('click')
28
+ expect(wrapper.emitted()['clear']).toBeTruthy()
29
+ })
30
+
31
+ it('should disable the clear button when disabled prop is true', () => {
32
+ const wrapper = mount(ChatToolBar, { props: { ...props, disabled: true } })
33
+ const button = wrapper.find<HTMLButtonElement>('.q-chatbot__tools-clear')
34
+ expect(button.element.disabled).toBe(true)
35
+ })
36
+
37
+ it('should not render the select when no agents are provided', () => {
38
+ const wrapper = mount(ChatToolBar, { props })
39
+ expect(wrapper.find('.q-chatbot__tools-select-input').exists()).toBe(false)
40
+ })
41
+
42
+ it('should render the select when agents are provided', () => {
43
+ const wrapper = mount(ChatToolBar, {
44
+ props: {
45
+ ...props,
46
+ availableAgents: [{ key: 'agent1', value: 'Agent 1', formId: 'key' }]
47
+ }
48
+ })
49
+ expect(wrapper.find('.q-chatbot__tools-select-input').exists()).toBe(true)
50
+ })
51
+
52
+ it('should emit change-agent event when a new agent is selected', async () => {
53
+ const wrapper = mount(ChatToolBar, {
54
+ props: {
55
+ ...props,
56
+ availableAgents: [
57
+ { key: 'agent1', value: 'Agent 1', formId: 'key' },
58
+ { key: 'agent2', value: 'Agent 2', formId: 'key' }
59
+ ],
60
+ selectedAgentKey: 'agent1'
61
+ }
62
+ })
63
+
64
+ const select = wrapper.findComponent({ name: 'QSelect' })
65
+ // Simulate selecting a new agent
66
+ await select.vm.$emit('update:modelValue', 'agent2')
67
+
68
+ expect(wrapper.emitted()['change-chat']).toBeTruthy()
69
+ expect(wrapper.emitted()['change-chat']?.[0]).toEqual([
70
+ {
71
+ key: 'agent2',
72
+ formId: 'key',
73
+ value: 'Agent 2'
74
+ }
75
+ ])
76
+ })
77
+
78
+ it('should not emit change-agent if it receive a non-existing agent key', async () => {
79
+ const wrapper = mount(ChatToolBar, {
80
+ props: {
81
+ ...props,
82
+ availableAgents: [
83
+ { key: 'agent1', value: 'Agent 1', formId: 'key' },
84
+ { key: 'agent2', value: 'Agent 2', formId: 'key' }
85
+ ],
86
+ selectedAgentKey: 'agent1'
87
+ }
88
+ })
89
+ const select = wrapper.findComponent({ name: 'QSelect' })
90
+ // Simulate selecting a new agent
91
+ await select.vm.$emit('update:modelValue', 'agent3')
92
+ expect(wrapper.emitted()['change-chat']).toBeFalsy()
93
+ })
94
+
95
+ it('shoudld emit change-agent when selecting the default option', async () => {
96
+ const wrapper = mount(ChatToolBar, {
97
+ props: {
98
+ ...props,
99
+ availableAgents: [
100
+ { key: 'agent1', value: 'Agent 1', formId: 'key' },
101
+ { key: 'agent2', value: 'Agent 2', formId: 'key' }
102
+ ],
103
+ selectedAgentKey: 'agent1'
104
+ }
105
+ })
106
+ const select = wrapper.findComponent({ name: 'QSelect' })
107
+ // Simulate selecting a new agent
108
+ await select.vm.$emit('update:modelValue', '')
109
+
110
+ expect(wrapper.emitted()['change-chat']).toBeTruthy()
111
+ expect(wrapper.emitted()['change-chat']?.[0]).toEqual([
112
+ {
113
+ key: '',
114
+ formId: ''
115
+ }
116
+ ])
117
+ })
118
+ })
@@ -0,0 +1,11 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`ChatToolBar > should render the component 1`] = `
4
+ "<div class="q-chatbot__tools">
5
+ <div class="q-chatbot__tools__select">
6
+ <!--v-if-->
7
+ </div><button type="button" class="q-button q-button--outlined q-button--primary q-button--borderless q-chatbot__tools-clear" title="Clear chat">
8
+ <!--v-if--><span class="q-button__content"><span data-test="bin"></span> </span>
9
+ </button>
10
+ </div>"
11
+ `;