ResponseCallsTest.php 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. <?php
  2. namespace Knuckles\Scribe\Tests\Strategies\Responses;
  3. use Dingo\Api\Routing\Router;
  4. use Illuminate\Routing\Route;
  5. use Knuckles\Scribe\Extracting\Strategies\Responses\ResponseCalls;
  6. use Knuckles\Scribe\ScribeServiceProvider;
  7. use Knuckles\Scribe\Tests\Fixtures\TestController;
  8. use Knuckles\Scribe\Tools\DocumentationConfig;
  9. use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;
  10. use Orchestra\Testbench\TestCase;
  11. use Illuminate\Support\Facades\Route as LaravelRouteFacade;
  12. class ResponseCallsTest extends TestCase
  13. {
  14. use ArraySubsetAsserts;
  15. protected function getPackageProviders($app)
  16. {
  17. $providers = [
  18. ScribeServiceProvider::class,
  19. ];
  20. if (class_exists(\Dingo\Api\Provider\LaravelServiceProvider::class)) {
  21. $providers[] = \Dingo\Api\Provider\LaravelServiceProvider::class;
  22. }
  23. return $providers;
  24. }
  25. /** @test */
  26. public function can_call_route_and_fetch_response()
  27. {
  28. $route = LaravelRouteFacade::post('/shouldFetchRouteResponse', [TestController::class, 'shouldFetchRouteResponse']);
  29. $rules = [
  30. 'headers' => [
  31. 'Content-Type' => 'application/json',
  32. 'Accept' => 'application/json',
  33. ],
  34. 'response_calls' => [
  35. 'methods' => ['*'],
  36. ],
  37. ];
  38. $strategy = new ResponseCalls(new DocumentationConfig([]));
  39. $results = $strategy->makeResponseCallIfEnabledAndNoSuccessResponses($route, $rules, []);
  40. $this->assertEquals(200, $results[0]['status']);
  41. $this->assertArraySubset([
  42. 'id' => 4,
  43. 'name' => 'banana',
  44. 'color' => 'red',
  45. 'weight' => '1 kg',
  46. 'delicious' => true,
  47. ], json_decode($results[0]['content'], true));
  48. }
  49. /** @test */
  50. public function uses_configured_settings_when_calling_route()
  51. {
  52. $route = LaravelRouteFacade::post('/echo/{id}', [TestController::class, 'shouldFetchRouteResponseWithEchoedSettings']);
  53. $rules = [
  54. 'response_calls' => [
  55. 'methods' => ['*'],
  56. 'queryParams' => [
  57. 'queryParam' => 'queryValue',
  58. ],
  59. 'bodyParams' => [
  60. 'bodyParam' => 'bodyValue',
  61. ],
  62. ],
  63. ];
  64. $context = [
  65. 'auth' => 'headers.Authorization.Bearer bearerToken',
  66. 'headers' => [
  67. 'Content-Type' => 'application/json',
  68. 'Accept' => 'application/json',
  69. 'header' => 'value',
  70. ],
  71. ];
  72. $strategy = new ResponseCalls(new DocumentationConfig([]));
  73. $results = $strategy->makeResponseCallIfEnabledAndNoSuccessResponses($route, $rules, $context);
  74. $this->assertEquals(200, $results[0]['status']);
  75. $responseContent = json_decode($results[0]['content'], true);
  76. $this->assertEquals('queryValue', $responseContent['queryParam']);
  77. $this->assertEquals('bodyValue', $responseContent['bodyParam']);
  78. $this->assertEquals('value', $responseContent['header']);
  79. $this->assertEquals('Bearer bearerToken', $responseContent['auth']);
  80. }
  81. /** @test */
  82. public function can_override_application_config_during_response_call()
  83. {
  84. $route = LaravelRouteFacade::post('/echoesConfig', [TestController::class, 'echoesConfig']);
  85. $rules = [
  86. 'response_calls' => [
  87. 'methods' => ['*'],
  88. ],
  89. ];
  90. $strategy = new ResponseCalls(new DocumentationConfig([]));
  91. $results = $strategy->makeResponseCallIfEnabledAndNoSuccessResponses($route, $rules, []);
  92. $originalValue = json_decode($results[0]['content'], true)['app.env'];
  93. $now = time();
  94. $rules = [
  95. 'response_calls' => [
  96. 'methods' => ['*'],
  97. 'config' => [
  98. 'app.env' => $now,
  99. ],
  100. ],
  101. ];
  102. $results = $strategy->makeResponseCallIfEnabledAndNoSuccessResponses($route, $rules, []);
  103. $newValue = json_decode($results[0]['content'], true)['app.env'];
  104. $this->assertEquals($now, $newValue);
  105. $this->assertNotEquals($originalValue, $newValue);
  106. }
  107. /**
  108. * @test
  109. * @group dingo
  110. */
  111. public function can_call_route_and_fetch_response_with_dingo()
  112. {
  113. $route = $this->registerDingoRoute('post', '/shouldFetchRouteResponse', 'shouldFetchRouteResponse');
  114. $rules = [
  115. 'headers' => [
  116. 'Content-Type' => 'application/json',
  117. 'Accept' => 'application/json',
  118. ],
  119. 'response_calls' => [
  120. 'methods' => ['*'],
  121. ],
  122. ];
  123. $strategy = new ResponseCalls(new DocumentationConfig(['router' => 'dingo']));
  124. $results = $strategy->makeResponseCallIfEnabledAndNoSuccessResponses($route, $rules, []);
  125. $this->assertEquals(200, $results[0]['status']);
  126. $this->assertArraySubset([
  127. 'id' => 4,
  128. 'name' => 'banana',
  129. 'color' => 'red',
  130. 'weight' => '1 kg',
  131. 'delicious' => true,
  132. ], json_decode($results[0]['content'], true));
  133. }
  134. /**
  135. * @test
  136. * @group dingo
  137. */
  138. public function uses_configured_settings_when_calling_route_with_dingo()
  139. {
  140. $route = $this->registerDingoRoute('post','/echo/{id}', 'shouldFetchRouteResponseWithEchoedSettings');
  141. $rules = [
  142. 'response_calls' => [
  143. 'methods' => ['*'],
  144. 'queryParams' => [
  145. 'queryParam' => 'queryValue',
  146. ],
  147. 'bodyParams' => [
  148. 'bodyParam' => 'bodyValue',
  149. ],
  150. ],
  151. ];
  152. $context = [
  153. 'headers' => [
  154. 'Content-Type' => 'application/json',
  155. 'Accept' => 'application/json',
  156. 'header' => 'value',
  157. ],
  158. ];
  159. $strategy = new ResponseCalls(new DocumentationConfig(['router' => 'dingo']));
  160. $results = $strategy->makeResponseCallIfEnabledAndNoSuccessResponses($route, $rules, $context);
  161. $this->assertEquals(200, $results[0]['status']);
  162. $responseContent = json_decode($results[0]['content'], true);
  163. $this->assertEquals('queryValue', $responseContent['queryParam']);
  164. $this->assertEquals('bodyValue', $responseContent['bodyParam']);
  165. $this->assertEquals('value', $responseContent['header']);
  166. }
  167. /**
  168. * @test
  169. * @group dingo
  170. */
  171. public function can_override_application_config_during_response_call_with_dingo()
  172. {
  173. $route = $this->registerDingoRoute('post','/echoesConfig', 'echoesConfig');
  174. $rules = [
  175. 'response_calls' => [
  176. 'methods' => ['*'],
  177. ],
  178. ];
  179. $strategy = new ResponseCalls(new DocumentationConfig(['router' => 'dingo']));
  180. $results = $strategy->makeResponseCallIfEnabledAndNoSuccessResponses($route, $rules, []);
  181. $originalValue = json_decode($results[0]['content'], true)['app.env'];
  182. $now = time();
  183. $rules = [
  184. 'response_calls' => [
  185. 'methods' => ['*'],
  186. 'config' => [
  187. 'app.env' => $now,
  188. ],
  189. ],
  190. ];
  191. $results = $strategy->makeResponseCallIfEnabledAndNoSuccessResponses($route, $rules, []);
  192. $newValue = json_decode($results[0]['content'], true)['app.env'];
  193. $this->assertEquals($now, $newValue);
  194. $this->assertNotEquals($originalValue, $newValue);
  195. }
  196. /** @test */
  197. public function does_not_make_response_call_if_success_response_already_gotten()
  198. {
  199. $route = LaravelRouteFacade::post('/shouldFetchRouteResponse', [TestController::class, 'shouldFetchRouteResponse']);
  200. $rules = [
  201. 'headers' => [
  202. 'Content-Type' => 'application/json',
  203. 'Accept' => 'application/json',
  204. ],
  205. 'response_calls' => [
  206. 'methods' => ['*'],
  207. ],
  208. ];
  209. $context = [
  210. 'responses' => [
  211. [
  212. 'status' => 200,
  213. 'content' => json_encode(['message' => 'LOL']),
  214. ]
  215. ]
  216. ];
  217. $strategy = new ResponseCalls(new DocumentationConfig([]));
  218. $results = $strategy->makeResponseCallIfEnabledAndNoSuccessResponses($route, $rules, $context);
  219. $this->assertNull($results);
  220. }
  221. /** @test */
  222. public function does_not_make_response_call_if_forbidden_by_config()
  223. {
  224. $route = LaravelRouteFacade::post('/shouldFetchRouteResponse', [TestController::class, 'shouldFetchRouteResponse']);
  225. $rules = [
  226. 'response_calls' => [
  227. 'methods' => [],
  228. ],
  229. ];
  230. $context = ['responses' => []];
  231. $strategy = new ResponseCalls(new DocumentationConfig([]));
  232. $results = $strategy->makeResponseCallIfEnabledAndNoSuccessResponses($route, $rules, $context);
  233. $this->assertNull($results);
  234. }
  235. public function registerDingoRoute(string $httpMethod, string $path, string $controllerMethod)
  236. {
  237. $desiredRoute = null;
  238. /** @var Router $api */
  239. $api = app(Router::class);
  240. $api->version('v1', function (Router $api) use ($controllerMethod, $path, $httpMethod, &$desiredRoute) {
  241. $desiredRoute = $api->$httpMethod($path, [TestController::class, $controllerMethod]);
  242. });
  243. $routes = app(\Dingo\Api\Routing\Router::class)->getRoutes('v1');
  244. /*
  245. * Doing this bc we want an instance of Dingo\Api\Routing\Route, not Illuminate\Routing\Route, which the method above returns
  246. */
  247. return collect($routes)
  248. ->first(function (Route $route) use ($desiredRoute) {
  249. return $route->uri() === $desiredRoute->uri();
  250. });
  251. }
  252. }