Update composer, remove self-rolled flash messages, update the tests to see if they work (they fail)

This commit is contained in:
Dave Smith-Hayes 2024-12-08 21:59:39 -05:00
parent 5e4a2289a1
commit 79de277f2d
10 changed files with 108 additions and 167 deletions

137
app/composer.lock generated
View File

@ -1078,16 +1078,16 @@
}, },
{ {
"name": "monolog/monolog", "name": "monolog/monolog",
"version": "3.8.0", "version": "3.8.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Seldaek/monolog.git", "url": "https://github.com/Seldaek/monolog.git",
"reference": "32e515fdc02cdafbe4593e30a9350d486b125b67" "reference": "aef6ee73a77a66e404dd6540934a9ef1b3c855b4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/32e515fdc02cdafbe4593e30a9350d486b125b67", "url": "https://api.github.com/repos/Seldaek/monolog/zipball/aef6ee73a77a66e404dd6540934a9ef1b3c855b4",
"reference": "32e515fdc02cdafbe4593e30a9350d486b125b67", "reference": "aef6ee73a77a66e404dd6540934a9ef1b3c855b4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1165,7 +1165,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/Seldaek/monolog/issues", "issues": "https://github.com/Seldaek/monolog/issues",
"source": "https://github.com/Seldaek/monolog/tree/3.8.0" "source": "https://github.com/Seldaek/monolog/tree/3.8.1"
}, },
"funding": [ "funding": [
{ {
@ -1177,7 +1177,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-11-12T13:57:08+00:00" "time": "2024-12-05T17:15:07+00:00"
}, },
{ {
"name": "nette/schema", "name": "nette/schema",
@ -4335,29 +4335,27 @@
"packages-dev": [ "packages-dev": [
{ {
"name": "doctrine/deprecations", "name": "doctrine/deprecations",
"version": "1.1.3", "version": "1.1.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/deprecations.git", "url": "https://github.com/doctrine/deprecations.git",
"reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab" "reference": "31610dbb31faa98e6b5447b62340826f54fbc4e9"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", "url": "https://api.github.com/repos/doctrine/deprecations/zipball/31610dbb31faa98e6b5447b62340826f54fbc4e9",
"reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", "reference": "31610dbb31faa98e6b5447b62340826f54fbc4e9",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^7.1 || ^8.0" "php": "^7.1 || ^8.0"
}, },
"require-dev": { "require-dev": {
"doctrine/coding-standard": "^9", "doctrine/coding-standard": "^9 || ^12",
"phpstan/phpstan": "1.4.10 || 1.10.15", "phpstan/phpstan": "1.4.10 || 2.0.3",
"phpstan/phpstan-phpunit": "^1.0", "phpstan/phpstan-phpunit": "^1.0 || ^2",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
"psalm/plugin-phpunit": "0.18.4", "psr/log": "^1 || ^2 || ^3"
"psr/log": "^1 || ^2 || ^3",
"vimeo/psalm": "4.30.0 || 5.12.0"
}, },
"suggest": { "suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation" "psr/log": "Allows logging deprecations via PSR-3 logger implementation"
@ -4365,7 +4363,7 @@
"type": "library", "type": "library",
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" "Doctrine\\Deprecations\\": "src"
} }
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
@ -4376,9 +4374,9 @@
"homepage": "https://www.doctrine-project.org/", "homepage": "https://www.doctrine-project.org/",
"support": { "support": {
"issues": "https://github.com/doctrine/deprecations/issues", "issues": "https://github.com/doctrine/deprecations/issues",
"source": "https://github.com/doctrine/deprecations/tree/1.1.3" "source": "https://github.com/doctrine/deprecations/tree/1.1.4"
}, },
"time": "2024-01-30T19:34:25+00:00" "time": "2024-12-07T21:18:45+00:00"
}, },
{ {
"name": "doctrine/instantiator", "name": "doctrine/instantiator",
@ -4741,16 +4739,16 @@
}, },
{ {
"name": "phpdocumentor/reflection-docblock", "name": "phpdocumentor/reflection-docblock",
"version": "5.6.0", "version": "5.6.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "f3558a4c23426d12bffeaab463f8a8d8b681193c" "reference": "e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/f3558a4c23426d12bffeaab463f8a8d8b681193c", "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8",
"reference": "f3558a4c23426d12bffeaab463f8a8d8b681193c", "reference": "e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4799,9 +4797,9 @@
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"support": { "support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.0" "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.1"
}, },
"time": "2024-11-12T11:25:25+00:00" "time": "2024-12-07T09:39:29+00:00"
}, },
{ {
"name": "phpdocumentor/type-resolver", "name": "phpdocumentor/type-resolver",
@ -5358,16 +5356,16 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "11.4.4", "version": "11.5.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "f9ba7bd3c9f3ff54ec379d7a1c2e3f13fe0bbde4" "reference": "0569902506a6c0878930b87ea79ec3b50ea563f7"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f9ba7bd3c9f3ff54ec379d7a1c2e3f13fe0bbde4", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0569902506a6c0878930b87ea79ec3b50ea563f7",
"reference": "f9ba7bd3c9f3ff54ec379d7a1c2e3f13fe0bbde4", "reference": "0569902506a6c0878930b87ea79ec3b50ea563f7",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -5391,11 +5389,12 @@
"sebastian/comparator": "^6.2.1", "sebastian/comparator": "^6.2.1",
"sebastian/diff": "^6.0.2", "sebastian/diff": "^6.0.2",
"sebastian/environment": "^7.2.0", "sebastian/environment": "^7.2.0",
"sebastian/exporter": "^6.1.3", "sebastian/exporter": "^6.3.0",
"sebastian/global-state": "^7.0.2", "sebastian/global-state": "^7.0.2",
"sebastian/object-enumerator": "^6.0.1", "sebastian/object-enumerator": "^6.0.1",
"sebastian/type": "^5.1.0", "sebastian/type": "^5.1.0",
"sebastian/version": "^5.0.2" "sebastian/version": "^5.0.2",
"staabm/side-effects-detector": "^1.0.5"
}, },
"suggest": { "suggest": {
"ext-soap": "To be able to generate mocks based on WSDL files" "ext-soap": "To be able to generate mocks based on WSDL files"
@ -5406,7 +5405,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "11.4-dev" "dev-main": "11.5-dev"
} }
}, },
"autoload": { "autoload": {
@ -5438,7 +5437,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues", "issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy", "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.4.4" "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.0"
}, },
"funding": [ "funding": [
{ {
@ -5454,7 +5453,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-11-27T10:44:52+00:00" "time": "2024-12-06T05:57:38+00:00"
}, },
{ {
"name": "sebastian/cli-parser", "name": "sebastian/cli-parser",
@ -5894,16 +5893,16 @@
}, },
{ {
"name": "sebastian/exporter", "name": "sebastian/exporter",
"version": "6.1.3", "version": "6.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git", "url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "c414673eee9a8f9d51bbf8d61fc9e3ef1e85b20e" "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/c414673eee9a8f9d51bbf8d61fc9e3ef1e85b20e", "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/3473f61172093b2da7de1fb5782e1f24cc036dc3",
"reference": "c414673eee9a8f9d51bbf8d61fc9e3ef1e85b20e", "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -5912,7 +5911,7 @@
"sebastian/recursion-context": "^6.0" "sebastian/recursion-context": "^6.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^11.2" "phpunit/phpunit": "^11.3"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@ -5960,7 +5959,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues", "issues": "https://github.com/sebastianbergmann/exporter/issues",
"security": "https://github.com/sebastianbergmann/exporter/security/policy", "security": "https://github.com/sebastianbergmann/exporter/security/policy",
"source": "https://github.com/sebastianbergmann/exporter/tree/6.1.3" "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.0"
}, },
"funding": [ "funding": [
{ {
@ -5968,7 +5967,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2024-07-03T04:56:19+00:00" "time": "2024-12-05T09:17:50+00:00"
}, },
{ {
"name": "sebastian/global-state", "name": "sebastian/global-state",
@ -6379,6 +6378,58 @@
], ],
"time": "2024-10-09T05:16:32+00:00" "time": "2024-10-09T05:16:32+00:00"
}, },
{
"name": "staabm/side-effects-detector",
"version": "1.0.5",
"source": {
"type": "git",
"url": "https://github.com/staabm/side-effects-detector.git",
"reference": "d8334211a140ce329c13726d4a715adbddd0a163"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163",
"reference": "d8334211a140ce329c13726d4a715adbddd0a163",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
"php": "^7.4 || ^8.0"
},
"require-dev": {
"phpstan/extension-installer": "^1.4.3",
"phpstan/phpstan": "^1.12.6",
"phpunit/phpunit": "^9.6.21",
"symfony/var-dumper": "^5.4.43",
"tomasvotruba/type-coverage": "1.0.0",
"tomasvotruba/unused-public": "1.0.0"
},
"type": "library",
"autoload": {
"classmap": [
"lib/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "A static analysis tool to detect side effects in PHP code",
"keywords": [
"static analysis"
],
"support": {
"issues": "https://github.com/staabm/side-effects-detector/issues",
"source": "https://github.com/staabm/side-effects-detector/tree/1.0.5"
},
"funding": [
{
"url": "https://github.com/staabm",
"type": "github"
}
],
"time": "2024-10-20T05:08:20+00:00"
},
{ {
"name": "theseer/tokenizer", "name": "theseer/tokenizer",
"version": "1.2.3", "version": "1.2.3",
@ -6490,12 +6541,12 @@
], ],
"aliases": [], "aliases": [],
"minimum-stability": "stable", "minimum-stability": "stable",
"stability-flags": {}, "stability-flags": [],
"prefer-stable": false, "prefer-stable": false,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
"ext-pdo": "*" "ext-pdo": "*"
}, },
"platform-dev": {}, "platform-dev": [],
"plugin-api-version": "2.6.0" "plugin-api-version": "2.6.0"
} }

View File

@ -16,7 +16,6 @@ use Monolog\Logger;
use Odan\Session\PhpSession; use Odan\Session\PhpSession;
use Odan\Session\SessionInterface; use Odan\Session\SessionInterface;
use Odan\Session\SessionManagerInterface; use Odan\Session\SessionManagerInterface;
use Odan\Session\FlashInterface;
use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface; use Psr\Container\ContainerInterface;
@ -27,7 +26,6 @@ use Psr\Log\LoggerInterface;
use Slim\App; use Slim\App;
use Slim\Factory\AppFactory; use Slim\Factory\AppFactory;
use Slim\Psr7\Factory\ResponseFactory; use Slim\Psr7\Factory\ResponseFactory;
use Slovocast\Infrastructure\Session\FlashMessages;
use Slovocast\Middleware\SessionMiddleware; use Slovocast\Middleware\SessionMiddleware;
use Twig\Error\LoaderError; use Twig\Error\LoaderError;
@ -133,14 +131,6 @@ class Bootstrap
'session' => function (ContainerInterface $container) { 'session' => function (ContainerInterface $container) {
return $container->get(SessionInterface::class); return $container->get(SessionInterface::class);
}, },
FlashInterface::class => function (ContainerInterface $container) {
return new FlashMessages(
$container->get(SessionInterface::class)
);
},
'flash' => function (ContainerInterface $container) {
return $container->get(FlashInterface::class);
},
SessionMiddleware::class => function (ContainerInterface $container) { SessionMiddleware::class => function (ContainerInterface $container) {
return new SessionMiddleware( return new SessionMiddleware(
$container->get(SessionManagerInterface::class), $container->get(SessionManagerInterface::class),

View File

@ -2,7 +2,6 @@
namespace Slovocast\Controller\User; namespace Slovocast\Controller\User;
use Odan\Session\FlashInterface;
use Odan\Session\SessionInterface; use Odan\Session\SessionInterface;
use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ResponseInterface as Response;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
@ -17,7 +16,6 @@ class LoginUserAction extends Controller
private UserAuthorizationInterface $auth, private UserAuthorizationInterface $auth,
private UserRepositoryInterface $userRepository, private UserRepositoryInterface $userRepository,
private SessionInterface $session, private SessionInterface $session,
private FlashInterface $flash,
private LoggerInterface $logger, private LoggerInterface $logger,
) { } ) { }
@ -29,20 +27,20 @@ class LoginUserAction extends Controller
$user = $this->userRepository->getFromEmail($credentials['email']); $user = $this->userRepository->getFromEmail($credentials['email']);
} catch (EntityNotFoundException $e) { } catch (EntityNotFoundException $e) {
$this->logger->error("Unable to login user."); $this->logger->error("Unable to login user.");
$this->flash->add('error', "Unable to login user."); $this->session->getFlash()->add('error', "Unable to login user.");
return $this->render('user/login.twig')->withStatus(400); return $this->render('user/login.twig')->withStatus(400);
} }
if (!$this->auth->verify($credentials['password'], $user->getPassword())) { if (!$this->auth->verify($credentials['password'], $user->getPassword())) {
$this->logger->error("Unable to verify user password."); $this->logger->error("Unable to verify user password.");
$this->flash->add('error', "Unable to login user."); $this->session->getFlash()->add('error', "Unable to login user.");
return $this->render('user/login.twig')->withStatus(400); return $this->render('user/login.twig')->withStatus(400);
} }
// start the session // start the session
$this->flash->add('success', "Successfully logged in."); $this->session->getFlash()->add('success', "Successfully logged in.");
$this->session->set('authenticated', true); $this->session->set('authenticated', true);
$this->session->set('user', $user->toArray()); $this->session->set('user', $user->toArray());
return $this->redirect('/dashboard', 302); return $this->redirect('/dashboard', 302);

View File

@ -11,7 +11,6 @@ class LogoutUserAction extends Controller
{ {
public function __construct( public function __construct(
protected SessionInterface $session, protected SessionInterface $session,
protected FlashInterface $flash
) { } ) { }
@ -25,7 +24,7 @@ class LogoutUserAction extends Controller
$this->session->delete('user'); $this->session->delete('user');
} }
$this->flash->add('notice', "Successfully logged out."); $this->session->getFlash()->add('notice', "Successfully logged out.");
return $this->redirect('/', 302); return $this->redirect('/', 302);
} }
} }

View File

@ -29,7 +29,7 @@ class RegisterUserAction extends Controller
if ($success) { if ($success) {
return $this->render('user/success.twig'); return $this->render('user/success.twig');
} else { } else {
$this->flash->add('error', "Unable to register user."); $this->session->getFlash()->add('error', "Unable to register user.");
return $this->render('user/register.twig')->withStatus(400); return $this->render('user/register.twig')->withStatus(400);
} }
} }

View File

@ -1,83 +0,0 @@
<?php
namespace Slovocast\Infrastructure\Session;
use Odan\Session\SessionInterface;
use Odan\Session\FlashInterface;
class FlashMessages implements FlashInterface
{
const LEVEL_ERROR = "error";
const LEVEL_NOTICE = "notice";
const LEVEL_SUCCESS = "success";
private string $key = "_flash";
public function __construct(
protected SessionInterface $session
) {
$this->session->set($this->key, []);
}
/**
* @return array<string, array<string>>
*/
protected function getMessages(): array
{
return $this->session->get($this->key);
}
/**
* @param array<string, array<string>> $messages
* @return void
*/
protected function saveMessages(array $messages): void
{
$this->session->set($this->key, $messages);
}
public function has(string $key): bool
{
return array_key_exists($key, $this->getMessages());
}
public function set(string $key, array $messages): void
{
$messages = $this->getMessages();
$messages[$key] = $messages;
$this->saveMessages($messages);
}
public function add(string $key, string $message): void
{
$messages = $this->getMessages();
$messages[$key][] = $message;
$this->saveMessages($messages);
}
public function get(string $level): array
{
$messages = $this->getMessages();
if (!array_key_exists($level, $messages)) {
return [];
}
$buffer = $messages[$level];
unset($messages[$level]);
$this->saveMessages($messages);
return $buffer;
}
public function all(): array
{
$messages = $this->getMessages();
$this->clear();
return $messages;
}
public function clear(): void
{
$this->session->set($this->key, []);
}
}

View File

@ -47,10 +47,10 @@ class Middlewares
$twig->getEnvironment()->addGlobal('site_name', $config->get('site.name')); $twig->getEnvironment()->addGlobal('site_name', $config->get('site.name'));
$twig->getEnvironment()->addGlobal('site_description', $config->get('site.description')); $twig->getEnvironment()->addGlobal('site_description', $config->get('site.description'));
/** @var SessionInterface $session */
$session = $container->get(SessionInterface::class); $session = $container->get(SessionInterface::class);
$flash = $container->get(FlashInterface::class);
$twig->getEnvironment()->addGlobal('session', $session); $twig->getEnvironment()->addGlobal('session', $session);
$twig->getEnvironment()->addGlobal('flash', $flash); $twig->getEnvironment()->addGlobal('flash', $session->getFlash());
$app->add(TwigMiddleware::create($app, $twig)); $app->add(TwigMiddleware::create($app, $twig));

View File

@ -1,17 +1,5 @@
{% for message in flash.get('success') %} {% for level, message in flash.all() %}
<div class="flash success" role="alert"> <div class="flash {{ level }}" role="alert">
{{ message }}
</div>
{% endfor %}
{% for message in flash.get('notice') %}
<div class="flash notice" role="alert">
{{ message }}
</div>
{% endfor %}
{% for message in flash.get('error') %}
<div class="flash error" role="alert">
{{ message }} {{ message }}
</div> </div>
{% endfor %} {% endfor %}

View File

@ -126,8 +126,9 @@ class ControllerTest extends TestCase
$flash = $app->getContainer()->get(SessionInterface::class)->getFlash(); $flash = $app->getContainer()->get(SessionInterface::class)->getFlash();
$body = $response->getBody(); $body = $response->getBody();
$body->read($body->getSize());
// the flash class is in the body for this test case // the flash class is in the body for this test case
//
echo (string) $body;
$this->assertTrue(str_contains($body, '<div class="flash error" role="alert">')); $this->assertTrue(str_contains($body, '<div class="flash error" role="alert">'));
$this->assertTrue(str_contains($body, "Error message")); $this->assertTrue(str_contains($body, "Error message"));
$this->assertEmpty($flash->all()); $this->assertEmpty($flash->all());

View File

@ -95,10 +95,7 @@ class RegisterUserActionTest extends TestCase
$userRepository = $this->prophesize(UserRepositoryInterface::class); $userRepository = $this->prophesize(UserRepositoryInterface::class);
$userRepository->create($user)->willReturn(false); $userRepository->create($user)->willReturn(false);
$container->set( $container->set(UserRepositoryInterface::class, $userRepository->reveal());
UserRepositoryInterface::class,
$userRepository->reveal()
);
// get the form key // get the form key
$getUserRequest = $this->createNewUserRequestForFormKey(); $getUserRequest = $this->createNewUserRequestForFormKey();
@ -113,9 +110,9 @@ class RegisterUserActionTest extends TestCase
$responseBody = $response->getBody(); $responseBody = $response->getBody();
// get the class of the flash on the rendered page // get the class of the flash on the rendered page
$this->assertTrue((bool)preg_match('/flash error/', $responseBody)); $this->assertTrue(str_contains($responseBody, 'flash error'));
// get the text inside the flash // get the text inside the flash
$this->assertTrue((bool)preg_match('/Unable to register user\./', $responseBody)); $this->assertTrue(str_contains($responseBody, 'Unable to register user.'));
/** /**
* The Flash messages are already exhausted while rendering the * The Flash messages are already exhausted while rendering the