createMock(MessageBusInterface::class); $messageBus ->expects(self::once()) ->method('dispatch') ->with(self::callback(static function (MailjetNewsletterEventMessage $message) use (&$dispatchedMessages): bool { $dispatchedMessages[] = $message; return true; })) ->willReturnCallback(static fn (object $message): Envelope => new Envelope($message)); $controller = new MailjetNewsletterWebhookController($messageBus, new NullLogger(), [123 => 'Newsletter']); $response = $controller->index(Request::create( '/webhooks/mailjet/newsletter', 'POST', content: json_encode([ [ 'event' => MailjetNewsletterEventMessage::EVENT_UNSUBSCRIBE, 'email' => ' Customer@Example.COM ', 'mj_list_id' => '123', 'time' => 1770000000, ], [ 'event' => 'open', 'email' => 'customer@example.com', 'mj_list_id' => '123', ], ], JSON_THROW_ON_ERROR), )); self::assertSame(200, $response->getStatusCode()); self::assertCount(1, $dispatchedMessages); self::assertSame('customer@example.com', $dispatchedMessages[0]->email); self::assertSame(123, $dispatchedMessages[0]->mailjetListId); self::assertSame(MailjetNewsletterEventMessage::EVENT_UNSUBSCRIBE, $dispatchedMessages[0]->event); self::assertSame(1770000000, $dispatchedMessages[0]->eventAt?->getTimestamp()); } public function testIgnoresEventsForUnconfiguredLists(): void { $messageBus = $this->createMock(MessageBusInterface::class); $messageBus->expects(self::never())->method('dispatch'); $controller = new MailjetNewsletterWebhookController($messageBus, new NullLogger(), [999 => 'Newsletter']); $response = $controller->index(Request::create( '/webhooks/mailjet/newsletter', 'POST', content: json_encode([ 'event' => MailjetNewsletterEventMessage::EVENT_UNSUBSCRIBE, 'email' => 'customer@example.com', 'mj_list_id' => '123', ], JSON_THROW_ON_ERROR), )); self::assertSame(200, $response->getStatusCode()); self::assertSame(['success' => true, 'dispatched' => 0], json_decode($response->getContent() ?: '', true, 512, JSON_THROW_ON_ERROR)); } public function testDispatchesOnlyConfiguredEventsFromBatchPayload(): void { $dispatchedMessages = []; $messageBus = $this->createMock(MessageBusInterface::class); $messageBus ->expects(self::once()) ->method('dispatch') ->with(self::callback(static function (MailjetNewsletterEventMessage $message) use (&$dispatchedMessages): bool { $dispatchedMessages[] = $message; return true; })) ->willReturnCallback(static fn (object $message): Envelope => new Envelope($message)); $controller = new MailjetNewsletterWebhookController($messageBus, new NullLogger(), [123 => 'Newsletter']); $response = $controller->index(Request::create( '/webhooks/mailjet/newsletter', 'POST', content: json_encode([ [ 'event' => MailjetNewsletterEventMessage::EVENT_UNSUBSCRIBE, 'email' => 'customer@example.com', 'mj_list_id' => '123', ], [ 'event' => MailjetNewsletterEventMessage::EVENT_UNSUBSCRIBE, 'email' => 'customer@example.com', 'mj_list_id' => '999', ], ], JSON_THROW_ON_ERROR), )); self::assertSame(200, $response->getStatusCode()); self::assertCount(1, $dispatchedMessages); self::assertSame(123, $dispatchedMessages[0]->mailjetListId); } public function testRejectsInvalidJson(): void { $messageBus = $this->createMock(MessageBusInterface::class); $messageBus->expects(self::never())->method('dispatch'); $controller = new MailjetNewsletterWebhookController($messageBus, new NullLogger(), [123 => 'Newsletter']); $response = $controller->index(Request::create('/webhooks/mailjet/newsletter', 'POST', content: '{')); self::assertSame(400, $response->getStatusCode()); } public function testAcceptsPayloadWithoutDispatchableEvents(): void { $messageBus = $this->createMock(MessageBusInterface::class); $messageBus->expects(self::never())->method('dispatch'); $controller = new MailjetNewsletterWebhookController($messageBus, new NullLogger(), [123 => 'Newsletter']); $response = $controller->index(Request::create( '/webhooks/mailjet/newsletter', 'POST', content: json_encode([ 'event' => MailjetNewsletterEventMessage::EVENT_UNSUBSCRIBE, 'email' => 'not-an-email', 'mj_list_id' => '123', ], JSON_THROW_ON_ERROR), )); self::assertSame(200, $response->getStatusCode()); } }