149 lines
4.5 KiB
PHP
149 lines
4.5 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit\User\UseCases;
|
|
|
|
use App\Email\EmailConfirmationToken\CreateEmailConfirmationTokenDto;
|
|
use App\Exceptions\BadRequestException;
|
|
use App\Shared\ValueObject\EmailAddress;
|
|
use App\User\CreateUserDto;
|
|
use App\User\UseCases\ConfirmUserEmail\ConfirmUserEmail;
|
|
use App\User\UseCases\ConfirmUserEmail\ConfirmUserEmailRequest;
|
|
use DateTimeImmutable;
|
|
use DateTimeZone;
|
|
use DomainException;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Tests\Fakes\FakeClock;
|
|
use Tests\Fakes\FakeEmailConfirmationTokenRepository;
|
|
use Tests\Fakes\FakePasswordHasher;
|
|
use Tests\Fakes\FakeUserRepository;
|
|
|
|
class ConfirmUserEmailTest extends TestCase
|
|
{
|
|
private DateTimeImmutable $now;
|
|
|
|
private FakeUserRepository $userRepository;
|
|
|
|
private FakeEmailConfirmationTokenRepository $tokenRepository;
|
|
|
|
private ConfirmUserEmail $confirmUserEmail;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->now = new DateTimeImmutable(
|
|
'2026-08-03T12:00:00',
|
|
new DateTimeZone('UTC'),
|
|
);
|
|
$this->userRepository = new FakeUserRepository;
|
|
$this->tokenRepository = new FakeEmailConfirmationTokenRepository;
|
|
$this->confirmUserEmail = new ConfirmUserEmail(
|
|
$this->tokenRepository,
|
|
$this->userRepository,
|
|
new FakePasswordHasher,
|
|
new FakeClock($this->now),
|
|
);
|
|
}
|
|
|
|
public function test_it_sets_the_password_and_consumes_the_token(): void
|
|
{
|
|
$this->createPendingUserToken(
|
|
'confirmation-token',
|
|
$this->now->modify('+10 minutes'),
|
|
);
|
|
|
|
$confirmedUser = $this->confirmUserEmail->execute(
|
|
new ConfirmUserEmailRequest(
|
|
token: 'confirmation-token',
|
|
password: 'password123',
|
|
),
|
|
);
|
|
|
|
$this->assertSame('hashed:password123', $confirmedUser->getPasswordHash());
|
|
$this->assertSame(
|
|
'hashed:password123',
|
|
$this->userRepository->find($confirmedUser->getId())
|
|
?->getPasswordHash(),
|
|
);
|
|
$this->assertNull(
|
|
$this->tokenRepository->findByToken('confirmation-token'),
|
|
);
|
|
}
|
|
|
|
public function test_it_rejects_an_expired_token(): void
|
|
{
|
|
$this->createPendingUserToken(
|
|
'expired-token',
|
|
$this->now->modify('-1 minute'),
|
|
);
|
|
|
|
$this->expectException(DomainException::class);
|
|
$this->expectExceptionMessage('token expired');
|
|
|
|
$this->confirmUserEmail->execute(new ConfirmUserEmailRequest(
|
|
token: 'expired-token',
|
|
password: 'password123',
|
|
));
|
|
}
|
|
|
|
public function test_it_rejects_an_unknown_token(): void
|
|
{
|
|
$this->expectException(DomainException::class);
|
|
$this->expectExceptionMessage('token not found');
|
|
|
|
$this->confirmUserEmail->execute(new ConfirmUserEmailRequest(
|
|
token: 'unknown-token',
|
|
password: 'password123',
|
|
));
|
|
}
|
|
|
|
public function test_it_requires_a_token(): void
|
|
{
|
|
$this->expectException(BadRequestException::class);
|
|
$this->expectExceptionMessage('token is required');
|
|
|
|
$this->confirmUserEmail->execute(new ConfirmUserEmailRequest(
|
|
token: null,
|
|
password: 'password123',
|
|
));
|
|
}
|
|
|
|
public function test_it_requires_a_password(): void
|
|
{
|
|
$this->expectException(BadRequestException::class);
|
|
$this->expectExceptionMessage('password is required');
|
|
|
|
$this->confirmUserEmail->execute(new ConfirmUserEmailRequest(
|
|
token: 'confirmation-token',
|
|
password: null,
|
|
));
|
|
}
|
|
|
|
public function test_it_rejects_a_short_password(): void
|
|
{
|
|
$this->expectException(BadRequestException::class);
|
|
$this->expectExceptionMessage(
|
|
'password must be at least 8 characters',
|
|
);
|
|
|
|
$this->confirmUserEmail->execute(new ConfirmUserEmailRequest(
|
|
token: 'confirmation-token',
|
|
password: 'short',
|
|
));
|
|
}
|
|
|
|
private function createPendingUserToken(
|
|
string $token,
|
|
DateTimeImmutable $availableTo,
|
|
): void {
|
|
$user = $this->userRepository->create(new CreateUserDto(
|
|
email: new EmailAddress('user@example.com'),
|
|
passwordHash: null,
|
|
));
|
|
$this->tokenRepository->create(
|
|
new CreateEmailConfirmationTokenDto(
|
|
user: $user,
|
|
availableTo: $availableTo,
|
|
token: $token,
|
|
),
|
|
);
|
|
}
|
|
}
|