Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
140 / 140
n/a
0 / 0
CRAP
n/a
0 / 0
1<?php
2
3// ╔════════════════════════════════════════════════════════════╗
4// ║ MIT Licence (#Expat) - https://opensource.org/licenses/MIT ║
5// ║ Copyright 2026 Frederic Poeydomenge <dyno@phexium.com>     ║
6// ╚════════════════════════════════════════════════════════════╝
7
8declare(strict_types=1);
9
10pest()->group('unit');
11
12use Phexium\Plugin\Mailer\EmailAddress;
13use Phexium\Plugin\Mailer\InvalidMessageException;
14use Phexium\Plugin\Mailer\Message;
15use Phexium\Plugin\Mailer\MessageBuilder;
16
17describe('Building', function (): void {
18    it('builds minimal message', function (): void {
19        $message = MessageBuilder::create()
20            ->from('sender@example.com')
21            ->to('recipient@example.com')
22            ->subject('Hello')
23            ->textBody('Hello World')
24            ->build()
25        ;
26
27        expect($message)->toBeInstanceOf(Message::class);
28        expect($message->from->getAddress())->toBe('sender@example.com');
29        expect($message->to)->toHaveCount(1);
30        expect($message->to[0]->getAddress())->toBe('recipient@example.com');
31        expect($message->subject)->toBe('Hello');
32        expect($message->textBody)->toBe('Hello World');
33        expect($message->htmlBody)->toBeNull();
34        expect($message->cc)->toBe([]);
35        expect($message->bcc)->toBe([]);
36        expect($message->replyTo)->toBeNull();
37        expect($message->attachments)->toBe([]);
38        expect($message->headers)->toBe([]);
39    });
40
41    it('builds message with all fields', function (): void {
42        $message = MessageBuilder::create()
43            ->from('sender@example.com', 'Sender')
44            ->to('to@example.com', 'Recipient')
45            ->cc('cc@example.com')
46            ->bcc('bcc@example.com')
47            ->replyTo('reply@example.com', 'Reply')
48            ->subject('Full message')
49            ->textBody('Text body')
50            ->htmlBody('<p>HTML body</p>')
51            ->header('X-Custom', 'value')
52            ->build()
53        ;
54
55        expect($message->from->getName())->toBe('Sender');
56        expect($message->to)->toHaveCount(1);
57        expect($message->cc)->toHaveCount(1);
58        expect($message->bcc)->toHaveCount(1);
59        expect($message->replyTo->getAddress())->toBe('reply@example.com');
60        expect($message->textBody)->toBe('Text body');
61        expect($message->htmlBody)->toBe('<p>HTML body</p>');
62        expect($message->headers)->toHaveCount(1);
63    });
64
65    it('supports multiple to/cc/bcc', function (): void {
66        $message = MessageBuilder::create()
67            ->from('sender@example.com')
68            ->to('to1@example.com')
69            ->to('to2@example.com')
70            ->cc('cc1@example.com')
71            ->cc('cc2@example.com')
72            ->bcc('bcc1@example.com')
73            ->bcc('bcc2@example.com')
74            ->subject('Multiple recipients')
75            ->textBody('Body')
76            ->build()
77        ;
78
79        expect($message->to)->toHaveCount(2);
80        expect($message->cc)->toHaveCount(2);
81        expect($message->bcc)->toHaveCount(2);
82    });
83
84    it('builds with htmlBody only', function (): void {
85        $message = MessageBuilder::create()
86            ->from('sender@example.com')
87            ->to('to@example.com')
88            ->subject('HTML only')
89            ->htmlBody('<p>HTML</p>')
90            ->build()
91        ;
92
93        expect($message->textBody)->toBeNull();
94        expect($message->htmlBody)->toBe('<p>HTML</p>');
95    });
96
97    it('accepts EmailAddress objects', function (): void {
98        $from = EmailAddress::withEmail('sender@example.com')->withName('Sender');
99        $to = EmailAddress::withEmail('to@example.com');
100
101        $message = MessageBuilder::create()
102            ->from($from)
103            ->to($to)
104            ->subject('With objects')
105            ->textBody('Body')
106            ->build()
107        ;
108
109        expect($message->from->getName())->toBe('Sender');
110        expect($message->to[0]->getAddress())->toBe('to@example.com');
111    });
112
113    it('builds with attachments', function (): void {
114        $message = MessageBuilder::create()
115            ->from('sender@example.com')
116            ->to('to@example.com')
117            ->subject('With attachments')
118            ->textBody('Body')
119            ->attach(__FILE__)
120            ->attachContent('binary-data', 'report.pdf', 'application/pdf')
121            ->build()
122        ;
123
124        expect($message->attachments)->toHaveCount(2);
125        expect($message->attachments[0]->isFile())->toBeTrue();
126        expect($message->attachments[1]->isFile())->toBeFalse();
127        expect($message->attachments[1]->getFilename())->toBe('report.pdf');
128    });
129});
130
131describe('Validation', function (): void {
132    it('rejects missing from', function (): void {
133        expect(
134            fn (): Message => MessageBuilder::create()
135                ->to('to@example.com')
136                ->subject('No sender')
137                ->textBody('Body')
138                ->build()
139        )->toThrow(InvalidMessageException::class);
140    });
141
142    it('rejects missing to', function (): void {
143        expect(
144            fn (): Message => MessageBuilder::create()
145                ->from('sender@example.com')
146                ->subject('No recipient')
147                ->textBody('Body')
148                ->build()
149        )->toThrow(InvalidMessageException::class);
150    });
151
152    it('rejects missing subject', function (): void {
153        expect(
154            fn (): Message => MessageBuilder::create()
155                ->from('sender@example.com')
156                ->to('to@example.com')
157                ->textBody('Body')
158                ->build()
159        )->toThrow(InvalidMessageException::class);
160    });
161
162    it('rejects missing body', function (): void {
163        expect(
164            fn (): Message => MessageBuilder::create()
165                ->from('sender@example.com')
166                ->to('to@example.com')
167                ->subject('No body')
168                ->build()
169        )->toThrow(InvalidMessageException::class);
170    });
171});