BehavioursTest.php 6.5 KB

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