seed(RolesAndPermissionsSeeder::class); $admin = User::factory()->create(['is_active' => true]); $admin->assignRole('admin'); $this->actingAs($admin); }); test('admin can render category create page', function () { /** @var TestCase $this */ $this->get(route('admin.categories.create')) ->assertSuccessful() ->assertSee('Kategorie anlegen'); }); test('admin can create a new category with both translations', function () { LivewireVolt::test('admin.categories.create') ->set('portal', Portal::Both->value) ->set('nameDe', 'Künstliche Intelligenz') ->set('nameEn', 'Artificial Intelligence') ->set('descriptionDe', 'Themen rund um KI.') ->set('descriptionEn', 'Topics around AI.') ->call('save') ->assertHasNoErrors() ->assertRedirect(route('admin.categories.index')); $category = Category::query()->latest('id')->firstOrFail(); expect($category->portal)->toBe(Portal::Both); expect($category->is_active)->toBeTrue(); expect($category->translations()->count())->toBe(2); $de = $category->translations->firstWhere('locale', 'de'); $en = $category->translations->firstWhere('locale', 'en'); expect($de->name)->toBe('Künstliche Intelligenz'); expect($de->slug)->toBe('kunstliche-intelligenz'); expect($en->slug)->toBe('artificial-intelligence'); }); test('category create requires both names', function () { LivewireVolt::test('admin.categories.create') ->set('nameDe', '') ->set('nameEn', '') ->call('save') ->assertHasErrors(['nameDe', 'nameEn']); }); test('category create generates unique slug per locale on collision', function () { $existing = Category::factory()->create(['portal' => Portal::Both->value]); $existing->translations()->createMany([ ['locale' => 'de', 'name' => 'Wirtschaft', 'slug' => 'wirtschaft'], ['locale' => 'en', 'name' => 'Business', 'slug' => 'business'], ]); LivewireVolt::test('admin.categories.create') ->set('nameDe', 'Wirtschaft') ->set('nameEn', 'Business') ->call('save') ->assertHasNoErrors(); $newCategory = Category::query()->latest('id')->firstOrFail(); $de = $newCategory->translations->firstWhere('locale', 'de'); $en = $newCategory->translations->firstWhere('locale', 'en'); expect($de->slug)->toBe('wirtschaft-2'); expect($en->slug)->toBe('business-2'); }); test('admin can edit an existing category and rename slugs in place', function () { $category = Category::factory()->create(['portal' => Portal::Both->value]); $category->translations()->createMany([ ['locale' => 'de', 'name' => 'Alter Name', 'slug' => 'alter-name'], ['locale' => 'en', 'name' => 'Old Name', 'slug' => 'old-name'], ]); LivewireVolt::test('admin.categories.edit', ['id' => $category->id]) ->set('nameDe', 'Neuer Name') ->set('slugDe', 'neuer-name') ->set('nameEn', 'New Name') ->set('slugEn', 'new-name') ->call('save') ->assertHasNoErrors(); $category->refresh()->load('translations'); $de = $category->translations->firstWhere('locale', 'de'); $en = $category->translations->firstWhere('locale', 'en'); expect($de->slug)->toBe('neuer-name'); expect($en->slug)->toBe('new-name'); }); test('category edit refuses parent assignment that would create a hierarchy loop', function () { $parent = Category::factory()->create(); $parent->translations()->createMany([ ['locale' => 'de', 'name' => 'Parent', 'slug' => 'parent'], ['locale' => 'en', 'name' => 'Parent', 'slug' => 'parent-en'], ]); $child = Category::factory()->create(['parent_id' => $parent->id]); $child->translations()->createMany([ ['locale' => 'de', 'name' => 'Child', 'slug' => 'child'], ['locale' => 'en', 'name' => 'Child', 'slug' => 'child-en'], ]); LivewireVolt::test('admin.categories.edit', ['id' => $parent->id]) ->set('nameDe', 'Parent') ->set('slugDe', 'parent') ->set('nameEn', 'Parent') ->set('slugEn', 'parent-en') ->set('parentId', $child->id) ->call('save') ->assertHasErrors(['parentId']); }); test('category cannot be deleted while it has press releases', function () { $category = Category::factory()->create(); $category->translations()->createMany([ ['locale' => 'de', 'name' => 'Used', 'slug' => 'used'], ['locale' => 'en', 'name' => 'Used', 'slug' => 'used-en'], ]); PressRelease::factory()->create([ 'category_id' => $category->id, ]); LivewireVolt::test('admin.categories.edit', ['id' => $category->id]) ->call('deleteCategory'); expect(Category::query()->find($category->id))->not->toBeNull(); }); test('category can be deleted when empty', function () { $category = Category::factory()->create(); $category->translations()->createMany([ ['locale' => 'de', 'name' => 'Empty', 'slug' => 'empty'], ['locale' => 'en', 'name' => 'Empty', 'slug' => 'empty-en'], ]); LivewireVolt::test('admin.categories.edit', ['id' => $category->id]) ->call('deleteCategory') ->assertRedirect(route('admin.categories.index')); expect(Category::query()->find($category->id))->toBeNull(); });