Issues (39)

tests/SparkPostTest.php (3 issues)

1
<?php
2
3
namespace LeKoala\SparkPost\Test;
4
5
use LeKoala\Base\Email\EmailHelper;
0 ignored issues
show
The type LeKoala\Base\Email\EmailHelper was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use LeKoala\SparkPost\SparkPostApiTransport;
7
use SilverStripe\Core\Environment;
8
use SilverStripe\Dev\SapphireTest;
9
use SilverStripe\Control\Email\Email;
10
use LeKoala\SparkPost\SparkPostHelper;
11
use SilverStripe\Core\Injector\Injector;
12
use Symfony\Component\Mailer\Envelope;
13
use Symfony\Component\Mailer\MailerInterface;
14
use Symfony\Component\Mime\Address;
15
16
/**
17
 * Test for SparkPost
18
 *
19
 * @group SparkPost
20
 */
21
class SparkPostTest extends SapphireTest
22
{
23
    /**
24
     * @var MailerInterface
25
     */
26
    protected $testMailer;
27
    protected bool $isDummy = false;
28
29
    protected function setUp(): void
30
    {
31
        parent::setUp();
32
33
        // add dummy api key
34
        if (!SparkPostHelper::getAPIKey()) {
35
            $this->isDummy = true;
36
            SparkPostHelper::config()->api_key = "dummy";
37
        }
38
39
        $this->testMailer = Injector::inst()->get(MailerInterface::class);
40
    }
41
42
    protected function tearDown(): void
43
    {
44
        parent::tearDown();
45
46
        Injector::inst()->registerService($this->testMailer, MailerInterface::class);
47
    }
48
49
    public function testSetup(): void
50
    {
51
        $inst = SparkPostHelper::registerTransport();
52
        $mailer = SparkPostHelper::getMailer();
53
        $instClass = get_class($inst);
54
        $instMailer = get_class($mailer);
55
        $this->assertEquals($instClass, $instMailer);
56
    }
57
58
    public function testClient(): void
59
    {
60
        $client = SparkPostHelper::getClient();
61
62
        if ($this->isDummy) {
63
            $this->assertTrue(true);
64
        } else {
65
            $result = $client->listAllSendingDomains();
66
            $this->assertTrue(is_array($result));
67
        }
68
    }
69
70
    public function testTLSVersion(): void
71
    {
72
        $ch = curl_init();
73
        // This fixes ca cert issues if server is not configured properly
74
        $cainfo = ini_get('curl.cainfo');
75
        if (is_string($cainfo) && strlen($cainfo) === 0) {
76
            curl_setopt($ch, CURLOPT_CAINFO, \Composer\CaBundle\CaBundle::getBundledCaBundlePath());
77
        }
78
        curl_setopt($ch, CURLOPT_URL, 'https://www.howsmyssl.com/a/check');
79
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
80
        $data = curl_exec($ch);
81
        if (!$data) {
82
            $this->markTestIncomplete('Error: "' . curl_error($ch) . '" - Code: ' . curl_errno($ch));
83
        }
84
        curl_close($ch);
85
        if (is_string($data)) {
86
            $json = json_decode($data);
87
            $this->assertNotEquals("TLS 1.0", $json->tls_version);
88
        }
89
    }
90
91
    public function testSendAllTo(): void
92
    {
93
        $sendAllTo = Environment::getEnv('SS_SEND_ALL_EMAILS_TO');
94
95
        $mailer = SparkPostHelper::registerTransport();
96
97
        $email = new Email();
98
        $email->setSubject('Test email');
99
        $email->setBody("Body of my email");
100
        $email->getHeaders()->addTextHeader('X-SendingDisabled', "true");
101
        $email->setTo("[email protected]");
102
103
        // This is async, therefore it does not return anything anymore
104
        $email->send();
105
106
        /** @var \LeKoala\SparkPost\SparkPostApiTransport $transport */
107
        $transport = SparkPostHelper::getTransportFromMailer($mailer);
108
        $result = $transport->getApiResult();
109
110
        // if we have a send all to, it should match
111
        $realRecipient = $sendAllTo ? $sendAllTo : "[email protected]";
112
        $this->assertEquals($realRecipient, $result["email"]);
113
114
        Environment::setEnv("SS_SEND_ALL_EMAILS_TO", "[email protected]");
115
116
        $email->send();
117
        $result = $transport->getApiResult();
118
119
        $this->assertEquals("[email protected]", $result["email"]);
120
121
        // reset env
122
        Environment::setEnv("SS_SEND_ALL_EMAILS_TO", $sendAllTo);
123
    }
124
125
    public function testSending(): void
126
    {
127
        $test_to = Environment::getEnv('SPARKPOST_TEST_TO');
128
        $test_from = Environment::getEnv('SPARKPOST_TEST_FROM');
129
130
        $mailer = SparkPostHelper::registerTransport();
131
132
        $email = new Email();
133
        $email->setSubject('Test email');
134
        $email->setBody("Body of my email");
135
136
        if (!$test_from || !$test_to || $this->isDummy) {
137
            $test_to = "example@localhost";
138
            $test_from =  "sender@localhost";
139
            // don't try to send it for real
140
            $email->getHeaders()->addTextHeader('X-SendingDisabled', "true");
141
        }
142
        $email->setTo($test_to);
143
        $email->setFrom($test_from);
144
145
        // This is async, therefore it does not return anything anymore
146
        $email->send();
147
148
        /** @var \LeKoala\SparkPost\SparkPostApiTransport $transport */
149
        $transport = SparkPostHelper::getTransportFromMailer($mailer);
150
        $result = $transport->getApiResult();
151
152
        $this->assertEquals(1, $result['total_accepted_recipients']);
153
    }
154
155
    public function testPayload(): void
156
    {
157
        $mailer = SparkPostHelper::registerTransport();
158
        /** @var \LeKoala\SparkPost\SparkPostApiTransport $transport */
159
        $transport = SparkPostHelper::getTransportFromMailer($mailer);
160
161
162
        $html = <<<HTML
163
<!DOCTYPE html>
164
<html>
165
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><style type="text/css">.red {color:red;}</style></head>
166
<body><span class="red">red</span></body>
167
</html>
168
HTML;
169
        $result = <<<HTML
170
<!DOCTYPE html>
171
<html>
172
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head>
173
<body><span class="red" style="color: red;">red</span></body>
174
</html>
175
176
HTML;
177
178
        $sender = new Address('[email protected]', "testman");
179
        $recipients = [
180
            new Address('[email protected]', "testrec"),
181
        ];
182
        $email = new Email();
183
        $email->setBody($html);
184
        $envelope = new Envelope($sender, $recipients);
185
        $payload = $transport->getPayload($email, $envelope);
186
        $content = $payload['content'];
187
188
        $payloadRecipients = $payload['recipients'][0];
189
        $this->assertEquals("testrec", $recipients[0]->getName());
190
        $this->assertEquals(
191
            [
192
                'address' => [
193
                    'email' => '[email protected]',
194
                    'name' => 'rec' // extracted from email due to how recipients work
195
                ]
196
            ],
197
            $payloadRecipients
198
        );
199
        $payloadSender = $content['from'];
200
        $this->assertEquals([
201
            'email' => '[email protected]',
202
            'name' => 'testman'
203
        ], $payloadSender);
204
205
        // Make sure our styles are properly inlined
206
        $this->assertEquals('red', $content['text']);
207
        $this->assertEquals($result, $content['html']);
208
    }
209
210
    public function testMeta()
211
    {
212
        $meta = [
213
            'TestID' => 1,
214
            'SomeText' => 'test',
215
        ];
216
        $wrongMeta = [
217
            'WrongMeta' => true
218
        ];
219
        $tags = ['test-tag'];
220
221
        // Meta can be set using the mandrill compat layer
222
        $email = new Email();
223
        // meta is json encoded
224
        // https://mailchimp.com/developer/transactional/docs/smtp-integration/#x-mc-metadata
225
        $email->getHeaders()->addTextHeader('X-MC-Metadata', json_encode($meta));
226
        // tags are , delimited
227
        // https://mailchimp.com/developer/transactional/docs/smtp-integration/#x-mc-tags
228
        $email->getHeaders()->addTextHeader('X-MC-Tags', implode(',', $tags));
229
        $email->setTo('dummy@localhost');
230
        $client = SparkPostHelper::getClient();
231
        $api = new SparkPostApiTransport($client);
232
233
        $sender = $email->getSender()[0] ?? $email->getFrom()[0] ?? null;
234
        $recipients = $email->getTo();
235
        $envelope ??= new Envelope($sender, $recipients);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $envelope seems to be never defined.
Loading history...
It seems like $sender can also be of type null; however, parameter $sender of Symfony\Component\Mailer\Envelope::__construct() does only seem to accept Symfony\Component\Mime\Address, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

235
        $envelope ??= new Envelope(/** @scrutinizer ignore-type */ $sender, $recipients);
Loading history...
236
        $payload = $api->getPayload($email, $envelope);
237
238
        $metaFromRecipients = $payload['recipients'][0]['metadata'];
239
        $this->assertEquals($meta, $metaFromRecipients);
240
        $tagsFromRecipients = $payload['recipients'][0]['tags'];
241
        $this->assertEquals($tags, $tagsFromRecipients);
242
243
        // Or using the smtp api
244
        // https://developers.sparkpost.com/api/smtp/#header-using-the-x-msys-api-custom-header
245
        $email = new Email();
246
        $msys = [
247
            'metadata' => $meta,
248
            // Tags are available in click/open events. Maximum number of tags is 10 per recipient, 100 system wide.
249
            'tags' => $tags
250
        ];
251
        // It's one big json blob
252
        $email->getHeaders()->addTextHeader('X-MSYS-API', json_encode($msys));
253
        $email->setTo('dummy@localhost');
254
        $client = SparkPostHelper::getClient();
255
        $api = new SparkPostApiTransport($client);
256
257
        $sender = $email->getSender()[0] ?? $email->getFrom()[0] ?? null;
258
        $recipients = $email->getTo();
259
        $envelope ??= new Envelope($sender, $recipients);
260
        $payload = $api->getPayload($email, $envelope);
261
262
        $metaFromRecipients = $payload['recipients'][0]['metadata'];
263
        $this->assertEquals($meta, $metaFromRecipients);
264
        $tagsFromRecipients = $payload['recipients'][0]['tags'];
265
        $this->assertEquals($tags, $tagsFromRecipients);
266
267
        // Beware of settings headers multiple times
268
269
        $email = new Email();
270
        $email->getHeaders()->addTextHeader('X-MC-Metadata', json_encode($wrongMeta));
271
        $email->getHeaders()->addTextHeader('X-MC-Metadata', json_encode($meta));
272
        $email->setTo('dummy@localhost');
273
        $client = SparkPostHelper::getClient();
274
        $api = new SparkPostApiTransport($client);
275
276
        $stringHeaders = $email->getHeaders()->toString();
277
        // It's not a unique header, it appears twice
278
        $this->assertEquals(2, substr_count($stringHeaders, 'X-MC-Metadata'));
279
280
        $sender = $email->getSender()[0] ?? $email->getFrom()[0] ?? null;
281
        $recipients = $email->getTo();
282
        $envelope ??= new Envelope($sender, $recipients);
283
        $payload = $api->getPayload($email, $envelope);
284
285
        $metaFromRecipients = $payload['recipients'][0]['metadata'];
286
        $this->assertEquals($wrongMeta, $metaFromRecipients);
287
        $this->assertNotEquals($meta, $metaFromRecipients);
288
289
        // Instead, use SparkPostHelper::addMetaData that can merge or replace headers
290
291
        $email = new Email();
292
293
        $mergedMeta = array_merge($wrongMeta, $meta);
294
        SparkPostHelper::addMetaData($email, $wrongMeta);
295
        SparkPostHelper::addMetaData($email, $meta);
296
        $email->setTo('dummy@localhost');
297
        $client = SparkPostHelper::getClient();
298
        $api = new SparkPostApiTransport($client);
299
300
        $stringHeaders = $email->getHeaders()->toString();
301
        // Only once!
302
        $this->assertEquals(1, substr_count($stringHeaders, 'X-MC-Metadata'));
303
304
        $sender = $email->getSender()[0] ?? $email->getFrom()[0] ?? null;
305
        $recipients = $email->getTo();
306
        $envelope ??= new Envelope($sender, $recipients);
307
        $payload = $api->getPayload($email, $envelope);
308
309
        $metaFromRecipients = $payload['recipients'][0]['metadata'];
310
        $this->assertEquals($mergedMeta, $metaFromRecipients);
311
312
        SparkPostHelper::addMetaData($email, $wrongMeta, true);
313
        SparkPostHelper::addMetaData($email, $meta, true);
314
        $email->setTo('dummy@localhost');
315
        $client = SparkPostHelper::getClient();
316
        $api = new SparkPostApiTransport($client);
317
318
        $stringHeaders = $email->getHeaders()->toString();
319
        // Only once!
320
        $this->assertEquals(1, substr_count($stringHeaders, 'X-MC-Metadata'));
321
322
        $sender = $email->getSender()[0] ?? $email->getFrom()[0] ?? null;
323
        $recipients = $email->getTo();
324
        $envelope ??= new Envelope($sender, $recipients);
325
        $payload = $api->getPayload($email, $envelope);
326
327
        $metaFromRecipients = $payload['recipients'][0]['metadata'];
328
        $this->assertEquals($meta, $metaFromRecipients);
329
    }
330
}
331