[ErrorHandler][FrameworkBundle] better error messages in failing tests
This commit is contained in:
parent
08bb79b174
commit
0da9469ee2
@ -14,6 +14,7 @@ CHANGELOG
|
|||||||
* Deprecated *not* setting the "framework.router.utf8" configuration option as it will default to `true` in Symfony 6.0
|
* Deprecated *not* setting the "framework.router.utf8" configuration option as it will default to `true` in Symfony 6.0
|
||||||
* Added tag `routing.expression_language_function` to define functions available in route conditions
|
* Added tag `routing.expression_language_function` to define functions available in route conditions
|
||||||
* Added `debug:container --deprecations` option to see compile-time deprecations.
|
* Added `debug:container --deprecations` option to see compile-time deprecations.
|
||||||
|
* Made `BrowserKitAssertionsTrait` report the original error message in case of a failure
|
||||||
|
|
||||||
5.0.0
|
5.0.0
|
||||||
-----
|
-----
|
||||||
|
@ -11,8 +11,10 @@
|
|||||||
|
|
||||||
namespace Symfony\Bundle\FrameworkBundle\Test;
|
namespace Symfony\Bundle\FrameworkBundle\Test;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\Constraint\Constraint;
|
||||||
use PHPUnit\Framework\Constraint\LogicalAnd;
|
use PHPUnit\Framework\Constraint\LogicalAnd;
|
||||||
use PHPUnit\Framework\Constraint\LogicalNot;
|
use PHPUnit\Framework\Constraint\LogicalNot;
|
||||||
|
use PHPUnit\Framework\ExpectationFailedException;
|
||||||
use Symfony\Component\BrowserKit\AbstractBrowser;
|
use Symfony\Component\BrowserKit\AbstractBrowser;
|
||||||
use Symfony\Component\BrowserKit\Test\Constraint as BrowserKitConstraint;
|
use Symfony\Component\BrowserKit\Test\Constraint as BrowserKitConstraint;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
@ -28,12 +30,12 @@ trait BrowserKitAssertionsTrait
|
|||||||
{
|
{
|
||||||
public static function assertResponseIsSuccessful(string $message = ''): void
|
public static function assertResponseIsSuccessful(string $message = ''): void
|
||||||
{
|
{
|
||||||
self::assertThat(self::getResponse(), new ResponseConstraint\ResponseIsSuccessful(), $message);
|
self::assertThatForResponse(new ResponseConstraint\ResponseIsSuccessful(), $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function assertResponseStatusCodeSame(int $expectedCode, string $message = ''): void
|
public static function assertResponseStatusCodeSame(int $expectedCode, string $message = ''): void
|
||||||
{
|
{
|
||||||
self::assertThat(self::getResponse(), new ResponseConstraint\ResponseStatusCodeSame($expectedCode), $message);
|
self::assertThatForResponse(new ResponseConstraint\ResponseStatusCodeSame($expectedCode), $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function assertResponseRedirects(string $expectedLocation = null, int $expectedCode = null, string $message = ''): void
|
public static function assertResponseRedirects(string $expectedLocation = null, int $expectedCode = null, string $message = ''): void
|
||||||
@ -46,42 +48,42 @@ trait BrowserKitAssertionsTrait
|
|||||||
$constraint = LogicalAnd::fromConstraints($constraint, new ResponseConstraint\ResponseStatusCodeSame($expectedCode));
|
$constraint = LogicalAnd::fromConstraints($constraint, new ResponseConstraint\ResponseStatusCodeSame($expectedCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
self::assertThat(self::getResponse(), $constraint, $message);
|
self::assertThatForResponse($constraint, $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function assertResponseHasHeader(string $headerName, string $message = ''): void
|
public static function assertResponseHasHeader(string $headerName, string $message = ''): void
|
||||||
{
|
{
|
||||||
self::assertThat(self::getResponse(), new ResponseConstraint\ResponseHasHeader($headerName), $message);
|
self::assertThatForResponse(new ResponseConstraint\ResponseHasHeader($headerName), $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function assertResponseNotHasHeader(string $headerName, string $message = ''): void
|
public static function assertResponseNotHasHeader(string $headerName, string $message = ''): void
|
||||||
{
|
{
|
||||||
self::assertThat(self::getResponse(), new LogicalNot(new ResponseConstraint\ResponseHasHeader($headerName)), $message);
|
self::assertThatForResponse(new LogicalNot(new ResponseConstraint\ResponseHasHeader($headerName)), $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function assertResponseHeaderSame(string $headerName, string $expectedValue, string $message = ''): void
|
public static function assertResponseHeaderSame(string $headerName, string $expectedValue, string $message = ''): void
|
||||||
{
|
{
|
||||||
self::assertThat(self::getResponse(), new ResponseConstraint\ResponseHeaderSame($headerName, $expectedValue), $message);
|
self::assertThatForResponse(new ResponseConstraint\ResponseHeaderSame($headerName, $expectedValue), $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function assertResponseHeaderNotSame(string $headerName, string $expectedValue, string $message = ''): void
|
public static function assertResponseHeaderNotSame(string $headerName, string $expectedValue, string $message = ''): void
|
||||||
{
|
{
|
||||||
self::assertThat(self::getResponse(), new LogicalNot(new ResponseConstraint\ResponseHeaderSame($headerName, $expectedValue)), $message);
|
self::assertThatForResponse(new LogicalNot(new ResponseConstraint\ResponseHeaderSame($headerName, $expectedValue)), $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function assertResponseHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void
|
public static function assertResponseHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void
|
||||||
{
|
{
|
||||||
self::assertThat(self::getResponse(), new ResponseConstraint\ResponseHasCookie($name, $path, $domain), $message);
|
self::assertThatForResponse(new ResponseConstraint\ResponseHasCookie($name, $path, $domain), $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function assertResponseNotHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void
|
public static function assertResponseNotHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void
|
||||||
{
|
{
|
||||||
self::assertThat(self::getResponse(), new LogicalNot(new ResponseConstraint\ResponseHasCookie($name, $path, $domain)), $message);
|
self::assertThatForResponse(new LogicalNot(new ResponseConstraint\ResponseHasCookie($name, $path, $domain)), $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function assertResponseCookieValueSame(string $name, string $expectedValue, string $path = '/', string $domain = null, string $message = ''): void
|
public static function assertResponseCookieValueSame(string $name, string $expectedValue, string $path = '/', string $domain = null, string $message = ''): void
|
||||||
{
|
{
|
||||||
self::assertThat(self::getResponse(), LogicalAnd::fromConstraints(
|
self::assertThatForResponse(LogicalAnd::fromConstraints(
|
||||||
new ResponseConstraint\ResponseHasCookie($name, $path, $domain),
|
new ResponseConstraint\ResponseHasCookie($name, $path, $domain),
|
||||||
new ResponseConstraint\ResponseCookieValueSame($name, $expectedValue, $path, $domain)
|
new ResponseConstraint\ResponseCookieValueSame($name, $expectedValue, $path, $domain)
|
||||||
), $message);
|
), $message);
|
||||||
@ -124,6 +126,21 @@ trait BrowserKitAssertionsTrait
|
|||||||
self::assertThat(self::getRequest(), $constraint, $message);
|
self::assertThat(self::getRequest(), $constraint, $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function assertThatForResponse(Constraint $constraint, string $message = ''): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
self::assertThat(self::getResponse(), $constraint, $message);
|
||||||
|
} catch (ExpectationFailedException $exception) {
|
||||||
|
if (($serverExceptionMessage = self::getResponse()->headers->get('X-Debug-Exception'))
|
||||||
|
&& ($serverExceptionFile = self::getResponse()->headers->get('X-Debug-Exception-File'))) {
|
||||||
|
$serverExceptionFile = explode(':', $serverExceptionFile);
|
||||||
|
$exception->__construct($exception->getMessage(), $exception->getComparisonFailure(), new \ErrorException(rawurldecode($serverExceptionMessage), 0, 1, rawurldecode($serverExceptionFile[0]), $serverExceptionFile[1]), $exception->getPrevious());
|
||||||
|
}
|
||||||
|
|
||||||
|
throw $exception;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static function getClient(AbstractBrowser $newClient = null): ?AbstractBrowser
|
private static function getClient(AbstractBrowser $newClient = null): ?AbstractBrowser
|
||||||
{
|
{
|
||||||
static $client;
|
static $client;
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
namespace Symfony\Bundle\FrameworkBundle\Tests\Test;
|
namespace Symfony\Bundle\FrameworkBundle\Tests\Test;
|
||||||
|
|
||||||
use PHPUnit\Framework\AssertionFailedError;
|
use PHPUnit\Framework\AssertionFailedError;
|
||||||
|
use PHPUnit\Framework\ExpectationFailedException;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
|
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
|
||||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestAssertionsTrait;
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestAssertionsTrait;
|
||||||
@ -235,6 +236,17 @@ class WebTestCaseTest extends TestCase
|
|||||||
$this->getRequestTester()->assertRouteSame('articles');
|
$this->getRequestTester()->assertRouteSame('articles');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testExceptionOnServerError()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->getResponseTester(new Response('', 500, ['X-Debug-Exception' => 'An exception has occurred', 'X-Debug-Exception-File' => '%2Fsrv%2Ftest.php:12']))->assertResponseIsSuccessful();
|
||||||
|
} catch (ExpectationFailedException $exception) {
|
||||||
|
$this->assertSame('An exception has occurred', $exception->getPrevious()->getMessage());
|
||||||
|
$this->assertSame('/srv/test.php', $exception->getPrevious()->getFile());
|
||||||
|
$this->assertSame(12, $exception->getPrevious()->getLine());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function getResponseTester(Response $response): WebTestCase
|
private function getResponseTester(Response $response): WebTestCase
|
||||||
{
|
{
|
||||||
$client = $this->createMock(KernelBrowser::class);
|
$client = $this->createMock(KernelBrowser::class);
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
5.1.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* The `HtmlErrorRenderer` and `SerializerErrorRenderer` add `X-Debug-Exception` and `X-Debug-Exception-File` headers in debug mode.
|
||||||
|
|
||||||
4.4.0
|
4.4.0
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
@ -66,9 +66,13 @@ class HtmlErrorRenderer implements ErrorRendererInterface
|
|||||||
*/
|
*/
|
||||||
public function render(\Throwable $exception): FlattenException
|
public function render(\Throwable $exception): FlattenException
|
||||||
{
|
{
|
||||||
$exception = FlattenException::createFromThrowable($exception, null, [
|
$headers = ['Content-Type' => 'text/html; charset='.$this->charset];
|
||||||
'Content-Type' => 'text/html; charset='.$this->charset,
|
if (\is_bool($this->debug) ? $this->debug : ($this->debug)($exception)) {
|
||||||
]);
|
$headers['X-Debug-Exception'] = rawurlencode($exception->getMessage());
|
||||||
|
$headers['X-Debug-Exception-File'] = rawurlencode($exception->getFile()).':'.$exception->getLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
$exception = FlattenException::createFromThrowable($exception, null, $headers);
|
||||||
|
|
||||||
return $exception->setAsString($this->renderException($exception));
|
return $exception->setAsString($this->renderException($exception));
|
||||||
}
|
}
|
||||||
|
@ -53,14 +53,21 @@ class SerializerErrorRenderer implements ErrorRendererInterface
|
|||||||
*/
|
*/
|
||||||
public function render(\Throwable $exception): FlattenException
|
public function render(\Throwable $exception): FlattenException
|
||||||
{
|
{
|
||||||
$flattenException = FlattenException::createFromThrowable($exception);
|
$headers = [];
|
||||||
|
$debug = \is_bool($this->debug) ? $this->debug : ($this->debug)($exception);
|
||||||
|
if ($debug) {
|
||||||
|
$headers['X-Debug-Exception'] = rawurlencode($exception->getMessage());
|
||||||
|
$headers['X-Debug-Exception-File'] = rawurlencode($exception->getFile()).':'.$exception->getLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
$flattenException = FlattenException::createFromThrowable($exception, null, $headers);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$format = \is_string($this->format) ? $this->format : ($this->format)($flattenException);
|
$format = \is_string($this->format) ? $this->format : ($this->format)($flattenException);
|
||||||
|
|
||||||
return $flattenException->setAsString($this->serializer->serialize($flattenException, $format, [
|
return $flattenException->setAsString($this->serializer->serialize($flattenException, $format, [
|
||||||
'exception' => $exception,
|
'exception' => $exception,
|
||||||
'debug' => \is_bool($this->debug) ? $this->debug : ($this->debug)($exception),
|
'debug' => $debug,
|
||||||
]));
|
]));
|
||||||
} catch (NotEncodableValueException $e) {
|
} catch (NotEncodableValueException $e) {
|
||||||
return $this->fallbackErrorRenderer->render($exception);
|
return $this->fallbackErrorRenderer->render($exception);
|
||||||
|
Reference in New Issue
Block a user