diff --git a/tests/http/stateless/ApplicationCoreTest.php b/tests/http/stateless/ApplicationCoreTest.php index 91ef7d2a..280309f6 100644 --- a/tests/http/stateless/ApplicationCoreTest.php +++ b/tests/http/stateless/ApplicationCoreTest.php @@ -5,16 +5,16 @@ namespace yii2\extensions\psrbridge\tests\http\stateless; use HttpSoft\Message\{ServerRequestFactory, StreamFactory, UploadedFileFactory}; -use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\{Group, TestWith}; use Psr\Http\Message\{ServerRequestFactoryInterface, StreamFactoryInterface, UploadedFileFactoryInterface}; use ReflectionException; use Yii; -use yii\base\{InvalidConfigException, Security}; +use yii\base\{Event, InvalidConfigException, Security}; use yii\di\NotInstantiableException; use yii\i18n\{Formatter, I18N}; use yii\log\Dispatcher; use yii\web\{AssetManager, Session, UrlManager, User, View}; -use yii2\extensions\psrbridge\http\{ErrorHandler, Request, Response}; +use yii2\extensions\psrbridge\http\{ErrorHandler, Request, Response, StatelessApplication}; use yii2\extensions\psrbridge\tests\support\FactoryHelper; use yii2\extensions\psrbridge\tests\support\stub\MockerFunctions; use yii2\extensions\psrbridge\tests\TestCase; @@ -85,6 +85,43 @@ public function testContainerResolvesPsrFactoriesWithDefinitions(): void ); } + public function testEventOrderDuringHandle(): void + { + $app = $this->statelessApplication(); + $sequence = []; + + $app->on( + StatelessApplication::EVENT_BEFORE_REQUEST, + static function () use (&$sequence): void { + $sequence[] = 'before'; + }, + ); + $app->on( + StatelessApplication::EVENT_AFTER_REQUEST, + static function () use (&$sequence): void { + $sequence[] = 'after'; + }, + ); + + $response = $app->handle(FactoryHelper::createRequest('GET', 'site/index')); + + self::assertSame( + 200, + $response->getStatusCode(), + "Expected HTTP '200' for route 'site/index'.", + ); + self::assertSame( + 'application/json; charset=UTF-8', + $response->getHeaderLine('Content-Type'), + "Expected Content-Type 'application/json; charset=UTF-8' for route 'site/index'.", + ); + self::assertSame( + ['before', 'after'], + $sequence, + "BEFORE should precede AFTER during 'handle()'.", + ); + } + /** * @throws InvalidConfigException if the configuration is invalid or incomplete. * @throws ReflectionException if the property does not exist or is inaccessible. @@ -94,14 +131,7 @@ public function testResponseAdapterCachingAndResetBehaviorAcrossMultipleRequests $app = $this->statelessApplication(); // first request - verify adapter caching behavior - $_SERVER = [ - 'REQUEST_METHOD' => 'GET', - 'REQUEST_URI' => 'site/index', - ]; - - $response1 = $app->handle( - FactoryHelper::createServerRequestCreator()->createFromGlobals(), - ); + $response1 = $app->handle(FactoryHelper::createRequest('GET', 'site/index')); self::assertSame( 200, @@ -135,14 +165,7 @@ public function testResponseAdapterCachingAndResetBehaviorAcrossMultipleRequests ); // second request with different route - verify stateless behavior - $_SERVER = [ - 'REQUEST_METHOD' => 'GET', - 'REQUEST_URI' => 'site/statuscode', - ]; - - $response2 = $app->handle( - FactoryHelper::createServerRequestCreator()->createFromGlobals(), - ); + $response2 = $app->handle(FactoryHelper::createRequest('GET', 'site/statuscode')); self::assertSame( 201, @@ -189,15 +212,7 @@ public function testResponseAdapterCachingAndResetBehaviorAcrossMultipleRequests ); // third request - verify adapter isolation between requests - $_COOKIE = ['test_cookie' => 'test_value']; - $_SERVER = [ - 'REQUEST_METHOD' => 'GET', - 'REQUEST_URI' => 'site/add-cookies-to-response', - ]; - - $response3 = $app->handle( - FactoryHelper::createServerRequestCreator()->createFromGlobals(), - ); + $response3 = $app->handle(FactoryHelper::createRequest('GET', 'site/add-cookies-to-response')); self::assertSame( 200, @@ -236,9 +251,14 @@ public function testResponseAdapterCachingAndResetBehaviorAcrossMultipleRequests "PSR-7 Response should contain 'test=test' or 'test2=test2' in 'Set-Cookie' headers, confirming correct " . 'adapter behavior.', ); - self::assertSame( - 'test=test; Path=/; HttpOnly; SameSite=Lax test2=test2; Path=/; HttpOnly; SameSite=Lax', - implode(' ', $cookieHeaders), + self::assertContains( + 'test=test; Path=/; HttpOnly; SameSite=Lax', + $cookieHeaders, + 'PSR-7 Response Set-Cookie headers should match the expected values, confirming correct adapter behavior.', + ); + self::assertContains( + 'test2=test2; Path=/; HttpOnly; SameSite=Lax', + $cookieHeaders, 'PSR-7 Response Set-Cookie headers should match the expected values, confirming correct adapter behavior.', ); } @@ -306,14 +326,9 @@ public function testSetsPsr7RequestWithStatelessAppStartTimeHeader(): void MockerFunctions::setMockedMicrotime($mockedTime); - $_SERVER = [ - 'REQUEST_METHOD' => 'GET', - 'REQUEST_URI' => 'site/index', - ]; - $app = $this->statelessApplication(); - $response = $app->handle(FactoryHelper::createServerRequestCreator()->createFromGlobals()); + $response = $app->handle(FactoryHelper::createRequest('GET', 'site/index')); self::assertSame( 200, @@ -347,8 +362,18 @@ public function testSetWebAndWebrootAliasesAfterHandleRequest(): void { $app = $this->statelessApplication(); - $app->handle(FactoryHelper::createServerRequestCreator()->createFromGlobals()); + $response = $app->handle(FactoryHelper::createRequest('GET', 'site/index')); + self::assertSame( + 200, + $response->getStatusCode(), + "Expected HTTP '200' for route 'site/index'.", + ); + self::assertSame( + 'application/json; charset=UTF-8', + $response->getHeaderLine('Content-Type'), + "Expected Content-Type 'application/json; charset=UTF-8' for route 'site/index'.", + ); self::assertSame( '', Yii::getAlias('@web'), @@ -360,4 +385,50 @@ public function testSetWebAndWebrootAliasesAfterHandleRequest(): void "'@webroot' alias should be set to the parent directory of the test directory after handling a request.", ); } + + /** + * @throws InvalidConfigException if the configuration is invalid or incomplete. + */ + #[TestWith([StatelessApplication::EVENT_AFTER_REQUEST])] + #[TestWith([StatelessApplication::EVENT_BEFORE_REQUEST])] + public function testTriggerEventDuringHandle(string $eventName): void + { + $invocations = 0; + $sender = null; + $sequence = []; + + $app = $this->statelessApplication(); + + $app->on( + $eventName, + static function (Event $event) use (&$invocations, &$sequence, &$sender): void { + $invocations++; + $sender = $event->sender ?? null; + $sequence[] = $event->name; + }, + ); + + $response = $app->handle(FactoryHelper::createRequest('GET', 'site/index')); + + self::assertSame( + 200, + $response->getStatusCode(), + "Expected HTTP '200' for route 'site/index'.", + ); + self::assertSame( + 'application/json; charset=UTF-8', + $response->getHeaderLine('Content-Type'), + "Expected Content-Type 'application/json; charset=UTF-8' for route 'site/index'.", + ); + self::assertSame( + 1, + $invocations, + "Should trigger '{$eventName}' exactly once during 'handle()'.", + ); + self::assertSame( + $app, + $sender, + 'Event sender should be the application instance.', + ); + } } diff --git a/tests/http/stateless/ApplicationTest.php b/tests/http/stateless/ApplicationTest.php index 63a02df0..f4b367ce 100644 --- a/tests/http/stateless/ApplicationTest.php +++ b/tests/http/stateless/ApplicationTest.php @@ -4,9 +4,8 @@ namespace yii2\extensions\psrbridge\tests\http\stateless; -use PHPUnit\Framework\Attributes\{Group, RequiresPhpExtension, TestWith}; +use PHPUnit\Framework\Attributes\{Group, RequiresPhpExtension}; use yii\base\InvalidConfigException; -use yii2\extensions\psrbridge\http\StatelessApplication; use yii2\extensions\psrbridge\tests\support\FactoryHelper; use yii2\extensions\psrbridge\tests\TestCase; @@ -256,27 +255,4 @@ public function testReturnsStatusCode201ForSiteStatusCodeRoute(): void "Response 'status code' should be '201' for 'site/statuscode' route in 'StatelessApplication'.", ); } - - /** - * @throws InvalidConfigException if the configuration is invalid or incomplete. - */ - #[TestWith([StatelessApplication::EVENT_AFTER_REQUEST])] - #[TestWith([StatelessApplication::EVENT_BEFORE_REQUEST])] - public function testTriggerEventDuringHandle(string $eventName): void - { - $eventTriggered = false; - - $app = $this->statelessApplication(); - - $app->on( - $eventName, - static function () use (&$eventTriggered): void { - $eventTriggered = true; - }, - ); - - $app->handle(FactoryHelper::createServerRequestCreator()->createFromGlobals()); - - self::assertTrue($eventTriggered, "Should trigger '{$eventName}' event during handle()"); - } }