UseResponseAttributesTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. <?php
  2. namespace Knuckles\Scribe\Tests\Strategies\Responses;
  3. use Illuminate\Foundation\Application;
  4. use Illuminate\Routing\Route;
  5. use Knuckles\Camel\Extraction\ExtractedEndpointData;
  6. use Knuckles\Scribe\Attributes\Response;
  7. use Knuckles\Scribe\Attributes\ResponseFromApiResource;
  8. use Knuckles\Scribe\Attributes\ResponseFromFile;
  9. use Knuckles\Scribe\Attributes\ResponseFromTransformer;
  10. use Knuckles\Scribe\Extracting\Strategies\Responses\UseResponseAttributes;
  11. use Knuckles\Scribe\ScribeServiceProvider;
  12. use Knuckles\Scribe\Tests\BaseLaravelTest;
  13. use Knuckles\Scribe\Tests\Fixtures\TestModel;
  14. use Knuckles\Scribe\Tests\Fixtures\TestPet;
  15. use Knuckles\Scribe\Tests\Fixtures\TestTransformer;
  16. use Knuckles\Scribe\Tests\Fixtures\TestUser;
  17. use Knuckles\Scribe\Tests\Fixtures\TestUserApiResource;
  18. use Knuckles\Scribe\Tools\DocumentationConfig;
  19. use Knuckles\Scribe\Tools\Utils;
  20. use League\Fractal\Pagination\IlluminatePaginatorAdapter;
  21. use ReflectionClass;
  22. class UseResponseAttributesTest extends BaseLaravelTest
  23. {
  24. protected function getPackageProviders($app)
  25. {
  26. $providers = parent::getPackageProviders($app);
  27. if (class_exists(\Illuminate\Database\Eloquent\LegacyFactoryServiceProvider::class)) {
  28. $providers[] = \Illuminate\Database\Eloquent\LegacyFactoryServiceProvider ::class;
  29. }
  30. return $providers;
  31. }
  32. public function setUp(): void
  33. {
  34. parent::setUp();
  35. $this->setConfig(['database_connections_to_transact' => []]);
  36. $factory = app(\Illuminate\Database\Eloquent\Factory::class);
  37. $factory->define(TestUser::class, function () {
  38. return [
  39. 'id' => 4,
  40. 'first_name' => 'Tested',
  41. 'last_name' => 'Again',
  42. 'email' => 'a@b.com',
  43. ];
  44. });
  45. $factory->state(TestUser::class, 'state1', ["state1" => true]);
  46. $factory->state(TestUser::class, 'random-state', ["random-state" => true]);
  47. $factory->define(TestPet::class, function () {
  48. return [
  49. 'id' => 1,
  50. 'name' => 'Mephistopheles',
  51. 'species' => 'dog',
  52. ];
  53. });
  54. }
  55. /** @test */
  56. public function can_parse_plain_response_attributes()
  57. {
  58. $results = $this->fetch($this->endpoint("plainResponseAttributes"));
  59. $this->assertArraySubset([
  60. [
  61. 'status' => 200,
  62. 'content' => json_encode(["all" => "good"]),
  63. "description" => "Success"
  64. ],
  65. [
  66. 'status' => 201,
  67. 'content' => json_encode(["all" => "good"]),
  68. ],
  69. [
  70. 'status' => 404,
  71. 'content' => null,
  72. ]
  73. ], $results);
  74. }
  75. /** @test */
  76. public function can_parse_responsefile_attributes()
  77. {
  78. $results = $this->fetch($this->endpoint("responseFileAttributes"));
  79. $this->assertArraySubset([
  80. [
  81. 'status' => 401,
  82. 'content' => json_encode(["message" => "Unauthorized", "merge" => "this"]),
  83. ],
  84. ], $results);
  85. }
  86. /** @test */
  87. public function can_parse_apiresource_attributes()
  88. {
  89. $factory = app(\Illuminate\Database\Eloquent\Factory::class);
  90. $factory->afterMaking(TestUser::class, function (TestUser $user, $faker) {
  91. if ($user->id === 4) {
  92. $child = Utils::getModelFactory(TestUser::class)->make(['id' => 5, 'parent_id' => 4]);
  93. $user->setRelation('children', collect([$child]));
  94. }
  95. });
  96. $results = $this->fetch($this->endpoint("apiResourceAttributes"));
  97. $this->assertArraySubset([
  98. [
  99. 'status' => 200,
  100. 'content' => json_encode([
  101. 'data' => [
  102. [
  103. 'id' => 4,
  104. 'name' => 'Tested Again',
  105. 'email' => 'a@b.com',
  106. 'children' => [
  107. [
  108. 'id' => 5,
  109. 'name' => 'Tested Again',
  110. 'email' => 'a@b.com',
  111. ],
  112. ],
  113. 'state1' => true,
  114. 'random-state' => true,
  115. ],
  116. ],
  117. 'links' => [
  118. "first" => '/?page=1',
  119. "last" => null,
  120. "prev" => null,
  121. "next" => '/?page=2',
  122. ],
  123. "meta" => [
  124. "current_page" => 1,
  125. "from" => 1,
  126. "path" => '/',
  127. "per_page" => 1,
  128. "to" => 1,
  129. ],
  130. "a" => "b",
  131. ]),
  132. ],
  133. ], $results);
  134. }
  135. /** @test */
  136. public function can_parse_apiresource_attributes_with_no_model_specified()
  137. {
  138. $factory = app(\Illuminate\Database\Eloquent\Factory::class);
  139. $factory->afterMaking(TestUser::class, function (TestUser $user, $faker) {
  140. if ($user->id === 4) {
  141. $child = Utils::getModelFactory(TestUser::class)->make(['id' => 5, 'parent_id' => 4]);
  142. $user->setRelation('children', collect([$child]));
  143. }
  144. });
  145. $results = $this->fetch($this->endpoint("apiResourceAttributesWithNoModel"));
  146. $this->assertArraySubset([
  147. [
  148. 'status' => 200,
  149. 'content' => json_encode([
  150. 'data' => [
  151. [
  152. 'id' => 4,
  153. 'name' => 'Tested Again',
  154. 'email' => 'a@b.com',
  155. 'children' => [
  156. [
  157. 'id' => 5,
  158. 'name' => 'Tested Again',
  159. 'email' => 'a@b.com',
  160. ],
  161. ],
  162. 'state1' => true,
  163. 'random-state' => true,
  164. ],
  165. ],
  166. 'links' => [
  167. "first" => '/?page=1',
  168. "last" => null,
  169. "prev" => null,
  170. "next" => '/?page=2',
  171. ],
  172. "meta" => [
  173. "current_page" => 1,
  174. "from" => 1,
  175. "path" => '/',
  176. "per_page" => 1,
  177. "to" => 1,
  178. ],
  179. "a" => "b",
  180. ]),
  181. ],
  182. ], $results);
  183. }
  184. /** @test */
  185. public function can_parse_transformer_attributes()
  186. {
  187. $results = $this->fetch($this->endpoint("transformerAttributes"));
  188. $this->assertArraySubset([
  189. [
  190. 'status' => 200,
  191. 'content' => json_encode([
  192. "data" => [
  193. [
  194. "id" => 1,
  195. "description" => "Welcome on this test versions",
  196. "name" => "TestName",
  197. ],
  198. ],
  199. 'meta' => [
  200. "pagination" => [
  201. "total" => 2,
  202. "count" => 1,
  203. "per_page" => 1,
  204. "current_page" => 1,
  205. "total_pages" => 2,
  206. "links" => ["next" => "/?page=2"],
  207. ],
  208. ],
  209. ]),
  210. ],
  211. ], $results);
  212. }
  213. /** @test */
  214. public function can_parse_apiresource_attributes_with_cursor_pagination()
  215. {
  216. $factory = app(\Illuminate\Database\Eloquent\Factory::class);
  217. $factory->afterMaking(TestUser::class, function (TestUser $user, $faker) {
  218. if ($user->id === 4) {
  219. $child = Utils::getModelFactory(TestUser::class)->make(['id' => 5, 'parent_id' => 4]);
  220. $user->setRelation('children', collect([$child]));
  221. }
  222. });
  223. $results = $this->fetch($this->endpoint("apiResourceAttributesWithCursorPaginate"));
  224. $nextCursor = base64_encode(json_encode(['_pointsToNextItems' => true]));
  225. $this->assertArraySubset([
  226. [
  227. 'status' => 200,
  228. 'content' => json_encode([
  229. 'data' => [
  230. [
  231. 'id' => 4,
  232. 'name' => 'Tested Again',
  233. 'email' => 'a@b.com',
  234. 'children' => [
  235. [
  236. 'id' => 5,
  237. 'name' => 'Tested Again',
  238. 'email' => 'a@b.com',
  239. ],
  240. ],
  241. ],
  242. ],
  243. 'links' => [
  244. "first" => null,
  245. "last" => null,
  246. "prev" => null,
  247. "next" => "/?cursor={$nextCursor}",
  248. ],
  249. "meta" => match (version_compare(Application::VERSION, '9.0', '>=')) {
  250. false => [
  251. "path" => '/',
  252. 'per_page' => 1,
  253. ],
  254. true => [
  255. "path" => '/',
  256. 'per_page' => 1,
  257. 'next_cursor' => $nextCursor,
  258. 'prev_cursor' => null,
  259. ]
  260. },
  261. ]),
  262. ],
  263. ], $results);
  264. }
  265. protected function fetch($endpoint): array
  266. {
  267. $strategy = new UseResponseAttributes(new DocumentationConfig([]));
  268. return $strategy($endpoint, []);
  269. }
  270. protected function endpoint(string $method): ExtractedEndpointData
  271. {
  272. $endpoint = new class extends ExtractedEndpointData {
  273. public function __construct(array $parameters = []) {}
  274. };
  275. $endpoint->controller = new ReflectionClass(ResponseAttributesTestController::class);
  276. $endpoint->method = $endpoint->controller->getMethod($method);
  277. $endpoint->route = new Route(['POST'], "/somethingRandom", ['uses' => [ResponseAttributesTestController::class, $method]]);
  278. return $endpoint;
  279. }
  280. }
  281. class ResponseAttributesTestController
  282. {
  283. #[Response(["all" => "good"], 200, "Success")]
  284. #[Response('{"all":"good"}', 201)]
  285. #[Response(status: 404)]
  286. public function plainResponseAttributes()
  287. {
  288. }
  289. #[ResponseFromFile("tests/Fixtures/response_error_test.json", 401, ["merge" => "this"])]
  290. public function responseFileAttributes()
  291. {
  292. }
  293. #[ResponseFromApiResource(TestUserApiResource::class, TestUser::class, collection: true,
  294. factoryStates: ["state1", "random-state"], simplePaginate: 1, additional: ["a" => "b"])]
  295. public function apiResourceAttributes()
  296. {
  297. }
  298. #[ResponseFromApiResource(TestUserApiResource::class, collection: true,
  299. factoryStates: ["state1", "random-state"], simplePaginate: 1, additional: ["a" => "b"])]
  300. public function apiResourceAttributesWithNoModel()
  301. {
  302. }
  303. #[ResponseFromTransformer(TestTransformer::class, TestModel::class, collection: true,
  304. paginate: [IlluminatePaginatorAdapter::class, 1])]
  305. public function transformerAttributes()
  306. {
  307. }
  308. #[ResponseFromApiResource(TestUserApiResource::class, collection: true, cursorPaginate: 1)]
  309. public function apiResourceAttributesWithCursorPaginate()
  310. {
  311. }
  312. }