Skip to content

Commit

Permalink
Merge 05156c9 into 4ea7945
Browse files Browse the repository at this point in the history
  • Loading branch information
wimski committed Apr 21, 2021
2 parents 4ea7945 + 05156c9 commit a1e21e0
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/GraphQL/Mutations/VerifyEmail.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public function __invoke($_, array $args): array
$user = $userProvider->retrieveById($args['id']);

if (! $user instanceof MustVerifyEmail) {
throw new RuntimeException('User not instance of MustVerifyEmail');
throw new RuntimeException('"' . get_class($user) . '" must implement "' . MustVerifyEmail::class . '".');
}

$this->emailVerificationService->verify($user, (string) $args['hash']);
Expand Down
77 changes: 77 additions & 0 deletions tests/Integration/GraphQL/Mutations/VerifyEmailTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

declare(strict_types=1);

namespace DanielDeWit\LighthouseSanctum\Tests\Integration\GraphQL\Mutations;

use DanielDeWit\LighthouseSanctum\Tests\Integration\AbstractIntegrationTest;
use DanielDeWit\LighthouseSanctum\Tests\stubs\Users\UserMustVerifyEmail;
use Illuminate\Support\Facades\Notification;

class VerifyEmailTest extends AbstractIntegrationTest
{
/**
* @test
*/
public function it_verifies_an_email(): void
{
Notification::fake();

$this->app['config']->set('auth.providers.users.model', UserMustVerifyEmail::class);

/** @var UserMustVerifyEmail $user */
$user = UserMustVerifyEmail::factory()->create([
'id' => 123,
'email_verified_at' => null,
]);

$user->sendEmailVerificationNotification();

$this->graphQL(/** @lang GraphQL */ '
mutation {
verifyEmail(input: {
id: 123,
hash: "' . sha1($user->getEmailForVerification()) . '"
}) {
status
}
}
')->assertJson([
'data' => [
'verifyEmail' => [
'status' => 'VERIFIED',
],
],
]);

$user->refresh();

static::assertNotNull($user->getAttribute('email_verified_at'));
}

/**
* @test
*/
public function it_returns_an_error_if_the_hash_is_incorrect(): void
{
$this->app['config']->set('auth.providers.users.model', UserMustVerifyEmail::class);

UserMustVerifyEmail::factory()->create([
'id' => 123,
'email_verified_at' => null,
]);

$response = $this->graphQL(/** @lang GraphQL */ '
mutation {
verifyEmail(input: {
id: 123,
hash: "foobar"
}) {
status
}
}
');

$this->assertGraphQLErrorMessage($response, 'The provided id and hash are incorrect.');
}
}
50 changes: 50 additions & 0 deletions tests/Traits/MocksUserProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

namespace DanielDeWit\LighthouseSanctum\Tests\Traits;

use Illuminate\Auth\AuthManager;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Contracts\Config\Repository as Config;
use Illuminate\Foundation\Auth\User;
use Mockery;
use Mockery\MockInterface;

trait MocksUserProvider
{
/**
* @return AuthManager|MockInterface
*/
protected function mockAuthManager(?UserProvider $userProvider)
{
/** @var AuthManager|MockInterface $authManager */
$authManager = Mockery::mock(AuthManager::class)
->shouldReceive('createUserProvider')
->with('sanctum-provider')
->andReturn($userProvider)
->getMock();

return $authManager;
}

/**
* @return Config|MockInterface
*/
protected function mockConfig()
{
/** @var Config|MockInterface $config */
$config = Mockery::mock(Config::class)
->shouldReceive('get')
->with('lighthouse-sanctum.provider')
->andReturn('sanctum-provider')
->getMock();

return $config;
}

/**
* @return UserProvider|MockInterface
*/
abstract protected function mockUserProvider(?User $user);
}
115 changes: 115 additions & 0 deletions tests/Unit/GraphQL/Mutations/VerifyEmailTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<?php

declare(strict_types=1);

namespace DanielDeWit\LighthouseSanctum\Tests\Unit\GraphQL\Mutations;

use DanielDeWit\LighthouseSanctum\Contracts\Services\EmailVerificationServiceInterface;
use DanielDeWit\LighthouseSanctum\Enums\EmailVerificationStatus;
use DanielDeWit\LighthouseSanctum\GraphQL\Mutations\VerifyEmail;
use DanielDeWit\LighthouseSanctum\Tests\stubs\Users\UserMustVerifyEmail;
use DanielDeWit\LighthouseSanctum\Tests\Traits\MocksUserProvider;
use DanielDeWit\LighthouseSanctum\Tests\Unit\AbstractUnitTest;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Foundation\Auth\User;
use Mockery;
use Mockery\MockInterface;
use RuntimeException;

class VerifyEmailTest extends AbstractUnitTest
{
use MocksUserProvider;

/**
* @test
*/
public function it_verifies_an_email(): void
{
/** @var UserMustVerifyEmail|MockInterface $user */
$user = Mockery::mock(UserMustVerifyEmail::class)
->shouldReceive('markEmailAsVerified')
->getMock();

/** @var EmailVerificationServiceInterface|MockInterface $verificationService */
$verificationService = Mockery::mock(EmailVerificationServiceInterface::class)
->shouldReceive('verify')
->with($user, '1234567890')
->getMock();

$userProvider = $this->mockUserProvider($user);

$mutation = new VerifyEmail(
$this->mockAuthManager($userProvider),
$this->mockConfig(),
$verificationService,
);

$result = $mutation(null, [
'id' => 123,
'hash' => '1234567890',
]);

static::assertIsArray($result);
static::assertCount(1, $result);
static::assertTrue(EmailVerificationStatus::VERIFIED()->is($result['status']));
}

/**
* @test
*/
public function it_throws_an_exception_if_the_user_provider_is_not_found(): void
{
static::expectException(RuntimeException::class);
static::expectExceptionMessage('User provider not found.');

$mutation = new VerifyEmail(
$this->mockAuthManager(null),
$this->mockConfig(),
Mockery::mock(EmailVerificationServiceInterface::class),
);

$mutation(null, [
'id' => 123,
'hash' => '1234567890',
]);
}

/**
* @test
*/
public function it_throws_an_exception_if_the_user_does_not_implement_the_must_verify_email_interface(): void
{
$user = Mockery::mock(User::class);

static::expectException(RuntimeException::class);
static::expectExceptionMessage('"' . get_class($user) . '" must implement "Illuminate\Contracts\Auth\MustVerifyEmail".');

$userProvider = $this->mockUserProvider($user);

$mutation = new VerifyEmail(
$this->mockAuthManager($userProvider),
$this->mockConfig(),
Mockery::mock(EmailVerificationServiceInterface::class),
);

$mutation(null, [
'id' => 123,
'hash' => '1234567890',
]);
}

/**
* @return UserProvider|MockInterface
*/
protected function mockUserProvider(?User $user)
{
/** @var UserProvider|MockInterface $userProvider */
$userProvider = Mockery::mock(UserProvider::class)
->shouldReceive('retrieveById')
->with(123)
->andReturn($user)
->getMock();

return $userProvider;
}
}
2 changes: 2 additions & 0 deletions tests/stubs/Users/UserHasApiTokens.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\Contracts\HasApiTokens as HasApiTokensContract;
use Laravel\Sanctum\HasApiTokens;

class UserHasApiTokens extends User implements HasApiTokensContract
{
use HasApiTokens;
use HasFactory;
use Notifiable;

protected $table = 'users';

Expand Down

0 comments on commit a1e21e0

Please sign in to comment.