mailer = $this->createMock(MailerInterface::class); $this->twig = $this->createMock(Environment::class); } #[Test] public function sendsEmailToActivatedUser(): void { $event = $this->createEvent('user@example.com', Role::PROF->value); $this->twig->method('render')->willReturn('

Votre compte est actif.

'); $sentEmail = null; $this->mailer->expects(self::once()) ->method('send') ->with(self::callback(static function (Email $email) use (&$sentEmail): bool { $sentEmail = $email; return true; })); $handler = new SendActivationConfirmationHandler( $this->mailer, $this->twig, self::APP_URL, self::FROM_EMAIL, ); ($handler)($event); self::assertNotNull($sentEmail); self::assertSame('user@example.com', $sentEmail->getTo()[0]->getAddress()); self::assertSame(self::FROM_EMAIL, $sentEmail->getFrom()[0]->getAddress()); self::assertSame('Votre compte Classeo est activé', $sentEmail->getSubject()); } #[Test] public function rendersTemplateWithCorrectVariables(): void { $event = $this->createEvent('teacher@example.com', Role::PROF->value); $this->twig->expects(self::once()) ->method('render') ->with( 'emails/activation_confirmation.html.twig', self::callback(static function (array $vars): bool { return $vars['email'] === 'teacher@example.com' && $vars['role'] === 'Enseignant' && $vars['loginUrl'] === 'https://ecole-alpha.classeo.fr/login'; }), ) ->willReturn('

HTML

'); $this->mailer->method('send'); $handler = new SendActivationConfirmationHandler( $this->mailer, $this->twig, self::APP_URL, self::FROM_EMAIL, ); ($handler)($event); } #[Test] public function handlesTrailingSlashInAppUrl(): void { $event = $this->createEvent('user@example.com', Role::PARENT->value); $this->twig->expects(self::once()) ->method('render') ->with( self::anything(), self::callback(static function (array $vars): bool { // Should not have double slash return $vars['loginUrl'] === 'https://ecole-alpha.classeo.fr/login'; }), ) ->willReturn('

HTML

'); $this->mailer->method('send'); $handler = new SendActivationConfirmationHandler( $this->mailer, $this->twig, 'https://ecole-alpha.classeo.fr/', self::FROM_EMAIL, ); ($handler)($event); } #[Test] public function usesRoleLabelForKnownRoles(): void { $event = $this->createEvent('admin@example.com', Role::ADMIN->value); $this->twig->expects(self::once()) ->method('render') ->with( self::anything(), self::callback(static function (array $vars): bool { return $vars['role'] === 'Directeur'; }), ) ->willReturn('

HTML

'); $this->mailer->method('send'); $handler = new SendActivationConfirmationHandler( $this->mailer, $this->twig, self::APP_URL, self::FROM_EMAIL, ); ($handler)($event); } #[Test] public function fallsBackToRawStringForUnknownRole(): void { $event = $this->createEvent('user@example.com', 'ROLE_CUSTOM'); $this->twig->expects(self::once()) ->method('render') ->with( self::anything(), self::callback(static function (array $vars): bool { return $vars['role'] === 'ROLE_CUSTOM'; }), ) ->willReturn('

HTML

'); $this->mailer->method('send'); $handler = new SendActivationConfirmationHandler( $this->mailer, $this->twig, self::APP_URL, self::FROM_EMAIL, ); ($handler)($event); } private function createEvent(string $email, string $role): CompteActive { return new CompteActive( userId: '550e8400-e29b-41d4-a716-446655440001', email: $email, tenantId: TenantId::fromString('a1b2c3d4-e5f6-7890-abcd-ef1234567890'), role: $role, occurredOn: new DateTimeImmutable('2026-02-15 10:00:00'), aggregateId: Uuid::uuid4(), ); } }