feat(history): complete messaging core before multi-account gateways
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import test from 'node:test'
|
||||
import {
|
||||
encryptEmailPassword,
|
||||
fetchEmailMessages,
|
||||
markEmailUidsSeen,
|
||||
sendEmailMessage,
|
||||
verifyEmailConnection,
|
||||
} from '../src/email.js'
|
||||
|
||||
const enabled = process.env.RUN_EMAIL_PROTOCOL_TEST === '1'
|
||||
|
||||
function channel(account) {
|
||||
return {
|
||||
id: `protocol-${account}`,
|
||||
type: 'email',
|
||||
account,
|
||||
displayName: account.startsWith('sender') ? 'Lingxi Sender' : 'Lingxi Receiver',
|
||||
encryptedPassword: encryptEmailPassword('pwd'),
|
||||
imapHost: process.env.EMAIL_TEST_HOST || '127.0.0.1',
|
||||
imapPort: Number(process.env.EMAIL_TEST_IMAP_PORT || 3143),
|
||||
imapSecure: false,
|
||||
imapFolder: 'INBOX',
|
||||
smtpHost: process.env.EMAIL_TEST_HOST || '127.0.0.1',
|
||||
smtpPort: Number(process.env.EMAIL_TEST_SMTP_PORT || 3025),
|
||||
smtpSecure: false,
|
||||
syncDays: 7,
|
||||
}
|
||||
}
|
||||
|
||||
async function waitForMessage(target, predicate) {
|
||||
for (let attempt = 0; attempt < 20; attempt += 1) {
|
||||
const result = await fetchEmailMessages(target, { full: true })
|
||||
const message = result.messages.find(predicate)
|
||||
if (message) return { message, result }
|
||||
await new Promise((resolve) => setTimeout(resolve, 150))
|
||||
}
|
||||
throw new Error('等待邮件进入 IMAP INBOX 超时')
|
||||
}
|
||||
|
||||
test('真实 SMTP 发件、IMAP 收件、附件解析、已读与回复头', { skip: !enabled }, async () => {
|
||||
process.env.JWT_SECRET ||= 'lingxi-email-protocol-test-secret'
|
||||
const sender = channel('sender@local.test')
|
||||
const receiver = channel('receiver@local.test')
|
||||
const subject = `Lingxi protocol ${Date.now()}`
|
||||
|
||||
const senderCheck = await verifyEmailConnection(sender, 'pwd')
|
||||
const receiverCheck = await verifyEmailConnection(receiver, 'pwd')
|
||||
assert.ok(senderCheck.latencyMs >= 0)
|
||||
assert.ok(receiverCheck.latencyMs >= 0)
|
||||
assert.ok(!sender.encryptedPassword.includes('pwd'))
|
||||
|
||||
const sent = await sendEmailMessage(sender, {
|
||||
to: receiver.account,
|
||||
subject,
|
||||
text: 'Lingxi IMAP/SMTP real protocol message',
|
||||
attachments: [{
|
||||
filename: 'lingxi-proof.txt',
|
||||
content: Buffer.from('real email attachment'),
|
||||
contentType: 'text/plain',
|
||||
}],
|
||||
})
|
||||
assert.ok(sent.messageId)
|
||||
|
||||
const received = await waitForMessage(receiver, (message) => message.subject === subject)
|
||||
assert.equal(received.message.text, 'Lingxi IMAP/SMTP real protocol message')
|
||||
assert.equal(received.message.from.email, sender.account)
|
||||
assert.equal(received.message.attachments.length, 1)
|
||||
assert.equal(received.message.attachments[0].name, 'lingxi-proof.txt')
|
||||
assert.equal(Buffer.from(received.message.attachments[0].base64, 'base64').toString(), 'real email attachment')
|
||||
|
||||
await markEmailUidsSeen(receiver, [received.message.uid])
|
||||
const marked = await fetchEmailMessages(receiver, { full: true })
|
||||
assert.equal(marked.messages.find((message) => message.uid === received.message.uid)?.seen, true)
|
||||
|
||||
const reply = await sendEmailMessage(receiver, {
|
||||
to: sender.account,
|
||||
subject: `Re: ${subject}`,
|
||||
text: 'Reply received by Lingxi',
|
||||
inReplyTo: received.message.messageId,
|
||||
references: [received.message.messageId],
|
||||
})
|
||||
const replyReceived = await waitForMessage(sender, (message) => message.messageId === reply.messageId)
|
||||
assert.equal(replyReceived.message.inReplyTo, received.message.messageId)
|
||||
assert.ok(replyReceived.message.references.includes(received.message.messageId))
|
||||
})
|
||||
Reference in New Issue
Block a user