test ConfirmUserEmail use case
This commit is contained in:
parent
2890781a56
commit
60308988f7
1 changed files with 182 additions and 0 deletions
182
backend/tests/Unit/User/UseCases/ConfirmUserEmailTest.php
Normal file
182
backend/tests/Unit/User/UseCases/ConfirmUserEmailTest.php
Normal file
|
|
@ -0,0 +1,182 @@
|
||||||
|
<?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 App\User\User;
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use DateTimeZone;
|
||||||
|
use DomainException;
|
||||||
|
use Tests\Fakes\FakeClock;
|
||||||
|
use Tests\Fakes\FakeEmailConfirmationTokenRepository;
|
||||||
|
use Tests\Fakes\FakePasswordHasher;
|
||||||
|
use Tests\Fakes\FakeUserRepository;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class ConfirmUserEmailTest extends TestCase
|
||||||
|
{
|
||||||
|
private FakeUserRepository $userRepo;
|
||||||
|
|
||||||
|
private FakeEmailConfirmationTokenRepository $tokenRepo;
|
||||||
|
|
||||||
|
private FakePasswordHasher $hasher;
|
||||||
|
|
||||||
|
private FakeClock $clock;
|
||||||
|
|
||||||
|
private ConfirmUserEmail $useCase;
|
||||||
|
|
||||||
|
private DateTimeImmutable $now;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
$this->now = new DateTimeImmutable(
|
||||||
|
'2026-05-06T12:00:00',
|
||||||
|
new DateTimeZone('UTC'),
|
||||||
|
);
|
||||||
|
$this->userRepo = new FakeUserRepository;
|
||||||
|
$this->tokenRepo = new FakeEmailConfirmationTokenRepository(
|
||||||
|
$this->userRepo,
|
||||||
|
);
|
||||||
|
$this->hasher = new FakePasswordHasher;
|
||||||
|
$this->clock = new FakeClock($this->now);
|
||||||
|
$this->useCase = new ConfirmUserEmail(
|
||||||
|
$this->userRepo,
|
||||||
|
$this->tokenRepo,
|
||||||
|
$this->hasher,
|
||||||
|
$this->clock,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function seedUserAndToken(DateTimeImmutable $availableTo): User
|
||||||
|
{
|
||||||
|
$user = $this->userRepo->create(new CreateUserDto(
|
||||||
|
email: new EmailAddress('user@example.com'),
|
||||||
|
displayName: 'user',
|
||||||
|
passwordHash: '',
|
||||||
|
isAdmin: false,
|
||||||
|
emailConfirmedAt: null,
|
||||||
|
));
|
||||||
|
$this->tokenRepo->create(new CreateEmailConfirmationTokenDto(
|
||||||
|
user: $user,
|
||||||
|
availableTo: $availableTo,
|
||||||
|
));
|
||||||
|
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function tokenStringForUser(User $user): string
|
||||||
|
{
|
||||||
|
$token = $this->tokenRepo->findByUser($user);
|
||||||
|
$this->assertNotNull($token);
|
||||||
|
|
||||||
|
return $token->getToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_null_token_throws_bad_request(): void
|
||||||
|
{
|
||||||
|
$this->expectException(BadRequestException::class);
|
||||||
|
$this->useCase->execute(new ConfirmUserEmailRequest(
|
||||||
|
token: null,
|
||||||
|
password: 'longenoughpassword',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_null_password_throws_bad_request(): void
|
||||||
|
{
|
||||||
|
$this->expectException(BadRequestException::class);
|
||||||
|
$this->useCase->execute(new ConfirmUserEmailRequest(
|
||||||
|
token: 'sometoken',
|
||||||
|
password: null,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_short_password_throws_bad_request(): void
|
||||||
|
{
|
||||||
|
$this->expectException(BadRequestException::class);
|
||||||
|
$this->useCase->execute(new ConfirmUserEmailRequest(
|
||||||
|
token: 'sometoken',
|
||||||
|
password: 'short',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_unknown_token_throws_domain_exception(): void
|
||||||
|
{
|
||||||
|
$this->expectException(DomainException::class);
|
||||||
|
$this->useCase->execute(new ConfirmUserEmailRequest(
|
||||||
|
token: 'no-such-token',
|
||||||
|
password: 'longenoughpassword',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_expired_token_throws_domain_exception(): void
|
||||||
|
{
|
||||||
|
$user = $this->seedUserAndToken(
|
||||||
|
$this->now->modify('-1 minute'),
|
||||||
|
);
|
||||||
|
$tokenStr = $this->tokenStringForUser($user);
|
||||||
|
|
||||||
|
$this->expectException(DomainException::class);
|
||||||
|
$this->useCase->execute(new ConfirmUserEmailRequest(
|
||||||
|
token: $tokenStr,
|
||||||
|
password: 'longenoughpassword',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_valid_confirmation_sets_password_hash(): void
|
||||||
|
{
|
||||||
|
$user = $this->seedUserAndToken(
|
||||||
|
$this->now->modify('+1 day'),
|
||||||
|
);
|
||||||
|
$tokenStr = $this->tokenStringForUser($user);
|
||||||
|
|
||||||
|
$this->useCase->execute(new ConfirmUserEmailRequest(
|
||||||
|
token: $tokenStr,
|
||||||
|
password: 'longenoughpassword',
|
||||||
|
));
|
||||||
|
|
||||||
|
$reloaded = $this->userRepo->find($user->getId());
|
||||||
|
$this->assertNotNull($reloaded);
|
||||||
|
$this->assertSame(
|
||||||
|
$this->hasher->hash('longenoughpassword'),
|
||||||
|
$reloaded->getPasswordHash(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_valid_confirmation_marks_email_confirmed(): void
|
||||||
|
{
|
||||||
|
$user = $this->seedUserAndToken(
|
||||||
|
$this->now->modify('+1 day'),
|
||||||
|
);
|
||||||
|
$tokenStr = $this->tokenStringForUser($user);
|
||||||
|
|
||||||
|
$this->useCase->execute(new ConfirmUserEmailRequest(
|
||||||
|
token: $tokenStr,
|
||||||
|
password: 'longenoughpassword',
|
||||||
|
));
|
||||||
|
|
||||||
|
$reloaded = $this->userRepo->find($user->getId());
|
||||||
|
$this->assertNotNull($reloaded);
|
||||||
|
$this->assertTrue($reloaded->isEmailConfirmed());
|
||||||
|
$this->assertEquals($this->now, $reloaded->getEmailConfirmedAt());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_valid_confirmation_consumes_token(): void
|
||||||
|
{
|
||||||
|
$user = $this->seedUserAndToken(
|
||||||
|
$this->now->modify('+1 day'),
|
||||||
|
);
|
||||||
|
$tokenStr = $this->tokenStringForUser($user);
|
||||||
|
|
||||||
|
$this->useCase->execute(new ConfirmUserEmailRequest(
|
||||||
|
token: $tokenStr,
|
||||||
|
password: 'longenoughpassword',
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->assertNull($this->tokenRepo->findByToken($tokenStr));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue