8000 [ErrorHandler][FrameworkBundle] better error messages in failing tests · symfony/symfony@0da9469 · GitHub
[go: up one dir, main page]

Skip to content

Commit 0da9469

Browse files
Guillaume Pédelagrabefabpot
authored andcommitted
[ErrorHandler][FrameworkBundle] better error messages in failing tests
1 parent 08bb79b commit 0da9469

File tree

6 files changed

+61
-15
lines changed

6 files changed

+61
-15
lines changed

src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ CHANGELOG
1414
* Deprecated *not* setting the "framework.router.utf8" configuration option as it will default to `true` in Symfony 6.0
1515
* Added tag `routing.expression_language_function` to define functions available in route conditions
1616
* Added `debug:container --deprecations` option to see compile-time deprecations.
17+
* Made `BrowserKitAssertionsTrait` report the original error message in case of a failure
1718

1819
5.0.0
1920
-----

src/Symfony/Bundle/FrameworkBundle/Test/BrowserKitAssertionsTrait.php

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111

1212
namespace Symfony\Bundle\FrameworkBundle\Test;
1313

14+
use PHPUnit\Framework\Constraint\Constraint;
1415
use PHPUnit\Framework\Constraint\LogicalAnd;
1516
use PHPUnit\Framework\Constraint\LogicalNot;
17+
use PHPUnit\Framework\ExpectationFailedException;
1618
use Symfony\Component\BrowserKit\AbstractBrowser;
1719
use Symfony\Component\BrowserKit\Test\Constraint as BrowserKitConstraint;
1820
use Symfony\Component\HttpFoundation\Request;
@@ -28,12 +30,12 @@ trait BrowserKitAssertionsTrait
2830
{
2931
public static function assertResponseIsSuccessful(string $message = ''): void
3032
{
31-
self::assertThat(self::getResponse(), new ResponseConstraint\ResponseIsSuccessful(), $message);
33+
self::assertThatForResponse(new ResponseConstraint\ResponseIsSuccessful(), $message);
3234
}
3335

3436
public static function assertResponseStatusCodeSame(int $expectedCode, string $message = ''): void
3537
{
36-
self::assertThat(self::getResponse(), new ResponseConstraint\ResponseStatusCodeSame($expectedCode), $message);
38+
self::assertThatForResponse(new ResponseConstraint\ResponseStatusCodeSame($expectedCode), $message);
3739
}
3840

3941
public static function assertResponseRedirects(string $expectedLocation = null, int $expectedCode = null, string $message = ''): void
@@ -46,42 +48,42 @@ public static function assertResponseRedirects(string $expectedLocation = null,
4648
$constraint = LogicalAnd::fromConstraints($constraint, new ResponseConstraint\ResponseStatusCodeSame($expectedCode));
4749
}
4850

49-
self::assertThat(self::getResponse(), $constraint, $message);
51+
self::assertThatForResponse($constraint, $message);
5052
}
5153

5254
public static function assertResponseHasHeader(string $headerName, string $message = ''): void
5355
{
54-
self::assertThat(self::getResponse(), new ResponseConstraint\ResponseHasHeader($headerName), $message);
56+
self::assertThatForResponse(new ResponseConstraint\ResponseHasHeader($headerName), $message);
5557
}
5658

5759
public static function assertResponseNotHasHeader(string $headerName, string $message = ''): void
5860
{
59-
self::assertThat(self::getResponse(), new LogicalNot(new ResponseConstraint\ResponseHasHeader($headerName)), $message);
61+
self::assertThatForResponse(new LogicalNot(new ResponseConstraint\ResponseHasHeader($headerName)), $message);
6062
}
6163

6264
public static function assertResponseHeaderSame(string $headerName, string $expectedValue, string $message = ''): void
6365
{
64-
self::assertThat(self::getResponse(), new ResponseConstraint\ResponseHeaderSame($headerName, $expectedValue), $message);
66+
self::assertThatForResponse(new ResponseConstraint\ResponseHeaderSame($headerName, $expectedValue), $message);
6567
}
6668

6769
public static function assertResponseHeaderNotSame(string $headerName, string $expectedValue, string $message = ''): void
6870
{
69-
self::assertThat(self::getResponse(), new LogicalNot(new ResponseConstraint\ResponseHeaderSame($headerName, $expectedValue)), $message);
71+
self::assertThatForResponse(new LogicalNot(new ResponseConstraint\ResponseHeaderSame($headerName, $expectedValue)), $message);
7072
}
7173

7274
public static function assertResponseHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void
7375
{
74-
self::assertThat(self::getResponse(), new ResponseConstraint\ResponseHasCookie($name, $path, $domain), $message);
76+
self::assertThatForResponse(new ResponseConstraint\ResponseHasCookie($name, $path, $domain), $message);
7577
}
7678

7779
public static function assertResponseNotHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void
7880
{
79-
self::assertThat(self::getResponse(), new LogicalNot(new ResponseConstraint\ResponseHasCookie($name, $path, $domain)), $message);
81+
self::assertThatForResponse(new LogicalNot(new ResponseConstraint\ResponseHasCookie($name, $path, $domain)), $message);
8082
}
8183

8284
public static function assertResponseCookieValueSame(string $name, string $expectedValue, string $path = '/', string $domain = null, string $message = ''): void
8385
{
84-
self::assertThat(self::getResponse(), LogicalAnd::fromConstraints(
86+
self::assertThatForResponse(LogicalAnd::fromConstraints(
8587
new ResponseConstraint\ResponseHasCookie($name, $path, $domain),
8688
new ResponseConstraint\ResponseCookieValueSame($name, $expectedValue, $path, $domain)
8789
), $message);
@@ -124,6 +126,21 @@ public static function assertRouteSame($expectedRoute, array $parameters = [], s
124126
self::assertThat(self::getRequest(), $constraint, $message);
125127
}
126128

129+
public static function assertThatForResponse(Constraint $constraint, string $message = ''): void
130+
{
131+
try {
132+
self::assertThat(self::getResponse(), $constraint, $message);
133+
} catch (ExpectationFailedException $exception) {
134+
if (($serverExceptionMessage = self::getResponse()->headers->get('X-Debug-Exception'))
135+
&& ($serverExceptionFile = self::getResponse()->headers->get('X-Debug-Exception-File'))) {
136+
$serverExceptionFile = explode(':', $serverExceptionFile);
137+
$exception->__construct($exception->getMessage(), $exception->getComparisonFailure(), new \ErrorException(rawurldecode($serverExceptionMessage), 0, 1, rawurldecode($serverExceptionFile[0]), $serverExceptionFile[1]), $exception->getPrevious());
138+
}
139+
140+
throw $exception;
141+
}
142+
}
143+
127144
private static function getClient(AbstractBrowser $newClient = null): ?AbstractBrowser
128145
{
129146
static $client;

src/Symfony/Bundle/FrameworkBundle/Tests/Test/WebTestCaseTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Bundle\FrameworkBundle\Tests\Test;
1313

1414
use PHPUnit\Framework\AssertionFailedError;
15+
use PHPUnit\Framework\ExpectationFailedException;
1516
use PHPUnit\Framework\TestCase;
1617
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
1718
use Symfony\Bundle\FrameworkBundle\Test\WebTestAssertionsTrait;
@@ -235,6 +236,17 @@ public function testAssertRouteSame()
235236
$this->getRequestTester()->assertRouteSame('articles');
236237
}
237238

239+
public function testExceptionOnServerError()
240+
{
241+
try {
242+
$this->getResponseTester(new Response('', 500, ['X-Debug-Exception' => 'An exception has occurred', 'X-Debug-Exception-File' => '%2Fsrv%2Ftest.php:12']))->assertResponseIsSuccessful();
243+
} catch (ExpectationFailedException $exception) {
244+
$this->assertSame('An exception has occurred', $exception->getPrevious()->getMessage());
245+
$this->assertSame('/srv/test.php', $exception->getPrevious()->getFile());
246+
$this->assertSame(12, $exception->getPrevious()->getLine());
247+
}
248+
}
249+
238250
private function getResponseTester(Response $response): WebTestCase
2392 10000 51
{
240252
$client = $this->createMock(KernelBrowser::class);

src/Symfony/Component/ErrorHandler/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
5.1.0
5+
-----
6+
7+
* The `HtmlErrorRenderer` and `SerializerErrorRenderer` add `X-Debug-Exception` and `X-Debug-Exception-File` headers in debug mode.
8+
49
4.4.0
510
-----
611

src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,13 @@ public function __construct($debug = false, string $charset = null, $fileLinkFor
6666
*/
6767
public function render(\Throwable $exception): FlattenException
6868
{
69-
$exception = FlattenException::createFromThrowable($exception, null, [
70-
'Content-Type' => 'text/html; charset='.$this->charset,
71-
]);
69+
$headers = ['Content-Type' => 'text/html; charset='.$this->charset];
70+
if (\is_bool($this->debug) ? $this->debug : ($this->debug)($exception)) {
71+
$headers['X-Debug-Exception'] = rawurlencode($exception->getMessage());
72+
$headers['X-Debug-Exception-File'] = rawurlencode($exception->getFile()).':'.$exception->getLine();
73+
}
74+
75+
$exception = FlattenException::createFromThrowable($exception, null, $headers);
7276

7377
return $exception->setAsString($this->renderException($exception));
7478
}

src/Symfony/Component/ErrorHandler/ErrorRenderer/SerializerErrorRenderer.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,21 @@ public function __construct(SerializerInterface $serializer, $format, ErrorRende
5353
*/
5454
public function render(\Throwable $exception): FlattenException
5555
{
56-
$flattenException = FlattenException::createFromThrowable($exception);
56+
$headers = [];
57+
$debug = \is_bool($this->debug) ? $this->debug : ($this->debug)($exception);
58+
if ($debug) {
59+
$headers['X-Debug-Exception'] = rawurlencode($exception->getMessage());
60+
$headers['X-Debug-Exception-File'] = rawurlencode($exception->getFile()).':'.$exception->getLine();
61+
}
62+
63+
$flattenException = FlattenException::createFromThrowable($exception, null, $headers);
5764

5865
try {
5966
$format = \is_string($this->format) ? $this->format : ($this->format)($flattenException);
6067

6168
return $flattenException->setAsString($this->serializer->serialize($flattenException, $format, [
6269
'exception' => $exception,
63-
'debug' => \is_bool($this->debug) ? $this->debug : ($this->debug)($exception),
70+
'debug' => $debug,
6471
]));
6572
} catch (NotEncodableValueException $e) {
6673
return $this->fallbackErrorRenderer->render($exception);

0 commit comments

Comments
 (0)
0