6
6
use FrameworkX \App ;
7
7
use FrameworkX \Container ;
8
8
use FrameworkX \ErrorHandler ;
9
+ use FrameworkX \FiberHandler ;
9
10
use FrameworkX \MiddlewareHandler ;
10
11
use FrameworkX \RouteHandler ;
11
12
use FrameworkX \SapiHandler ;
26
27
use React \EventLoop \Loop ;
27
28
use React \Http \Message \Response ;
28
29
use React \Http \Message \ServerRequest ;
30
+ use React \Promise \Deferred ;
29
31
use React \Promise \Promise ;
30
32
use React \Promise \PromiseInterface ;
31
33
use ReflectionMethod ;
32
34
use ReflectionProperty ;
35
+ use function React \Async \await ;
33
36
use function React \Promise \reject ;
34
37
use function React \Promise \resolve ;
35
38
@@ -72,6 +75,11 @@ public function testConstructWithMiddlewareAssignsGivenMiddleware()
72
75
$ ref ->setAccessible (true );
73
76
$ handlers = $ ref ->getValue ($ handler );
74
77
78
+ if (PHP_VERSION_ID >= 80100 ) {
79
+ $ first = array_shift ($ handlers );
80
+ $ this ->assertInstanceOf (FiberHandler::class, $ first );
81
+ }
82
+
75
83
$ this ->assertCount (4 , $ handlers );
76
84
$ this ->assertInstanceOf (AccessLogHandler::class, $ handlers [0 ]);
77
85
$ this ->assertInstanceOf (ErrorHandler::class, $ handlers [1 ]);
@@ -93,6 +101,11 @@ public function testConstructWithContainerAssignsContainerForRouteHandlerOnly()
93
101
$ ref ->setAccessible (true );
94
102
$ handlers = $ ref ->getValue ($ handler );
95
103
104
+ if (PHP_VERSION_ID >= 80100 ) {
105
+ $ first = array_shift ($ handlers );
106
+ $ this ->assertInstanceOf (FiberHandler::class, $ first );
107
+ }
108
+
96
109
$ this ->assertCount (3 , $ handlers );
97
110
$ this ->assertInstanceOf (AccessLogHandler::class, $ handlers [0 ]);
98
111
$ this ->assertInstanceOf (ErrorHandler::class, $ handlers [1 ]);
@@ -122,6 +135,11 @@ public function testConstructWithContainerAndMiddlewareClassNameAssignsCallableF
122
135
$ ref ->setAccessible (true );
123
136
$ handlers = $ ref ->getValue ($ handler );
124
137
138
+ if (PHP_VERSION_ID >= 80100 ) {
139
+ $ first = array_shift ($ handlers );
140
+ $ this ->assertInstanceOf (FiberHandler::class, $ first );
141
+ }
142
+
125
143
$ this ->assertCount (4 , $ handlers );
126
144
$ this ->assertInstanceOf (AccessLogHandler::class, $ handlers [0 ]);
127
145
$ this ->assertInstanceOf (ErrorHandler::class, $ handlers [1 ]);
@@ -820,6 +838,57 @@ public function testHandleRequestWithMatchingRouteReturnsPendingPromiseWhenHandl
820
838
$ this ->assertFalse ($ resolved );
821
839
}
822
840
841
+ public function testHandleRequestWithMatchingRouteReturnsPromiseResolvingWithResponseWhenHandlerReturnsResponseAfterAwaitingPromiseResolvingWithResponse ()
842
+ {
843
+ if (PHP_VERSION_ID < 80100 || !function_exists ('React\Async\async ' )) {
844
+ $ this ->markTestSkipped ('Requires PHP 8.1+ with react/async 4+ ' );
845
+ }
846
+
847
+ $ app = $ this ->createAppWithoutLogger ();
848
+
849
+ $ deferred = new Deferred ();
850
+
851
+ $ app ->get ('/users ' , function () use ($ deferred ) {
852
+ return await ($ deferred ->promise ());
853
+ });
854
+
855
+ $ request = new ServerRequest ('GET ' , 'http://localhost/users ' );
856
+
857
+ // $promise = $app->handleRequest($request);
858
+ $ ref = new ReflectionMethod ($ app , 'handleRequest ' );
859
+ $ ref ->setAccessible (true );
860
+ $ promise = $ ref ->invoke ($ app , $ request );
861
+
862
+ /** @var PromiseInterface $promise */
863
+ $ this ->assertInstanceOf (PromiseInterface::class, $ promise );
864
+
865
+ $ response = null ;
866
+ $ promise ->then (function ($ value ) use (&$ response ) {
867
+ $ response = $ value ;
868
+ });
869
+
870
+ $ this ->assertNull ($ response );
871
+
872
+ $ deferred ->resolve (new Response (
873
+ 200 ,
874
+ [
875
+ 'Content-Type ' => 'text/html '
876
+ ],
877
+ "OK \n"
878
+ ));
879
+
880
+ // await next tick: https://github.com/reactphp/async/issues/27
881
+ await (new Promise (function ($ resolve ) {
882
+ Loop::futureTick ($ resolve );
883
+ }));
884
+
885
+ /** @var ResponseInterface $response */
886
+ $ this ->assertInstanceOf (ResponseInterface::class, $ response );
887
+ $ this ->assertEquals (200 , $ response ->getStatusCode ());
888
+ $ this ->assertEquals ('text/html ' , $ response ->getHeaderLine ('Content-Type ' ));
889
+ $ this ->assertEquals ("OK \n" , (string ) $ response ->getBody ());
890
+ }
891
+
823
892
public function testHandleRequestWithMatchingRouteAndRouteVariablesReturnsResponseFromHandlerWithRouteVariablesAssignedAsRequestAttributes ()
824
893
{
825
894
$ app = $ this ->createAppWithoutLogger ();
@@ -1047,6 +1116,58 @@ public function testHandleRequestWithMatchingRouteReturnsPromiseWhichFulfillsWit
1047
1116
$ this ->assertStringContainsString ("<p>Expected request handler to return <code>Psr\Http\Message\ResponseInterface</code> but got uncaught <code>RuntimeException</code> with message <code>Foo</code> in <code title= \"See " . __FILE__ . " line $ line \">AppTest.php: $ line</code>.</p> \n" , (string ) $ response ->getBody ());
1048
1117
}
1049
1118
1119
+ public function testHandleRequestWithMatchingRouteReturnsPromiseWhichFulfillsWithInternalServerErrorResponseWhenHandlerThrowsAfterAwaitingPromiseRejectingWithException ()
1120
+ {
1121
+ if (PHP_VERSION_ID < 80100 || !function_exists ('React\Async\async ' )) {
1122
+ $ this ->markTestSkipped ('Requires PHP 8.1+ with react/async 4+ ' );
1123
+ }
1124
+
1125
+ $ app = $ this ->createAppWithoutLogger ();
1126
+
1127
+ $ deferred = new Deferred ();
1128
+
1129
+ $ line = __LINE__ + 1 ;
1130
+ $ exception = new \RuntimeException ('Foo ' );
1131
+
1132
+ $ app ->get ('/users ' , function () use ($ deferred ) {
1133
+ return await ($ deferred ->promise ());
1134
+ });
1135
+
1136
+ $ request = new ServerRequest ('GET ' , 'http://localhost/users ' );
1137
+
1138
+ // $promise = $app->handleRequest($request);
1139
+ $ ref = new ReflectionMethod ($ app , 'handleRequest ' );
1140
+ $ ref ->setAccessible (true );
1141
+ $ promise = $ ref ->invoke ($ app , $ request );
1142
+
1143
+ /** @var PromiseInterface $promise */
1144
+ $ this ->assertInstanceOf (PromiseInterface::class, $ promise );
1145
+
1146
+ $ response = null ;
1147
+ $ promise ->then (function ($ value ) use (&$ response ) {
1148
+ $ response = $ value ;
1149
+ });
1150
+
1151
+ $ this ->assertNull ($ response );
1152
+
1153
+ $ deferred ->reject ($ exception );
1154
+
1155
+ // await next tick: https://github.com/reactphp/async/issues/27
1156
+ await (new Promise (function ($ resolve ) {
1157
+ Loop::futureTick ($ resolve );
1158
+ }));
1159
+
1160
+ /** @var ResponseInterface $response */
1161
+ $ this ->assertInstanceOf (ResponseInterface::class, $ response );
1162
+ $ this ->assertEquals (500 , $ response ->getStatusCode ());
1163
+ $ this ->assertEquals ('text/html; charset=utf-8 ' , $ response ->getHeaderLine ('Content-Type ' ));
1164
+ $ this ->assertStringMatchesFormat ("<!DOCTYPE html> \n<html>%a</html> \n" , (string ) $ response ->getBody ());
1165
+
1166
+ $ this ->assertStringContainsString ("<title>Error 500: Internal Server Error</title> \n" , (string ) $ response ->getBody ());
1167
+ $ this ->assertStringContainsString ("<p>The requested page failed to load, please try again later.</p> \n" , (string ) $ response ->getBody ());
1168
+ $ this ->assertStringContainsString ("<p>Expected request handler to return <code>Psr\Http\Message\ResponseInterface</code> but got uncaught <code>RuntimeException</code> with message <code>Foo</code> in <code title= \"See " . __FILE__ . " line $ line \">AppTest.php: $ line</code>.</p> \n" , (string ) $ response ->getBody ());
1169
+ }
1170
+
1050
1171
public function testHandleRequestWithMatchingRouteReturnsPromiseWhichFulfillsWithInternalServerErrorResponseWhenHandlerReturnsCoroutineWhichReturnsNull ()
1051
1172
{
1052
1173
$ app = $ this ->createAppWithoutLogger ();
@@ -1386,8 +1507,20 @@ private function createAppWithoutLogger(): App
1386
1507
$ ref ->setAccessible (true );
1387
1508
$ handlers = $ ref ->getValue ($ middleware );
1388
1509
1389
- unset($ handlers [0 ]);
1390
- $ ref ->setValue ($ middleware , array_values ($ handlers ));
1510
+ if (PHP_VERSION_ID >= 80100 ) {
1511
+ $ first = array_shift ($ handlers );
1512
+ $ this ->assertInstanceOf (FiberHandler::class, $ first );
1513
+
1514
+ $ next = array_shift ($ handlers );
1515
+ $ this ->assertInstanceOf (AccessLogHandler::class, $ next );
1516
+
1517
+ array_unshift ($ handlers , $ next , $ first );
1518
+ }
1519
+
1520
+ $ first = array_shift ($ handlers );
1521
+ $ this ->assertInstanceOf (AccessLogHandler::class, $ first );
1522
+
1523
+ $ ref ->setValue ($ middleware , $ handlers );
1391
1524
1392
1525
return $ app ;
1393
1526
}
0 commit comments