Skip to content

Instantly share code, notes, and snippets.

@sidigi
Forked from colindecarlo/TestFormRequest.php
Created September 14, 2021 17:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sidigi/34c67a75b139949656ba55d8557530a9 to your computer and use it in GitHub Desktop.
Save sidigi/34c67a75b139949656ba55d8557530a9 to your computer and use it in GitHub Desktop.
<?php
namespace Tests;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\ValidationException;
use Illuminate\Validation\Validator;
use Symfony\Component\HttpFoundation\ParameterBag;
use function PHPUnit\Framework\assertFalse;
use function PHPUnit\Framework\assertTrue;
class TestFormRequest
{
private FormRequest $request;
public function __construct(FormRequest $request)
{
$this->request = $request;
}
public function validate(array $data)
{
$this->request->request = new ParameterBag($data);
/** @var Validator $validator */
$validator = \Closure::fromCallable(function () {
return $this->getValidatorInstance();
})->call($this->request);
try {
$validator->validate();
} catch (ValidationException $e) {
return new TestValidationResult($validator, $e);
}
return new TestValidationResult($validator);
}
public function by(Authenticatable $user = null)
{
$this->request->setUserResolver(fn() => $user);
return $this;
}
public function withParams(array $params)
{
foreach($params as $param => $value) {
$this->withParam($param, $value);
}
return $this;
}
public function withParam(string $param, $value)
{
$this->request->route()->setParameter($param, $value);
return $this;
}
public function assertAuthorized()
{
assertTrue(
$this->bully(fn() => $this->passesAuthorization(), $this->request),
'The provided user is not authorized by this request'
);
}
public function assertNotAuthorized()
{
assertFalse(
$this->bully(fn() => $this->passesAuthorization(), $this->request),
'The provided user is authorized by this request'
);
}
private function bully(\Closure $elevatedFunction, object $targetObject)
{
return \Closure::fromCallable($elevatedFunction)->call($targetObject);
}
}
<?php
namespace Tests;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Illuminate\Validation\Validator;
use function PHPUnit\Framework\assertArrayHasKey;
use function PHPUnit\Framework\assertContains;
use function PHPUnit\Framework\assertStringContainsString;
use function PHPUnit\Framework\assertTrue;
class TestValidationResult
{
private Validator $validator;
private ?ValidationException $failed;
public function __construct(Validator $validator, ?ValidationException $failed = null)
{
$this->validator = $validator;
$this->failed = $failed;
}
public function assertPassesValidation()
{
assertTrue($this->validator->passes(),
sprintf("Validation of the payload:\n%s\ndid not pass validation rules\n%s\n",
json_encode($this->validator->getData(), JSON_PRETTY_PRINT),
json_encode($this->getFailedRules(), JSON_PRETTY_PRINT)
)
);
return $this;
}
public function assertFailsValidation($expectedFailedRules = [])
{
assertTrue($this->validator->fails());
if (empty($expectedFailedRules)) {
return $this;
}
$failedRules = $this->getFailedRules();
foreach ($expectedFailedRules as $expectedFailedRule => $constraints) {
assertArrayHasKey($expectedFailedRule, $failedRules);
assertStringContainsString($constraints, $failedRules[$expectedFailedRule]);
}
return $this;
}
public function assertHasMessage($message, $rule = null)
{
$validationMessages = $this->getValidationMessages($rule);
assertContains($message, $validationMessages,
sprintf("\"%s\" was not contained in the failed%s validation messages\n%s",
$message, $rule ? ' '.$rule : '', json_encode($validationMessages, JSON_PRETTY_PRINT)
)
);
return $this;
}
public function getFailedRules()
{
if (!$this->failed) {
return [];
}
$failedRules = collect($this->validator->failed())
->map(function ($details) {
return collect($details)->reduce(function ($aggregateRule, $constraints, $ruleName) {
$failedRule = Str::lower($ruleName);
if (count($constraints)) {
$failedRule .= ':'.implode(',', $constraints);
}
return $aggregateRule.$failedRule;
});
});
return $failedRules;
}
private function getValidationMessages($rule = null)
{
$messages = $this->validator->messages()->getMessages();
if ($rule) {
return $messages[$rule] ?? [];
}
return Arr::flatten($messages);
}
}
<?php
namespace Tests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Request;
use Illuminate\Routing\Route;
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
trait ValidatesRequests
{
protected function createRequest(string $requestClass, $headers = [])
{
$symfonyRequest = SymfonyRequest::create(
$this->prepareUrlForRequest('/test/route'),
'POST',
[],
$this->prepareCookiesForRequest(),
[],
array_replace($this->serverVariables, $this->transformHeadersToServerVars($headers))
);
$formRequest = FormRequest::createFrom(
Request::createFromBase($symfonyRequest),
new $requestClass
)->setContainer($this->app);
$route = new Route('POST', '/test/route', fn() => null);
$route->parameters = [];
$formRequest->setRouteResolver(fn() => $route);
return new TestFormRequest($formRequest);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment