BehavioursTest.php 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. <?php
  2. namespace Knuckles\Scribe\Tests\GenerateDocumentation;
  3. use Illuminate\Support\Facades\Route as RouteFacade;
  4. use Knuckles\Scribe\Commands\GenerateDocumentation;
  5. use Knuckles\Scribe\Scribe;
  6. use Knuckles\Scribe\Tests\BaseLaravelTest;
  7. use Knuckles\Scribe\Tests\Fixtures\TestController;
  8. use Knuckles\Scribe\Tests\Fixtures\TestGroupController;
  9. use Knuckles\Scribe\Tests\Fixtures\TestIgnoreThisController;
  10. use Knuckles\Scribe\Tests\Fixtures\TestPartialResourceController;
  11. use Knuckles\Scribe\Tests\Fixtures\TestResourceController;
  12. use Knuckles\Scribe\Tests\Fixtures\TestUser;
  13. use Knuckles\Scribe\Tests\TestHelpers;
  14. use Knuckles\Scribe\Tools\Utils;
  15. class BehavioursTest extends BaseLaravelTest
  16. {
  17. use TestHelpers;
  18. protected function setUp(): void
  19. {
  20. parent::setUp();
  21. config(['scribe.database_connections_to_transact' => []]);
  22. config(['scribe.routes.0.match.prefixes' => ['api/*']]);
  23. // Skip these ones for faster tests
  24. config(['scribe.openapi.enabled' => false]);
  25. config(['scribe.postman.enabled' => false]);
  26. $factory = app(\Illuminate\Database\Eloquent\Factory::class);
  27. $factory->define(TestUser::class, function () {
  28. return [
  29. 'id' => 4,
  30. 'first_name' => 'Tested',
  31. 'last_name' => 'Again',
  32. 'email' => 'a@b.com',
  33. ];
  34. });
  35. }
  36. public function tearDown(): void
  37. {
  38. Utils::deleteDirectoryAndContents('public/docs');
  39. Utils::deleteDirectoryAndContents('.scribe');
  40. }
  41. /** @test */
  42. public function can_process_traditional_laravel_route_syntax_and_callable_tuple_syntax()
  43. {
  44. RouteFacade::get('/api/test', [TestController::class, 'withEndpointDescription']);
  45. RouteFacade::get('/api/array/test', [TestController::class, 'withEndpointDescription']);
  46. $this->generateAndExpectConsoleOutput(
  47. 'Processed route: [GET] api/test',
  48. 'Processed route: [GET] api/array/test'
  49. );
  50. }
  51. /** @test */
  52. public function processes_head_routes_as_head_not_get()
  53. {
  54. RouteFacade::addRoute('HEAD', '/api/test', [TestController::class, 'withEndpointDescription']);
  55. $this->generateAndExpectConsoleOutput('Processed route: [HEAD] api/test');
  56. }
  57. /**
  58. * @test
  59. * @see https://github.com/knuckleswtf/scribe/issues/53
  60. */
  61. public function can_process_closure_routes()
  62. {
  63. RouteFacade::get('/api/closure', function () {
  64. return 'hi';
  65. });
  66. $this->generateAndExpectConsoleOutput('Processed route: [GET] api/closure');
  67. }
  68. /**
  69. * @group dingo
  70. * @test
  71. */
  72. public function can_process_routes_on_dingo()
  73. {
  74. $api = app(\Dingo\Api\Routing\Router::class);
  75. $api->version('v1', function ($api) {
  76. $api->get('/closure', function () {
  77. return 'foo';
  78. });
  79. $api->get('/test', [TestController::class, 'withEndpointDescription']);
  80. });
  81. config(['scribe.routes.0.match.prefixes' => ['*']]);
  82. config(['scribe.routes.0.match.versions' => ['v1']]);
  83. $this->generateAndExpectConsoleOutput(
  84. 'Processed route: [GET] closure',
  85. 'Processed route: [GET] test'
  86. );
  87. }
  88. /** @test */
  89. public function calls_afterGenerating_hook()
  90. {
  91. $paths = [];
  92. Scribe::afterGenerating(function (array $outputPaths) use (&$paths) {
  93. $paths = $outputPaths;
  94. });
  95. RouteFacade::get('/api/test', [TestController::class, 'withEndpointDescription']);
  96. $this->generate();
  97. $this->assertEquals([
  98. 'html' => realpath('public/docs/index.html'),
  99. 'blade' => null,
  100. 'postman' => realpath('public/docs/collection.json') ?: null,
  101. 'openapi' => realpath('public/docs/openapi.yaml') ?: null,
  102. 'assets' => [
  103. 'js' => realpath('public/docs/js'),
  104. 'css' => realpath('public/docs/css'),
  105. 'images' => realpath('public/docs/images'),
  106. ],
  107. ], $paths);
  108. Scribe::afterGenerating(fn() => null);
  109. }
  110. /** @test */
  111. public function calls_beforeGenerating_hook()
  112. {
  113. $commandInstance = null;
  114. Scribe::beforeGenerateCommandStarts(function (GenerateDocumentation $command) use (&$commandInstance){
  115. $commandInstance = $command;
  116. });
  117. RouteFacade::get('/api/test', [TestController::class, 'withEndpointDescription']);
  118. $this->generate();
  119. $this->assertTrue($commandInstance instanceof GenerateDocumentation);
  120. Scribe::beforeGenerateCommandStarts(fn() => null);
  121. }
  122. /** @test */
  123. public function skips_methods_and_classes_with_hidefromapidocumentation_tag()
  124. {
  125. RouteFacade::get('/api/skip', [TestController::class, 'skip']);
  126. RouteFacade::get('/api/skipClass', TestIgnoreThisController::class . '@dummy');
  127. RouteFacade::get('/api/test', [TestController::class, 'withEndpointDescription']);
  128. $this->generateAndExpectConsoleOutput(
  129. 'Skipping route: [GET] api/skip',
  130. 'Skipping route: [GET] api/skipClass',
  131. 'Processed route: [GET] api/test'
  132. );
  133. }
  134. /** @test */
  135. public function warns_of_nonexistent_response_files()
  136. {
  137. RouteFacade::get('/api/non-existent', [TestController::class, 'withNonExistentResponseFile']);
  138. $this->generateAndExpectConsoleOutput('@responseFile i-do-not-exist.json does not exist');
  139. }
  140. /** @test */
  141. public function can_parse_resource_routes()
  142. {
  143. RouteFacade::resource('/api/users', TestResourceController::class)
  144. ->only(['index', 'store']);
  145. $output = $this->generate();
  146. $this->assertStringContainsString('Processed route: [GET] api/users', $output);
  147. $this->assertStringContainsString('Processed route: [POST] api/users', $output);
  148. $this->assertStringNotContainsString('Processed route: [PUT,PATCH] api/users/{user}', $output);
  149. $this->assertStringNotContainsString('Processed route: [DELETE] api/users/{user}', $output);
  150. }
  151. /** @test */
  152. public function supports_partial_resource_controller()
  153. {
  154. RouteFacade::resource('/api/users', TestPartialResourceController::class);
  155. $this->generateAndExpectConsoleOutput(
  156. 'Processed route: [GET] api/users',
  157. 'Processed route: [PUT,PATCH] api/users/{user}'
  158. );
  159. }
  160. /** @test */
  161. public function can_customise_static_output_path()
  162. {
  163. RouteFacade::get('/api/action1', TestGroupController::class . '@action1');
  164. config(['scribe.static.output_path' => 'static/docs']);
  165. $this->assertFileDoesNotExist('static/docs/index.html');
  166. $this->generate();
  167. $this->assertFileExists('static/docs/index.html');
  168. Utils::deleteDirectoryAndContents('static/');
  169. }
  170. /** @test */
  171. public function checks_for_upgrades_after_run_unless_disabled()
  172. {
  173. file_put_contents("config/scribe_test.php", str_replace("'logo' => false,", "", file_get_contents("config/scribe.php")));
  174. config(["scribe_test" => require "config/scribe_test.php"]);
  175. $output = $this->artisan('scribe:generate', ['--config' => 'scribe_test']);
  176. $this->assertStringContainsString("Checking for any pending upgrades to your config file...", $output);
  177. $this->assertStringContainsString("`logo` will be added", $output);
  178. $output = $this->artisan('scribe:generate', ['--config' => 'scribe_test', '--no-upgrade-check' => true]);
  179. $this->assertStringNotContainsString("Checking for any pending upgrades to your config file...", $output);
  180. unlink("config/scribe_test.php");
  181. Utils::deleteDirectoryAndContents(".scribe_test");
  182. }
  183. }