buildEntityWorkflow(); // Prepare attachments (2 attachments) $attachmentStoredObject1 = new StoredObject(); $attachmentStoredObject2 = new StoredObject(); new EntityWorkflowAttachment('generic_doc', ['id' => 1], $entityWorkflow, $attachmentStoredObject1); new EntityWorkflowAttachment('generic_doc', ['id' => 2], $entityWorkflow, $attachmentStoredObject2); // Prepare transition DTO and sends $dto = new WorkflowTransitionContextDTO($entityWorkflow); $dto->futureDestineeEmails = ['external@example.com']; $dto->futureDestineeThirdParties = [(new ThirdParty())->setEmail('3party@example.com')]; $entityWorkflow->setStep('send_external', $dto, 'to_send_external', new \DateTimeImmutable(), new User()); // Repository returns our workflow $repository = $this->prophesize(EntityWorkflowRepository::class); $repository->find(1)->willReturn($entityWorkflow); // Mailer must send to both recipients $mailer = $this->prophesize(MailerInterface::class); $mailer->send(Argument::that($this->buildCheckAddressCallback('3party@example.com')))->shouldBeCalledOnce(); $mailer->send(Argument::that($this->buildCheckAddressCallback('external@example.com')))->shouldBeCalledOnce(); // Workflow manager and handler $workflowHandler = $this->prophesize(EntityWorkflowHandlerInterface::class); $workflowHandler->getEntityTitle($entityWorkflow, Argument::any())->willReturn('title'); $workflowManager = $this->prophesize(EntityWorkflowManager::class); $workflowManager->getHandler($entityWorkflow)->willReturn($workflowHandler->reveal()); // Associated stored object for the workflow $associatedStoredObject = new StoredObject(); $workflowManager->getAssociatedStoredObject($entityWorkflow)->willReturn($associatedStoredObject); // Converter should be called for each attachment and the associated stored object $converter = $this->prophesize(StoredObjectToPdfConverter::class); $converter->addConvertedVersion($attachmentStoredObject1, 'fr')->shouldBeCalledOnce(); $converter->addConvertedVersion($attachmentStoredObject2, 'fr')->shouldBeCalledOnce(); $converter->addConvertedVersion($associatedStoredObject, 'fr')->shouldBeCalledOnce(); // Logger (not used in happy path, but required by handler) $logger = $this->prophesize(LoggerInterface::class); $handler = new PostSendExternalMessageHandler( $repository->reveal(), $mailer->reveal(), $workflowManager->reveal(), $converter->reveal(), $logger->reveal(), ); $handler(new PostSendExternalMessage(1, 'fr')); // prophecy should do the check at the end of this test } private function buildCheckAddressCallback(string $emailToCheck): callable { return fn (TemplatedEmail $email): bool => in_array($emailToCheck, array_map(fn (Address $addr) => $addr->getAddress(), $email->getTo()), true); } private function buildEntityWorkflow(): EntityWorkflow { $entityWorkflow = new EntityWorkflow(); $reflection = new \ReflectionClass($entityWorkflow); $idProperty = $reflection->getProperty('id'); $idProperty->setValue($entityWorkflow, 1); return $entityWorkflow; } }