engelsystem/tests/Unit/Controllers/PasswordResetControllerTest...

270 lines
8.8 KiB
PHP
Raw Normal View History

2019-10-08 16:17:06 +02:00
<?php
declare(strict_types=1);
2019-10-08 16:17:06 +02:00
namespace Engelsystem\Test\Unit\Controllers;
use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;
2019-10-08 16:17:06 +02:00
use Engelsystem\Config\Config;
2023-02-02 22:53:51 +01:00
use Engelsystem\Controllers\NotificationType;
2019-10-08 16:17:06 +02:00
use Engelsystem\Controllers\PasswordResetController;
use Engelsystem\Helpers\Authenticator;
use Engelsystem\Http\Exceptions\HttpNotFound;
use Engelsystem\Http\Exceptions\ValidationException;
use Engelsystem\Http\Request;
use Engelsystem\Http\Response;
use Engelsystem\Http\Validation\Validator;
use Engelsystem\Mail\EngelsystemMailer;
2023-09-17 20:25:48 +02:00
use Engelsystem\Models\Session as SessionModel;
2019-10-08 16:17:06 +02:00
use Engelsystem\Models\User\PasswordReset;
use Engelsystem\Models\User\User;
use Engelsystem\Renderer\Renderer;
use Engelsystem\Test\Unit\HasDatabase;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\Test\TestLogger;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
2023-02-02 22:53:51 +01:00
class PasswordResetControllerTest extends ControllerTest
2019-10-08 16:17:06 +02:00
{
use ArraySubsetAsserts;
2019-10-08 16:17:06 +02:00
use HasDatabase;
protected array $args = [];
2019-10-08 16:17:06 +02:00
/**
* @covers \Engelsystem\Controllers\PasswordResetController::reset
* @covers \Engelsystem\Controllers\PasswordResetController::__construct
*/
public function testReset(): void
{
$controller = $this->getController('pages/password/reset');
$response = $controller->reset();
$this->assertEquals(200, $response->getStatusCode());
}
/**
* @covers \Engelsystem\Controllers\PasswordResetController::postReset
*/
public function testPostReset(): void
{
$this->initDatabase();
$request = new Request([], ['email' => 'foo@bar.batz']);
$user = $this->createUser();
$controller = $this->getController(
'pages/password/reset-success',
2023-02-02 22:53:51 +01:00
['type' => 'email']
2019-10-08 16:17:06 +02:00
);
/** @var TestLogger $log */
$log = $this->args['log'];
/** @var EngelsystemMailer|MockObject $mailer */
$mailer = $this->args['mailer'];
$this->setExpects($mailer, 'sendViewTranslated');
$controller->postReset($request);
$this->assertNotEmpty((new PasswordReset())->find($user->id)->first());
2019-10-08 16:17:06 +02:00
$this->assertTrue($log->hasInfoThatContains($user->name));
2023-02-02 22:53:51 +01:00
$this->assertHasNoNotifications();
2019-10-08 16:17:06 +02:00
}
/**
* @covers \Engelsystem\Controllers\PasswordResetController::postReset
*/
public function testPostResetInvalidRequest(): void
{
$request = new Request();
$controller = $this->getController();
$this->expectException(ValidationException::class);
$controller->postReset($request);
}
/**
* @covers \Engelsystem\Controllers\PasswordResetController::postReset
*/
public function testPostResetNoUser(): void
{
$this->initDatabase();
$request = new Request([], ['email' => 'foo@bar.batz']);
$controller = $this->getController(
'pages/password/reset-success',
2023-02-02 22:53:51 +01:00
['type' => 'email']
2019-10-08 16:17:06 +02:00
);
$controller->postReset($request);
2023-02-02 22:53:51 +01:00
$this->assertHasNoNotifications();
2019-10-08 16:17:06 +02:00
}
/**
* @covers \Engelsystem\Controllers\PasswordResetController::resetPassword
* @covers \Engelsystem\Controllers\PasswordResetController::requireToken
*/
public function testResetPassword(): void
{
$this->initDatabase();
2020-11-24 17:27:21 +01:00
$this->app->instance('config', new Config(['min_password_length' => 3]));
2019-10-08 16:17:06 +02:00
$user = $this->createUser();
$token = $this->createToken($user);
$request = new Request([], [], ['token' => $token->token]);
$controller = $this->getController('pages/password/reset-form');
$controller->resetPassword($request);
}
/**
* @covers \Engelsystem\Controllers\PasswordResetController::resetPassword
* @covers \Engelsystem\Controllers\PasswordResetController::requireToken
*/
public function testResetPasswordNoToken(): void
{
$this->initDatabase();
$controller = $this->getController();
$this->expectException(HttpNotFound::class);
$controller->resetPassword(new Request());
}
/**
* @covers \Engelsystem\Controllers\PasswordResetController::postResetPassword
*/
public function testPostResetPassword(): void
{
$this->initDatabase();
$this->app->instance('config', new Config(['min_password_length' => 3]));
$user = $this->createUser();
$token = $this->createToken($user);
$password = 'SomeRandomPasswordForAmazingSecurity';
$request = new Request(
[],
['password' => $password, 'password_confirmation' => $password],
['token' => $token->token]
);
2023-09-17 20:25:48 +02:00
SessionModel::factory()->create(); // Some other session
SessionModel::factory(3)->create(['user_id' => $user->id]);
2019-10-08 16:17:06 +02:00
$controller = $this->getController(
'pages/password/reset-success',
2023-02-02 22:53:51 +01:00
['type' => 'reset']
2019-10-08 16:17:06 +02:00
);
$auth = new Authenticator($request, $this->args['session'], $user);
$this->app->instance('authenticator', $auth);
$response = $controller->postResetPassword($request);
$this->assertEquals(200, $response->getStatusCode());
2019-11-10 23:26:23 +01:00
$this->assertEmpty((new PasswordReset())->find($user->id));
2019-10-08 16:17:06 +02:00
$this->assertNotNull(auth()->authenticate($user->name, $password));
2023-02-02 22:53:51 +01:00
$this->assertHasNoNotifications();
2023-09-17 20:25:48 +02:00
$this->assertEmpty(
SessionModel::whereUserId($user->id)->get(),
'All user sessions should be deleted after successful password reset'
);
$this->assertCount(1, SessionModel::all()); // Another session should be still there
2019-10-08 16:17:06 +02:00
}
/**
* @covers \Engelsystem\Controllers\PasswordResetController::postResetPassword
* @covers \Engelsystem\Controllers\PasswordResetController::showView
*/
public function testPostResetPasswordNotMatching(): void
{
$this->initDatabase();
$this->app->instance('config', new Config(['min_password_length' => 3]));
$user = $this->createUser();
$token = $this->createToken($user);
$password = 'SomeRandomPasswordForAmazingSecurity';
$request = new Request(
[],
['password' => $password, 'password_confirmation' => $password . 'OrNot'],
['token' => $token->token]
);
2023-02-02 22:53:51 +01:00
$controller = $this->getController('pages/password/reset-form');
2019-10-08 16:17:06 +02:00
$controller->postResetPassword($request);
2023-02-02 22:53:51 +01:00
$this->assertHasNotification('validation.password.confirmed', NotificationType::ERROR);
2019-10-08 16:17:06 +02:00
}
protected function getControllerArgs(): array
{
$response = new Response();
$session = new Session(new MockArraySessionStorage());
/** @var EngelsystemMailer|MockObject $mailer */
$mailer = $this->createMock(EngelsystemMailer::class);
$log = new TestLogger();
$renderer = $this->createMock(Renderer::class);
$response->setRenderer($renderer);
$this->app->instance('session', $session);
2023-02-02 22:53:51 +01:00
$this->session = $session;
$this->response = $response;
$this->log = $log;
2019-10-08 16:17:06 +02:00
return $this->args = [
'response' => $response,
'session' => $session,
'mailer' => $mailer,
'log' => $log,
'renderer' => $renderer,
2019-10-08 16:17:06 +02:00
];
}
protected function getController(?string $view = null, ?array $data = null): PasswordResetController
{
/** @var Response $response */
/** @var Session $session */
/** @var EngelsystemMailer|MockObject $mailer */
/** @var TestLogger $log */
/** @var Renderer|MockObject $renderer */
list($response, $session, $mailer, $log, $renderer) = array_values($this->getControllerArgs());
$controller = new PasswordResetController($response, $session, $mailer, $log);
$controller->setValidator(new Validator());
if ($view) {
/** @var array|mixed[] $args */
2019-10-08 16:17:06 +02:00
$args = [$view];
if ($data) {
$args[] = $data;
}
$renderer->expects($this->atLeastOnce())
->method('render')
->willReturnCallback(function ($template, $data = []) use ($args) {
$this->assertEquals($args[0], $template);
if (isset($args[1])) {
$this->assertArraySubset($args[1], $data);
}
return 'Foo';
});
2019-10-08 16:17:06 +02:00
}
return $controller;
}
protected function createUser(): User
{
2021-06-29 00:27:57 +02:00
return User::factory()->create(['email' => 'foo@bar.batz']);
2019-10-08 16:17:06 +02:00
}
protected function createToken(User $user): PasswordReset
{
$reset = new PasswordReset(['user_id' => $user->id, 'token' => 'SomeTestToken123']);
$reset->save();
return $reset;
}
}