ResponseCallsTest.php 11 KB

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