ResponseCallsTest.php 11 KB

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