266 lines
7.4 KiB
TypeScript
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)
|
|
})
|