AdminDistrictControllerTest.php 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. <?php
  2. namespace Tests\Feature;
  3. use App\Models\Dictionary\Area;
  4. use App\Models\Dictionary\District;
  5. use App\Models\Role;
  6. use App\Models\User;
  7. use Illuminate\Foundation\Testing\RefreshDatabase;
  8. use Illuminate\Http\UploadedFile;
  9. use Illuminate\Support\Facades\Storage;
  10. use Tests\TestCase;
  11. class AdminDistrictControllerTest extends TestCase
  12. {
  13. use RefreshDatabase;
  14. protected $seed = true;
  15. private User $adminUser;
  16. private User $managerUser;
  17. protected function setUp(): void
  18. {
  19. parent::setUp();
  20. $this->adminUser = User::factory()->create(['role' => Role::ADMIN]);
  21. $this->managerUser = User::factory()->create(['role' => Role::MANAGER]);
  22. }
  23. // ==================== Authentication & Authorization ====================
  24. public function test_guest_cannot_access_districts_index(): void
  25. {
  26. $response = $this->get(route('admin.district.index'));
  27. $response->assertRedirect(route('login'));
  28. }
  29. public function test_manager_cannot_access_districts_index(): void
  30. {
  31. $response = $this->actingAs($this->managerUser)
  32. ->get(route('admin.district.index'));
  33. $response->assertStatus(403);
  34. }
  35. public function test_admin_can_access_districts_index(): void
  36. {
  37. $response = $this->actingAs($this->adminUser)
  38. ->get(route('admin.district.index'));
  39. $response->assertStatus(200);
  40. $response->assertViewIs('admin.districts.index');
  41. }
  42. // ==================== Index ====================
  43. public function test_districts_index_displays_districts(): void
  44. {
  45. $district = District::factory()->create(['name' => 'Тестовый округ']);
  46. $response = $this->actingAs($this->adminUser)
  47. ->get(route('admin.district.index'));
  48. $response->assertStatus(200);
  49. $response->assertSee('Тестовый округ');
  50. }
  51. public function test_districts_index_displays_areas_count(): void
  52. {
  53. $district = District::factory()->create();
  54. Area::factory()->count(3)->create(['district_id' => $district->id]);
  55. $response = $this->actingAs($this->adminUser)
  56. ->get(route('admin.district.index'));
  57. $response->assertStatus(200);
  58. $response->assertSee('3');
  59. }
  60. // ==================== Show ====================
  61. public function test_admin_can_view_district_edit_form(): void
  62. {
  63. $district = District::factory()->create();
  64. $response = $this->actingAs($this->adminUser)
  65. ->get(route('admin.district.show', $district->id));
  66. $response->assertStatus(200);
  67. $response->assertViewIs('admin.districts.edit');
  68. $response->assertSee($district->name);
  69. }
  70. public function test_district_show_uses_nav_context_back_url(): void
  71. {
  72. $district = District::factory()->create();
  73. $response = $this->actingAs($this->adminUser)
  74. ->withSession([
  75. 'navigation' => [
  76. 'district-nav' => [
  77. 'updated_at' => now()->timestamp,
  78. 'stack' => [
  79. route('admin.district.index', ['page' => 2]),
  80. ],
  81. ],
  82. ],
  83. ])
  84. ->get(route('admin.district.show', ['district' => $district->id, 'nav' => 'district-nav']));
  85. $response->assertOk();
  86. $response->assertViewHas('nav', 'district-nav');
  87. $response->assertViewHas('back_url', route('admin.district.index', ['page' => 2]));
  88. }
  89. public function test_manager_cannot_view_district_edit_form(): void
  90. {
  91. $district = District::factory()->create();
  92. $response = $this->actingAs($this->managerUser)
  93. ->get(route('admin.district.show', $district->id));
  94. $response->assertStatus(403);
  95. }
  96. // ==================== Store ====================
  97. public function test_admin_can_create_new_district(): void
  98. {
  99. $response = $this->actingAs($this->adminUser)
  100. ->post(route('admin.district.store'), [
  101. 'shortname' => 'ТСТ',
  102. 'name' => 'Тестовый округ',
  103. ]);
  104. $response->assertRedirect(route('admin.district.index'));
  105. $this->assertDatabaseHas('districts', [
  106. 'shortname' => 'ТСТ',
  107. 'name' => 'Тестовый округ',
  108. ]);
  109. }
  110. public function test_admin_can_update_existing_district(): void
  111. {
  112. $district = District::factory()->create([
  113. 'shortname' => 'СТР',
  114. 'name' => 'Старое название',
  115. ]);
  116. $response = $this->actingAs($this->adminUser)
  117. ->post(route('admin.district.store'), [
  118. 'id' => $district->id,
  119. 'shortname' => 'НВ',
  120. 'name' => 'Новое название',
  121. ]);
  122. $response->assertRedirect(route('admin.district.index'));
  123. $this->assertDatabaseHas('districts', [
  124. 'id' => $district->id,
  125. 'shortname' => 'НВ',
  126. 'name' => 'Новое название',
  127. ]);
  128. }
  129. public function test_store_district_requires_name(): void
  130. {
  131. $response = $this->actingAs($this->adminUser)
  132. ->post(route('admin.district.store'), [
  133. 'shortname' => 'ТСТ',
  134. ]);
  135. $response->assertSessionHasErrors('name');
  136. }
  137. public function test_store_district_requires_shortname(): void
  138. {
  139. $response = $this->actingAs($this->adminUser)
  140. ->post(route('admin.district.store'), [
  141. 'name' => 'Тестовый округ',
  142. ]);
  143. $response->assertSessionHasErrors('shortname');
  144. }
  145. // ==================== Destroy ====================
  146. public function test_admin_can_delete_district_without_areas(): void
  147. {
  148. $district = District::factory()->create();
  149. $response = $this->actingAs($this->adminUser)
  150. ->delete(route('admin.district.destroy', $district->id));
  151. $response->assertRedirect(route('admin.district.index'));
  152. $this->assertSoftDeleted('districts', ['id' => $district->id]);
  153. }
  154. public function test_admin_cannot_delete_district_with_areas(): void
  155. {
  156. $district = District::factory()->create();
  157. Area::factory()->create(['district_id' => $district->id]);
  158. $response = $this->actingAs($this->adminUser)
  159. ->delete(route('admin.district.destroy', $district->id));
  160. $response->assertRedirect(route('admin.district.index'));
  161. $response->assertSessionHas('error');
  162. $this->assertDatabaseHas('districts', ['id' => $district->id, 'deleted_at' => null]);
  163. }
  164. // ==================== Undelete ====================
  165. public function test_admin_can_restore_deleted_district(): void
  166. {
  167. $district = District::factory()->create();
  168. $district->delete();
  169. $response = $this->actingAs($this->adminUser)
  170. ->post(route('admin.district.undelete', $district->id));
  171. $response->assertRedirect(route('admin.district.index'));
  172. $this->assertDatabaseHas('districts', [
  173. 'id' => $district->id,
  174. 'deleted_at' => null,
  175. ]);
  176. }
  177. // ==================== Export ====================
  178. public function test_admin_can_export_districts(): void
  179. {
  180. District::factory()->count(3)->create();
  181. $response = $this->actingAs($this->adminUser)
  182. ->post(route('admin.district.export'));
  183. $response->assertRedirect();
  184. }
  185. // ==================== Import ====================
  186. public function test_admin_can_import_districts(): void
  187. {
  188. Storage::fake('upload');
  189. // Создаем тестовый XLSX файл
  190. $file = $this->createTestDistrictsXlsx();
  191. $response = $this->actingAs($this->adminUser)
  192. ->post(route('admin.district.import'), [
  193. 'import_file' => $file,
  194. ]);
  195. $response->assertRedirect(route('admin.district.index'));
  196. }
  197. public function test_import_requires_file(): void
  198. {
  199. $response = $this->actingAs($this->adminUser)
  200. ->post(route('admin.district.import'), []);
  201. $response->assertSessionHasErrors('import_file');
  202. }
  203. public function test_import_requires_xlsx_file(): void
  204. {
  205. $file = UploadedFile::fake()->create('test.txt', 100, 'text/plain');
  206. $response = $this->actingAs($this->adminUser)
  207. ->post(route('admin.district.import'), [
  208. 'import_file' => $file,
  209. ]);
  210. $response->assertSessionHasErrors('import_file');
  211. }
  212. // ==================== Helper Methods ====================
  213. private function createTestDistrictsXlsx(): UploadedFile
  214. {
  215. $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
  216. $sheet = $spreadsheet->getActiveSheet();
  217. $sheet->setCellValue('A1', 'ID');
  218. $sheet->setCellValue('B1', 'Сокращение');
  219. $sheet->setCellValue('C1', 'Название');
  220. $sheet->setCellValue('A2', '');
  221. $sheet->setCellValue('B2', 'ТСТ');
  222. $sheet->setCellValue('C2', 'Тестовый округ');
  223. $tempPath = sys_get_temp_dir() . '/test_districts_' . uniqid() . '.xlsx';
  224. $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
  225. $writer->save($tempPath);
  226. return new UploadedFile(
  227. $tempPath,
  228. 'test_districts.xlsx',
  229. 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  230. null,
  231. true
  232. );
  233. }
  234. }