@n8n/chat 0.3.0 → 0.4.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.
- package/README.md +22 -5
- package/chat.bundle.es.js +10757 -0
- package/chat.bundle.umd.js +18 -0
- package/chat.es.js +6867 -0
- package/chat.umd.js +18 -0
- package/package.json +62 -2
- package/style.css +1 -0
- package/types/App.vue.d.ts +8 -0
- package/types/__stories__/App.stories.d.ts +17 -0
- package/types/__tests__/index.spec.d.ts +1 -0
- package/types/__tests__/setup.d.ts +0 -0
- package/types/__tests__/utils/create.d.ts +5 -0
- package/types/__tests__/utils/fetch.d.ts +4 -0
- package/types/__tests__/utils/selectors.d.ts +12 -0
- package/types/api/generic.d.ts +6 -0
- package/types/api/message.d.ts +3 -0
- package/types/components/Button.vue.d.ts +9 -0
- package/types/components/Chat.vue.d.ts +2 -0
- package/types/components/ChatWindow.vue.d.ts +2 -0
- package/types/components/GetStarted.vue.d.ts +2 -0
- package/types/components/GetStartedFooter.vue.d.ts +2 -0
- package/types/components/Input.vue.d.ts +2 -0
- package/types/components/Layout.vue.d.ts +11 -0
- package/types/components/Message.vue.d.ts +21 -0
- package/types/components/MessageTyping.vue.d.ts +15 -0
- package/types/components/MessagesList.vue.d.ts +14 -0
- package/types/components/PoweredBy.vue.d.ts +2 -0
- package/types/composables/useChat.d.ts +2 -0
- package/types/composables/useI18n.d.ts +4 -0
- package/types/composables/useOptions.d.ts +4 -0
- package/types/constants/defaults.d.ts +3 -0
- package/types/constants/localStorage.d.ts +2 -0
- package/types/constants/symbols.d.ts +4 -0
- package/types/event-buses/chatEventBus.d.ts +1 -0
- package/types/index.d.ts +2 -0
- package/types/plugins/chat.d.ts +3 -0
- package/types/types/chat.d.ts +11 -0
- package/types/types/messages.d.ts +6 -0
- package/types/types/options.d.ts +24 -0
- package/types/types/webhook.d.ts +15 -0
- package/types/utils/event-bus.d.ts +8 -0
- package/types/utils/mount.d.ts +1 -0
- package/.eslintignore +0 -2
- package/.eslintrc.cjs +0 -52
- package/.np-config.json +0 -5
- package/.storybook/main.ts +0 -27
- package/.storybook/preview.scss +0 -4
- package/.storybook/preview.ts +0 -16
- package/.vscode/extensions.json +0 -3
- package/env.d.ts +0 -1
- package/index.html +0 -13
- package/resources/workflow.json +0 -293
- package/scripts/pack.js +0 -11
- package/scripts/postbuild.js +0 -16
- package/src/App.vue +0 -23
- package/src/__stories__/App.stories.ts +0 -43
- package/src/__tests__/index.spec.ts +0 -223
- package/src/__tests__/setup.ts +0 -1
- package/src/__tests__/utils/create.ts +0 -16
- package/src/__tests__/utils/fetch.ts +0 -18
- package/src/__tests__/utils/selectors.ts +0 -53
- package/src/api/generic.ts +0 -64
- package/src/api/message.ts +0 -31
- package/src/components/Button.vue +0 -41
- package/src/components/Chat.vue +0 -48
- package/src/components/ChatWindow.vue +0 -125
- package/src/components/GetStarted.vue +0 -24
- package/src/components/GetStartedFooter.vue +0 -20
- package/src/components/Input.vue +0 -93
- package/src/components/Layout.vue +0 -82
- package/src/components/Message.vue +0 -97
- package/src/components/MessageTyping.vue +0 -109
- package/src/components/MessagesList.vue +0 -37
- package/src/components/PoweredBy.vue +0 -17
- package/src/composables/useChat.ts +0 -7
- package/src/composables/useI18n.ts +0 -16
- package/src/composables/useOptions.ts +0 -11
- package/src/constants/defaults.ts +0 -25
- package/src/constants/localStorage.ts +0 -2
- package/src/constants/symbols.ts +0 -8
- package/src/event-buses/chatEventBus.ts +0 -3
- package/src/index.ts +0 -42
- package/src/main.scss +0 -40
- package/src/plugins/chat.ts +0 -101
- package/src/shims.d.ts +0 -6
- package/src/types/chat.ts +0 -12
- package/src/types/messages.ts +0 -6
- package/src/types/options.ts +0 -23
- package/src/types/webhook.ts +0 -17
- package/src/utils/event-bus.ts +0 -51
- package/src/utils/mount.ts +0 -16
- package/tsconfig.json +0 -27
- package/vite.config.ts +0 -51
- package/vitest.config.ts +0 -20
- /package/{public/favicon.ico → favicon.ico} +0 -0
- /package/{src/__tests__/utils/index.ts → types/__tests__/utils/index.d.ts} +0 -0
- /package/{src/api/index.ts → types/api/index.d.ts} +0 -0
- /package/{src/components/index.ts → types/components/index.d.ts} +0 -0
- /package/{src/composables/index.ts → types/composables/index.d.ts} +0 -0
- /package/{src/constants/index.ts → types/constants/index.d.ts} +0 -0
- /package/{src/event-buses/index.ts → types/event-buses/index.d.ts} +0 -0
- /package/{src/plugins/index.ts → types/plugins/index.d.ts} +0 -0
- /package/{src/types/index.ts → types/types/index.d.ts} +0 -0
- /package/{src/utils/index.ts → types/utils/index.d.ts} +0 -0
package/resources/workflow.json
DELETED
|
@@ -1,293 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "AI Webhook Chat",
|
|
3
|
-
"nodes": [
|
|
4
|
-
{
|
|
5
|
-
"parameters": {
|
|
6
|
-
"httpMethod": "POST",
|
|
7
|
-
"path": "513107b3-6f3a-4a1e-af21-659f0ed14183",
|
|
8
|
-
"responseMode": "responseNode",
|
|
9
|
-
"options": {
|
|
10
|
-
"domainAllowlist": "*.localhost"
|
|
11
|
-
}
|
|
12
|
-
},
|
|
13
|
-
"id": "51ab2689-647d-4cff-9d6f-0ba4df45e904",
|
|
14
|
-
"name": "Webhook",
|
|
15
|
-
"type": "n8n-nodes-base.webhook",
|
|
16
|
-
"typeVersion": 1,
|
|
17
|
-
"position": [
|
|
18
|
-
900,
|
|
19
|
-
200
|
|
20
|
-
],
|
|
21
|
-
"webhookId": "513107b3-6f3a-4a1e-af21-659f0ed14183"
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
"parameters": {
|
|
25
|
-
"options": {}
|
|
26
|
-
},
|
|
27
|
-
"id": "3c7fd563-f610-41fa-b198-7fcf100e2815",
|
|
28
|
-
"name": "Chat OpenAI",
|
|
29
|
-
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
|
|
30
|
-
"typeVersion": 1,
|
|
31
|
-
"position": [
|
|
32
|
-
1720,
|
|
33
|
-
620
|
|
34
|
-
],
|
|
35
|
-
"credentials": {
|
|
36
|
-
"openAiApi": {
|
|
37
|
-
"id": "B5Fiv70Adfg6htxn",
|
|
38
|
-
"name": "Alex's OpenAI Account"
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
"parameters": {
|
|
44
|
-
"sessionKey": "={{ $json.body.sessionId }}"
|
|
45
|
-
},
|
|
46
|
-
"id": "ebc23ffa-3bcf-494f-bcb8-51a5fff91885",
|
|
47
|
-
"name": "Window Buffer Memory",
|
|
48
|
-
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
|
|
49
|
-
"typeVersion": 1,
|
|
50
|
-
"position": [
|
|
51
|
-
1920,
|
|
52
|
-
620
|
|
53
|
-
]
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
"parameters": {
|
|
57
|
-
"simplifyOutput": false
|
|
58
|
-
},
|
|
59
|
-
"id": "d6721a60-159b-4a93-ac6b-b81e16d9f16f",
|
|
60
|
-
"name": "Memory Chat Retriever",
|
|
61
|
-
"type": "@n8n/n8n-nodes-langchain.memoryChatRetriever",
|
|
62
|
-
"typeVersion": 1,
|
|
63
|
-
"position": [
|
|
64
|
-
1780,
|
|
65
|
-
-40
|
|
66
|
-
]
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
"parameters": {
|
|
70
|
-
"sessionKey": "={{ $json.body.sessionId }}"
|
|
71
|
-
},
|
|
72
|
-
"id": "347edc3a-1dda-4996-b778-dcdc447ecfd8",
|
|
73
|
-
"name": "Memory Chat Retriever Window Buffer Memory",
|
|
74
|
-
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
|
|
75
|
-
"typeVersion": 1,
|
|
76
|
-
"position": [
|
|
77
|
-
1800,
|
|
78
|
-
160
|
|
79
|
-
]
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
"parameters": {
|
|
83
|
-
"options": {
|
|
84
|
-
"responseCode": 200,
|
|
85
|
-
"responseHeaders": {
|
|
86
|
-
"entries": [
|
|
87
|
-
{
|
|
88
|
-
"name": "sessionId",
|
|
89
|
-
"value": "={{ $json.body.sessionId }}"
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
"name": "Access-Control-Allow-Headers",
|
|
93
|
-
"value": "*"
|
|
94
|
-
}
|
|
95
|
-
]
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
},
|
|
99
|
-
"id": "d229963e-e2f1-4381-87d2-47043bd6ccc7",
|
|
100
|
-
"name": "Respond to Webhook",
|
|
101
|
-
"type": "n8n-nodes-base.respondToWebhook",
|
|
102
|
-
"typeVersion": 1,
|
|
103
|
-
"position": [
|
|
104
|
-
2460,
|
|
105
|
-
220
|
|
106
|
-
]
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
"parameters": {
|
|
110
|
-
"dataType": "string",
|
|
111
|
-
"value1": "={{ $json.body.action }}",
|
|
112
|
-
"rules": {
|
|
113
|
-
"rules": [
|
|
114
|
-
{
|
|
115
|
-
"value2": "loadPreviousSession"
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
"value2": "sendMessage",
|
|
119
|
-
"output": 1
|
|
120
|
-
}
|
|
121
|
-
]
|
|
122
|
-
}
|
|
123
|
-
},
|
|
124
|
-
"id": "fc4ad994-5f38-4dce-b1e5-397acc512687",
|
|
125
|
-
"name": "Chatbot Action",
|
|
126
|
-
"type": "n8n-nodes-base.switch",
|
|
127
|
-
"typeVersion": 1,
|
|
128
|
-
"position": [
|
|
129
|
-
1320,
|
|
130
|
-
200
|
|
131
|
-
]
|
|
132
|
-
},
|
|
133
|
-
{
|
|
134
|
-
"parameters": {
|
|
135
|
-
"jsCode": "const response = { data: [] };\n\nfor (const item of $input.all()) {\n response.data.push(item.json);\n}\n\nreturn {\n json: response,\n pairedItem: 0\n};"
|
|
136
|
-
},
|
|
137
|
-
"id": "e1a80bdc-411a-42df-88dd-36915b1ae8f4",
|
|
138
|
-
"name": "Code",
|
|
139
|
-
"type": "n8n-nodes-base.code",
|
|
140
|
-
"typeVersion": 2,
|
|
141
|
-
"position": [
|
|
142
|
-
2160,
|
|
143
|
-
-40
|
|
144
|
-
]
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
"parameters": {
|
|
148
|
-
"text": "={{ $json.body.message }}",
|
|
149
|
-
"options": {}
|
|
150
|
-
},
|
|
151
|
-
"id": "f28f5c00-c742-41d5-8ddb-f0f59ab111a3",
|
|
152
|
-
"name": "Agent",
|
|
153
|
-
"type": "@n8n/n8n-nodes-langchain.agent",
|
|
154
|
-
"typeVersion": 1,
|
|
155
|
-
"position": [
|
|
156
|
-
1780,
|
|
157
|
-
340
|
|
158
|
-
]
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
"parameters": {
|
|
162
|
-
"jsCode": "// Loop over input items and add a new field called 'myNewField' to the JSON of each one\nfor (const item of $input.all()) {\n item.json.body = JSON.parse(item.json.body);\n}\n\nreturn $input.all();"
|
|
163
|
-
},
|
|
164
|
-
"id": "415c071b-18b2-4ac5-8634-e3d939bf36ac",
|
|
165
|
-
"name": "Transform request body",
|
|
166
|
-
"type": "n8n-nodes-base.code",
|
|
167
|
-
"typeVersion": 2,
|
|
168
|
-
"position": [
|
|
169
|
-
1120,
|
|
170
|
-
200
|
|
171
|
-
]
|
|
172
|
-
}
|
|
173
|
-
],
|
|
174
|
-
"pinData": {},
|
|
175
|
-
"connections": {
|
|
176
|
-
"Webhook": {
|
|
177
|
-
"main": [
|
|
178
|
-
[
|
|
179
|
-
{
|
|
180
|
-
"node": "Transform request body",
|
|
181
|
-
"type": "main",
|
|
182
|
-
"index": 0
|
|
183
|
-
}
|
|
184
|
-
]
|
|
185
|
-
]
|
|
186
|
-
},
|
|
187
|
-
"Memory Chat Retriever": {
|
|
188
|
-
"main": [
|
|
189
|
-
[
|
|
190
|
-
{
|
|
191
|
-
"node": "Code",
|
|
192
|
-
"type": "main",
|
|
193
|
-
"index": 0
|
|
194
|
-
}
|
|
195
|
-
]
|
|
196
|
-
]
|
|
197
|
-
},
|
|
198
|
-
"Memory Chat Retriever Window Buffer Memory": {
|
|
199
|
-
"ai_memory": [
|
|
200
|
-
[
|
|
201
|
-
{
|
|
202
|
-
"node": "Memory Chat Retriever",
|
|
203
|
-
"type": "ai_memory",
|
|
204
|
-
"index": 0
|
|
205
|
-
}
|
|
206
|
-
]
|
|
207
|
-
]
|
|
208
|
-
},
|
|
209
|
-
"Chatbot Action": {
|
|
210
|
-
"main": [
|
|
211
|
-
[
|
|
212
|
-
{
|
|
213
|
-
"node": "Memory Chat Retriever",
|
|
214
|
-
"type": "main",
|
|
215
|
-
"index": 0
|
|
216
|
-
}
|
|
217
|
-
],
|
|
218
|
-
[
|
|
219
|
-
{
|
|
220
|
-
"node": "Agent",
|
|
221
|
-
"type": "main",
|
|
222
|
-
"index": 0
|
|
223
|
-
}
|
|
224
|
-
]
|
|
225
|
-
]
|
|
226
|
-
},
|
|
227
|
-
"Code": {
|
|
228
|
-
"main": [
|
|
229
|
-
[
|
|
230
|
-
{
|
|
231
|
-
"node": "Respond to Webhook",
|
|
232
|
-
"type": "main",
|
|
233
|
-
"index": 0
|
|
234
|
-
}
|
|
235
|
-
]
|
|
236
|
-
]
|
|
237
|
-
},
|
|
238
|
-
"Chat OpenAI": {
|
|
239
|
-
"ai_languageModel": [
|
|
240
|
-
[
|
|
241
|
-
{
|
|
242
|
-
"node": "Agent",
|
|
243
|
-
"type": "ai_languageModel",
|
|
244
|
-
"index": 0
|
|
245
|
-
}
|
|
246
|
-
]
|
|
247
|
-
]
|
|
248
|
-
},
|
|
249
|
-
"Window Buffer Memory": {
|
|
250
|
-
"ai_memory": [
|
|
251
|
-
[
|
|
252
|
-
{
|
|
253
|
-
"node": "Agent",
|
|
254
|
-
"type": "ai_memory",
|
|
255
|
-
"index": 0
|
|
256
|
-
}
|
|
257
|
-
]
|
|
258
|
-
]
|
|
259
|
-
},
|
|
260
|
-
"Agent": {
|
|
261
|
-
"main": [
|
|
262
|
-
[
|
|
263
|
-
{
|
|
264
|
-
"node": "Respond to Webhook",
|
|
265
|
-
"type": "main",
|
|
266
|
-
"index": 0
|
|
267
|
-
}
|
|
268
|
-
]
|
|
269
|
-
]
|
|
270
|
-
},
|
|
271
|
-
"Transform request body": {
|
|
272
|
-
"main": [
|
|
273
|
-
[
|
|
274
|
-
{
|
|
275
|
-
"node": "Chatbot Action",
|
|
276
|
-
"type": "main",
|
|
277
|
-
"index": 0
|
|
278
|
-
}
|
|
279
|
-
]
|
|
280
|
-
]
|
|
281
|
-
}
|
|
282
|
-
},
|
|
283
|
-
"active": true,
|
|
284
|
-
"settings": {
|
|
285
|
-
"executionOrder": "v1"
|
|
286
|
-
},
|
|
287
|
-
"versionId": "12c145a2-74bf-48b5-a87a-ba707949eaed",
|
|
288
|
-
"id": "L3FlJuFOxZcHtoFT",
|
|
289
|
-
"meta": {
|
|
290
|
-
"instanceId": "374b43d8b8d6299cc777811a4ad220fc688ee2d54a308cfb0de4450a5233ca9e"
|
|
291
|
-
},
|
|
292
|
-
"tags": []
|
|
293
|
-
}
|
package/scripts/pack.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const shelljs = require('shelljs');
|
|
3
|
-
|
|
4
|
-
const rootDirPath = path.resolve(__dirname, '..');
|
|
5
|
-
const distDirPath = path.resolve(rootDirPath, 'dist');
|
|
6
|
-
|
|
7
|
-
shelljs.cd(rootDirPath);
|
|
8
|
-
shelljs.exec('npm run build');
|
|
9
|
-
|
|
10
|
-
shelljs.cd(distDirPath);
|
|
11
|
-
shelljs.exec('npm pack');
|
package/scripts/postbuild.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const shelljs = require('shelljs');
|
|
3
|
-
|
|
4
|
-
const rootDirPath = path.resolve(__dirname, '..');
|
|
5
|
-
const n8nRootDirPath = path.resolve(rootDirPath, '..', '..', '..');
|
|
6
|
-
const distDirPath = path.resolve(rootDirPath, 'dist');
|
|
7
|
-
|
|
8
|
-
const packageJsonFilePath = path.resolve(rootDirPath, 'package.json');
|
|
9
|
-
const readmeFilePath = path.resolve(rootDirPath, 'README.md');
|
|
10
|
-
const licenseFilePath = path.resolve(n8nRootDirPath, 'LICENSE.md');
|
|
11
|
-
|
|
12
|
-
shelljs.cp(packageJsonFilePath, distDirPath);
|
|
13
|
-
shelljs.cp(readmeFilePath, distDirPath);
|
|
14
|
-
shelljs.cp(licenseFilePath, distDirPath);
|
|
15
|
-
|
|
16
|
-
shelljs.mv(path.resolve(distDirPath, 'src'), path.resolve(distDirPath, 'types'));
|
package/src/App.vue
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
import { Chat, ChatWindow } from '@/components';
|
|
3
|
-
import { computed, onMounted } from 'vue';
|
|
4
|
-
import hljs from 'highlight.js/lib/core';
|
|
5
|
-
import hljsXML from 'highlight.js/lib/languages/xml';
|
|
6
|
-
import hljsJavascript from 'highlight.js/lib/languages/javascript';
|
|
7
|
-
import { useOptions } from '@/composables';
|
|
8
|
-
|
|
9
|
-
defineProps({});
|
|
10
|
-
|
|
11
|
-
const { options } = useOptions();
|
|
12
|
-
|
|
13
|
-
const isFullscreen = computed<boolean>(() => options.mode === 'fullscreen');
|
|
14
|
-
|
|
15
|
-
onMounted(() => {
|
|
16
|
-
hljs.registerLanguage('xml', hljsXML);
|
|
17
|
-
hljs.registerLanguage('javascript', hljsJavascript);
|
|
18
|
-
});
|
|
19
|
-
</script>
|
|
20
|
-
<template>
|
|
21
|
-
<Chat v-if="isFullscreen" class="n8n-chat" />
|
|
22
|
-
<ChatWindow v-else class="n8n-chat" />
|
|
23
|
-
</template>
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/naming-convention */
|
|
2
|
-
import type { StoryObj } from '@storybook/vue3';
|
|
3
|
-
import type { ChatOptions } from '@/types';
|
|
4
|
-
import { createChat } from '@/index';
|
|
5
|
-
import { onMounted } from 'vue';
|
|
6
|
-
|
|
7
|
-
const webhookUrl = 'http://localhost:5678/webhook/513107b3-6f3a-4a1e-af21-659f0ed14183';
|
|
8
|
-
|
|
9
|
-
const meta = {
|
|
10
|
-
title: 'Chat',
|
|
11
|
-
render: (args: Partial<ChatOptions>) => ({
|
|
12
|
-
setup() {
|
|
13
|
-
onMounted(() => {
|
|
14
|
-
createChat(args);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
return {};
|
|
18
|
-
},
|
|
19
|
-
template: '<div id="n8n-chat" />',
|
|
20
|
-
}),
|
|
21
|
-
parameters: {
|
|
22
|
-
layout: 'fullscreen',
|
|
23
|
-
},
|
|
24
|
-
tags: ['autodocs'],
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
// eslint-disable-next-line import/no-default-export
|
|
28
|
-
export default meta;
|
|
29
|
-
type Story = StoryObj<typeof meta>;
|
|
30
|
-
|
|
31
|
-
export const Fullscreen: Story = {
|
|
32
|
-
args: {
|
|
33
|
-
webhookUrl,
|
|
34
|
-
mode: 'fullscreen',
|
|
35
|
-
} satisfies Partial<ChatOptions>,
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export const Windowed: Story = {
|
|
39
|
-
args: {
|
|
40
|
-
webhookUrl,
|
|
41
|
-
mode: 'window',
|
|
42
|
-
} satisfies Partial<ChatOptions>,
|
|
43
|
-
};
|
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
import { fireEvent, waitFor } from '@testing-library/vue';
|
|
2
|
-
import {
|
|
3
|
-
createFetchResponse,
|
|
4
|
-
createGetLatestMessagesResponse,
|
|
5
|
-
createSendMessageResponse,
|
|
6
|
-
getChatInputSendButton,
|
|
7
|
-
getChatInputTextarea,
|
|
8
|
-
getChatMessage,
|
|
9
|
-
getChatMessageByText,
|
|
10
|
-
getChatMessages,
|
|
11
|
-
getChatMessageTyping,
|
|
12
|
-
getChatWindowToggle,
|
|
13
|
-
getChatWindowWrapper,
|
|
14
|
-
getChatWrapper,
|
|
15
|
-
getGetStartedButton,
|
|
16
|
-
getMountingTarget,
|
|
17
|
-
} from '@/__tests__/utils';
|
|
18
|
-
import { createChat } from '@/index';
|
|
19
|
-
import { useChat } from '@/composables';
|
|
20
|
-
|
|
21
|
-
describe('createChat()', () => {
|
|
22
|
-
let app: ReturnType<typeof createChat>;
|
|
23
|
-
|
|
24
|
-
afterEach(() => {
|
|
25
|
-
vi.clearAllMocks();
|
|
26
|
-
|
|
27
|
-
app.unmount();
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
describe('mode', () => {
|
|
31
|
-
it('should create fullscreen chat app with default options', () => {
|
|
32
|
-
const fetchSpy = vi.spyOn(window, 'fetch');
|
|
33
|
-
fetchSpy.mockImplementationOnce(createFetchResponse(createGetLatestMessagesResponse()));
|
|
34
|
-
|
|
35
|
-
app = createChat({
|
|
36
|
-
mode: 'fullscreen',
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
expect(getMountingTarget()).toBeVisible();
|
|
40
|
-
expect(getChatWrapper()).toBeVisible();
|
|
41
|
-
expect(getChatWindowWrapper()).not.toBeInTheDocument();
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('should create window chat app with default options', () => {
|
|
45
|
-
const fetchSpy = vi.spyOn(window, 'fetch');
|
|
46
|
-
fetchSpy.mockImplementationOnce(createFetchResponse(createGetLatestMessagesResponse()));
|
|
47
|
-
|
|
48
|
-
app = createChat({
|
|
49
|
-
mode: 'window',
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
expect(getMountingTarget()).toBeDefined();
|
|
53
|
-
expect(getChatWindowWrapper()).toBeVisible();
|
|
54
|
-
expect(getChatWrapper()).not.toBeVisible();
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('should open window chat app using toggle button', async () => {
|
|
58
|
-
const fetchSpy = vi.spyOn(window, 'fetch');
|
|
59
|
-
fetchSpy.mockImplementationOnce(createFetchResponse(createGetLatestMessagesResponse()));
|
|
60
|
-
|
|
61
|
-
app = createChat();
|
|
62
|
-
|
|
63
|
-
expect(getMountingTarget()).toBeVisible();
|
|
64
|
-
expect(getChatWindowWrapper()).toBeVisible();
|
|
65
|
-
|
|
66
|
-
const trigger = getChatWindowToggle();
|
|
67
|
-
await fireEvent.click(trigger as HTMLElement);
|
|
68
|
-
|
|
69
|
-
expect(getChatWrapper()).toBeVisible();
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
describe('loadPreviousMessages', () => {
|
|
74
|
-
it('should load previous messages on mount', async () => {
|
|
75
|
-
const fetchSpy = vi.spyOn(global, 'fetch');
|
|
76
|
-
fetchSpy.mockImplementation(createFetchResponse(createGetLatestMessagesResponse()));
|
|
77
|
-
|
|
78
|
-
app = createChat({
|
|
79
|
-
mode: 'fullscreen',
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
const getStartedButton = getGetStartedButton();
|
|
83
|
-
await fireEvent.click(getStartedButton as HTMLElement);
|
|
84
|
-
|
|
85
|
-
expect(fetchSpy.mock.calls[0][1]).toEqual(
|
|
86
|
-
expect.objectContaining({
|
|
87
|
-
method: 'POST',
|
|
88
|
-
headers: {},
|
|
89
|
-
body: expect.stringContaining('"action":"loadPreviousSession"') as unknown,
|
|
90
|
-
mode: 'cors',
|
|
91
|
-
cache: 'no-cache',
|
|
92
|
-
}),
|
|
93
|
-
);
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
describe('initialMessages', () => {
|
|
98
|
-
it.each(['fullscreen', 'window'] as Array<'fullscreen' | 'window'>)(
|
|
99
|
-
'should show initial default messages in %s mode',
|
|
100
|
-
async (mode) => {
|
|
101
|
-
const fetchSpy = vi.spyOn(window, 'fetch');
|
|
102
|
-
fetchSpy.mockImplementationOnce(createFetchResponse(createGetLatestMessagesResponse()));
|
|
103
|
-
|
|
104
|
-
const initialMessages = ['Hello tester!', 'How are you?'];
|
|
105
|
-
app = createChat({
|
|
106
|
-
mode,
|
|
107
|
-
initialMessages,
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
if (mode === 'window') {
|
|
111
|
-
const trigger = getChatWindowToggle();
|
|
112
|
-
await fireEvent.click(trigger as HTMLElement);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const getStartedButton = getGetStartedButton();
|
|
116
|
-
await fireEvent.click(getStartedButton as HTMLElement);
|
|
117
|
-
|
|
118
|
-
expect(getChatMessages().length).toBe(initialMessages.length);
|
|
119
|
-
expect(getChatMessageByText(initialMessages[0])).toBeInTheDocument();
|
|
120
|
-
expect(getChatMessageByText(initialMessages[1])).toBeInTheDocument();
|
|
121
|
-
},
|
|
122
|
-
);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
describe('sendMessage', () => {
|
|
126
|
-
it.each(['window', 'fullscreen'] as Array<'fullscreen' | 'window'>)(
|
|
127
|
-
'should send a message and render a text message in %s mode',
|
|
128
|
-
async (mode) => {
|
|
129
|
-
const input = 'Hello User World!';
|
|
130
|
-
const output = 'Hello Bot World!';
|
|
131
|
-
|
|
132
|
-
const fetchSpy = vi.spyOn(window, 'fetch');
|
|
133
|
-
fetchSpy
|
|
134
|
-
.mockImplementationOnce(createFetchResponse(createGetLatestMessagesResponse))
|
|
135
|
-
.mockImplementationOnce(createFetchResponse(createSendMessageResponse(output)));
|
|
136
|
-
|
|
137
|
-
app = createChat({
|
|
138
|
-
mode,
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
if (mode === 'window') {
|
|
142
|
-
const trigger = getChatWindowToggle();
|
|
143
|
-
await fireEvent.click(trigger as HTMLElement);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
expect(getChatMessageTyping()).not.toBeInTheDocument();
|
|
147
|
-
|
|
148
|
-
const getStartedButton = getGetStartedButton();
|
|
149
|
-
await fireEvent.click(getStartedButton as HTMLElement);
|
|
150
|
-
|
|
151
|
-
expect(getChatMessages().length).toBe(2);
|
|
152
|
-
|
|
153
|
-
const textarea = getChatInputTextarea();
|
|
154
|
-
const sendButton = getChatInputSendButton();
|
|
155
|
-
await fireEvent.update(textarea as HTMLElement, input);
|
|
156
|
-
expect(sendButton).not.toBeDisabled();
|
|
157
|
-
await fireEvent.click(sendButton as HTMLElement);
|
|
158
|
-
|
|
159
|
-
expect(fetchSpy.mock.calls[1][1]).toEqual(
|
|
160
|
-
expect.objectContaining({
|
|
161
|
-
method: 'POST',
|
|
162
|
-
headers: {},
|
|
163
|
-
body: expect.stringMatching(/"action":"sendMessage"/) as unknown,
|
|
164
|
-
mode: 'cors',
|
|
165
|
-
cache: 'no-cache',
|
|
166
|
-
}),
|
|
167
|
-
);
|
|
168
|
-
expect(fetchSpy.mock.calls[1][1]?.body).toContain(`"${input}"`);
|
|
169
|
-
|
|
170
|
-
expect(getChatMessages().length).toBe(3);
|
|
171
|
-
expect(getChatMessageByText(input)).toBeInTheDocument();
|
|
172
|
-
expect(getChatMessageTyping()).toBeVisible();
|
|
173
|
-
|
|
174
|
-
await waitFor(() => expect(getChatMessageTyping()).not.toBeInTheDocument());
|
|
175
|
-
expect(getChatMessageByText(output)).toBeInTheDocument();
|
|
176
|
-
},
|
|
177
|
-
);
|
|
178
|
-
|
|
179
|
-
it.each(['fullscreen', 'window'] as Array<'fullscreen' | 'window'>)(
|
|
180
|
-
'should send a message and render a code markdown message in %s mode',
|
|
181
|
-
async (mode) => {
|
|
182
|
-
const input = 'Teach me javascript!';
|
|
183
|
-
const output = '# Code\n```js\nconsole.log("Hello World!");\n```';
|
|
184
|
-
|
|
185
|
-
const chatStore = useChat();
|
|
186
|
-
console.log(chatStore);
|
|
187
|
-
|
|
188
|
-
const fetchSpy = vi.spyOn(window, 'fetch');
|
|
189
|
-
fetchSpy
|
|
190
|
-
.mockImplementationOnce(createFetchResponse(createGetLatestMessagesResponse))
|
|
191
|
-
.mockImplementationOnce(createFetchResponse(createSendMessageResponse(output)));
|
|
192
|
-
|
|
193
|
-
app = createChat({
|
|
194
|
-
mode,
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
if (mode === 'window') {
|
|
198
|
-
const trigger = getChatWindowToggle();
|
|
199
|
-
await fireEvent.click(trigger as HTMLElement);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const getStartedButton = getGetStartedButton();
|
|
203
|
-
await fireEvent.click(getStartedButton as HTMLElement);
|
|
204
|
-
|
|
205
|
-
const textarea = getChatInputTextarea();
|
|
206
|
-
const sendButton = getChatInputSendButton();
|
|
207
|
-
await fireEvent.update(textarea as HTMLElement, input);
|
|
208
|
-
await fireEvent.click(sendButton as HTMLElement);
|
|
209
|
-
|
|
210
|
-
expect(getChatMessageByText(input)).toBeInTheDocument();
|
|
211
|
-
expect(getChatMessages().length).toBe(3);
|
|
212
|
-
|
|
213
|
-
await waitFor(() => expect(getChatMessageTyping()).not.toBeInTheDocument());
|
|
214
|
-
|
|
215
|
-
const lastMessage = getChatMessage(-1);
|
|
216
|
-
expect(lastMessage).toBeInTheDocument();
|
|
217
|
-
|
|
218
|
-
expect(lastMessage.querySelector('h1')).toHaveTextContent('Code');
|
|
219
|
-
expect(lastMessage.querySelector('code')).toHaveTextContent('console.log("Hello World!");');
|
|
220
|
-
},
|
|
221
|
-
);
|
|
222
|
-
});
|
|
223
|
-
});
|
package/src/__tests__/setup.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import '@testing-library/jest-dom';
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { createChat } from '@/index';
|
|
2
|
-
|
|
3
|
-
export function createTestChat(options: Parameters<typeof createChat>[0] = {}): {
|
|
4
|
-
unmount: () => void;
|
|
5
|
-
container: Element;
|
|
6
|
-
} {
|
|
7
|
-
const app = createChat(options);
|
|
8
|
-
|
|
9
|
-
const container = app._container as Element;
|
|
10
|
-
const unmount = () => app.unmount();
|
|
11
|
-
|
|
12
|
-
return {
|
|
13
|
-
unmount,
|
|
14
|
-
container,
|
|
15
|
-
};
|
|
16
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { LoadPreviousSessionResponse, SendMessageResponse } from '@/types';
|
|
2
|
-
|
|
3
|
-
export function createFetchResponse<T>(data: T) {
|
|
4
|
-
return async () =>
|
|
5
|
-
({
|
|
6
|
-
json: async () => new Promise<T>((resolve) => resolve(data)),
|
|
7
|
-
}) as Response;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export const createGetLatestMessagesResponse = (
|
|
11
|
-
data: LoadPreviousSessionResponse['data'] = [],
|
|
12
|
-
): LoadPreviousSessionResponse => ({ data });
|
|
13
|
-
|
|
14
|
-
export const createSendMessageResponse = (
|
|
15
|
-
output: SendMessageResponse['output'],
|
|
16
|
-
): SendMessageResponse => ({
|
|
17
|
-
output,
|
|
18
|
-
});
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { screen } from '@testing-library/vue';
|
|
2
|
-
import { defaultMountingTarget } from '@/constants';
|
|
3
|
-
|
|
4
|
-
export function getMountingTarget(target = defaultMountingTarget) {
|
|
5
|
-
return document.querySelector(target);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function getChatWindowWrapper() {
|
|
9
|
-
return document.querySelector('.chat-window-wrapper');
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function getChatWindowToggle() {
|
|
13
|
-
return document.querySelector('.chat-window-toggle');
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function getChatWrapper() {
|
|
17
|
-
return document.querySelector('.chat-wrapper');
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function getChatMessages() {
|
|
21
|
-
return document.querySelectorAll('.chat-message:not(.chat-message-typing)');
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function getChatMessage(index: number) {
|
|
25
|
-
const messages = getChatMessages();
|
|
26
|
-
return index < 0 ? messages[messages.length + index] : messages[index];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function getChatMessageByText(text: string) {
|
|
30
|
-
return screen.queryByText(text, {
|
|
31
|
-
selector: '.chat-message:not(.chat-message-typing) .chat-message-markdown p',
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function getChatMessageTyping() {
|
|
36
|
-
return document.querySelector('.chat-message-typing');
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function getGetStartedButton() {
|
|
40
|
-
return document.querySelector('.chat-get-started .chat-button');
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function getChatInput() {
|
|
44
|
-
return document.querySelector('.chat-input');
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function getChatInputTextarea() {
|
|
48
|
-
return document.querySelector('.chat-input textarea');
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function getChatInputSendButton() {
|
|
52
|
-
return document.querySelector('.chat-input .chat-input-send-button');
|
|
53
|
-
}
|