SparePartControllerTest.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. <?php
  2. namespace Tests\Feature;
  3. use App\Models\Role;
  4. use App\Models\SparePart;
  5. use App\Models\User;
  6. use Illuminate\Foundation\Testing\RefreshDatabase;
  7. use Illuminate\Support\Facades\Queue;
  8. use Tests\TestCase;
  9. class SparePartControllerTest extends TestCase
  10. {
  11. use RefreshDatabase;
  12. protected $seed = true;
  13. private User $adminUser;
  14. private User $managerUser;
  15. protected function setUp(): void
  16. {
  17. parent::setUp();
  18. $this->adminUser = User::factory()->create(['role' => Role::ADMIN]);
  19. $this->managerUser = User::factory()->create(['role' => Role::MANAGER]);
  20. }
  21. // ==================== Authentication ====================
  22. public function test_guest_cannot_access_spare_parts_index(): void
  23. {
  24. $response = $this->get(route('spare_parts.index'));
  25. $response->assertRedirect(route('login'));
  26. }
  27. public function test_admin_can_access_spare_parts_index(): void
  28. {
  29. $response = $this->actingAs($this->adminUser)
  30. ->get(route('spare_parts.index'));
  31. $response->assertStatus(200);
  32. $response->assertViewIs('spare_parts.index');
  33. }
  34. public function test_manager_can_access_spare_parts_index(): void
  35. {
  36. $response = $this->actingAs($this->managerUser)
  37. ->get(route('spare_parts.index'));
  38. $response->assertStatus(200);
  39. $response->assertViewIs('spare_parts.index');
  40. }
  41. // ==================== Show ====================
  42. public function test_admin_can_view_spare_part(): void
  43. {
  44. $sparePart = SparePart::factory()->create();
  45. $response = $this->actingAs($this->adminUser)
  46. ->get(route('spare_parts.show', $sparePart));
  47. $response->assertStatus(200);
  48. $response->assertViewIs('spare_parts.edit');
  49. }
  50. public function test_manager_can_view_spare_part(): void
  51. {
  52. $sparePart = SparePart::factory()->create();
  53. $response = $this->actingAs($this->managerUser)
  54. ->get(route('spare_parts.show', $sparePart));
  55. $response->assertStatus(200);
  56. $response->assertViewIs('spare_parts.edit');
  57. }
  58. public function test_guest_cannot_view_spare_part(): void
  59. {
  60. $sparePart = SparePart::factory()->create();
  61. $response = $this->get(route('spare_parts.show', $sparePart));
  62. $response->assertRedirect(route('login'));
  63. }
  64. // ==================== Store (create) ====================
  65. public function test_admin_can_create_spare_part(): void
  66. {
  67. $response = $this->actingAs($this->adminUser)
  68. ->post(route('spare_parts.store'), [
  69. 'article' => 'SP-TEST-001',
  70. 'used_in_maf' => 'MAF-100',
  71. 'customer_price' => 150.00,
  72. 'purchase_price' => 100.00,
  73. 'min_stock' => 5,
  74. ]);
  75. $response->assertRedirect();
  76. $this->assertDatabaseHas('spare_parts', [
  77. 'article' => 'SP-TEST-001',
  78. 'used_in_maf' => 'MAF-100',
  79. ]);
  80. }
  81. public function test_store_requires_article(): void
  82. {
  83. $response = $this->actingAs($this->adminUser)
  84. ->post(route('spare_parts.store'), [
  85. 'customer_price' => 150.00,
  86. ]);
  87. $response->assertSessionHasErrors('article');
  88. }
  89. public function test_manager_cannot_create_spare_part(): void
  90. {
  91. $response = $this->actingAs($this->managerUser)
  92. ->post(route('spare_parts.store'), [
  93. 'article' => 'SP-TEST-MANAGER',
  94. 'customer_price' => 150.00,
  95. ]);
  96. $response->assertStatus(403);
  97. }
  98. public function test_guest_cannot_create_spare_part(): void
  99. {
  100. $response = $this->post(route('spare_parts.store'), [
  101. 'article' => 'SP-TEST-GUEST',
  102. 'customer_price' => 150.00,
  103. ]);
  104. $response->assertRedirect(route('login'));
  105. }
  106. // ==================== Update ====================
  107. public function test_admin_can_update_spare_part(): void
  108. {
  109. $sparePart = SparePart::factory()->create(['article' => 'SP-OLD', 'min_stock' => 3]);
  110. $response = $this->actingAs($this->adminUser)
  111. ->put(route('spare_parts.update', $sparePart), [
  112. 'article' => 'SP-UPDATED',
  113. 'min_stock' => 10,
  114. ]);
  115. $response->assertRedirect();
  116. $this->assertDatabaseHas('spare_parts', [
  117. 'id' => $sparePart->id,
  118. 'article' => 'SP-UPDATED',
  119. 'min_stock' => 10,
  120. ]);
  121. }
  122. public function test_manager_cannot_update_spare_part(): void
  123. {
  124. $sparePart = SparePart::factory()->create();
  125. $response = $this->actingAs($this->managerUser)
  126. ->put(route('spare_parts.update', $sparePart), [
  127. 'article' => 'SP-MANAGER-UPDATE',
  128. ]);
  129. $response->assertStatus(403);
  130. }
  131. public function test_guest_cannot_update_spare_part(): void
  132. {
  133. $sparePart = SparePart::factory()->create();
  134. $response = $this->put(route('spare_parts.update', $sparePart), [
  135. 'article' => 'SP-GUEST-UPDATE',
  136. ]);
  137. $response->assertRedirect(route('login'));
  138. }
  139. // ==================== Destroy ====================
  140. public function test_admin_can_delete_spare_part(): void
  141. {
  142. $sparePart = SparePart::factory()->create();
  143. $sparePartId = $sparePart->id;
  144. $response = $this->actingAs($this->adminUser)
  145. ->delete(route('spare_parts.destroy', $sparePart));
  146. $response->assertRedirect(route('spare_parts.index'));
  147. $this->assertSoftDeleted('spare_parts', ['id' => $sparePartId]);
  148. }
  149. public function test_cannot_delete_spare_part_with_orders(): void
  150. {
  151. $sparePart = SparePart::factory()->create();
  152. // Создаём заказ запчасти через фабрику чтобы привязать к запчасти
  153. \App\Models\SparePartOrder::factory()->create(['spare_part_id' => $sparePart->id]);
  154. $response = $this->actingAs($this->adminUser)
  155. ->delete(route('spare_parts.destroy', $sparePart));
  156. $response->assertRedirect();
  157. $response->assertSessionHas('error');
  158. $this->assertDatabaseHas('spare_parts', ['id' => $sparePart->id, 'deleted_at' => null]);
  159. }
  160. public function test_manager_cannot_delete_spare_part(): void
  161. {
  162. $sparePart = SparePart::factory()->create();
  163. $response = $this->actingAs($this->managerUser)
  164. ->delete(route('spare_parts.destroy', $sparePart));
  165. $response->assertStatus(403);
  166. }
  167. public function test_guest_cannot_delete_spare_part(): void
  168. {
  169. $sparePart = SparePart::factory()->create();
  170. $response = $this->delete(route('spare_parts.destroy', $sparePart));
  171. $response->assertRedirect(route('login'));
  172. }
  173. // ==================== Export ====================
  174. public function test_admin_can_trigger_export(): void
  175. {
  176. Queue::fake();
  177. $response = $this->actingAs($this->adminUser)
  178. ->post(route('spare_parts.export'));
  179. $response->assertRedirect();
  180. $response->assertSessionHas('success');
  181. Queue::assertPushed(\App\Jobs\Export\ExportSparePartsJob::class);
  182. }
  183. public function test_manager_cannot_trigger_export(): void
  184. {
  185. $response = $this->actingAs($this->managerUser)
  186. ->post(route('spare_parts.export'));
  187. $response->assertStatus(403);
  188. }
  189. public function test_guest_cannot_trigger_export(): void
  190. {
  191. $response = $this->post(route('spare_parts.export'));
  192. $response->assertRedirect(route('login'));
  193. }
  194. // ==================== Search API ====================
  195. public function test_admin_can_search_spare_parts(): void
  196. {
  197. SparePart::factory()->create(['article' => 'SP-SEARCH-001']);
  198. $response = $this->actingAs($this->adminUser)
  199. ->getJson(route('spare_parts.search', ['query' => 'SP-SEARCH']));
  200. $response->assertStatus(200);
  201. $response->assertJsonStructure([['id', 'article', 'used_in_maf']]);
  202. }
  203. public function test_guest_cannot_search_spare_parts(): void
  204. {
  205. $response = $this->get(route('spare_parts.search', ['query' => 'SP-SEARCH']));
  206. $response->assertRedirect(route('login'));
  207. }
  208. }