get(Connection::class); } private function rowCount(string $table): int { return (int) $this->db()->fetchOne('SELECT COUNT(*) FROM ' . $table); } public function testValidImportReplacesTheWholeTable(): void { $admin = $this->createUser(['ROLE_ADMIN']); $body = $this->authJson('POST', '/api/v1/admin/categories/tags/import', $admin, [ ['id' => 90001, 'name' => 'تگ یک', 'slug' => 'imp-tag-1', 'status' => 1], ['id' => 90002, 'name' => 'تگ دو', 'slug' => 'imp-tag-2', 'status' => 0], ]); $this->assertSame(200, $this->responseCode()); $this->assertSame(2, $body['data']['imported'] ?? null); // wipe+replace: the table now holds exactly the imported rows $this->assertSame(2, $this->rowCount('tags')); $this->assertSame('imp-tag-1', $this->db()->fetchOne('SELECT slug FROM tags WHERE id = 90001')); } public function testInvalidFileIsRejectedAndNothingIsWritten(): void { $admin = $this->createUser(['ROLE_ADMIN']); // seed a known state, then attempt a bad import — count must not change $this->authJson('POST', '/api/v1/admin/categories/tags/import', $admin, [ ['id' => 91001, 'name' => 'پایه', 'slug' => 'seed-tag', 'status' => 1], ]); $before = $this->rowCount('tags'); $body = $this->authJson('POST', '/api/v1/admin/categories/tags/import', $admin, [ ['id' => 1, 'name' => 'خوب', 'slug' => 'ok', 'status' => 1], ['id' => 1, 'name' => '', 'slug' => 'ok', 'status' => 9], // dup id, empty name, dup slug, bad status ]); $this->assertSame(422, $this->responseCode()); $this->assertNotEmpty($body['errors']); $this->assertSame($before, $this->rowCount('tags')); // table untouched } public function testSpecialtyParentMustExistWithinTheFile(): void { $admin = $this->createUser(['ROLE_ADMIN']); $body = $this->authJson('POST', '/api/v1/admin/categories/specialties/import', $admin, [ ['id' => 1, 'name' => 'ریشه', 'slug' => 'imp-root', 'status' => 1, 'weight' => 0, 'parent_id' => null], ['id' => 2, 'name' => 'فرزند', 'slug' => 'imp-child', 'status' => 1, 'weight' => 0, 'parent_id' => 9999], ]); $this->assertSame(422, $this->responseCode()); $fields = array_column($body['errors'], 'field'); $this->assertContains('parent_id', $fields); } public function testCityTitleAndSocialMediaRoundTripThroughImportExport(): void { $admin = $this->createUser(['ROLE_ADMIN']); $this->authJson('POST', '/api/v1/admin/categories/cities/import', $admin, [ [ 'id' => 95001, 'name' => 'شهر تست', 'status' => 1, 'weight' => 0, 'site_name' => 'تست نوبت', 'title' => 'نوبت‌دهی آنلاین پزشکان شهر تست | تست نوبت', 'slogan' => 'شعار تست', 'keywords' => 'کلمه یک, کلمه دو', 'province_id' => null, 'social_media' => ['instagram' => 'test_nobat'], ], ]); $this->assertSame(200, $this->responseCode()); $this->assertSame( 'نوبت‌دهی آنلاین پزشکان شهر تست | تست نوبت', $this->db()->fetchOne('SELECT title FROM cities WHERE id = 95001'), ); // export must round-trip lossless in the shape nobat724_front/data/city.json uses $body = $this->authJson('GET', '/api/v1/admin/categories/cities/export', $admin); $row = null; foreach ($body['data'] as $r) { if (($r['id'] ?? null) === 95001) { $row = $r; break; } } $this->assertNotNull($row); $this->assertSame('نوبت‌دهی آنلاین پزشکان شهر تست | تست نوبت', $row['title']); $this->assertSame(['instagram' => 'test_nobat'], $row['social_media']); $this->assertArrayHasKey('province_name', $row); } public function testNonAdminIsForbidden(): void { $user = $this->createUser(['ROLE_USER']); $this->authJson('POST', '/api/v1/admin/categories/tags/import', $user, [ ['id' => 1, 'name' => 'x', 'slug' => 'x', 'status' => 1], ]); $this->assertSame(403, $this->responseCode()); } public function testUnknownBundleIs404(): void { $admin = $this->createUser(['ROLE_ADMIN']); $this->authJson('POST', '/api/v1/admin/categories/nope/import', $admin, [ ['id' => 1, 'name' => 'x', 'slug' => 'x', 'status' => 1], ]); $this->assertSame(404, $this->responseCode()); } }