GetFromLaravelAPITest.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. <?php
  2. namespace Knuckles\Scribe\Tests\Strategies\UrlParameters;
  3. use Closure;
  4. use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;
  5. use Illuminate\Database\Schema\Blueprint;
  6. use Illuminate\Routing\Router;
  7. use Illuminate\Support\Facades\Schema;
  8. use Knuckles\Camel\Extraction\ExtractedEndpointData;
  9. use Knuckles\Scribe\Extracting\Shared\UrlParamsNormalizer;
  10. use Knuckles\Scribe\Extracting\Strategies\UrlParameters\GetFromLaravelAPI;
  11. use Knuckles\Scribe\Tests\BaseLaravelTest;
  12. use Knuckles\Scribe\Tests\Fixtures\TestController;
  13. use Knuckles\Scribe\Tests\Fixtures\TestUser;
  14. use Knuckles\Scribe\Tools\DocumentationConfig;
  15. class GetFromLaravelAPITest extends BaseLaravelTest
  16. {
  17. use ArraySubsetAsserts;
  18. /** @test */
  19. public function can_infer_type_from_model_binding()
  20. {
  21. $endpoint = $this->endpointForRoute("users/{id}", TestController::class, 'withInjectedModel');
  22. // Can only run on PHP 8.1
  23. // $endpoint = $this->endpointForRoute("categories/{category}/users/{id}/", TestController::class, 'withInjectedEnumAndModel');
  24. $results = $this->fetch($endpoint);
  25. $this->assertArraySubset([
  26. "name" => "id",
  27. "description" => "The ID of the user.",
  28. "required" => true,
  29. "type" => "integer",
  30. ], $results['id']);/*
  31. $this->assertArraySubset([
  32. "name" => "category",
  33. "description" => "The category.",
  34. "required" => true,
  35. "type" => "string",
  36. "example" => \Knuckles\Scribe\Tests\Fixtures\Category::cases()[0]->value,
  37. ], $results['category']);*/
  38. $this->assertIsInt($results['id']['example']);
  39. }
  40. /** @test */
  41. public function can_infer_description_from_url()
  42. {
  43. $endpoint = $this->endpointForRoute("everything/{cat_id}", TestController::class, 'dummy');
  44. $results = $this->fetch($endpoint);
  45. $this->assertArraySubset([
  46. "name" => "cat_id",
  47. "description" => "The ID of the cat.",
  48. "required" => true,
  49. "type" => "string",
  50. ], $results['cat_id']);
  51. $endpoint->route = app(Router::class)->addRoute(['GET'], 'dogs/{id}', ['uses' => [TestController::class, 'dummy']]);;
  52. $endpoint->uri = $endpoint->route->uri;
  53. $results = $this->fetch($endpoint);
  54. $this->assertArraySubset([
  55. "name" => "id",
  56. "description" => "The ID of the dog.",
  57. "required" => true,
  58. "type" => "string",
  59. ], $results['id']);
  60. }
  61. /** @test */
  62. public function can_infer_example_from_wheres()
  63. {
  64. $regex = '/catz\d+-\d/';
  65. $endpoint = $this->endpoint(function (ExtractedEndpointData $e) use ($regex) {
  66. $e->method = new \ReflectionMethod(TestController::class, 'dummy');
  67. $e->route = app(Router::class)->addRoute(['GET'], "everything/{cat_id}", ['uses' => [TestController::class, 'dummy']])
  68. ->where('cat_id', $regex);
  69. $e->uri = UrlParamsNormalizer::normalizeParameterNamesInRouteUri($e->route, $e->method);
  70. });
  71. $results = $this->fetch($endpoint);
  72. $this->assertArraySubset([
  73. "name" => "cat_id",
  74. "description" => "The ID of the cat.",
  75. "required" => true,
  76. "type" => "string",
  77. ], $results['cat_id']);
  78. $this->assertMatchesRegularExpression($regex, $results['cat_id']['example']);
  79. }
  80. /** @test */
  81. public function can_infer_data_from_field_bindings()
  82. {
  83. $endpoint = $this->endpointForRoute("audio/{audio:slug}", TestController::class, 'dummy');
  84. $results = $this->fetch($endpoint);
  85. $this->assertArraySubset([
  86. "name" => "audio_slug",
  87. "description" => "The slug of the audio.",
  88. "required" => true,
  89. "type" => "string",
  90. ], $results['audio_slug']);
  91. Schema::create('test_users', function (Blueprint $table) {
  92. $table->id();
  93. $table->string('name');
  94. });
  95. $user = TestUser::create(['name' => 'Bully Maguire', 'id' => 23]);
  96. $endpoint = $this->endpointForRoute("users/{user:id}", TestController::class, 'withInjectedModel');
  97. $results = $this->fetch($endpoint);
  98. $this->assertArraySubset([
  99. "name" => "user_id",
  100. "description" => "The ID of the user.",
  101. "required" => true,
  102. "type" => "integer",
  103. "example" => $user->id,
  104. ], $results['user_id']);
  105. }
  106. /** @test */
  107. public function can_infer_from_model_even_if_not_bound()
  108. {
  109. $oldNamespace = $this->app->getNamespace();
  110. $reflectedApp = new \ReflectionClass($this->app);
  111. $property = $reflectedApp->getProperty('namespace');
  112. $property->setAccessible(true);
  113. $property->setValue($this->app, "Knuckles\\Scribe\\Tests\\Fixtures\\");
  114. $endpoint = $this->endpointForRoute("test-users/{id}", TestController::class, 'dummy');
  115. $results = $this->fetch($endpoint);
  116. $this->assertArraySubset([
  117. "name" => "id",
  118. "description" => "The ID of the test user.",
  119. "required" => true,
  120. "type" => "integer",
  121. ], $results['id']);
  122. $property->setValue($this->app, $oldNamespace);
  123. }
  124. protected function endpointForRoute($path, $controller, $method): ExtractedEndpointData
  125. {
  126. return $this->endpoint(function (ExtractedEndpointData $e) use ($path, $method, $controller) {
  127. $e->method = new \ReflectionMethod($controller, $method);
  128. $e->route = app(Router::class)->addRoute(['GET'], $path, ['uses' => [$controller, $method]]);
  129. $e->uri = UrlParamsNormalizer::normalizeParameterNamesInRouteUri($e->route, $e->method);
  130. });
  131. }
  132. protected function endpoint(Closure $configure): ExtractedEndpointData
  133. {
  134. $endpoint = new class extends ExtractedEndpointData {
  135. public function __construct(array $parameters = [])
  136. {
  137. }
  138. };
  139. $configure($endpoint);
  140. return $endpoint;
  141. }
  142. protected function fetch($endpoint): array
  143. {
  144. $strategy = new GetFromLaravelAPI(new DocumentationConfig([]));
  145. return $strategy($endpoint, []);
  146. }
  147. }