Files
2026-07-13 13:34:48 +08:00

266 lines
7.4 KiB
TypeScript

import { expect, test } from 'vitest'
import _ from 'lodash'
import * as utils from './utils'
import * as config from './config'
import * as chat from '../src'
const apiUrl = config.get('API_URL')
const encryptionKey = config.get('ENCRYPTION_KEY')
const serverEventsProtocols = ['sse', 'websocket'] as const
type CheckApiCanSendAndReceiveMessagesProps = {
client: chat.AuthenticatedClient
conversationId: string
protocol: chat.ServerEventsProtocol
}
type MessagePayload = chat.AuthenticatedClientRequests['createMessage']['payload']
const checkApiCanSendAndReceiveMessages = async (
props: CheckApiCanSendAndReceiveMessagesProps,
payload: MessagePayload
): Promise<MessagePayload> => {
const { client, conversationId } = props
const listener = await client.listenConversation({
id: conversationId,
protocol: props.protocol,
})
const waitForResponsePromise = new Promise<chat.Signals['message_created']>((resolve) => {
listener.onceOrMore('message_created', (ev) => {
if (ev.userId === client.user.id) {
return 'keep-listening'
}
resolve(ev)
return 'stop-listening'
})
})
const createMessageRequest: chat.AuthenticatedClientRequests['createMessage'] = {
conversationId: conversationId,
payload,
}
const createMessagePromise = client.createMessage(createMessageRequest).then((res) => res.message)
const [{ isBot, ...messageReceived }, messageSent] = await Promise.all([waitForResponsePromise, createMessagePromise])
const { messages } = await client
.listMessages({
conversationId,
})
.then(({ messages }) => ({
messages: _.sortBy(messages, (m) => new Date(m.createdAt).getTime()),
}))
expect(messages.length).toBe(2)
expect(messages[0]).toEqual(messageSent)
expect(messages[1]).toEqual(messageReceived)
return messageReceived.payload
}
test.each(serverEventsProtocols)('api allows sending and receiving messages using botpress IDs', async (protocol) => {
const client = await chat.Client.connect({ apiUrl })
const {
conversation: { id: conversationId },
} = await client.createConversation({})
await checkApiCanSendAndReceiveMessages(
{
client,
conversationId,
protocol,
},
{
type: 'text',
text: 'hello world',
}
)
})
test.each(serverEventsProtocols)('api allows sending and receiving messages using foreign IDs', async (protocol) => {
const userId = utils.getUserFid()
const conversationId = utils.getConversationFid()
const client = await chat.Client.connect({ apiUrl, userId })
await client.createConversation({ id: conversationId })
await checkApiCanSendAndReceiveMessages(
{
client,
conversationId,
protocol,
},
{
type: 'text',
text: 'hello world',
}
)
})
test.each(serverEventsProtocols)(
'api allows sending and receiving messages using remotly generated JWTs',
async (protocol) => {
const userId = utils.getUserFid()
const conversationId = utils.getConversationFid()
const client = await chat.Client.connect({ apiUrl, userId, encryptionKey })
await client.getOrCreateConversation({ id: conversationId })
await checkApiCanSendAndReceiveMessages(
{
client,
conversationId,
protocol,
},
{
type: 'text',
text: 'hello world',
}
)
}
)
test.each(serverEventsProtocols)('api allows deleting a message', async (protocol) => {
const client = await chat.Client.connect({ apiUrl })
const { conversation } = await client.createConversation({})
const signalListener = await client.listenConversation({ id: conversation.id, protocol })
const [{ isBot, ...createdMessage }] = await Promise.all([
utils.waitFor(signalListener, 'message_created'),
client.createMessage({
conversationId: conversation.id,
payload: {
type: 'text',
text: 'hello world',
},
}),
])
const { message: fetchedMessage } = await client.getMessage({
id: createdMessage.id,
})
expect(fetchedMessage).toEqual(createdMessage)
const [deletedMessage] = await Promise.all([
utils.waitFor(signalListener, 'message_deleted'),
client.deleteMessage({
id: createdMessage.id,
}),
])
expect(deletedMessage.id).toEqual(createdMessage.id)
await expect(
client.getMessage({
id: createdMessage.id,
})
).rejects.toThrow(chat.ResourceNotFoundError)
})
test.each(serverEventsProtocols)('api allows sending and receiving messages with metadata', async (protocol) => {
type Message = Awaited<ReturnType<chat.Client['listMessages']>>['messages'][number]
const metadata = { foo: 'bar' }
const client = await chat.Client.connect({ apiUrl })
const { conversation } = await client.createConversation({})
const { id: conversationId } = conversation
const sendMessagePromise = client.createMessage({
conversationId,
payload: { type: 'text', text: 'metadata' }, // hello-bot forwards metadata when message is 'metadata'
metadata,
})
const listener = await client.listenConversation({ id: conversationId, protocol })
const receiveSelfMessagePromise = new Promise<Message>((resolve) =>
listener.on('message_created', (m) => {
if (m.userId === client.user.id) {
resolve(m)
}
})
)
const receiveBotMessagePromise = new Promise<Message>((resolve) =>
listener.on('message_created', (m) => {
if (m.userId !== client.user.id) {
resolve(m)
}
})
)
const [sentMessage, receivedSelfMessage, receivedBotMessage] = await Promise.all([
sendMessagePromise,
receiveSelfMessagePromise,
receiveBotMessagePromise,
])
expect(sentMessage.message.metadata).toEqual(metadata)
expect(receivedSelfMessage.metadata).toEqual(metadata)
expect(receivedBotMessage.metadata).toEqual(metadata)
expect(sentMessage.message.payload).not.toHaveProperty('metadata')
expect(receivedSelfMessage.payload).not.toHaveProperty('metadata')
expect(receivedBotMessage.payload).not.toHaveProperty('metadata')
const fetchedMessages = await client.listMessages({ conversationId }).then((r) => r.messages)
const fetchedSelfMessages = fetchedMessages.filter((m) => m.userId === client.user.id)
expect(fetchedSelfMessages.length).toBe(1)
const [fetchedSelfMessage] = fetchedSelfMessages
expect(fetchedSelfMessage!.metadata).toEqual(metadata)
})
test.each(serverEventsProtocols)('api allows sending bloc messages', async (protocol) => {
const client = await chat.Client.connect({ apiUrl })
const {
conversation: { id: conversationId },
} = await client.createConversation({})
await checkApiCanSendAndReceiveMessages(
{
client,
conversationId,
protocol,
},
{
type: 'bloc',
items: [
{
type: 'text',
text: 'hello world',
},
{
type: 'image',
imageUrl: 'https://fastly.picsum.photos/id/329/200/300.jpg?hmac=_yLyj0EqdpQ-cX84OlMxz3YzOjjd7liq6b25ldkVSpA',
},
],
}
)
})
test.each(serverEventsProtocols)('api allows receiving bloc messages from bot', async (protocol) => {
const client = await chat.Client.connect({ apiUrl })
const {
conversation: { id: conversationId },
} = await client.createConversation({})
const responsePayload: MessagePayload = await checkApiCanSendAndReceiveMessages(
{ client, conversationId, protocol },
{ type: 'text', text: 'bloc' }
)
expect(responsePayload.type).toEqual('bloc')
expect(responsePayload.items.length).toEqual(3)
})