Feat improve testing coverage e2e (#1799)
* fix: ensure proper socket closure and await connection termination in tests * feat(tests): enhance E2E tests for image and video message handling, including downloads and group interactions
This commit is contained in:
committed by
GitHub
parent
0b3b2a88cd
commit
e53fa7b8e5
@@ -45,7 +45,14 @@ export class WebSocketClient extends AbstractSocketClient {
|
||||
return
|
||||
}
|
||||
|
||||
const closePromise = new Promise<void>(resolve => {
|
||||
this.socket?.once('close', resolve)
|
||||
})
|
||||
|
||||
this.socket.close()
|
||||
|
||||
await closePromise
|
||||
|
||||
this.socket = null
|
||||
}
|
||||
send(str: string | Uint8Array, cb?: (err?: Error) => void): boolean {
|
||||
|
||||
@@ -605,7 +605,7 @@ export const makeSocket = (config: SocketConfig) => {
|
||||
})
|
||||
}
|
||||
|
||||
const end = (error: Error | undefined) => {
|
||||
const end = async (error: Error | undefined) => {
|
||||
if (closed) {
|
||||
logger.trace({ trace: error?.stack }, 'connection already closed')
|
||||
return
|
||||
@@ -623,7 +623,7 @@ export const makeSocket = (config: SocketConfig) => {
|
||||
|
||||
if (!ws.isClosed && !ws.isClosing) {
|
||||
try {
|
||||
ws.close()
|
||||
await ws.close()
|
||||
} catch {}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,15 +2,23 @@ import { Boom } from '@hapi/boom'
|
||||
import { jest } from '@jest/globals'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import P from 'pino'
|
||||
import makeWASocket, { DisconnectReason, jidNormalizedUser, proto, useMultiFileAuthState } from '../../index'
|
||||
import makeWASocket, {
|
||||
DisconnectReason,
|
||||
downloadContentFromMessage,
|
||||
downloadMediaMessage,
|
||||
jidNormalizedUser,
|
||||
proto,
|
||||
toBuffer,
|
||||
useMultiFileAuthState
|
||||
} from '../../index'
|
||||
|
||||
jest.setTimeout(30_000)
|
||||
|
||||
describe('E2E Tests', () => {
|
||||
jest.useFakeTimers()
|
||||
|
||||
let sock: ReturnType<typeof makeWASocket>
|
||||
let meJid: string | undefined
|
||||
let meLid: string | undefined
|
||||
let groupJid: string | undefined
|
||||
|
||||
beforeAll(async () => {
|
||||
const { state, saveCreds } = await useMultiFileAuthState('baileys_auth_info')
|
||||
@@ -28,7 +36,20 @@ describe('E2E Tests', () => {
|
||||
const { connection, lastDisconnect } = update
|
||||
if (connection === 'open') {
|
||||
meJid = jidNormalizedUser(sock.user?.id)
|
||||
resolve()
|
||||
meLid = sock.user?.lid
|
||||
|
||||
sock
|
||||
.groupFetchAllParticipating()
|
||||
.then(groups => {
|
||||
const group = Object.values(groups).find(g => g.subject === 'Baileys Group Test')
|
||||
if (group) {
|
||||
groupJid = group.id
|
||||
console.log(`Found test group "${group.subject}" with JID: ${groupJid}`)
|
||||
}
|
||||
|
||||
resolve()
|
||||
})
|
||||
.catch(reject)
|
||||
} else if (connection === 'close') {
|
||||
const reason = (lastDisconnect?.error as Boom)?.output?.statusCode
|
||||
if (reason === DisconnectReason.loggedOut) {
|
||||
@@ -45,14 +66,7 @@ describe('E2E Tests', () => {
|
||||
|
||||
afterAll(async () => {
|
||||
if (sock) {
|
||||
await new Promise<void>(resolve => {
|
||||
sock.ev.on('connection.update', update => {
|
||||
if (update.connection === 'close') {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
sock.end(undefined)
|
||||
})
|
||||
await sock.end(undefined)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -253,10 +267,6 @@ describe('E2E Tests', () => {
|
||||
console.log('Sent poll message:', sentPoll!.key.id)
|
||||
expect(sentPoll?.message?.pollCreationMessageV3).toBeDefined()
|
||||
expect(sentPoll?.message?.pollCreationMessageV3?.name).toBe('E2E Test Poll')
|
||||
|
||||
// This part of the test would require a second participant to vote
|
||||
// and for the test to listen for the poll update message.
|
||||
// For simplicity, we are only testing the sending of the poll here.
|
||||
})
|
||||
|
||||
test('should send a contact (vCard) message', async () => {
|
||||
@@ -279,4 +289,355 @@ describe('E2E Tests', () => {
|
||||
expect(sentMessage!.message?.contactMessage).toBeDefined()
|
||||
expect(sentMessage!.message?.contactMessage?.vcard).toContain('FN:E2E Test Contact')
|
||||
})
|
||||
|
||||
test('should send and download an image message', async () => {
|
||||
const image = readFileSync('./Media/cat.jpeg')
|
||||
const caption = 'E2E Test Image Download Success'
|
||||
|
||||
let listener: ((data: { messages: proto.IWebMessageInfo[] }) => void) | undefined
|
||||
let timeoutId: NodeJS.Timeout | undefined
|
||||
|
||||
try {
|
||||
const receivedMsgPromise = new Promise<proto.IWebMessageInfo>((resolve, reject) => {
|
||||
listener = ({ messages }) => {
|
||||
const msg = messages.find(m => m.message?.imageMessage?.caption === caption)
|
||||
if (msg) {
|
||||
resolve(msg)
|
||||
}
|
||||
}
|
||||
|
||||
timeoutId = setTimeout(() => {
|
||||
reject(new Error('Timed out waiting for the image message to be received'))
|
||||
}, 30_000)
|
||||
|
||||
sock.ev.on('messages.upsert', listener)
|
||||
})
|
||||
|
||||
await sock.sendMessage(meJid!, {
|
||||
image: image,
|
||||
caption: caption
|
||||
})
|
||||
|
||||
const receivedMsg = await receivedMsgPromise
|
||||
|
||||
clearTimeout(timeoutId)
|
||||
timeoutId = undefined
|
||||
|
||||
console.log('Received image message, attempting to download...')
|
||||
|
||||
const buffer = await downloadMediaMessage(
|
||||
receivedMsg,
|
||||
'buffer',
|
||||
{},
|
||||
{
|
||||
logger: sock.logger,
|
||||
reuploadRequest: m => sock.updateMediaMessage(m)
|
||||
}
|
||||
)
|
||||
|
||||
expect(Buffer.isBuffer(buffer)).toBe(true)
|
||||
expect(buffer.length).toBeGreaterThan(0)
|
||||
|
||||
console.log('Successfully downloaded the image.')
|
||||
} finally {
|
||||
if (listener) {
|
||||
sock.ev.off('messages.upsert', listener)
|
||||
}
|
||||
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('should send and download an image message via LID', async () => {
|
||||
console.log(`Testing with self-LID: ${meLid}`)
|
||||
|
||||
const image = readFileSync('./Media/cat.jpeg')
|
||||
const caption = 'E2E Test LID Image Download'
|
||||
|
||||
let listener: ((data: { messages: proto.IWebMessageInfo[] }) => void) | undefined
|
||||
let timeoutId: NodeJS.Timeout | undefined
|
||||
|
||||
try {
|
||||
const receivedMsgPromise = new Promise<proto.IWebMessageInfo>((resolve, reject) => {
|
||||
listener = ({ messages }) => {
|
||||
const msg = messages.find(m => m.message?.imageMessage?.caption === caption)
|
||||
if (msg) {
|
||||
resolve(msg)
|
||||
}
|
||||
}
|
||||
|
||||
timeoutId = setTimeout(() => {
|
||||
reject(new Error('Timed out waiting for the LID image message to be received'))
|
||||
}, 30_000)
|
||||
|
||||
sock.ev.on('messages.upsert', listener)
|
||||
})
|
||||
|
||||
await sock.sendMessage(meLid!, {
|
||||
image: image,
|
||||
caption: caption
|
||||
})
|
||||
|
||||
const receivedMsg = await receivedMsgPromise
|
||||
clearTimeout(timeoutId)
|
||||
timeoutId = undefined
|
||||
|
||||
console.log('Received LID image message, attempting to download...')
|
||||
|
||||
const buffer = await downloadMediaMessage(
|
||||
receivedMsg,
|
||||
'buffer',
|
||||
{},
|
||||
{
|
||||
logger: sock.logger,
|
||||
reuploadRequest: m => sock.updateMediaMessage(m)
|
||||
}
|
||||
)
|
||||
|
||||
expect(Buffer.isBuffer(buffer)).toBe(true)
|
||||
expect(buffer.length).toBeGreaterThan(0)
|
||||
|
||||
console.log('Successfully downloaded the image sent via LID.')
|
||||
} finally {
|
||||
if (listener) {
|
||||
sock.ev.off('messages.upsert', listener)
|
||||
}
|
||||
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('should send and download an image using the low-level downloadContentFromMessage', async () => {
|
||||
const image = readFileSync('./Media/cat.jpeg')
|
||||
const caption = 'E2E Test Low-Level Download'
|
||||
|
||||
let listener: ((data: { messages: proto.IWebMessageInfo[] }) => void) | undefined
|
||||
let timeoutId: NodeJS.Timeout | undefined
|
||||
|
||||
try {
|
||||
const receivedMsgPromise = new Promise<proto.IWebMessageInfo>((resolve, reject) => {
|
||||
listener = ({ messages }) => {
|
||||
const msg = messages.find(m => m.message?.imageMessage?.caption === caption)
|
||||
if (msg) {
|
||||
resolve(msg)
|
||||
}
|
||||
}
|
||||
|
||||
timeoutId = setTimeout(() => {
|
||||
reject(new Error('Timed out waiting for the low-level test message'))
|
||||
}, 30_000)
|
||||
|
||||
sock.ev.on('messages.upsert', listener)
|
||||
})
|
||||
|
||||
await sock.sendMessage(meJid!, {
|
||||
image: image,
|
||||
caption: caption
|
||||
})
|
||||
|
||||
const receivedMsg = await receivedMsgPromise
|
||||
clearTimeout(timeoutId)
|
||||
timeoutId = undefined
|
||||
|
||||
console.log('Received message for low-level download test, preparing to download...')
|
||||
|
||||
const imageMessage = receivedMsg.message?.imageMessage
|
||||
expect(imageMessage).toBeDefined()
|
||||
|
||||
const downloadable: proto.Message.IImageMessage = {
|
||||
url: imageMessage!.url,
|
||||
mediaKey: imageMessage!.mediaKey,
|
||||
directPath: imageMessage!.directPath
|
||||
}
|
||||
|
||||
const stream = await downloadContentFromMessage(downloadable, 'image')
|
||||
const buffer = await toBuffer(stream)
|
||||
|
||||
expect(Buffer.isBuffer(buffer)).toBe(true)
|
||||
expect(buffer.length).toBeGreaterThan(0)
|
||||
|
||||
console.log('Successfully downloaded the image using downloadContentFromMessage.')
|
||||
} finally {
|
||||
if (listener) {
|
||||
sock.ev.off('messages.upsert', listener)
|
||||
}
|
||||
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('should download a quoted image message using downloadContentFromMessage', async () => {
|
||||
const image = readFileSync('./Media/cat.jpeg')
|
||||
const originalCaption = 'This is the original media message'
|
||||
const commandText = '-download'
|
||||
|
||||
let imageListener: ((data: { messages: proto.IWebMessageInfo[] }) => void) | undefined
|
||||
let commandListener: ((data: { messages: proto.IWebMessageInfo[] }) => void) | undefined
|
||||
let timeoutId: NodeJS.Timeout | undefined
|
||||
|
||||
try {
|
||||
console.log('Sending initial image message...')
|
||||
const receivedImagePromise = new Promise<proto.IWebMessageInfo>((resolve, reject) => {
|
||||
imageListener = ({ messages }) => {
|
||||
const msg = messages.find(m => m.message?.imageMessage?.caption === originalCaption)
|
||||
if (msg) resolve(msg)
|
||||
}
|
||||
|
||||
sock.ev.on('messages.upsert', imageListener)
|
||||
timeoutId = setTimeout(() => reject(new Error('Timed out waiting for initial image message')), 30_000)
|
||||
})
|
||||
|
||||
const sentImageMessage = await sock.sendMessage(meJid!, {
|
||||
image: image,
|
||||
caption: originalCaption
|
||||
})
|
||||
await receivedImagePromise
|
||||
clearTimeout(timeoutId)
|
||||
timeoutId = undefined
|
||||
|
||||
if (imageListener) {
|
||||
sock.ev.off('messages.upsert', imageListener)
|
||||
}
|
||||
|
||||
console.log('Initial image message sent and received.')
|
||||
|
||||
console.log('Sending command message as a reply...')
|
||||
const receivedCommandPromise = new Promise<proto.IWebMessageInfo>((resolve, reject) => {
|
||||
commandListener = ({ messages }) => {
|
||||
const msg = messages.find(m => m.message?.extendedTextMessage?.text === commandText)
|
||||
if (msg) resolve(msg)
|
||||
}
|
||||
|
||||
sock.ev.on('messages.upsert', commandListener)
|
||||
timeoutId = setTimeout(() => reject(new Error('Timed out waiting for command message')), 30_000)
|
||||
})
|
||||
|
||||
await sock.sendMessage(meJid!, { text: commandText }, { quoted: sentImageMessage })
|
||||
const receivedCommandMessage = await receivedCommandPromise
|
||||
clearTimeout(timeoutId)
|
||||
timeoutId = undefined
|
||||
console.log('Command message received.')
|
||||
|
||||
console.log('Extracting quoted message and attempting download...')
|
||||
|
||||
const quotedMessage = receivedCommandMessage.message?.extendedTextMessage?.contextInfo?.quotedMessage
|
||||
expect(quotedMessage).toBeDefined()
|
||||
|
||||
const quotedImage = quotedMessage!.imageMessage
|
||||
expect(quotedImage).toBeDefined()
|
||||
|
||||
const downloadable: proto.Message.IImageMessage = {
|
||||
url: quotedImage!.url,
|
||||
mediaKey: quotedImage!.mediaKey,
|
||||
directPath: quotedImage!.directPath
|
||||
}
|
||||
|
||||
const stream = await downloadContentFromMessage(downloadable, 'image')
|
||||
const buffer = await toBuffer(stream)
|
||||
|
||||
expect(Buffer.isBuffer(buffer)).toBe(true)
|
||||
expect(buffer.length).toBeGreaterThan(0)
|
||||
|
||||
console.log('Successfully downloaded quoted image using downloadContentFromMessage.')
|
||||
} finally {
|
||||
if (imageListener) sock.ev.off('messages.upsert', imageListener)
|
||||
if (commandListener) sock.ev.off('messages.upsert', commandListener)
|
||||
if (timeoutId) clearTimeout(timeoutId)
|
||||
}
|
||||
})
|
||||
|
||||
test('should download a quoted videos message within a group', async () => {
|
||||
if (!groupJid) {
|
||||
console.warn('⚠️ Skipping group test because "Baileys Group Test" was not found.')
|
||||
return
|
||||
}
|
||||
|
||||
const video = readFileSync('./Media/ma_gif.mp4')
|
||||
const originalCaption = 'This is the original media message for the group test'
|
||||
const commandText = '-download group'
|
||||
|
||||
let videoListener: ((data: { messages: proto.IWebMessageInfo[] }) => void) | undefined
|
||||
let commandListener: ((data: { messages: proto.IWebMessageInfo[] }) => void) | undefined
|
||||
let timeoutId: NodeJS.Timeout | undefined
|
||||
|
||||
try {
|
||||
console.log(`Sending initial video message to group ${groupJid}...`)
|
||||
const receivedVideoPromise = new Promise<proto.IWebMessageInfo>((resolve, reject) => {
|
||||
videoListener = ({ messages }) => {
|
||||
const msg = messages.find(
|
||||
m => m.key.remoteJid === groupJid && m.message?.videoMessage?.caption === originalCaption
|
||||
)
|
||||
if (msg) resolve(msg)
|
||||
}
|
||||
|
||||
sock.ev.on('messages.upsert', videoListener)
|
||||
timeoutId = setTimeout(() => reject(new Error('Timed out waiting for initial group image message')), 30_000)
|
||||
})
|
||||
|
||||
const sentVideoMessage = await sock.sendMessage(groupJid, {
|
||||
video: video,
|
||||
caption: originalCaption
|
||||
})
|
||||
await receivedVideoPromise
|
||||
clearTimeout(timeoutId)
|
||||
timeoutId = undefined
|
||||
if (videoListener) sock.ev.off('messages.upsert', videoListener)
|
||||
console.log('Initial group image message sent and received.')
|
||||
|
||||
console.log('Sending command message as a reply in the group...')
|
||||
const receivedCommandPromise = new Promise<proto.IWebMessageInfo>((resolve, reject) => {
|
||||
commandListener = ({ messages }) => {
|
||||
const msg = messages.find(
|
||||
m => m.key.remoteJid === groupJid && m.message?.extendedTextMessage?.text === commandText
|
||||
)
|
||||
if (msg) resolve(msg)
|
||||
}
|
||||
|
||||
sock.ev.on('messages.upsert', commandListener)
|
||||
timeoutId = setTimeout(() => reject(new Error('Timed out waiting for group command message')), 30_000)
|
||||
})
|
||||
|
||||
await sock.sendMessage(groupJid, { text: commandText }, { quoted: sentVideoMessage })
|
||||
const receivedCommandMessage = await receivedCommandPromise
|
||||
clearTimeout(timeoutId)
|
||||
timeoutId = undefined
|
||||
console.log('Group command message received.')
|
||||
|
||||
console.log('Extracting quoted message from group chat and attempting download...')
|
||||
|
||||
const quotedMessage = receivedCommandMessage.message?.extendedTextMessage?.contextInfo?.quotedMessage
|
||||
expect(quotedMessage).toBeDefined()
|
||||
|
||||
console.log('quotedMessage', JSON.stringify(quotedMessage, null, 2))
|
||||
|
||||
const quotedVideo = quotedMessage!.videoMessage
|
||||
expect(quotedVideo).toBeDefined()
|
||||
|
||||
console.log('quotedVideo', JSON.stringify(quotedVideo, null, 2))
|
||||
|
||||
const downloadable: proto.Message.IVideoMessage = {
|
||||
url: quotedVideo!.url,
|
||||
mediaKey: quotedVideo!.mediaKey,
|
||||
directPath: quotedVideo!.directPath
|
||||
}
|
||||
|
||||
const stream = await downloadContentFromMessage(downloadable, 'video')
|
||||
const buffer = await toBuffer(stream)
|
||||
|
||||
expect(Buffer.isBuffer(buffer)).toBe(true)
|
||||
expect(buffer.length).toBeGreaterThan(0)
|
||||
|
||||
console.log('Successfully downloaded quoted image from group message.')
|
||||
} finally {
|
||||
if (videoListener) sock.ev.off('messages.upsert', videoListener)
|
||||
if (commandListener) sock.ev.off('messages.upsert', commandListener)
|
||||
if (timeoutId) clearTimeout(timeoutId)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user