Files
e-ticket/tests/Controller/ForgotPasswordControllerTest.php
Serreau Jovann 52e6e2c14c Add email verification, organizer approval, and forgot password features
- Add isVerified, emailVerificationToken, emailVerifiedAt fields to User entity
- Send verification email on registration with token link
- Add /verification-email/{token} route to confirm email
- Send notification emails to organizer and staff on organizer email verification
- Add isApproved and offer fields to User entity for organizer approval workflow
- Auto-verify and auto-approve SSO Keycloak users with offer='custom'
- Add resetCode and resetCodeExpiresAt fields to User entity
- Create ForgotPasswordController with 2-step flow (email -> code + new password)
- Block forgot password for SSO users (no local password)
- Add "Mot de passe oublie" link on login page
- Create email templates: verification, reset_code, organizer_pending, organizer_request
- Add migrations for all new fields
- Add tests: ForgotPasswordControllerTest (9 tests), update RegistrationControllerTest,
  update UserTest with verification, approval, offer, and reset code fields

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:13:32 +01:00

177 lines
5.3 KiB
PHP

<?php
namespace App\Tests\Controller;
use App\Entity\User;
use App\Service\MailerService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class ForgotPasswordControllerTest extends WebTestCase
{
public function testPageReturnsSuccess(): void
{
$client = static::createClient();
$client->request('GET', '/mot-de-passe-oublie');
self::assertResponseIsSuccessful();
}
public function testEmailStepWithEmptyEmail(): void
{
$client = static::createClient();
$client->request('POST', '/mot-de-passe-oublie', [
'step' => 'email',
'email' => '',
]);
self::assertResponseIsSuccessful();
}
public function testEmailStepSendsCode(): void
{
$client = static::createClient();
$em = static::getContainer()->get(EntityManagerInterface::class);
$user = new User();
$user->setEmail('test-forgot-'.uniqid().'@example.com');
$user->setFirstName('Test');
$user->setLastName('User');
$user->setPassword('$2y$13$hashed');
$em->persist($user);
$em->flush();
$mailer = $this->createMock(MailerService::class);
$mailer->expects(self::once())->method('sendEmail');
static::getContainer()->set(MailerService::class, $mailer);
$client->request('POST', '/mot-de-passe-oublie', [
'step' => 'email',
'email' => $user->getEmail(),
]);
self::assertResponseIsSuccessful();
$em->refresh($user);
self::assertNotNull($user->getResetCode());
self::assertNotNull($user->getResetCodeExpiresAt());
}
public function testEmailStepIgnoresSsoUser(): void
{
$client = static::createClient();
$em = static::getContainer()->get(EntityManagerInterface::class);
$user = new User();
$user->setEmail('test-sso-'.uniqid().'@example.com');
$user->setFirstName('SSO');
$user->setLastName('User');
$user->setPassword('');
$user->setKeycloakId('kc-'.uniqid());
$em->persist($user);
$em->flush();
$client->request('POST', '/mot-de-passe-oublie', [
'step' => 'email',
'email' => $user->getEmail(),
]);
self::assertResponseIsSuccessful();
$em->refresh($user);
self::assertNull($user->getResetCode());
}
public function testEmailStepWithUnknownEmailDoesNotReveal(): void
{
$client = static::createClient();
$client->request('POST', '/mot-de-passe-oublie', [
'step' => 'email',
'email' => 'unknown-'.uniqid().'@example.com',
]);
self::assertResponseIsSuccessful();
}
public function testCodeStepWithEmptyFields(): void
{
$client = static::createClient();
$client->request('POST', '/mot-de-passe-oublie', [
'step' => 'code',
'email' => 'test@example.com',
'code' => '',
'password' => '',
]);
self::assertResponseIsSuccessful();
}
public function testCodeStepWithInvalidCode(): void
{
$client = static::createClient();
$client->request('POST', '/mot-de-passe-oublie', [
'step' => 'code',
'email' => 'test@example.com',
'code' => '000000',
'password' => 'NewPassword123!',
]);
self::assertResponseIsSuccessful();
}
public function testCodeStepWithExpiredCode(): void
{
$client = static::createClient();
$em = static::getContainer()->get(EntityManagerInterface::class);
$user = new User();
$user->setEmail('test-expired-'.uniqid().'@example.com');
$user->setFirstName('Test');
$user->setLastName('User');
$user->setPassword('$2y$13$hashed');
$user->setResetCode('123456');
$user->setResetCodeExpiresAt(new \DateTimeImmutable('-1 hour'));
$em->persist($user);
$em->flush();
$client->request('POST', '/mot-de-passe-oublie', [
'step' => 'code',
'email' => $user->getEmail(),
'code' => '123456',
'password' => 'NewPassword123!',
]);
self::assertResponseIsSuccessful();
}
public function testCodeStepWithValidCodeResetsPassword(): void
{
$client = static::createClient();
$em = static::getContainer()->get(EntityManagerInterface::class);
$user = new User();
$user->setEmail('test-reset-'.uniqid().'@example.com');
$user->setFirstName('Test');
$user->setLastName('User');
$user->setPassword('$2y$13$hashed');
$user->setResetCode('654321');
$user->setResetCodeExpiresAt(new \DateTimeImmutable('+15 minutes'));
$em->persist($user);
$em->flush();
$client->request('POST', '/mot-de-passe-oublie', [
'step' => 'code',
'email' => $user->getEmail(),
'code' => '654321',
'password' => 'NewPassword123!',
]);
self::assertResponseRedirects('/connexion');
$em->refresh($user);
self::assertNull($user->getResetCode());
self::assertNull($user->getResetCodeExpiresAt());
self::assertNotSame('$2y$13$hashed', $user->getPassword());
}
}