From 26c07f27f3faa627b28e192d5cf9bbe8c0e52d2e Mon Sep 17 00:00:00 2001 From: John Linhart Date: Wed, 5 Mar 2025 11:29:48 +0100 Subject: [PATCH 1/7] Adding an option to enable/disable Sparkpost tracking --- Config/config.php | 3 ++ EventSubscriber/CallbackSubscriber.php | 2 +- Mailer/Factory/SparkpostTransportFactory.php | 7 ++-- Mailer/Transport/SparkpostTransport.php | 12 ++++--- .../Transport/SparkpostTransportTest.php | 35 +++++++++++++------ 5 files changed, 41 insertions(+), 18 deletions(-) diff --git a/Config/config.php b/Config/config.php index 8cb8d4f..8216c37 100644 --- a/Config/config.php +++ b/Config/config.php @@ -7,4 +7,7 @@ 'description' => 'Sparkpost Mailer Plugin for Mautic', 'version' => '1.0.0', 'author' => 'Acquia', + 'parameters' => [ + 'sparkpost_tracking_enabled' => false, + ], ]; diff --git a/EventSubscriber/CallbackSubscriber.php b/EventSubscriber/CallbackSubscriber.php index 9522870..e7f7087 100644 --- a/EventSubscriber/CallbackSubscriber.php +++ b/EventSubscriber/CallbackSubscriber.php @@ -18,7 +18,7 @@ class CallbackSubscriber implements EventSubscriberInterface { public function __construct( private TransportCallback $transportCallback, - private CoreParametersHelper $coreParametersHelper + private CoreParametersHelper $coreParametersHelper, ) { } diff --git a/Mailer/Factory/SparkpostTransportFactory.php b/Mailer/Factory/SparkpostTransportFactory.php index db8ede6..73ceb94 100644 --- a/Mailer/Factory/SparkpostTransportFactory.php +++ b/Mailer/Factory/SparkpostTransportFactory.php @@ -4,6 +4,7 @@ namespace MauticPlugin\SparkpostBundle\Mailer\Factory; +use Mautic\CoreBundle\Helper\CoreParametersHelper; use Mautic\EmailBundle\Model\TransportCallback; use MauticPlugin\SparkpostBundle\Mailer\Transport\SparkpostTransport; use Psr\Log\LoggerInterface; @@ -21,9 +22,10 @@ class SparkpostTransportFactory extends AbstractTransportFactory public function __construct( private TransportCallback $transportCallback, private TranslatorInterface $translator, + private CoreParametersHelper $coreParametersHelper, EventDispatcherInterface $eventDispatcher, HttpClientInterface $client = null, - LoggerInterface $logger = null + LoggerInterface $logger = null, ) { parent::__construct($eventDispatcher, $client, $logger); } @@ -51,9 +53,10 @@ public function create(Dsn $dsn): TransportInterface $this->getPassword($dsn), $region, $this->transportCallback, + $this->coreParametersHelper, $this->client, $this->dispatcher, - $this->logger + $this->logger, ); } diff --git a/Mailer/Transport/SparkpostTransport.php b/Mailer/Transport/SparkpostTransport.php index ef4eced..3534169 100644 --- a/Mailer/Transport/SparkpostTransport.php +++ b/Mailer/Transport/SparkpostTransport.php @@ -4,6 +4,7 @@ namespace MauticPlugin\SparkpostBundle\Mailer\Transport; +use Mautic\CoreBundle\Helper\CoreParametersHelper; use Mautic\EmailBundle\Helper\MailHelper; use Mautic\EmailBundle\Mailer\Message\MauticMessage; use Mautic\EmailBundle\Mailer\Transport\TokenTransportInterface; @@ -56,9 +57,10 @@ public function __construct( private string $apiKey, string $region, private TransportCallback $callback, + private CoreParametersHelper $coreParametersHelper, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null, - LoggerInterface $logger = null + LoggerInterface $logger = null, ) { parent::__construct($client, $dispatcher, $logger); $this->host = self::SPARK_POST_HOSTS[$region] ?? self::SPARK_POST_HOSTS['us']; @@ -131,6 +133,8 @@ private function getSparkpostPayload(SentMessage $message): array } } + $trackingEnabled = (bool) $this->coreParametersHelper->get('sparkpost_tracking_enabled', false); + return [ 'content' => $this->buildContent($email), 'recipients' => $this->buildRecipients($email, $metadata, $mergeVars), @@ -142,8 +146,8 @@ private function getSparkpostPayload(SentMessage $message): array : [], 'campaign_id' => $this->getCampaignId($metadata, $metadataSet), 'options' => [ - 'open_tracking' => false, - 'click_tracking' => false, + 'open_tracking' => $trackingEnabled, + 'click_tracking' => $trackingEnabled, ], ]; } @@ -367,7 +371,7 @@ private function checkTemplateIsValid(array $payload): void private function getSparkpostResponse( string $endpoint, array $payload, - string $method = Request::METHOD_POST + string $method = Request::METHOD_POST, ): ResponseInterface { return $this->client->request( $method, diff --git a/Tests/Functional/Mailer/Transport/SparkpostTransportTest.php b/Tests/Functional/Mailer/Transport/SparkpostTransportTest.php index 4e4b6e2..c4551e6 100644 --- a/Tests/Functional/Mailer/Transport/SparkpostTransportTest.php +++ b/Tests/Functional/Mailer/Transport/SparkpostTransportTest.php @@ -21,29 +21,33 @@ class SparkpostTransportTest extends MauticMysqlTestCase protected function setUp(): void { - $this->configParams['mailer_dsn'] = 'mautic+sparkpost+api://:some_api@some_host:25?region=us'; - $this->configParams['messenger_dsn_email'] = 'sync://'; - $this->configParams['mailer_custom_headers'] = ['x-global-custom-header' => 'value123']; - $this->configParams['mailer_from_email'] = 'admin@mautic.test'; - $this->configParams['mailer_from_name'] = 'Admin'; + $this->configParams['mailer_dsn'] = 'mautic+sparkpost+api://:some_api@some_host:25?region=us'; + $this->configParams['messenger_dsn_email'] = 'sync://'; + $this->configParams['mailer_custom_headers'] = ['x-global-custom-header' => 'value123']; + $this->configParams['mailer_from_email'] = 'admin@mautic.test'; + $this->configParams['mailer_from_name'] = 'Admin'; + $this->configParams['sparkpost_tracking_enabled'] = $this->getName() === 'testEmailSendToContactSync' ? $this->getProvidedData()[0] : false; parent::setUp(); $this->translator = self::getContainer()->get('translator'); } - public function testEmailSendToContactSync(): void + /** + * @dataProvider provideTrackingConfig + */ + public function testEmailSendToContactSync(bool $expectedTrackingConfig): void { $expectedResponses = [ - function ($method, $url, $options): MockResponse { + function ($method, $url, $options) use ($expectedTrackingConfig): MockResponse { Assert::assertSame(Request::METHOD_POST, $method); Assert::assertSame('https://api.sparkpost.com/api/v1/utils/content-previewer/', $url); - $this->assertSparkpostRequestBody($options['body']); + $this->assertSparkpostRequestBody($options['body'], $expectedTrackingConfig); return new MockResponse('{"results": {"subject": "Hello there!", "html": "This is test body for {contactfield=email}!"}}'); }, - function ($method, $url, $options): MockResponse { + function ($method, $url, $options) use ($expectedTrackingConfig): MockResponse { Assert::assertSame(Request::METHOD_POST, $method); Assert::assertSame('https://api.sparkpost.com/api/v1/transmissions/', $url); - $this->assertSparkpostRequestBody($options['body']); + $this->assertSparkpostRequestBody($options['body'], $expectedTrackingConfig); return new MockResponse('{"results": {"total_rejected_recipients": 0, "total_accepted_recipients": 1, "id": "11668787484950529"}}'); }, @@ -90,6 +94,15 @@ function ($method, $url, $options): MockResponse { Assert::assertSame('', $email->getReplyTo()[0]->getName()); } + /** + * @return array + */ + public function provideTrackingConfig(): iterable + { + yield 'sparkpost_tracking_enabled is TRUE' => [true]; + yield 'sparkpost_tracking_enabled is FALSE' => [false]; + } + public function testTestTransportButton(): void { $expectedResponses = [ @@ -127,7 +140,7 @@ private function assertSparkpostTestRequestBody(string $body): void Assert::assertSame('Hi! This is a test email from Mautic. Testing...testing...1...2...3!', $bodyArray['content']['text']); } - private function assertSparkpostRequestBody(string $body): void + private function assertSparkpostRequestBody(string $body, bool $expectedTrackingConfig): void { $bodyArray = json_decode($body, true); Assert::assertSame('Admin User ', $bodyArray['content']['from']); From a4a474b6717d5f46ffe0b65ea773695dc1ee020a Mon Sep 17 00:00:00 2001 From: John Linhart Date: Wed, 5 Mar 2025 15:01:36 +0100 Subject: [PATCH 2/7] Adding installation and config optioin to the readme --- README.md | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index dcebbbf..f78adb5 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,46 @@ -### Mautic Sparkpost Plugin +# Mautic Sparkpost Plugin This plugin enable Mautic 5 to run Sparkpost as an email transport. Features: - API transport. This transport can send up to 2000 emails per API request which makes it very fast compared to SMTP. - Bounce webhook handling. This plugin will unsubscribe contacts in Mautic based on the hard bounces while Sparkpost will take care of the soft bounce retrieals. +## Installation -#### Mautic Mailer DSN Scheme +There are several ways how to install this plugin. Here are the options from best to worst. + +### Via Composer + +This is the best option for Mautic instances that were installed via Composer (recommended way to install Mautic) + +Steps: +1. `composer install acquia/mc-cs-plugin-sparkpost` +2. `bin/console mautic:plugins:install` + +### Via Git + +This option is useful for development or testing of this plugin as you'll be able to checkout different branches of this repository. + +Steps: +1. `cd plugins` +2. `git clone git@github.com:acquia/mc-cs-plugin-sparkpost.git SparkpostBundle` +3. `cd ..` +4. `bin/console mautic:plugins:install` + +### Via SFTP + +You should reconsider using this method as the other two above are way better, but this is also possible. + +Steps: +1. [Download this plugin](https://github.com/acquia/mc-cs-plugin-sparkpost/archive/refs/heads/main.zip) +2. Rename the folder `mc-cs-plugin-sparkpost-main` to `SparkpostBundle` +3. Upload this folder to the `plugins` directory of your Mautic files. +4. `bin/console mautic:plugins:install` + +## Configuration + +After the plugin is installed go to the Mautic's global configuration, the Email settings and configure the DSN. + +### Mautic Mailer DSN Scheme `mautic+sparkpost+api` #### Mautic Mailer DSN Example @@ -16,7 +51,15 @@ This plugin enable Mautic 5 to run Sparkpost as an email transport. Features: sparkpost-email-dsn-example -### Testing +### Sparkpost tracking + +The Sparkpost tracking is disabled by default as then the email open and clicks would be tracked twice. Once by Sparkpost, second time by Mautic. This can create some unexpected behavior. The Sparkpost tracking is disabled by default, but you can enable it by adding this row to the Mautic configuration file located at `config/local.php`: + +```php +'sparkpost_tracking_enabled' => true, +``` + +## Testing To run all tests `composer phpunit` From 4f67cd9c51f26c5f06c13d3ed8915703dc209e89 Mon Sep 17 00:00:00 2001 From: John Linhart Date: Wed, 5 Mar 2025 15:23:09 +0100 Subject: [PATCH 3/7] CS fix --- Tests/Functional/Mailer/Transport/SparkpostTransportTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Functional/Mailer/Transport/SparkpostTransportTest.php b/Tests/Functional/Mailer/Transport/SparkpostTransportTest.php index c4551e6..d057ed4 100644 --- a/Tests/Functional/Mailer/Transport/SparkpostTransportTest.php +++ b/Tests/Functional/Mailer/Transport/SparkpostTransportTest.php @@ -26,7 +26,7 @@ protected function setUp(): void $this->configParams['mailer_custom_headers'] = ['x-global-custom-header' => 'value123']; $this->configParams['mailer_from_email'] = 'admin@mautic.test'; $this->configParams['mailer_from_name'] = 'Admin'; - $this->configParams['sparkpost_tracking_enabled'] = $this->getName() === 'testEmailSendToContactSync' ? $this->getProvidedData()[0] : false; + $this->configParams['sparkpost_tracking_enabled'] = 'testEmailSendToContactSync' === $this->getName() ? $this->getProvidedData()[0] : false; parent::setUp(); $this->translator = self::getContainer()->get('translator'); } From d99efa8090d331dfd4e11053e89c914cd5ea9ed9 Mon Sep 17 00:00:00 2001 From: John Linhart Date: Wed, 5 Mar 2025 15:41:19 +0100 Subject: [PATCH 4/7] STAN fixes --- .../Factory/SparkpostTransportFactoryTest.php | 16 ++++++++++------ .../Transport/SparkpostTransportMessageTest.php | 3 +++ .../Mailer/Transport/SparkpostTransportTest.php | 5 +++++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Tests/Unit/Mailer/Factory/SparkpostTransportFactoryTest.php b/Tests/Unit/Mailer/Factory/SparkpostTransportFactoryTest.php index eec7a73..64ca6c3 100644 --- a/Tests/Unit/Mailer/Factory/SparkpostTransportFactoryTest.php +++ b/Tests/Unit/Mailer/Factory/SparkpostTransportFactoryTest.php @@ -4,6 +4,7 @@ namespace MauticPlugin\SparkpostBundle\Tests\Unit\Mailer\Factory; +use Mautic\CoreBundle\Helper\CoreParametersHelper; use Mautic\EmailBundle\Model\TransportCallback; use MauticPlugin\SparkpostBundle\Mailer\Factory\SparkpostTransportFactory; use MauticPlugin\SparkpostBundle\Mailer\Transport\SparkpostTransport; @@ -22,19 +23,22 @@ class SparkpostTransportFactoryTest extends TestCase { private SparkpostTransportFactory $sparkpostTransportFactory; - private TranslatorInterface|MockObject $translatorMock; + private TranslatorInterface&MockObject $translatorMock; + private CoreParametersHelper&MockObject $coreParametersHelper; protected function setUp(): void { - $eventDispatcherMock = $this->createMock(EventDispatcherInterface::class); - $this->translatorMock = $this->createMock(TranslatorInterface::class); - $transportCallbackMock = $this->createMock(TransportCallback::class); - $httpClientMock = $this->createMock(HttpClientInterface::class); - $loggerMock = $this->createMock(LoggerInterface::class); + $eventDispatcherMock = $this->createMock(EventDispatcherInterface::class); + $this->translatorMock = $this->createMock(TranslatorInterface::class); + $transportCallbackMock = $this->createMock(TransportCallback::class); + $this->coreParametersHelper = $this->createMock(CoreParametersHelper::class); + $httpClientMock = $this->createMock(HttpClientInterface::class); + $loggerMock = $this->createMock(LoggerInterface::class); $this->sparkpostTransportFactory = new SparkpostTransportFactory( $transportCallbackMock, $this->translatorMock, + $this->coreParametersHelper, $eventDispatcherMock, $httpClientMock, $loggerMock diff --git a/Tests/Unit/Mailer/Transport/SparkpostTransportMessageTest.php b/Tests/Unit/Mailer/Transport/SparkpostTransportMessageTest.php index cc9cf87..e0bcafd 100644 --- a/Tests/Unit/Mailer/Transport/SparkpostTransportMessageTest.php +++ b/Tests/Unit/Mailer/Transport/SparkpostTransportMessageTest.php @@ -4,6 +4,7 @@ namespace MauticPlugin\SparkpostBundle\Tests\Unit\Mailer\Transport; +use Mautic\CoreBundle\Helper\CoreParametersHelper; use Mautic\EmailBundle\Mailer\Message\MauticMessage; use Mautic\EmailBundle\Model\TransportCallback; use MauticPlugin\SparkpostBundle\Mailer\Transport\SparkpostTransport; @@ -27,6 +28,7 @@ public function testCcAndBccFields(): void $transportCallbackMock = $this->createMock(TransportCallback::class); $httpClientMock = $this->createMock(HttpClientInterface::class); + $coreParametersHelper = $this->createMock(CoreParametersHelper::class); $eventDispatcherMock = $this->createMock(EventDispatcherInterface::class); $loggerMock = $this->createMock(LoggerInterface::class); @@ -34,6 +36,7 @@ public function testCcAndBccFields(): void '1234', 'us', $transportCallbackMock, + $coreParametersHelper, $httpClientMock, $eventDispatcherMock, $loggerMock diff --git a/Tests/Unit/Mailer/Transport/SparkpostTransportTest.php b/Tests/Unit/Mailer/Transport/SparkpostTransportTest.php index d0adedd..b2d47a6 100644 --- a/Tests/Unit/Mailer/Transport/SparkpostTransportTest.php +++ b/Tests/Unit/Mailer/Transport/SparkpostTransportTest.php @@ -4,6 +4,7 @@ namespace MauticPlugin\SparkpostBundle\Tests\Unit\Mailer\Transport; +use Mautic\CoreBundle\Helper\CoreParametersHelper; use Mautic\EmailBundle\Mailer\Message\MauticMessage; use Mautic\EmailBundle\Model\TransportCallback; use MauticPlugin\SparkpostBundle\Mailer\Transport\SparkpostTransport; @@ -23,6 +24,8 @@ class SparkpostTransportTest extends TestCase { private TransportCallback|MockObject $transportCallbackMock; + private CoreParametersHelper&MockObject $coreParametersHelper; + private HttpClientInterface|MockObject $httpClientMock; private EventDispatcherInterface|MockObject $eventDispatcherMock; @@ -34,6 +37,7 @@ class SparkpostTransportTest extends TestCase protected function setUp(): void { $this->transportCallbackMock = $this->createMock(TransportCallback::class); + $this->coreParametersHelper = $this->createMock(CoreParametersHelper::class); $this->httpClientMock = $this->createMock(HttpClientInterface::class); $this->eventDispatcherMock = $this->createMock(EventDispatcherInterface::class); $this->loggerMock = $this->createMock(LoggerInterface::class); @@ -41,6 +45,7 @@ protected function setUp(): void 'api-key', 'some-region', $this->transportCallbackMock, + $this->coreParametersHelper, $this->httpClientMock, $this->eventDispatcherMock, $this->loggerMock From 5965fd311c468d816cbfca0b18d3fc2ce8511e7d Mon Sep 17 00:00:00 2001 From: John Linhart Date: Thu, 6 Mar 2025 14:47:40 +0100 Subject: [PATCH 5/7] The test assertions were failing but the test was still green. We cannot catch all \Exception to avoid this. --- Mailer/Transport/SparkpostTransport.php | 10 ++-- .../Transport/SparkpostTransportTest.php | 48 ++++++++++++------- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/Mailer/Transport/SparkpostTransport.php b/Mailer/Transport/SparkpostTransport.php index 3534169..4cacaf6 100644 --- a/Mailer/Transport/SparkpostTransport.php +++ b/Mailer/Transport/SparkpostTransport.php @@ -24,7 +24,7 @@ use Symfony\Component\Mime\Header\ParameterizedHeader; use Symfony\Component\Mime\Header\UnstructuredHeader; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; -use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; @@ -72,10 +72,6 @@ public function __toString(): string } /** - * @throws ClientExceptionInterface - * @throws DecodingExceptionInterface - * @throws RedirectionExceptionInterface - * @throws ServerExceptionInterface * @throws TransportExceptionInterface */ protected function doSendApi(SentMessage $sentMessage, Email $email, Envelope $envelope): ResponseInterface @@ -94,8 +90,8 @@ protected function doSendApi(SentMessage $sentMessage, Email $email, Envelope $e } return $response; - } catch (\Exception $e) { - throw new TransportException($e->getMessage()); + } catch (ExceptionInterface $e) { + throw new TransportException($e->getMessage(), 0, $e); } } diff --git a/Tests/Functional/Mailer/Transport/SparkpostTransportTest.php b/Tests/Functional/Mailer/Transport/SparkpostTransportTest.php index d057ed4..01d5d9c 100644 --- a/Tests/Functional/Mailer/Transport/SparkpostTransportTest.php +++ b/Tests/Functional/Mailer/Transport/SparkpostTransportTest.php @@ -26,7 +26,7 @@ protected function setUp(): void $this->configParams['mailer_custom_headers'] = ['x-global-custom-header' => 'value123']; $this->configParams['mailer_from_email'] = 'admin@mautic.test'; $this->configParams['mailer_from_name'] = 'Admin'; - $this->configParams['sparkpost_tracking_enabled'] = 'testEmailSendToContactSync' === $this->getName() ? $this->getProvidedData()[0] : false; + $this->configParams['sparkpost_tracking_enabled'] = 'testEmailSendToContactSync' === $this->getName(false) ? $this->getProvidedData()[0] : false; parent::setUp(); $this->translator = self::getContainer()->get('translator'); } @@ -36,18 +36,23 @@ protected function setUp(): void */ public function testEmailSendToContactSync(bool $expectedTrackingConfig): void { + $this->client->catchExceptions(false); $expectedResponses = [ function ($method, $url, $options) use ($expectedTrackingConfig): MockResponse { Assert::assertSame(Request::METHOD_POST, $method); Assert::assertSame('https://api.sparkpost.com/api/v1/utils/content-previewer/', $url); - $this->assertSparkpostRequestBody($options['body'], $expectedTrackingConfig); + $bodyArray = json_decode($options['body'], true); + $this->assertSparkpostRequestBody($bodyArray, $expectedTrackingConfig); + $this->assertSubstitutionData($bodyArray['substitution_data']); return new MockResponse('{"results": {"subject": "Hello there!", "html": "This is test body for {contactfield=email}!"}}'); }, function ($method, $url, $options) use ($expectedTrackingConfig): MockResponse { Assert::assertSame(Request::METHOD_POST, $method); Assert::assertSame('https://api.sparkpost.com/api/v1/transmissions/', $url); - $this->assertSparkpostRequestBody($options['body'], $expectedTrackingConfig); + $bodyArray = json_decode($options['body'], true); + $this->assertSparkpostRequestBody($bodyArray, $expectedTrackingConfig); + $this->assertSubstitutionData($bodyArray['recipients'][0]['substitution_data']); return new MockResponse('{"results": {"total_rejected_recipients": 0, "total_accepted_recipients": 1, "id": "11668787484950529"}}'); }, @@ -61,7 +66,7 @@ function ($method, $url, $options) use ($expectedTrackingConfig): MockResponse { $this->em->flush(); $this->client->request(Request::METHOD_GET, "/s/contacts/email/{$contact->getId()}"); - Assert::assertTrue($this->client->getResponse()->isOk()); + $this->assertResponseIsSuccessful(); $newContent = json_decode($this->client->getResponse()->getContent(), true)['newContent']; $crawler = new Crawler($newContent, $this->client->getInternalRequest()->getUri()); $form = $crawler->selectButton('Send')->form(); @@ -72,7 +77,7 @@ function ($method, $url, $options) use ($expectedTrackingConfig): MockResponse { ] ); $this->client->submit($form); - Assert::assertTrue($this->client->getResponse()->isOk()); + $this->assertResponseIsSuccessful(); self::assertQueuedEmailCount(1); $email = self::getMailerMessage(); @@ -140,24 +145,33 @@ private function assertSparkpostTestRequestBody(string $body): void Assert::assertSame('Hi! This is a test email from Mautic. Testing...testing...1...2...3!', $bodyArray['content']['text']); } - private function assertSparkpostRequestBody(string $body, bool $expectedTrackingConfig): void + /** + * @param mixed[] $bodyArray + */ + private function assertSparkpostRequestBody(array $bodyArray, bool $expectedTrackingConfig): void { - $bodyArray = json_decode($body, true); Assert::assertSame('Admin User ', $bodyArray['content']['from']); Assert::assertSame('value123', $bodyArray['content']['headers']['x-global-custom-header']); Assert::assertSame('This is test body for {{{ CONTACTFIELDEMAIL }}}!', $bodyArray['content']['html']); - Assert::assertSame('admin@mautic.test', $bodyArray['content']['reply_to']); + Assert::assertSame('admin@yoursite.com', $bodyArray['content']['reply_to']); Assert::assertSame('Hello there!', $bodyArray['content']['subject']); Assert::assertSame('This is test body for {{{ CONTACTFIELDEMAIL }}}!', $bodyArray['content']['text']); - Assert::assertSame(['open_tracking' => false, 'click_tracking' => false], $bodyArray['options']); - Assert::assertSame('contact@an.email', $bodyArray['substitution_data']['CONTACTFIELDEMAIL']); - Assert::assertSame('Hello there!', $bodyArray['substitution_data']['SUBJECT']); - Assert::assertArrayHasKey('SIGNATURE', $bodyArray['substitution_data']); - Assert::assertArrayHasKey('TRACKINGPIXEL', $bodyArray['substitution_data']); - Assert::assertArrayHasKey('UNSUBSCRIBETEXT', $bodyArray['substitution_data']); - Assert::assertArrayHasKey('UNSUBSCRIBEURL', $bodyArray['substitution_data']); - Assert::assertArrayHasKey('WEBVIEWTEXT', $bodyArray['substitution_data']); - Assert::assertArrayHasKey('WEBVIEWURL', $bodyArray['substitution_data']); + Assert::assertSame(['open_tracking' => $expectedTrackingConfig, 'click_tracking' => $expectedTrackingConfig], $bodyArray['options']); + } + + /** + * @param array $substitutionData + */ + private function assertSubstitutionData(array $substitutionData): void + { + Assert::assertSame('contact@an.email', $substitutionData['CONTACTFIELDEMAIL']); + Assert::assertSame('Hello there!', $substitutionData['SUBJECT']); + Assert::assertArrayHasKey('SIGNATURE', $substitutionData); + Assert::assertArrayHasKey('TRACKINGPIXEL', $substitutionData); + Assert::assertArrayHasKey('UNSUBSCRIBETEXT', $substitutionData); + Assert::assertArrayHasKey('UNSUBSCRIBEURL', $substitutionData); + Assert::assertArrayHasKey('WEBVIEWTEXT', $substitutionData); + Assert::assertArrayHasKey('WEBVIEWURL', $substitutionData); } private function createContact(string $email): Lead From 81ddc1e7c44e0c2b1da467cc186cd319c74e8ad9 Mon Sep 17 00:00:00 2001 From: John Linhart Date: Thu, 6 Mar 2025 14:51:09 +0100 Subject: [PATCH 6/7] Fixing mock types --- .../Factory/SparkpostTransportFactoryTest.php | 11 ++++++-- .../Transport/SparkpostTransportTest.php | 25 +++++++++++++++---- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/Tests/Unit/Mailer/Factory/SparkpostTransportFactoryTest.php b/Tests/Unit/Mailer/Factory/SparkpostTransportFactoryTest.php index 64ca6c3..f313b5f 100644 --- a/Tests/Unit/Mailer/Factory/SparkpostTransportFactoryTest.php +++ b/Tests/Unit/Mailer/Factory/SparkpostTransportFactoryTest.php @@ -23,8 +23,15 @@ class SparkpostTransportFactoryTest extends TestCase { private SparkpostTransportFactory $sparkpostTransportFactory; - private TranslatorInterface&MockObject $translatorMock; - private CoreParametersHelper&MockObject $coreParametersHelper; + /** + * @var TranslatorInterface&MockObject + */ + private MockObject $translatorMock; + + /** + * @var CoreParametersHelper&MockObject + */ + private MockObject $coreParametersHelper; protected function setUp(): void { diff --git a/Tests/Unit/Mailer/Transport/SparkpostTransportTest.php b/Tests/Unit/Mailer/Transport/SparkpostTransportTest.php index b2d47a6..c92c500 100644 --- a/Tests/Unit/Mailer/Transport/SparkpostTransportTest.php +++ b/Tests/Unit/Mailer/Transport/SparkpostTransportTest.php @@ -22,15 +22,30 @@ class SparkpostTransportTest extends TestCase { - private TransportCallback|MockObject $transportCallbackMock; + /** + * @var TransportCallback&MockObject + */ + private MockObject $transportCallbackMock; - private CoreParametersHelper&MockObject $coreParametersHelper; + /** + * @var CoreParametersHelper&MockObject + */ + private MockObject $coreParametersHelper; - private HttpClientInterface|MockObject $httpClientMock; + /** + * @var HttpClientInterface&MockObject + */ + private MockObject $httpClientMock; - private EventDispatcherInterface|MockObject $eventDispatcherMock; + /** + * @var EventDispatcherInterface&MockObject + */ + private MockObject $eventDispatcherMock; - private LoggerInterface|MockObject $loggerMock; + /** + * @var LoggerInterface&MockObject + */ + private MockObject $loggerMock; private SparkpostTransport $transport; From bb78d496cc81d292b8633ff1be28118884007949 Mon Sep 17 00:00:00 2001 From: John Linhart Date: Thu, 6 Mar 2025 15:55:09 +0100 Subject: [PATCH 7/7] This line isn't necessary --- Tests/Functional/Mailer/Transport/SparkpostTransportTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/Functional/Mailer/Transport/SparkpostTransportTest.php b/Tests/Functional/Mailer/Transport/SparkpostTransportTest.php index c7673f6..7add0b9 100644 --- a/Tests/Functional/Mailer/Transport/SparkpostTransportTest.php +++ b/Tests/Functional/Mailer/Transport/SparkpostTransportTest.php @@ -36,7 +36,6 @@ protected function setUp(): void */ public function testEmailSendToContactSync(bool $expectedTrackingConfig): void { - $this->client->catchExceptions(false); $expectedResponses = [ function ($method, $url, $options) use ($expectedTrackingConfig): MockResponse { Assert::assertSame(Request::METHOD_POST, $method);