From e78049d04416d4e575b04428f2a817fb1f530f66 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Tue, 26 Aug 2025 06:11:36 -0400 Subject: [PATCH 1/3] test(http): Enhance `ApplicationRoutingTest` with improved assertion messages and add test for `NotFoundHttpException` handling. --- .../http/stateless/ApplicationRoutingTest.php | 53 ++++++++++++++++--- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/tests/http/stateless/ApplicationRoutingTest.php b/tests/http/stateless/ApplicationRoutingTest.php index 870f9983..9030bfaa 100644 --- a/tests/http/stateless/ApplicationRoutingTest.php +++ b/tests/http/stateless/ApplicationRoutingTest.php @@ -6,6 +6,8 @@ use PHPUnit\Framework\Attributes\Group; use yii\base\InvalidConfigException; +use yii\web\NotFoundHttpException; +use yii2\extensions\psrbridge\exception\Message; use yii2\extensions\psrbridge\tests\support\FactoryHelper; use yii2\extensions\psrbridge\tests\TestCase; @@ -46,8 +48,7 @@ public function testHandlePostParameters(): void {"foo":"bar","a":{"b":"c"}} JSON, $response->getBody()->getContents(), - "Response body should match expected JSON string '{\"foo\":\"bar\",\"a\":{\"b\":\"c\"}}' for " . - "'site/post' route.", + "Response body should match expected JSON string '{\"foo\":\"bar\",\"a\":{\"b\":\"c\"}}'.", ); } @@ -80,8 +81,7 @@ public function testHandleQueryParameters(): void {"foo":"bar","a":{"b":"c"}} JSON, $response->getBody()->getContents(), - "Response body should match expected JSON string '{\"foo\":\"bar\",\"a\":{\"b\":\"c\"}}' for " . - "'site/get' route.", + "Response body should match expected JSON string '{\"foo\":\"bar\",\"a\":{\"b\":\"c\"}}'.", ); } @@ -114,7 +114,7 @@ public function testHandleRouteAndQueryParameters(): void {"test":"foo","q":"1","queryParams":{"test":"foo","q":"1"}} JSON, $response->getBody()->getContents(), - "Response body should contain valid JSON with route and query parameters for 'site/query/foo?q=1' route.", + 'Response body should contain valid JSON with route and query parameters.', ); } @@ -142,12 +142,51 @@ public function testHandleRouteParameters(): void self::assertSame( '{"site/update":"123"}', $response->getBody()->getContents(), - "Response body should contain valid JSON with the route parameter for 'site/update/123' route.", + 'Response body should contain valid JSON with the route parameter.', ); self::assertSame( 'site/update/123', $request->getUri()->getPath(), - "Request path should be 'site/update/123' for 'site/update/123' route.", + "Request path should be 'site/update/123'.", ); } + + /** + * @throws InvalidConfigException if the configuration is invalid or incomplete. + */ + public function testThrowNotFoundHttpExceptionWhenRouteNotFound(): void + { + $app = $this->statelessApplication( + [ + 'components' => [ + 'urlManager' => [ + 'enableStrictParsing' => true, + ], + ], + ], + ); + + $response = $app->handle(FactoryHelper::createRequest('GET', '/nonexistent/route')); + + self::assertSame( + 404, + $response->getStatusCode(), + "Expected HTTP '404' for route '/nonexistent/route'.", + ); + self::assertSame( + 'text/html; charset=UTF-8', + $response->getHeaderLine('Content-Type'), + "Expected Content-Type 'text/html; charset=UTF-8' for route '/nonexistent/route'.", + ); + self::assertSame( + '
Not Found: Page not found.
', + $response->getBody()->getContents(), + "Response body should match expected HTML string '
Not Found: Page not found.
'.", + ); + + $this->expectException(NotFoundHttpException::class); + $this->expectExceptionMessage(Message::PAGE_NOT_FOUND->getMessage()); + + $app->request->resolve(); + } } From ab006cd1f17a49152c7ee7efb4ab8ed20762f56b Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Tue, 26 Aug 2025 07:33:23 -0400 Subject: [PATCH 2/3] test(http): Refactor `ApplicationErrorHandlerTest` to use `createRequest` for improved clarity and remove redundant server variable assignments. --- src/exception/Message.php | 4 +- .../stateless/ApplicationErrorHandlerTest.php | 130 +++++++----------- .../http/stateless/ApplicationRoutingTest.php | 41 ------ 3 files changed, 54 insertions(+), 121 deletions(-) diff --git a/src/exception/Message.php b/src/exception/Message.php index 8d17f620..a6c28abd 100644 --- a/src/exception/Message.php +++ b/src/exception/Message.php @@ -127,9 +127,9 @@ enum Message: string /** * Error when the page is not found. * - * Format: "Page not found." + * Format: "Page not found in StatelessApplication." */ - case PAGE_NOT_FOUND = 'Page not found.'; + case PAGE_NOT_FOUND = 'Page not found in StatelessApplication.'; /** * Error when the PSR-7 request adapter is not set. diff --git a/tests/http/stateless/ApplicationErrorHandlerTest.php b/tests/http/stateless/ApplicationErrorHandlerTest.php index b8a1099e..80099f17 100644 --- a/tests/http/stateless/ApplicationErrorHandlerTest.php +++ b/tests/http/stateless/ApplicationErrorHandlerTest.php @@ -8,8 +8,6 @@ use yii\base\{Exception, InvalidConfigException}; use yii\helpers\Json; use yii\log\{FileTarget, Logger}; -use yii\web\NotFoundHttpException; -use yii2\extensions\psrbridge\exception\Message; use yii2\extensions\psrbridge\http\Response; use yii2\extensions\psrbridge\tests\provider\StatelessApplicationProvider; use yii2\extensions\psrbridge\tests\support\FactoryHelper; @@ -48,11 +46,6 @@ public function testErrorViewLogic( ): void { @\runkit_constant_redefine('YII_DEBUG', $debug); - $_SERVER = [ - 'REQUEST_METHOD' => 'GET', - 'REQUEST_URI' => $route, - ]; - $app = $this->statelessApplication( [ 'components' => [ @@ -61,7 +54,7 @@ public function testErrorViewLogic( ], ); - $response = $app->handle(FactoryHelper::createServerRequestCreator()->createFromGlobals()); + $response = $app->handle(FactoryHelper::createRequest('GET', $route)); self::assertSame( $expectedStatusCode, @@ -173,11 +166,6 @@ public function testFiltersSensitiveServerVariablesInFallbackExceptionMessage(): */ public function testLogExceptionIsCalledWhenHandlingException(): void { - $_SERVER = [ - 'REQUEST_METHOD' => 'GET', - 'REQUEST_URI' => 'site/trigger-exception', - ]; - $app = $this->statelessApplication( [ 'flushLogger' => false, @@ -196,7 +184,7 @@ public function testLogExceptionIsCalledWhenHandlingException(): void ], ); - $response = $app->handle(FactoryHelper::createServerRequestCreator()->createFromGlobals()); + $response = $app->handle(FactoryHelper::createRequest('GET', '/site/trigger-exception')); self::assertSame( 500, @@ -238,7 +226,7 @@ public function testLogExceptionIsCalledWhenHandlingException(): void self::assertTrue( $exceptionLogFound, "Logger should contain an error log entry with category '{$expectedCategory}' and message " . - "'Exception error message.' when 'logException()' is called during exception handling.", + "'Exception error message.'.", ); self::assertFalse( $app->flushLogger, @@ -256,11 +244,6 @@ public function testRenderExceptionPassesExceptionParameterToTemplateView(): voi $initialBufferLevel = ob_get_level(); - $_SERVER = [ - 'REQUEST_METHOD' => 'GET', - 'REQUEST_URI' => 'site/trigger-exception', - ]; - $warningsCaptured = []; set_error_handler( @@ -287,7 +270,7 @@ static function ($errno, $errstr, $errfile, $errline) use (&$warningsCaptured): ], ); - $response = $app->handle(FactoryHelper::createServerRequestCreator()->createFromGlobals()); + $response = $app->handle(FactoryHelper::createRequest('GET', '/site/trigger-exception')); self::assertSame( 500, @@ -307,8 +290,7 @@ static function ($errno, $errstr, $errfile, $errline) use (&$warningsCaptured): self::assertEmpty( $undefinedExceptionWarnings, - "Should be no 'Undefined variable' warnings, confirming that exception parameter is defined in the " . - 'view context when rendering exception.', + "Should be no 'Undefined variable' warnings.", ); $responseBody = $response->getBody()->getContents(); @@ -316,24 +298,22 @@ static function ($errno, $errstr, $errfile, $errline) use (&$warningsCaptured): self::assertStringContainsString( Exception::class, $responseBody, - "Response body should contain exception class when exception parameter is passed to 'renderFile()'.", + 'Response body should contain exception class.', ); self::assertStringContainsString( 'Stack trace:', $responseBody, - "Response body should contain 'Stack trace:' section, confirming exception object is available to template.", + "Response body should contain 'Stack trace:' section.", ); self::assertStringContainsString( 'Exception error message.', $responseBody, - "Response body should contain the exact exception message 'Exception error message.', confirming " . - 'the exception object was properly passed to the view.', + "Response body should contain the exact exception message 'Exception error message.'.", ); self::assertStringContainsString( 'SiteController.php', $responseBody, - "Response body should contain reference to 'SiteController.php' where the exception was throw, " . - 'confirming full exception details are available in the view.', + "Response body should contain reference to 'SiteController.php'.", ); } finally { restore_error_handler(); @@ -359,11 +339,6 @@ public function testRenderExceptionWithDifferentFormats( string $route, array $expectedContent, ): void { - $_SERVER = [ - 'REQUEST_METHOD' => 'GET', - 'REQUEST_URI' => $route, - ]; - $app = $this->statelessApplication( [ 'components' => [ @@ -373,7 +348,7 @@ public function testRenderExceptionWithDifferentFormats( ], ); - $response = $app->handle(FactoryHelper::createServerRequestCreator()->createFromGlobals()); + $response = $app->handle(FactoryHelper::createRequest('GET', $route)); self::assertSame( $expectedStatusCode, @@ -432,22 +407,15 @@ public function testRenderExceptionWithErrorActionReturningResponseObject(): voi { @\runkit_constant_redefine('YII_DEBUG', false); - $_SERVER = [ - 'REQUEST_METHOD' => 'GET', - 'REQUEST_URI' => 'site/trigger-exception', - ]; - $app = $this->statelessApplication( [ 'components' => [ - 'errorHandler' => [ - 'errorAction' => 'site/error-with-response', - ], + 'errorHandler' => ['errorAction' => 'site/error-with-response'], ], ], ); - $response = $app->handle(FactoryHelper::createServerRequestCreator()->createFromGlobals()); + $response = $app->handle(FactoryHelper::createRequest('GET', '/site/trigger-exception')); self::assertSame( 500, @@ -468,7 +436,7 @@ public function testRenderExceptionWithErrorActionReturningResponseObject(): voi HTML, ), self::normalizeLineEndings($response->getBody()->getContents()), - "Response body should contain content from Response object returned by 'errorAction'.", + 'Response body should contain content from Response object.', ); @\runkit_constant_redefine('YII_DEBUG', true); @@ -479,11 +447,6 @@ public function testRenderExceptionWithErrorActionReturningResponseObject(): voi */ public function testReturnHtmlErrorResponseWhenErrorHandlerActionIsInvalid(): void { - $_SERVER = [ - 'REQUEST_METHOD' => 'GET', - 'REQUEST_URI' => 'site/nonexistent-action', - ]; - $app = $this->statelessApplication( [ 'components' => [ @@ -492,7 +455,7 @@ public function testReturnHtmlErrorResponseWhenErrorHandlerActionIsInvalid(): vo ], ); - $response = $app->handle(FactoryHelper::createServerRequestCreator()->createFromGlobals()); + $response = $app->handle(FactoryHelper::createRequest('GET', '/site/nonexistent-action')); self::assertSame( 500, @@ -512,8 +475,7 @@ public function testReturnHtmlErrorResponseWhenErrorHandlerActionIsInvalid(): vo HTML, ), self::normalizeLineEndings($response->getBody()->getContents()), - "Response body should contain error message about 'An Error occurred while handling another error' and " . - 'the InvalidRouteException when errorHandler action is invalid.', + "Response body should contain error message about 'An Error occurred while handling another error'.", ); } @@ -522,14 +484,9 @@ public function testReturnHtmlErrorResponseWhenErrorHandlerActionIsInvalid(): vo */ public function testThrowableOccursDuringRequestHandling(): void { - $_SERVER = [ - 'REQUEST_METHOD' => 'GET', - 'REQUEST_URI' => 'nonexistent/invalidaction', - ]; - $app = $this->statelessApplication(); - $response = $app->handle(FactoryHelper::createServerRequestCreator()->createFromGlobals()); + $response = $app->handle(FactoryHelper::createRequest('GET', '/nonexistent/invalidaction')); self::assertSame( 404, @@ -544,8 +501,7 @@ public function testThrowableOccursDuringRequestHandling(): void self::assertStringContainsString( '
Not Found: Page not found.
', $response->getBody()->getContents(), - "Response body should contain error message about 'Not Found: Page not found' when Throwable occurs " . - 'during request handling.', + "Response body should contain error message about 'Not Found: Page not found'.", ); } @@ -554,14 +510,9 @@ public function testThrowableOccursDuringRequestHandling(): void */ public function testThrowNotFoundHttpExceptionWhenStrictParsingDisabledAndRouteIsMissing(): void { - $_SERVER = [ - 'REQUEST_METHOD' => 'GET', - 'REQUEST_URI' => 'site/profile/123', - ]; - $app = $this->statelessApplication(); - $response = $app->handle(FactoryHelper::createServerRequestCreator()->createFromGlobals()); + $response = $app->handle(FactoryHelper::createRequest('GET', '/site/profile/123')); self::assertSame( 404, @@ -576,34 +527,57 @@ public function testThrowNotFoundHttpExceptionWhenStrictParsingDisabledAndRouteI self::assertStringContainsString( '
Not Found: Page not found.
', $response->getBody()->getContents(), - "Response body should contain the default not found message '
Not Found: Page not found.
' " . - 'when a NotFoundHttpException is thrown.', + "Response body should contain the default not found message '
Not Found: Page not found.
'.", ); } /** * @throws InvalidConfigException if the configuration is invalid or incomplete. */ + #[RequiresPhpExtension('runkit7')] public function testThrowNotFoundHttpExceptionWhenStrictParsingEnabledAndRouteIsMissing(): void { - $_SERVER = [ - 'REQUEST_METHOD' => 'GET', - 'REQUEST_URI' => 'site/profile/123', - ]; + @\runkit_constant_redefine('YII_ENV_TEST', false); + + $initialBufferLevel = ob_get_level(); $app = $this->statelessApplication( [ 'components' => [ - 'urlManager' => ['enableStrictParsing' => true], + 'errorHandler' => ['errorAction' => null], + 'response' => ['format' => Response::FORMAT_JSON], + 'urlManager' => [ + 'enableStrictParsing' => true, + 'rules' => [], + ], ], ], ); - $app->handle(FactoryHelper::createServerRequestCreator()->createFromGlobals()); + $response = $app->handle(FactoryHelper::createRequest('GET', '/site/profile/123')); - $this->expectException(NotFoundHttpException::class); - $this->expectExceptionMessage(Message::PAGE_NOT_FOUND->getMessage()); + self::assertSame( + 404, + $response->getStatusCode(), + "Expected HTTP '404' for route 'site/profile/123'.", + ); + self::assertSame( + 'application/json; charset=UTF-8', + $response->getHeaderLine('Content-Type'), + "Expected Content-Type 'application/json; charset=UTF-8' for route 'site/profile/123'.", + ); + self::assertJsonStringEqualsJsonString( + <<getBody()->getContents(), + 'Response body should contain JSON with NotFoundHttpException details.', + ); + + while (ob_get_level() < $initialBufferLevel) { + ob_start(); + } - $app->request->resolve(); + @\runkit_constant_redefine('YII_ENV_TEST', true); } } diff --git a/tests/http/stateless/ApplicationRoutingTest.php b/tests/http/stateless/ApplicationRoutingTest.php index 9030bfaa..eb733925 100644 --- a/tests/http/stateless/ApplicationRoutingTest.php +++ b/tests/http/stateless/ApplicationRoutingTest.php @@ -6,8 +6,6 @@ use PHPUnit\Framework\Attributes\Group; use yii\base\InvalidConfigException; -use yii\web\NotFoundHttpException; -use yii2\extensions\psrbridge\exception\Message; use yii2\extensions\psrbridge\tests\support\FactoryHelper; use yii2\extensions\psrbridge\tests\TestCase; @@ -150,43 +148,4 @@ public function testHandleRouteParameters(): void "Request path should be 'site/update/123'.", ); } - - /** - * @throws InvalidConfigException if the configuration is invalid or incomplete. - */ - public function testThrowNotFoundHttpExceptionWhenRouteNotFound(): void - { - $app = $this->statelessApplication( - [ - 'components' => [ - 'urlManager' => [ - 'enableStrictParsing' => true, - ], - ], - ], - ); - - $response = $app->handle(FactoryHelper::createRequest('GET', '/nonexistent/route')); - - self::assertSame( - 404, - $response->getStatusCode(), - "Expected HTTP '404' for route '/nonexistent/route'.", - ); - self::assertSame( - 'text/html; charset=UTF-8', - $response->getHeaderLine('Content-Type'), - "Expected Content-Type 'text/html; charset=UTF-8' for route '/nonexistent/route'.", - ); - self::assertSame( - '
Not Found: Page not found.
', - $response->getBody()->getContents(), - "Response body should match expected HTML string '
Not Found: Page not found.
'.", - ); - - $this->expectException(NotFoundHttpException::class); - $this->expectExceptionMessage(Message::PAGE_NOT_FOUND->getMessage()); - - $app->request->resolve(); - } } From 3d7748cb3fa8bd73d540d0064405649f5974d6b8 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Tue, 26 Aug 2025 07:46:52 -0400 Subject: [PATCH 3/3] Apply fixed review coderabbitai nitpick comments. --- tests/http/stateless/ApplicationErrorHandlerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/http/stateless/ApplicationErrorHandlerTest.php b/tests/http/stateless/ApplicationErrorHandlerTest.php index 80099f17..261ecf10 100644 --- a/tests/http/stateless/ApplicationErrorHandlerTest.php +++ b/tests/http/stateless/ApplicationErrorHandlerTest.php @@ -226,7 +226,7 @@ public function testLogExceptionIsCalledWhenHandlingException(): void self::assertTrue( $exceptionLogFound, "Logger should contain an error log entry with category '{$expectedCategory}' and message " . - "'Exception error message.'.", + "'Exception error message'.", ); self::assertFalse( $app->flushLogger,