2025-05-24 16:19:19 +00:00
import { tap , expect } from '@git.zone/tstest/tapbundle' ;
import { startTestServer , stopTestServer , type ITestServer } from '../../helpers/server.loader.js' ;
import { createSmtpClient } from '../../../ts/mail/delivery/smtpclient/index.js' ;
import type { SmtpClient } from '../../../ts/mail/delivery/smtpclient/smtp-client.js' ;
import { Email } from '../../../ts/mail/core/classes.email.js' ;
import * as crypto from 'crypto' ;
let testServer : ITestServer ;
let smtpClient : SmtpClient ;
tap . test ( 'setup - start SMTP server for attachment encoding tests' , async ( ) = > {
testServer = await startTestServer ( {
port : 2572 ,
tlsEnabled : false ,
authRequired : false ,
size : 50 * 1024 * 1024 // 50MB for large attachment tests
} ) ;
expect ( testServer . port ) . toEqual ( 2572 ) ;
} ) ;
tap . test ( 'setup - create SMTP client' , async ( ) = > {
smtpClient = createSmtpClient ( {
host : testServer.hostname ,
port : testServer.port ,
secure : false ,
connectionTimeout : 5000 ,
socketTimeout : 120000 , // 2 minutes for large attachments
debug : true
} ) ;
const isConnected = await smtpClient . verify ( ) ;
expect ( isConnected ) . toBeTrue ( ) ;
} ) ;
tap . test ( 'CEP-03: Attachment Encoding - should encode text attachment with base64' , async ( ) = > {
const textContent = 'This is a test text file.\nIt contains multiple lines.\nAnd some special characters: © ® ™' ;
const email = new Email ( {
from : 'sender@example.com' ,
to : 'recipient@example.com' ,
subject : 'Text Attachment Base64 Test' ,
text : 'Email with text attachment' ,
attachments : [ {
filename : 'test.txt' ,
content : Buffer.from ( textContent ) ,
contentType : 'text/plain' ,
encoding : 'base64'
} ]
} ) ;
const result = await smtpClient . sendMail ( email ) ;
expect ( result . success ) . toBeTrue ( ) ;
console . log ( '✅ Text attachment encoded with base64' ) ;
} ) ;
tap . test ( 'CEP-03: Attachment Encoding - should encode binary data correctly' , async ( ) = > {
// Create binary data with all possible byte values
const binaryData = Buffer . alloc ( 256 ) ;
for ( let i = 0 ; i < 256 ; i ++ ) {
binaryData [ i ] = i ;
}
const email = new Email ( {
from : 'sender@example.com' ,
to : 'recipient@example.com' ,
subject : 'Binary Attachment Test' ,
text : 'Email with binary attachment' ,
attachments : [ {
filename : 'binary.dat' ,
content : binaryData ,
contentType : 'application/octet-stream'
} ]
} ) ;
const result = await smtpClient . sendMail ( email ) ;
expect ( result . success ) . toBeTrue ( ) ;
console . log ( '✅ Binary data encoded correctly' ) ;
} ) ;
tap . test ( 'CEP-03: Attachment Encoding - should handle various file types' , async ( ) = > {
const attachments = [
{
filename : 'image.jpg' ,
content : Buffer.from ( '/9j/4AAQSkZJRgABAQEASABIAAD/2wBD' , 'base64' ) , // Partial JPEG header
contentType : 'image/jpeg'
} ,
{
filename : 'document.pdf' ,
content : Buffer.from ( '%PDF-1.4\n%âÃÏÓ\n' , 'utf8' ) ,
contentType : 'application/pdf'
} ,
{
filename : 'archive.zip' ,
content : Buffer.from ( 'PK\x03\x04' ) , // ZIP magic number
contentType : 'application/zip'
} ,
{
filename : 'audio.mp3' ,
content : Buffer.from ( 'ID3' ) , // MP3 ID3 tag
contentType : 'audio/mpeg'
}
] ;
const email = new Email ( {
from : 'sender@example.com' ,
to : 'recipient@example.com' ,
subject : 'Multiple File Types Test' ,
text : 'Testing various attachment types' ,
attachments
} ) ;
const result = await smtpClient . sendMail ( email ) ;
expect ( result . success ) . toBeTrue ( ) ;
console . log ( '✅ Various file types encoded correctly' ) ;
} ) ;
tap . test ( 'CEP-03: Attachment Encoding - should handle quoted-printable encoding' , async ( ) = > {
const textWithSpecialChars = 'This line has special chars: café, naïve, résumé\r\nThis line is very long and might need soft line breaks when encoded with quoted-printable encoding method\r\n=This line starts with equals sign' ;
const email = new Email ( {
from : 'sender@example.com' ,
to : 'recipient@example.com' ,
subject : 'Quoted-Printable Test' ,
text : 'Email with quoted-printable attachment' ,
attachments : [ {
filename : 'special-chars.txt' ,
content : Buffer.from ( textWithSpecialChars , 'utf8' ) ,
contentType : 'text/plain; charset=utf-8' ,
encoding : 'quoted-printable'
} ]
} ) ;
const result = await smtpClient . sendMail ( email ) ;
expect ( result . success ) . toBeTrue ( ) ;
console . log ( '✅ Quoted-printable encoding handled correctly' ) ;
} ) ;
tap . test ( 'CEP-03: Attachment Encoding - should handle content-disposition' , async ( ) = > {
const email = new Email ( {
from : 'sender@example.com' ,
to : 'recipient@example.com' ,
subject : 'Content-Disposition Test' ,
text : 'Testing attachment vs inline disposition' ,
html : '<p>Image below: <img src="cid:inline-image"></p>' ,
attachments : [
{
filename : 'attachment.txt' ,
content : Buffer.from ( 'This is an attachment' ) ,
contentType : 'text/plain'
// Default disposition is 'attachment'
} ,
{
filename : 'inline-image.png' ,
content : Buffer.from ( 'fake png data' ) ,
contentType : 'image/png' ,
contentId : 'inline-image' // Makes it inline
}
]
} ) ;
const result = await smtpClient . sendMail ( email ) ;
expect ( result . success ) . toBeTrue ( ) ;
console . log ( '✅ Content-disposition handled correctly' ) ;
} ) ;
tap . test ( 'CEP-03: Attachment Encoding - should handle large attachments efficiently' , async ( ) = > {
// Create a 10MB attachment
const largeSize = 10 * 1024 * 1024 ;
const largeData = crypto . randomBytes ( largeSize ) ;
const email = new Email ( {
from : 'sender@example.com' ,
to : 'recipient@example.com' ,
subject : 'Large Attachment Test' ,
text : 'Email with large attachment' ,
attachments : [ {
filename : 'large-file.bin' ,
content : largeData ,
contentType : 'application/octet-stream'
} ]
} ) ;
const startTime = Date . now ( ) ;
const result = await smtpClient . sendMail ( email ) ;
const duration = Date . now ( ) - startTime ;
expect ( result . success ) . toBeTrue ( ) ;
console . log ( ` ✅ Large attachment ( ${ largeSize / 1024 / 1024 } MB) sent in ${ duration } ms ` ) ;
console . log ( ` Throughput: ${ ( largeSize / 1024 / 1024 / ( duration / 1000 ) ) . toFixed ( 2 ) } MB/s ` ) ;
} ) ;
tap . test ( 'CEP-03: Attachment Encoding - should handle Unicode filenames' , async ( ) = > {
const unicodeAttachments = [
{
filename : '文档.txt' , // Chinese
content : Buffer.from ( 'Chinese filename test' ) ,
contentType : 'text/plain'
} ,
{
filename : 'файл.txt' , // Russian
content : Buffer.from ( 'Russian filename test' ) ,
contentType : 'text/plain'
} ,
{
filename : 'ファイル.txt' , // Japanese
content : Buffer.from ( 'Japanese filename test' ) ,
contentType : 'text/plain'
} ,
{
filename : '🎉emoji🎊.txt' , // Emoji
content : Buffer.from ( 'Emoji filename test' ) ,
contentType : 'text/plain'
}
] ;
const email = new Email ( {
from : 'sender@example.com' ,
to : 'recipient@example.com' ,
subject : 'Unicode Filenames Test' ,
text : 'Testing Unicode characters in filenames' ,
attachments : unicodeAttachments
} ) ;
const result = await smtpClient . sendMail ( email ) ;
expect ( result . success ) . toBeTrue ( ) ;
console . log ( '✅ Unicode filenames encoded correctly' ) ;
} ) ;
tap . test ( 'CEP-03: Attachment Encoding - should handle special MIME headers' , async ( ) = > {
const email = new Email ( {
from : 'sender@example.com' ,
to : 'recipient@example.com' ,
subject : 'MIME Headers Test' ,
text : 'Testing special MIME headers' ,
attachments : [ {
filename : 'report.xml' ,
content : Buffer.from ( '<?xml version="1.0"?><root>test</root>' ) ,
contentType : 'application/xml; charset=utf-8' ,
encoding : 'base64' ,
headers : {
'Content-Description' : 'Monthly Report' ,
'Content-Transfer-Encoding' : 'base64' ,
'Content-ID' : '<report-2024-01@example.com>'
}
} ]
} ) ;
const result = await smtpClient . sendMail ( email ) ;
expect ( result . success ) . toBeTrue ( ) ;
console . log ( '✅ Special MIME headers handled correctly' ) ;
} ) ;
tap . test ( 'CEP-03: Attachment Encoding - should handle attachment size limits' , async ( ) = > {
// Test with attachment near server limit
const nearLimitSize = 45 * 1024 * 1024 ; // 45MB (near 50MB limit)
const nearLimitData = Buffer . alloc ( nearLimitSize ) ;
// Fill with some pattern to avoid compression benefits
for ( let i = 0 ; i < nearLimitSize ; i ++ ) {
nearLimitData [ i ] = i % 256 ;
}
const email = new Email ( {
from : 'sender@example.com' ,
to : 'recipient@example.com' ,
subject : 'Near Size Limit Test' ,
text : 'Testing attachment near size limit' ,
attachments : [ {
filename : 'near-limit.bin' ,
content : nearLimitData ,
contentType : 'application/octet-stream'
} ]
} ) ;
const result = await smtpClient . sendMail ( email ) ;
expect ( result . success ) . toBeTrue ( ) ;
console . log ( ` ✅ Attachment near size limit ( ${ nearLimitSize / 1024 / 1024 } MB) accepted ` ) ;
} ) ;
tap . test ( 'CEP-03: Attachment Encoding - should handle mixed encoding types' , async ( ) = > {
const email = new Email ( {
from : 'sender@example.com' ,
to : 'recipient@example.com' ,
subject : 'Mixed Encoding Test' ,
text : 'Plain text body' ,
html : '<p>HTML body with special chars: café</p>' ,
attachments : [
{
filename : 'base64.bin' ,
content : crypto.randomBytes ( 1024 ) ,
contentType : 'application/octet-stream' ,
encoding : 'base64'
} ,
{
filename : 'quoted.txt' ,
content : Buffer.from ( 'Text with special chars: naïve café résumé' ) ,
contentType : 'text/plain; charset=utf-8' ,
encoding : 'quoted-printable'
} ,
{
filename : '7bit.txt' ,
content : Buffer.from ( 'Simple ASCII text only' ) ,
contentType : 'text/plain' ,
encoding : '7bit'
}
]
} ) ;
const result = await smtpClient . sendMail ( email ) ;
expect ( result . success ) . toBeTrue ( ) ;
console . log ( '✅ Mixed encoding types handled correctly' ) ;
} ) ;
tap . test ( 'cleanup - close SMTP client' , async ( ) = > {
if ( smtpClient && smtpClient . isConnected ( ) ) {
await smtpClient . close ( ) ;
}
} ) ;
tap . test ( 'cleanup - stop SMTP server' , async ( ) = > {
await stopTestServer ( testServer ) ;
} ) ;
2025-05-25 19:05:43 +00:00
export default tap . start ( ) ;