Last active
August 22, 2023 14:59
-
-
Save colindecarlo/9ba9bd6524127fee7580ae66c6d4709d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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); | |
} | |
} |
Did somebody make this a package yet?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nice