Skip to content

Commit

Permalink
Add tests for email verification
Browse files Browse the repository at this point in the history
  • Loading branch information
blackshadev committed Sep 20, 2022
1 parent 50e3505 commit df18843
Show file tree
Hide file tree
Showing 8 changed files with 258 additions and 6 deletions.
7 changes: 6 additions & 1 deletion app/Http/Requests/SendVerificationEmailRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ public function rules(): array

public function findUser(): User
{
return $this->userRepository->findByEmail($this->validated('email'));
return $this->userRepository->findByEmail($this->email());
}

public function email(): string
{
return isset($this->validator) ? $this->validated('email') : $this->get('email');
}
}
12 changes: 12 additions & 0 deletions app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace App\Models;

use App\Domain\Users\Entities\User as UserVO;
use App\Domain\Users\ValueObjects\OriginUrl;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
Expand Down Expand Up @@ -74,4 +76,14 @@ public function equipment()
{
return $this->hasOne(Equipment::class);
}

public function toValueObject(): UserVO
{
return new UserVO(
id: $this->id,
name: $this->name,
email: $this->email,
origin: OriginUrl::fromString($this->origin),
);
}
}
5 changes: 3 additions & 2 deletions app/Services/Users/LaravelUserRegistrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@ final class LaravelUserRegistrator implements UserRegistrator
{
public function register(RegisterUser $registerUser): User
{
$origin = OriginUrl::fromString($registerUser->origin);
$user = UserModel::create([
'name' => $registerUser->name,
'email' => $registerUser->email,
'password' => $registerUser->password,
'origin' => $registerUser->origin,
'origin' => $origin->toString(),
]);

event(new Registered($user));

return new User($user->id, $user->name, $user->email, OriginUrl::fromString($user->origin));
return new User($user->id, $user->name, $user->email, $origin);
}
}
9 changes: 7 additions & 2 deletions database/factories/UserFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,15 @@ public function definition()

public function filled(): self
{
$this->has(
return $this->has(
Dive::factory()->filled()->count($this->faker->numberBetween(1, 50))
);
}

return $this;
public function notVerified(): self
{
return $this->state([
'email_verified_at' => null,
]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

declare(strict_types=1);

namespace Tests\Integration\Http\Controllers\Api;

use App\Domain\Users\Repositories\UserRepository;
use App\Domain\Users\Services\UserEmailVerifier;
use App\Http\Controllers\Api\UserEmailVerifyController;
use App\Http\Requests\EmailVerificationRequest;
use App\Http\Requests\SendVerificationEmailRequest;
use App\Models\User;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;

final class UserEmailVerifyControllerTest extends TestCase
{
private UserEmailVerifyController $subject;

private UserRepository & MockObject $userRepository;

private UserEmailVerifier & MockObject $emailVerifier;

protected function setUp(): void
{
parent::setUp();

$this->userRepository = $this->createMock(UserRepository::class);
$this->emailVerifier = $this->createMock(UserEmailVerifier::class);
$this->subject = new UserEmailVerifyController($this->emailVerifier);
}

public function testItVerifies(): void
{
/** @var User $model */
$model = User::factory()->notVerified()->createOne();
$user = $model->toValueObject();

$this->userRepository
->expects($this->once())
->method('findById')
->with(null)
->willReturn($user);

$this->emailVerifier
->expects($this->once())
->method('verify')
->with($this->equalTo($user));

$this->subject
->verifyEmail(new EmailVerificationRequest($this->userRepository))
->isRedirect($user->getOrigin()->withMessage('account.verified')->toString());
}

public function testResendSends(): void
{
/** @var User $model */
$model = User::factory()->notVerified()->createOne();

$this->userRepository
->expects($this->once())
->method('findByEmail')
->with($model->email)
->willReturn($model->toValueObject());

$this->emailVerifier
->expects($this->once())
->method('resend')
->with($this->equalTo($model->toValueObject()));

$this->subject->sendVerificationEmail(
new SendVerificationEmailRequest($this->userRepository, [], [ 'email' => $model->email ])
);
}
}
27 changes: 26 additions & 1 deletion tests/Integration/RegistrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
namespace Tests\Integration;

use App\Models\User;
use Illuminate\Auth\Notifications\VerifyEmail;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Notification;
use Tests\TestCase;

final class RegistrationTest extends TestCase
Expand Down Expand Up @@ -71,8 +73,10 @@ public function testFailsOnDuplicatedUser(): void
]);
}

public function testSuccessfullRegistration(): void
public function testSuccessfulRegistrationCreatesUser(): void
{
Mail::fake();

$data = [
'email' => $this->faker->email,
'name' => $this->faker->name,
Expand All @@ -90,4 +94,25 @@ public function testSuccessfullRegistration(): void
$data
);
}

public function testSuccessfulRegistrationSentsNotification(): void
{
Notification::fake();

$data = [
'email' => $this->faker->email,
'name' => $this->faker->name,
];

$this->json(
'post',
self::REGISTRATION_URL,
array_merge($data, ['password' => $this->faker->password])
)
->assertStatus(201);

$user = User::query()->where('email', '=', $data['email'])->get();

Notification::assertSentTo($user, VerifyEmail::class);
}
}
70 changes: 70 additions & 0 deletions tests/Integration/Services/Users/LaravelUserEmailVerifierTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php

declare(strict_types=1);

namespace Tests\Integration\Services\Users;

use App\Error\Auth\AlreadyVerified;
use App\Models\User as UserModel;
use App\Services\Users\LaravelUserEmailVerifier;
use Illuminate\Auth\Notifications\VerifyEmail;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Notification;
use Tests\TestCase;

final class LaravelUserEmailVerifierTest extends TestCase
{
use DatabaseTransactions;

private LaravelUserEmailVerifier $subject;

protected function setUp(): void
{
parent::setUp();

$this->subject = new LaravelUserEmailVerifier();
}

public function testVerifyThrowsOnVerifiedUser(): void
{
/** @var UserModel $user */
$user = UserModel::factory()->createOne();

$this->expectException(AlreadyVerified::class);

$this->subject->verify($user->toValueObject());
}

public function testVerifyUser(): void
{
/** @var UserModel $user */
$user = UserModel::factory()->notVerified()->createOne();

$this->subject->verify($user->toValueObject());

$user->refresh();
self::assertTrue($user->hasVerifiedEmail());
}

public function testResendThrowsOnVerifiedUser(): void
{
/** @var UserModel $user */
$user = UserModel::factory()->createOne();

$this->expectException(AlreadyVerified::class);

$this->subject->resend($user->toValueObject());
}

public function testResendMails(): void
{
Notification::fake();

/** @var UserModel $user */
$user = UserModel::factory()->notVerified()->createOne();

$this->subject->resend($user->toValueObject());

Notification::assertSentTo($user, VerifyEmail::class);
}
}
59 changes: 59 additions & 0 deletions tests/Integration/Services/Users/LaravelUserRegistratorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

declare(strict_types=1);

namespace Tests\Integration\Services\Users;

use App\Domain\Users\Commands\RegisterUser;
use App\Services\Users\LaravelUserRegistrator;
use Illuminate\Auth\Events\Registered;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Event;
use Tests\TestCase;

final class LaravelUserRegistratorTest extends TestCase
{
use DatabaseTransactions;

protected function setUp(): void
{
parent::setUp();

$this->subject = new LaravelUserRegistrator();
}

public function testRegisterCreatesANewUser(): void
{
$registerUser = new RegisterUser(
name: ':test:',
email: 'user@example.com',
password: ':password:',
origin: 'https://origin.com',
);

$this->subject->register($registerUser);

$this->assertDatabaseHas('users', [
'name' => $registerUser->name,
'email' => $registerUser->email,
'origin' => $registerUser->origin,
'email_verified_at' => null,
]);
}

public function testRegisterEmitEvent(): void
{
Event::fake();

$registerUser = new RegisterUser(
name: ':test:',
email: 'user@example.com',
password: ':password:',
origin: 'https://origin.com',
);

$this->subject->register($registerUser);

Event::assertDispatched(Registered::class);
}
}

0 comments on commit df18843

Please sign in to comment.