GeneratorTestCase.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834
  1. <?php
  2. /** @noinspection ALL */
  3. namespace Mpociot\ApiDoc\Tests\Unit;
  4. use Illuminate\Support\Arr;
  5. use Orchestra\Testbench\TestCase;
  6. use Mpociot\ApiDoc\Tools\Generator;
  7. use Mpociot\ApiDoc\Tools\DocumentationConfig;
  8. use Mpociot\ApiDoc\Tests\Fixtures\TestController;
  9. use Mpociot\ApiDoc\ApiDocGeneratorServiceProvider;
  10. use Mpociot\ApiDoc\Tests\Fixtures\TestResourceController;
  11. abstract class GeneratorTestCase extends TestCase
  12. {
  13. /**
  14. * @var \Mpociot\ApiDoc\Tools\Generator
  15. */
  16. protected $generator;
  17. private $config = [
  18. 'strategies' => [
  19. 'metadata' => [
  20. \Mpociot\ApiDoc\Strategies\Metadata\GetFromDocBlocks::class,
  21. ],
  22. 'bodyParameters' => [
  23. \Mpociot\ApiDoc\Strategies\BodyParameters\GetFromBodyParamTag::class,
  24. ],
  25. 'queryParameters' => [
  26. \Mpociot\ApiDoc\Strategies\QueryParameters\GetFromQueryParamTag::class,
  27. ],
  28. 'responses' => [
  29. \Mpociot\ApiDoc\Strategies\Responses\UseResponseTag::class,
  30. \Mpociot\ApiDoc\Strategies\Responses\UseResponseFileTag::class,
  31. \Mpociot\ApiDoc\Strategies\Responses\UseTransformerTags::class,
  32. \Mpociot\ApiDoc\Strategies\Responses\ResponseCalls::class,
  33. ],
  34. ],
  35. 'default_group' => 'general',
  36. ];
  37. protected function getPackageProviders($app)
  38. {
  39. return [
  40. ApiDocGeneratorServiceProvider::class,
  41. ];
  42. }
  43. /**
  44. * Setup the test environment.
  45. */
  46. public function setUp(): void
  47. {
  48. parent::setUp();
  49. $this->generator = new Generator(new DocumentationConfig($this->config));
  50. }
  51. /** @test */
  52. public function can_parse_endpoint_description()
  53. {
  54. $route = $this->createRoute('GET', '/api/test', 'withEndpointDescription');
  55. $parsed = $this->generator->processRoute($route);
  56. $this->assertSame('Example title.', $parsed['title']);
  57. $this->assertSame("This will be the long description.\nIt can also be multiple lines long.", $parsed['description']);
  58. }
  59. /** @test */
  60. public function can_parse_body_parameters()
  61. {
  62. $route = $this->createRoute('GET', '/api/test', 'withBodyParameters');
  63. $bodyParameters = $this->generator->processRoute($route)['bodyParameters'];
  64. $this->assertArraySubset([
  65. 'user_id' => [
  66. 'type' => 'integer',
  67. 'required' => true,
  68. 'description' => 'The id of the user.',
  69. 'value' => 9,
  70. ],
  71. 'room_id' => [
  72. 'type' => 'string',
  73. 'required' => false,
  74. 'description' => 'The id of the room.',
  75. ],
  76. 'forever' => [
  77. 'type' => 'boolean',
  78. 'required' => false,
  79. 'description' => 'Whether to ban the user forever.',
  80. 'value' => false,
  81. ],
  82. 'another_one' => [
  83. 'type' => 'number',
  84. 'required' => false,
  85. 'description' => 'Just need something here.',
  86. ],
  87. 'yet_another_param' => [
  88. 'type' => 'object',
  89. 'required' => true,
  90. 'description' => 'Some object params.',
  91. ],
  92. 'yet_another_param.name' => [
  93. 'type' => 'string',
  94. 'description' => 'Subkey in the object param.',
  95. 'required' => true,
  96. ],
  97. 'even_more_param' => [
  98. 'type' => 'array',
  99. 'required' => false,
  100. 'description' => 'Some array params.',
  101. ],
  102. 'even_more_param.*' => [
  103. 'type' => 'float',
  104. 'description' => 'Subkey in the array param.',
  105. 'required' => false,
  106. ],
  107. 'book.name' => [
  108. 'type' => 'string',
  109. 'description' => '',
  110. 'required' => false,
  111. ],
  112. 'book.author_id' => [
  113. 'type' => 'integer',
  114. 'description' => '',
  115. 'required' => false,
  116. ],
  117. 'book[pages_count]' => [
  118. 'type' => 'integer',
  119. 'description' => '',
  120. 'required' => false,
  121. ],
  122. 'ids.*' => [
  123. 'type' => 'integer',
  124. 'description' => '',
  125. 'required' => false,
  126. ],
  127. 'users.*.first_name' => [
  128. 'type' => 'string',
  129. 'description' => 'The first name of the user.',
  130. 'required' => false,
  131. 'value' => 'John',
  132. ],
  133. 'users.*.last_name' => [
  134. 'type' => 'string',
  135. 'description' => 'The last name of the user.',
  136. 'required' => false,
  137. 'value' => 'Doe',
  138. ],
  139. ], $bodyParameters);
  140. }
  141. /** @test */
  142. public function it_ignores_non_commented_form_request()
  143. {
  144. $route = $this->createRoute('GET', '/api/test', 'withNonCommentedFormRequestParameter');
  145. $bodyParameters = $this->generator->processRoute($route)['bodyParameters'];
  146. $this->assertArraySubset([
  147. 'direct_one' => [
  148. 'type' => 'string',
  149. 'description' => 'Is found directly on the method.',
  150. ],
  151. ], $bodyParameters);
  152. }
  153. /** @test */
  154. public function can_parse_form_request_body_parameters()
  155. {
  156. $route = $this->createRoute('GET', '/api/test', 'withFormRequestParameter');
  157. $bodyParameters = $this->generator->processRoute($route)['bodyParameters'];
  158. $this->assertArraySubset([
  159. 'user_id' => [
  160. 'type' => 'integer',
  161. 'required' => true,
  162. 'description' => 'The id of the user.',
  163. 'value' => 9,
  164. ],
  165. 'room_id' => [
  166. 'type' => 'string',
  167. 'required' => false,
  168. 'description' => 'The id of the room.',
  169. ],
  170. 'forever' => [
  171. 'type' => 'boolean',
  172. 'required' => false,
  173. 'description' => 'Whether to ban the user forever.',
  174. 'value' => false,
  175. ],
  176. 'another_one' => [
  177. 'type' => 'number',
  178. 'required' => false,
  179. 'description' => 'Just need something here.',
  180. ],
  181. 'yet_another_param' => [
  182. 'type' => 'object',
  183. 'required' => true,
  184. 'description' => '',
  185. ],
  186. 'even_more_param' => [
  187. 'type' => 'array',
  188. 'required' => false,
  189. 'description' => '',
  190. ],
  191. ], $bodyParameters);
  192. }
  193. /** @test */
  194. public function can_parse_multiple_form_request_body_parameters()
  195. {
  196. $route = $this->createRoute('GET', '/api/test', 'withMultipleFormRequestParameters');
  197. $bodyParameters = $this->generator->processRoute($route)['bodyParameters'];
  198. $this->assertArraySubset([
  199. 'user_id' => [
  200. 'type' => 'integer',
  201. 'required' => true,
  202. 'description' => 'The id of the user.',
  203. 'value' => 9,
  204. ],
  205. 'room_id' => [
  206. 'type' => 'string',
  207. 'required' => false,
  208. 'description' => 'The id of the room.',
  209. ],
  210. 'forever' => [
  211. 'type' => 'boolean',
  212. 'required' => false,
  213. 'description' => 'Whether to ban the user forever.',
  214. 'value' => false,
  215. ],
  216. 'another_one' => [
  217. 'type' => 'number',
  218. 'required' => false,
  219. 'description' => 'Just need something here.',
  220. ],
  221. 'yet_another_param' => [
  222. 'type' => 'object',
  223. 'required' => true,
  224. 'description' => '',
  225. ],
  226. 'even_more_param' => [
  227. 'type' => 'array',
  228. 'required' => false,
  229. 'description' => '',
  230. ],
  231. ], $bodyParameters);
  232. }
  233. /** @test */
  234. public function can_parse_query_parameters()
  235. {
  236. $route = $this->createRoute('GET', '/api/test', 'withQueryParameters');
  237. $queryParameters = $this->generator->processRoute($route)['queryParameters'];
  238. $this->assertArraySubset([
  239. 'location_id' => [
  240. 'required' => true,
  241. 'description' => 'The id of the location.',
  242. ],
  243. 'user_id' => [
  244. 'required' => true,
  245. 'description' => 'The id of the user.',
  246. 'value' => 'me',
  247. ],
  248. 'page' => [
  249. 'required' => true,
  250. 'description' => 'The page number.',
  251. 'value' => '4',
  252. ],
  253. 'filters' => [
  254. 'required' => false,
  255. 'description' => 'The filters.',
  256. ],
  257. ], $queryParameters);
  258. }
  259. /** @test */
  260. public function it_does_not_generate_values_for_excluded_params_and_excludes_them_from_clean_params()
  261. {
  262. $route = $this->createRoute('GET', '/api/test', 'withExcludedExamples');
  263. $parsed = $this->generator->processRoute($route);
  264. $cleanBodyParameters = $parsed['cleanBodyParameters'];
  265. $cleanQueryParameters = $parsed['cleanQueryParameters'];
  266. $bodyParameters = $parsed['bodyParameters'];
  267. $queryParameters = $parsed['queryParameters'];
  268. $this->assertArrayHasKey('included', $cleanBodyParameters);
  269. $this->assertArrayNotHasKey('excluded_body_param', $cleanBodyParameters);
  270. $this->assertEmpty($cleanQueryParameters);
  271. $this->assertArraySubset([
  272. 'included' => [
  273. 'required' => true,
  274. 'type' => 'string',
  275. 'description' => 'Exists in examples.',
  276. ],
  277. 'excluded_body_param' => [
  278. 'type' => 'integer',
  279. 'description' => 'Does not exist in examples.',
  280. ],
  281. ], $bodyParameters);
  282. $this->assertArraySubset([
  283. 'excluded_query_param' => [
  284. 'description' => 'Does not exist in examples.',
  285. ],
  286. ], $queryParameters);
  287. }
  288. /** @test */
  289. public function can_parse_route_group()
  290. {
  291. $route = $this->createRoute('GET', '/api/test', 'dummy');
  292. $routeGroup = $this->generator->processRoute($route)['groupName'];
  293. $this->assertSame('Group A', $routeGroup);
  294. }
  295. /** @test */
  296. public function method_can_override_controller_group()
  297. {
  298. $route = $this->createRoute('GET', '/group/1', 'withGroupOverride');
  299. $parsedRoute = $this->generator->processRoute($route);
  300. $this->assertSame('Group B', $parsedRoute['groupName']);
  301. $this->assertSame('', $parsedRoute['groupDescription']);
  302. $route = $this->createRoute('GET', '/group/2', 'withGroupOverride2');
  303. $parsedRoute = $this->generator->processRoute($route);
  304. $this->assertSame('Group B', $parsedRoute['groupName']);
  305. $this->assertSame('', $parsedRoute['groupDescription']);
  306. $this->assertSame('This is also in Group B. No route description. Route title before gropp.', $parsedRoute['title']);
  307. $route = $this->createRoute('GET', '/group/3', 'withGroupOverride3');
  308. $parsedRoute = $this->generator->processRoute($route);
  309. $this->assertSame('Group B', $parsedRoute['groupName']);
  310. $this->assertSame('', $parsedRoute['groupDescription']);
  311. $this->assertSame('This is also in Group B. Route title after group.', $parsedRoute['title']);
  312. $route = $this->createRoute('GET', '/group/4', 'withGroupOverride4');
  313. $parsedRoute = $this->generator->processRoute($route);
  314. $this->assertSame('Group C', $parsedRoute['groupName']);
  315. $this->assertSame('Group description after group.', $parsedRoute['groupDescription']);
  316. $this->assertSame('This is in Group C. Route title before group.', $parsedRoute['title']);
  317. }
  318. /** @test */
  319. public function can_parse_auth_tags()
  320. {
  321. $route = $this->createRoute('GET', '/api/test', 'withAuthenticatedTag');
  322. $authenticated = $this->generator->processRoute($route)['authenticated'];
  323. $this->assertTrue($authenticated);
  324. $route = $this->createRoute('GET', '/api/test', 'dummy');
  325. $authenticated = $this->generator->processRoute($route)['authenticated'];
  326. $this->assertFalse($authenticated);
  327. }
  328. /** @test */
  329. public function can_parse_route_methods()
  330. {
  331. $route = $this->createRoute('GET', '/get', 'withEndpointDescription');
  332. $parsed = $this->generator->processRoute($route);
  333. $this->assertSame(['GET'], $parsed['methods']);
  334. $route = $this->createRoute('POST', '/post', 'withEndpointDescription');
  335. $parsed = $this->generator->processRoute($route);
  336. $this->assertSame(['POST'], $parsed['methods']);
  337. $route = $this->createRoute('PUT', '/put', 'withEndpointDescription');
  338. $parsed = $this->generator->processRoute($route);
  339. $this->assertSame(['PUT'], $parsed['methods']);
  340. $route = $this->createRoute('DELETE', '/delete', 'withEndpointDescription');
  341. $parsed = $this->generator->processRoute($route);
  342. $this->assertSame(['DELETE'], $parsed['methods']);
  343. }
  344. /** @test */
  345. public function can_parse_response_tag()
  346. {
  347. $route = $this->createRoute('POST', '/responseTag', 'withResponseTag');
  348. $parsed = $this->generator->processRoute($route);
  349. $response = Arr::first($parsed['response']);
  350. $this->assertTrue(is_array($parsed));
  351. $this->assertArrayHasKey('showresponse', $parsed);
  352. $this->assertTrue($parsed['showresponse']);
  353. $this->assertTrue(is_array($response));
  354. $this->assertEquals(200, $response['status']);
  355. $this->assertArraySubset([
  356. 'id' => 4,
  357. 'name' => 'banana',
  358. 'color' => 'red',
  359. 'weight' => '1 kg',
  360. 'delicious' => true,
  361. ], json_decode($response['content'], true));
  362. }
  363. /** @test */
  364. public function can_parse_response_tag_with_status_code()
  365. {
  366. $route = $this->createRoute('POST', '/responseTag', 'withResponseTagAndStatusCode');
  367. $parsed = $this->generator->processRoute($route);
  368. $response = Arr::first($parsed['response']);
  369. $this->assertTrue(is_array($parsed));
  370. $this->assertArrayHasKey('showresponse', $parsed);
  371. $this->assertTrue($parsed['showresponse']);
  372. $this->assertTrue(is_array($response));
  373. $this->assertEquals(422, $response['status']);
  374. $this->assertArraySubset([
  375. 'message' => 'Validation error',
  376. ], json_decode($response['content'], true));
  377. }
  378. /** @test */
  379. public function can_parse_multiple_response_tags()
  380. {
  381. $route = $this->createRoute('POST', '/responseTag', 'withMultipleResponseTagsAndStatusCode');
  382. $parsed = $this->generator->processRoute($route);
  383. $this->assertTrue(is_array($parsed));
  384. $this->assertArrayHasKey('showresponse', $parsed);
  385. $this->assertTrue($parsed['showresponse']);
  386. $this->assertTrue(is_array($parsed['response'][0]));
  387. $this->assertEquals(200, $parsed['response'][0]['status']);
  388. $this->assertArraySubset([
  389. 'id' => 4,
  390. 'name' => 'banana',
  391. 'color' => 'red',
  392. 'weight' => '1 kg',
  393. 'delicious' => true,
  394. ], json_decode($parsed['response'][0]['content'], true));
  395. $this->assertTrue(is_array($parsed['response'][1]));
  396. $this->assertEquals(401, $parsed['response'][1]['status']);
  397. $this->assertArraySubset([
  398. 'message' => 'Unauthorized',
  399. ], json_decode($parsed['response'][1]['content'], true));
  400. }
  401. /**
  402. * @param $serializer
  403. * @param $expected
  404. *
  405. * @test
  406. * @dataProvider dataResources
  407. */
  408. public function can_parse_transformer_tag($serializer, $expected)
  409. {
  410. config(['apidoc.fractal.serializer' => $serializer]);
  411. $route = $this->createRoute('GET', '/transformerTag', 'transformerTag');
  412. $parsed = $this->generator->processRoute($route);
  413. $response = Arr::first($parsed['response']);
  414. $this->assertTrue(is_array($parsed));
  415. $this->assertArrayHasKey('showresponse', $parsed);
  416. $this->assertTrue($parsed['showresponse']);
  417. $this->assertTrue(is_array($response));
  418. $this->assertEquals(200, $response['status']);
  419. $this->assertSame(
  420. $expected,
  421. $response['content']
  422. );
  423. }
  424. /** @test */
  425. public function can_parse_transformer_tag_with_model()
  426. {
  427. $route = $this->createRoute('GET', '/transformerTagWithModel', 'transformerTagWithModel');
  428. $parsed = $this->generator->processRoute($route);
  429. $response = Arr::first($parsed['response']);
  430. $this->assertTrue(is_array($parsed));
  431. $this->assertArrayHasKey('showresponse', $parsed);
  432. $this->assertTrue($parsed['showresponse']);
  433. $this->assertTrue(is_array($response));
  434. $this->assertEquals(200, $response['status']);
  435. $this->assertSame(
  436. '{"data":{"id":1,"description":"Welcome on this test versions","name":"TestName"}}',
  437. $response['content']
  438. );
  439. }
  440. /** @test */
  441. public function can_parse_transformer_tag_with_status_code()
  442. {
  443. $route = $this->createRoute('GET', '/transformerTagWithStatusCode', 'transformerTagWithStatusCode');
  444. $parsed = $this->generator->processRoute($route);
  445. $response = Arr::first($parsed['response']);
  446. $this->assertTrue(is_array($parsed));
  447. $this->assertArrayHasKey('showresponse', $parsed);
  448. $this->assertTrue($parsed['showresponse']);
  449. $this->assertTrue(is_array($response));
  450. $this->assertEquals(201, $response['status']);
  451. $this->assertSame(
  452. '{"data":{"id":1,"description":"Welcome on this test versions","name":"TestName"}}',
  453. $response['content']
  454. );
  455. }
  456. /** @test */
  457. public function can_parse_transformer_collection_tag()
  458. {
  459. $route = $this->createRoute('GET', '/transformerCollectionTag', 'transformerCollectionTag');
  460. $parsed = $this->generator->processRoute($route);
  461. $response = Arr::first($parsed['response']);
  462. $this->assertTrue(is_array($parsed));
  463. $this->assertArrayHasKey('showresponse', $parsed);
  464. $this->assertTrue($parsed['showresponse']);
  465. $this->assertTrue(is_array($response));
  466. $this->assertEquals(200, $response['status']);
  467. $this->assertSame(
  468. $response['content'],
  469. '{"data":[{"id":1,"description":"Welcome on this test versions","name":"TestName"},'.
  470. '{"id":1,"description":"Welcome on this test versions","name":"TestName"}]}'
  471. );
  472. }
  473. /** @test */
  474. public function can_parse_transformer_collection_tag_with_model()
  475. {
  476. $route = $this->createRoute('GET', '/transformerCollectionTagWithModel', 'transformerCollectionTagWithModel');
  477. $parsed = $this->generator->processRoute($route);
  478. $response = Arr::first($parsed['response']);
  479. $this->assertTrue(is_array($parsed));
  480. $this->assertArrayHasKey('showresponse', $parsed);
  481. $this->assertTrue($parsed['showresponse']);
  482. $this->assertTrue(is_array($response));
  483. $this->assertEquals(200, $response['status']);
  484. $this->assertSame(
  485. $response['content'],
  486. '{"data":[{"id":1,"description":"Welcome on this test versions","name":"TestName"},'.
  487. '{"id":1,"description":"Welcome on this test versions","name":"TestName"}]}'
  488. );
  489. }
  490. /** @test */
  491. public function can_call_route_and_generate_response()
  492. {
  493. $route = $this->createRoute('POST', '/shouldFetchRouteResponse', 'shouldFetchRouteResponse', true);
  494. $rules = [
  495. 'response_calls' => [
  496. 'methods' => ['*'],
  497. 'headers' => [
  498. 'Content-Type' => 'application/json',
  499. 'Accept' => 'application/json',
  500. ],
  501. ],
  502. ];
  503. $parsed = $this->generator->processRoute($route, $rules);
  504. $response = Arr::first($parsed['response']);
  505. $this->assertTrue(is_array($parsed));
  506. $this->assertArrayHasKey('showresponse', $parsed);
  507. $this->assertTrue($parsed['showresponse']);
  508. $this->assertTrue(is_array($response));
  509. $this->assertEquals(200, $response['status']);
  510. $this->assertArraySubset([
  511. 'id' => 4,
  512. 'name' => 'banana',
  513. 'color' => 'red',
  514. 'weight' => '1 kg',
  515. 'delicious' => true,
  516. ], json_decode($response['content'], true));
  517. }
  518. /** @test */
  519. public function can_override_config_during_response_call()
  520. {
  521. $route = $this->createRoute('POST', '/echoesConfig', 'echoesConfig', true);
  522. $rules = [
  523. 'response_calls' => [
  524. 'methods' => ['*'],
  525. ],
  526. ];
  527. $parsed = $this->generator->processRoute($route, $rules);
  528. $response = json_decode(Arr::first($parsed['response'])['content'], true);
  529. $originalValue = $response['app.env'];
  530. $now = time();
  531. $rules = [
  532. 'response_calls' => [
  533. 'methods' => ['*'],
  534. 'config' => [
  535. 'app.env' => $now,
  536. ],
  537. ],
  538. ];
  539. $parsed = $this->generator->processRoute($route, $rules);
  540. $response = json_decode(Arr::first($parsed['response'])['content'], true);
  541. $newValue = $response['app.env'];
  542. $this->assertEquals($now, $newValue);
  543. $this->assertNotEquals($originalValue, $newValue);
  544. }
  545. /** @test */
  546. public function can_override_url_path_parameters_with_urlparam_annotation()
  547. {
  548. $route = $this->createRoute('POST', '/echoesUrlParameters/{param}', 'echoesUrlParameters', true);
  549. $rules = [
  550. 'response_calls' => [
  551. 'methods' => ['*'],
  552. ],
  553. ];
  554. $parsed = $this->generator->processRoute($route, $rules);
  555. $response = json_decode(Arr::first($parsed['response'])['content'], true);
  556. $this->assertEquals(4, $response['param']);
  557. }
  558. /** @test */
  559. public function ignores_or_inserts_optional_url_path_parameters_according_to_annotations()
  560. {
  561. $route = $this->createRoute('POST', '/echoesUrlParameters/{param}/{param2?}/{param3}/{param4?}', 'echoesUrlParameters', true);
  562. $rules = [
  563. 'response_calls' => [
  564. 'methods' => ['*'],
  565. ],
  566. ];
  567. $parsed = $this->generator->processRoute($route, $rules);
  568. $response = json_decode(Arr::first($parsed['response'])['content'], true);
  569. $this->assertEquals(4, $response['param']);
  570. $this->assertNotNull($response['param2']);
  571. $this->assertEquals(1, $response['param3']);
  572. $this->assertNull($response['param4']);
  573. }
  574. /** @test */
  575. public function can_parse_response_file_tag()
  576. {
  577. // copy file to storage
  578. $filePath = __DIR__.'/../Fixtures/response_test.json';
  579. $fixtureFileJson = file_get_contents($filePath);
  580. copy($filePath, storage_path('response_test.json'));
  581. $route = $this->createRoute('GET', '/responseFileTag', 'responseFileTag');
  582. $parsed = $this->generator->processRoute($route);
  583. $response = Arr::first($parsed['response']);
  584. $this->assertTrue(is_array($parsed));
  585. $this->assertArrayHasKey('showresponse', $parsed);
  586. $this->assertTrue($parsed['showresponse']);
  587. $this->assertTrue(is_array($response));
  588. $this->assertEquals(200, $response['status']);
  589. $this->assertSame(
  590. $response['content'],
  591. $fixtureFileJson
  592. );
  593. unlink(storage_path('response_test.json'));
  594. }
  595. /** @test */
  596. public function can_add_or_replace_key_value_pair_in_response_file()
  597. {
  598. // copy file to storage
  599. $filePath = __DIR__.'/../Fixtures/response_test.json';
  600. $fixtureFileJson = file_get_contents($filePath);
  601. copy($filePath, storage_path('response_test.json'));
  602. $route = $this->createRoute('GET', '/responseFileTagAndCustomJson', 'responseFileTagAndCustomJson');
  603. $parsed = $this->generator->processRoute($route);
  604. $response = Arr::first($parsed['response']);
  605. $this->assertTrue(is_array($parsed));
  606. $this->assertArrayHasKey('showresponse', $parsed);
  607. $this->assertTrue($parsed['showresponse']);
  608. $this->assertTrue(is_array($response));
  609. $this->assertEquals(200, $response['status']);
  610. $this->assertNotSame(
  611. $response['content'],
  612. $fixtureFileJson
  613. );
  614. unlink(storage_path('response_test.json'));
  615. }
  616. /** @test */
  617. public function can_parse_multiple_response_file_tags_with_status_codes()
  618. {
  619. // copy file to storage
  620. $successFilePath = __DIR__.'/../Fixtures/response_test.json';
  621. $successFixtureFileJson = file_get_contents($successFilePath);
  622. copy($successFilePath, storage_path('response_test.json'));
  623. $errorFilePath = __DIR__.'/../Fixtures/response_error_test.json';
  624. $errorFixtureFileJson = file_get_contents($errorFilePath);
  625. copy($errorFilePath, storage_path('response_error_test.json'));
  626. $route = $this->createRoute('GET', '/responseFileTag', 'withResponseFileTagAndStatusCode');
  627. $parsed = $this->generator->processRoute($route);
  628. $this->assertTrue(is_array($parsed));
  629. $this->assertArrayHasKey('showresponse', $parsed);
  630. $this->assertTrue($parsed['showresponse']);
  631. $this->assertTrue(is_array($parsed['response'][0]));
  632. $this->assertEquals(200, $parsed['response'][0]['status']);
  633. $this->assertSame(
  634. $parsed['response'][0]['content'],
  635. $successFixtureFileJson
  636. );
  637. $this->assertTrue(is_array($parsed['response'][1]));
  638. $this->assertEquals(401, $parsed['response'][1]['status']);
  639. $this->assertSame(
  640. $parsed['response'][1]['content'],
  641. $errorFixtureFileJson
  642. );
  643. unlink(storage_path('response_test.json'));
  644. unlink(storage_path('response_error_test.json'));
  645. }
  646. /** @test */
  647. public function generates_consistent_examples_when_faker_seed_is_set()
  648. {
  649. $route = $this->createRoute('GET', '/withBodyParameters', 'withBodyParameters');
  650. $paramName = 'room_id';
  651. $results = [];
  652. $results[$this->generator->processRoute($route)['cleanBodyParameters'][$paramName]] = true;
  653. $results[$this->generator->processRoute($route)['cleanBodyParameters'][$paramName]] = true;
  654. $results[$this->generator->processRoute($route)['cleanBodyParameters'][$paramName]] = true;
  655. $results[$this->generator->processRoute($route)['cleanBodyParameters'][$paramName]] = true;
  656. $results[$this->generator->processRoute($route)['cleanBodyParameters'][$paramName]] = true;
  657. // Examples should have different values
  658. $this->assertNotEquals(count($results), 1);
  659. $generator = new Generator(new DocumentationConfig($this->config + ['faker_seed' => 12345]));
  660. $results = [];
  661. $results[$generator->processRoute($route)['cleanBodyParameters'][$paramName]] = true;
  662. $results[$generator->processRoute($route)['cleanBodyParameters'][$paramName]] = true;
  663. $results[$generator->processRoute($route)['cleanBodyParameters'][$paramName]] = true;
  664. $results[$generator->processRoute($route)['cleanBodyParameters'][$paramName]] = true;
  665. // Examples should have same values
  666. $this->assertEquals(count($results), 1);
  667. }
  668. /** @test */
  669. public function uses_configured_settings_when_calling_route()
  670. {
  671. $route = $this->createRoute('PUT', '/echo/{id}', 'shouldFetchRouteResponseWithEchoedSettings', true);
  672. $rules = [
  673. 'response_calls' => [
  674. 'methods' => ['*'],
  675. 'headers' => [
  676. 'Content-Type' => 'application/json',
  677. 'Accept' => 'application/json',
  678. 'header' => 'value',
  679. ],
  680. 'query' => [
  681. 'queryParam' => 'queryValue',
  682. ],
  683. 'body' => [
  684. 'bodyParam' => 'bodyValue',
  685. ],
  686. ],
  687. ];
  688. $parsed = $this->generator->processRoute($route, $rules);
  689. $response = Arr::first($parsed['response']);
  690. $this->assertTrue(is_array($parsed));
  691. $this->assertArrayHasKey('showresponse', $parsed);
  692. $this->assertTrue($parsed['showresponse']);
  693. $this->assertTrue(is_array($response));
  694. $this->assertEquals(200, $response['status']);
  695. $responseContent = json_decode($response['content'], true);
  696. $this->assertEquals('queryValue', $responseContent['queryParam']);
  697. $this->assertEquals('bodyValue', $responseContent['bodyParam']);
  698. $this->assertEquals('value', $responseContent['header']);
  699. }
  700. /** @test */
  701. public function can_use_arrays_in_routes_uses()
  702. {
  703. $route = $this->createRouteUsesArray('GET', '/api/array/test', 'withEndpointDescription');
  704. $parsed = $this->generator->processRoute($route);
  705. $this->assertSame('Example title.', $parsed['title']);
  706. $this->assertSame("This will be the long description.\nIt can also be multiple lines long.", $parsed['description']);
  707. }
  708. /** @test */
  709. public function combines_responses_from_different_strategies()
  710. {
  711. $route = $this->createRoute('GET', '/api/indexResource', 'index', true, TestResourceController::class);
  712. $rules = [
  713. 'response_calls' => [
  714. 'methods' => ['*'],
  715. 'headers' => [
  716. 'Accept' => 'application/json',
  717. ],
  718. ],
  719. ];
  720. $parsed = $this->generator->processRoute($route, $rules);
  721. $this->assertTrue(is_array($parsed));
  722. $this->assertArrayHasKey('showresponse', $parsed);
  723. $this->assertTrue($parsed['showresponse']);
  724. $this->assertSame(1, count($parsed['response']));
  725. $this->assertTrue(is_array($parsed['response'][0]));
  726. $this->assertEquals(200, $parsed['response'][0]['status']);
  727. $this->assertArraySubset([
  728. 'index_resource' => true,
  729. ], json_decode($parsed['response'][0]['content'], true));
  730. }
  731. abstract public function createRoute(string $httpMethod, string $path, string $controllerMethod, $register = false, $class = TestController::class);
  732. abstract public function createRouteUsesArray(string $httpMethod, string $path, string $controllerMethod, $register = false, $class = TestController::class);
  733. public function dataResources()
  734. {
  735. return [
  736. [
  737. null,
  738. '{"data":{"id":1,"description":"Welcome on this test versions","name":"TestName"}}',
  739. ],
  740. [
  741. 'League\Fractal\Serializer\JsonApiSerializer',
  742. '{"data":{"type":null,"id":"1","attributes":{"description":"Welcome on this test versions","name":"TestName"}}}',
  743. ],
  744. ];
  745. }
  746. }