From ece4d1ecdc5d6c12af1c5c2e359e3f972e9afb08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20Demirel?= Date: Sun, 14 Dec 2025 15:17:12 +0300 Subject: [PATCH 1/2] refactor(category): remove follow seeder --- packages/Category/database/seeders/CategorySeeder.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/Category/database/seeders/CategorySeeder.php b/packages/Category/database/seeders/CategorySeeder.php index a2554be..b612f55 100755 --- a/packages/Category/database/seeders/CategorySeeder.php +++ b/packages/Category/database/seeders/CategorySeeder.php @@ -5,7 +5,6 @@ use Illuminate\Database\Seeder; use Packages\Category\Models\Category; use Packages\Category\Models\CategoryProfile; -use Packages\React\Models\Follow; class CategorySeeder extends Seeder { @@ -13,7 +12,6 @@ public function run(): void { Category::factory(10)->create()->each(function ($category) { CategoryProfile::factory()->for($category)->create(); - Follow::factory(3)->forModel($category)->create(); }); } } From 3fd7a37283fef6cd99b6819c844400aaf4a4b1ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20Demirel?= Date: Sun, 14 Dec 2025 15:19:00 +0300 Subject: [PATCH 2/2] test(category): implement category tests --- composer.json | 5 +- .../Database/Seeders/CategorySeederTest.php | 42 +++++ .../Controllers/CategoryControllerTest.php | 117 +++++++++++++ packages/Category/tests/TestCase.php | 10 ++ .../tests/Unit/Data/CategoryDataTest.php | 107 ++++++++++++ .../Unit/Data/CategoryProfileDataTest.php | 34 ++++ .../Factories/CategoryFactoryTest.php | 65 ++++++++ .../Factories/CategoryProfileFactoryTest.php | 50 ++++++ .../tests/Unit/Models/CategoryProfileTest.php | 117 +++++++++++++ .../tests/Unit/Models/CategoryTest.php | 113 +++++++++++++ .../Unit/Observers/CategoryObserverTest.php | 78 +++++++++ .../Observers/CategoryProfileObserverTest.php | 42 +++++ .../Unit/Policies/CategoryPolicyTest.php | 156 ++++++++++++++++++ .../Unit/Services/CategoryServiceTest.php | 118 +++++++++++++ phpunit.xml | 1 + 15 files changed, 1053 insertions(+), 2 deletions(-) create mode 100644 packages/Category/tests/Feature/Database/Seeders/CategorySeederTest.php create mode 100644 packages/Category/tests/Feature/Http/Controllers/CategoryControllerTest.php create mode 100644 packages/Category/tests/TestCase.php create mode 100644 packages/Category/tests/Unit/Data/CategoryDataTest.php create mode 100644 packages/Category/tests/Unit/Data/CategoryProfileDataTest.php create mode 100644 packages/Category/tests/Unit/Database/Factories/CategoryFactoryTest.php create mode 100644 packages/Category/tests/Unit/Database/Factories/CategoryProfileFactoryTest.php create mode 100644 packages/Category/tests/Unit/Models/CategoryProfileTest.php create mode 100644 packages/Category/tests/Unit/Models/CategoryTest.php create mode 100644 packages/Category/tests/Unit/Observers/CategoryObserverTest.php create mode 100644 packages/Category/tests/Unit/Observers/CategoryProfileObserverTest.php create mode 100644 packages/Category/tests/Unit/Policies/CategoryPolicyTest.php create mode 100644 packages/Category/tests/Unit/Services/CategoryServiceTest.php diff --git a/composer.json b/composer.json index 02603cf..097b7fb 100755 --- a/composer.json +++ b/composer.json @@ -91,7 +91,8 @@ "autoload-dev": { "psr-4": { "Tests\\": "tests/", - "Packages\\Tag\\Tests\\": "packages/Tag/tests/" + "Packages\\Tag\\Tests\\": "packages/Tag/tests/", + "Packages\\Category\\Tests\\": "packages/Category/tests/" } }, "scripts": { @@ -147,4 +148,4 @@ }, "minimum-stability": "stable", "prefer-stable": true -} +} \ No newline at end of file diff --git a/packages/Category/tests/Feature/Database/Seeders/CategorySeederTest.php b/packages/Category/tests/Feature/Database/Seeders/CategorySeederTest.php new file mode 100644 index 0000000..edafe22 --- /dev/null +++ b/packages/Category/tests/Feature/Database/Seeders/CategorySeederTest.php @@ -0,0 +1,42 @@ +seed(CategorySeeder::class); + + $this->assertDatabaseCount(Category::class, 10); + + $this->assertDatabaseCount(CategoryProfile::class, 10); + + Category::all()->each(function (Category $category) { + $this->assertNotNull( + $category->profile, + ); + }); + + CategoryProfile::all()->each(function (CategoryProfile $profile) { + $this->assertDatabaseHas(Category::class, [ + 'id' => $profile->category_id, + ]); + }); + + $this->assertEquals( + 10, + Category::has('profile')->count(), + ); + + $this->assertEquals( + Category::count(), + CategoryProfile::count() + ); + } +} diff --git a/packages/Category/tests/Feature/Http/Controllers/CategoryControllerTest.php b/packages/Category/tests/Feature/Http/Controllers/CategoryControllerTest.php new file mode 100644 index 0000000..cbdc352 --- /dev/null +++ b/packages/Category/tests/Feature/Http/Controllers/CategoryControllerTest.php @@ -0,0 +1,117 @@ +shouldReceive('getId') + ->once() + ->with($slug) + ->andReturn($categoryId); + + $categoryService->shouldReceive('getData') + ->once() + ->with($categoryId) + ->andReturn($categoryData); + + $categoryService->shouldReceive('getProfileData') + ->once() + ->with($categoryId) + ->andReturn($profileData); + + $categoryService->shouldReceive('getArticlesCount') + ->once() + ->with($categoryId) + ->andReturn(10); + + $categoryService->shouldReceive('getNewsCount') + ->once() + ->with($categoryId) + ->andReturn(5); + + $categoryService->shouldReceive('listTags') + ->once() + ->with($categoryId) + ->andReturn($tags); + + $this->app->instance(CategoryService::class, $categoryService); + + $metadata = Mockery::mock(BuildsMetadata::class); + $metadata->shouldReceive('generate')->once()->andReturn('seo-html'); + + $seoService = Mockery::mock(SeoService::class); + $seoService->shouldReceive('getCategorySeo') + ->once() + ->with($categoryData, $profileData) + ->andReturn($metadata); + + $this->app->instance(SeoService::class, $seoService); + + $response = $this->get(route('category.view', $slug)); + + $response->assertStatus(Response::HTTP_OK); + + $response->assertInertia( + fn (Assert $page) => $page + ->component('Category/Detail') + + ->where('category.id', $categoryId) + ->where('category.slug', $slug) + ->where('category.name', 'Test Category') + + ->where('profile.description', 'Test Description') + ->where('profile.color', '#fff') + + ->where('articles', 10) + ->where('news', 5) + + ->has('tags', 1) + ->where('tags.0.id', 5) + ->where('tags.0.name', 'Test Tag') + ->where('tags.0.slug', 'test-tag') + ); + + $this->assertArrayHasKey('seo', $response->original->getData()); + } +} diff --git a/packages/Category/tests/TestCase.php b/packages/Category/tests/TestCase.php new file mode 100644 index 0000000..d8c2bab --- /dev/null +++ b/packages/Category/tests/TestCase.php @@ -0,0 +1,10 @@ +assertSame(1, $data->id); + $this->assertSame('Test Category', $data->name); + $this->assertSame('test-category', $data->slug); + $this->assertSame(10, $data->followers); + $this->assertTrue($data->isFollowing); + + $this->assertSame('category', $data->type); + } + + public function test_it_creates_data_from_model_without_id_by_default(): void + { + $category = Category::factory()->create([ + 'name' => 'Inertia', + 'slug' => 'inertia', + ]); + + $categoryData = CategoryData::fromModel($category); + + $this->assertSame(0, $categoryData->id); + $this->assertSame('Inertia', $categoryData->name); + $this->assertSame('inertia', $categoryData->slug); + $this->assertSame('category', $categoryData->type); + } + + public function test_it_sets_id_when_flag_is_true(): void + { + $category = Category::factory()->create([ + 'name' => 'Laravel', + 'slug' => 'laravel', + ]); + + $categoryData = CategoryData::fromModel($category, true); + + $this->assertSame($category->id, $categoryData->id); + $this->assertSame('Laravel', $categoryData->name); + $this->assertSame('laravel', $categoryData->slug); + $this->assertSame('category', $categoryData->type); + } + + public function test_it_uses_model_methods_for_followers_and_follow_state(): void + { + $userId = 123; + Auth::shouldReceive('id')->once()->andReturn($userId); + + $category = Mockery::mock(Category::class)->makePartial(); + $category->id = 99; + $category->name = 'PHP'; + $category->slug = 'php'; + + $category->shouldReceive('followersCount') + ->once() + ->andReturn(42); + + $category->shouldReceive('isFollowedBy') + ->once() + ->with($userId) + ->andReturn(true); + + $data = CategoryData::fromModel($category, true); + + $this->assertSame(99, $data->id); + $this->assertSame(42, $data->followers); + $this->assertTrue($data->isFollowing); + } + + public function test_it_handles_guest_user(): void + { + Auth::shouldReceive('id')->once()->andReturn(null); + + $category = Mockery::mock(Category::class)->makePartial(); + $category->id = 1; + $category->name = 'Guest'; + $category->slug = 'guest'; + + $category->shouldReceive('followersCount')->once()->andReturn(0); + $category->shouldReceive('isFollowedBy') + ->once() + ->with(null) + ->andReturn(false); + + $data = CategoryData::fromModel($category); + + $this->assertFalse($data->isFollowing); + } +} diff --git a/packages/Category/tests/Unit/Data/CategoryProfileDataTest.php b/packages/Category/tests/Unit/Data/CategoryProfileDataTest.php new file mode 100644 index 0000000..68b4434 --- /dev/null +++ b/packages/Category/tests/Unit/Data/CategoryProfileDataTest.php @@ -0,0 +1,34 @@ +assertSame(1, $data->id); + $this->assertSame('Test Description', $data->description); + $this->assertSame('#ffffff', $data->color); + } + + public function test_it_sets_id_when_flag_is_true(): void + { + $profile = CategoryProfile::factory()->create(); + + $data = CategoryProfileData::fromModel($profile, true); + + $this->assertSame($profile->id, $data->id); + $this->assertSame($profile->description, $data->description); + $this->assertSame($profile->color, $data->color); + } +} diff --git a/packages/Category/tests/Unit/Database/Factories/CategoryFactoryTest.php b/packages/Category/tests/Unit/Database/Factories/CategoryFactoryTest.php new file mode 100644 index 0000000..e8dfd15 --- /dev/null +++ b/packages/Category/tests/Unit/Database/Factories/CategoryFactoryTest.php @@ -0,0 +1,65 @@ +create(); + + $this->assertInstanceOf(Category::class, $category); + + $this->assertNotEmpty($category->name); + $this->assertNotEmpty($category->slug); + } + + public function test_name_starts_with_uppercase_letter(): void + { + $category = Category::factory()->create(); + + $this->assertSame( + ucfirst(strtolower($category->name)), + $category->name + ); + } + + public function test_slug_is_a_valid_slug(): void + { + $category = Category::factory()->create(); + + $this->assertSame( + Str::slug($category->name), + $category->slug + ); + } + + public function test_slug_contains_only_slug_characters(): void + { + $category = Category::factory()->create(); + + $this->assertMatchesRegularExpression( + '/^[a-z0-9]+(?:-[a-z0-9]+)*$/', + $category->slug + ); + } + + public function test_factory_creates_unique_categories(): void + { + $categories = Category::factory()->count(10)->create(); + + $this->assertCount( + 10, + $categories->pluck('name')->unique() + ); + + $this->assertCount( + 10, + $categories->pluck('slug')->unique() + ); + } +} diff --git a/packages/Category/tests/Unit/Database/Factories/CategoryProfileFactoryTest.php b/packages/Category/tests/Unit/Database/Factories/CategoryProfileFactoryTest.php new file mode 100644 index 0000000..3fb297b --- /dev/null +++ b/packages/Category/tests/Unit/Database/Factories/CategoryProfileFactoryTest.php @@ -0,0 +1,50 @@ +create(); + + $this->assertInstanceOf(CategoryProfile::class, $profile); + + $this->assertNotEmpty($profile->description); + + $this->assertNotEmpty($profile->color); + $this->assertMatchesRegularExpression( + '/^#[0-9a-fA-F]{6}$/', + $profile->color + ); + + $this->assertDatabaseHas('categories', ['id' => $profile->category_id]); + } + + public function test_it_creates_profile_for_given_category(): void + { + $category = Category::factory()->create(); + + $profile = CategoryProfile::factory()->create([ + 'category_id' => $category->id, + ]); + + $this->assertSame($category->id, $profile->category_id); + $this->assertTrue($profile->category->is($category)); + } + + public function test_factory_creates_profiles_with_valid_foreign_keys(): void + { + $profiles = CategoryProfile::factory()->count(5)->create(); + + foreach ($profiles as $profile) { + $this->assertDatabaseHas('categories', [ + 'id' => $profile->category_id, + ]); + } + } +} diff --git a/packages/Category/tests/Unit/Models/CategoryProfileTest.php b/packages/Category/tests/Unit/Models/CategoryProfileTest.php new file mode 100644 index 0000000..b0082f5 --- /dev/null +++ b/packages/Category/tests/Unit/Models/CategoryProfileTest.php @@ -0,0 +1,117 @@ +assertSame( + ['description', 'color', 'category_id'], + $profile->getFillable() + ); + } + + public function test_it_can_be_created_via_factory(): void + { + $profile = CategoryProfile::factory()->create(); + + $this->assertInstanceOf(CategoryProfile::class, $profile); + $this->assertNotEmpty($profile->description); + $this->assertNotEmpty($profile->color); + } + + public function test_it_can_be_mass_assigned(): void + { + $category = Category::factory()->create(); + + $data = [ + 'description' => 'test-description', + 'color' => '#ffffff', + 'category_id' => $category->id, + ]; + + $profile = CategoryProfile::create($data); + + $this->assertDatabaseHas(CategoryProfile::class, $data); + $this->assertInstanceOf(CategoryProfile::class, $profile); + $this->assertEquals($data['description'], $profile->description); + $this->assertEquals($data['color'], $profile->color); + } + + public function test_it_belongs_to_a_category(): void + { + $category = Category::factory()->create(); + $profile = CategoryProfile::create([ + 'description' => 'test-description', + 'color' => '#ffffff', + 'category_id' => $category->id, + ]); + + $this->assertInstanceOf( + \Illuminate\Database\Eloquent\Relations\BelongsTo::class, + $profile->category() + ); + + $this->assertTrue($profile->category->is($category)); + } + + public function test_it_logs_activity_on_create(): void + { + $category = Category::factory()->create(); + CategoryProfile::create([ + 'description' => 'test-description', + 'color' => '#ffffff', + 'category_id' => $category->id, + ]); + + $activity = Activity::orderBy('id', 'desc')->first(); + + $this->assertSame('category_profile', $activity->log_name); + $this->assertSame('created', $activity->description); + $this->assertArrayHasKey('description', $activity->properties['attributes']); + $this->assertArrayHasKey('color', $activity->properties['attributes']); + $this->assertSame('test-description', $activity->properties['attributes']['description']); + $this->assertSame('#ffffff', $activity->properties['attributes']['color']); + } + + public function test_it_logs_only_dirty_attributes_on_update(): void + { + $category = Category::factory()->create(); + $profile = CategoryProfile::create([ + 'description' => 'Old', + 'color' => '#ffffff', + 'category_id' => $category->id, + ]); + + $profile->update([ + 'description' => 'New', + ]); + + $activity = Activity::orderBy('id', 'desc')->first(); + + $this->assertSame('category_profile', $activity->log_name); + $this->assertSame('updated', $activity->description); + $this->assertArrayHasKey('description', $activity->properties['attributes']); + $this->assertSame('New', $activity->properties['attributes']['description']); + $this->assertSame('Old', $activity->properties['old']['description']); + } + + public function test_it_does_not_log_when_nothing_changes(): void + { + $category = CategoryProfile::factory()->create(); + + $initialCount = Activity::count(); + + $category->update(['description' => $category->description]); + + $this->assertSame($initialCount, Activity::count()); + } +} diff --git a/packages/Category/tests/Unit/Models/CategoryTest.php b/packages/Category/tests/Unit/Models/CategoryTest.php new file mode 100644 index 0000000..e77e059 --- /dev/null +++ b/packages/Category/tests/Unit/Models/CategoryTest.php @@ -0,0 +1,113 @@ +assertSame( + ['name', 'slug'], + $category->getFillable() + ); + } + + public function test_it_can_be_created_via_factory(): void + { + $category = Category::factory()->create(); + + $this->assertInstanceOf(Category::class, $category); + $this->assertNotEmpty($category->name); + $this->assertNotEmpty($category->slug); + } + + public function test_it_can_be_mass_assigned(): void + { + $data = [ + 'name' => 'Laravel', + 'slug' => 'laravel', + ]; + + $category = Category::create($data); + + $this->assertDatabaseHas(Category::class, $data); + $this->assertInstanceOf(Category::class, $category); + $this->assertEquals($data['name'], $category->name); + $this->assertEquals($data['slug'], $category->slug); + } + + public function test_it_has_a_profile_relationship(): void + { + $category = Category::factory()->create(); + $profile = CategoryProfile::factory()->create(['category_id' => $category->id]); + + $this->assertTrue($category->profile()->exists()); + $this->assertInstanceOf(CategoryProfile::class, $category->profile); + $this->assertEquals($profile->id, $category->profile->id); + } + + public function test_it_can_have_many_articles(): void + { + $category = Category::factory()->create(); + $articles = Article::factory()->count(3)->create(); + + $category->articles()->attach($articles->pluck('id')); + + $this->assertCount(3, $category->articles); + $this->assertInstanceOf(Article::class, $category->articles->first()); + } + + public function test_it_logs_activity_on_create(): void + { + Category::factory()->create([ + 'name' => 'PHP', + 'slug' => 'php', + ]); + + $activity = Activity::latest()->first(); + + $this->assertSame('category', $activity->log_name); + $this->assertSame('created', $activity->description); + $this->assertArrayHasKey('name', $activity->properties['attributes']); + $this->assertArrayHasKey('slug', $activity->properties['attributes']); + $this->assertSame('PHP', $activity->properties['attributes']['name']); + $this->assertSame('php', $activity->properties['attributes']['slug']); + } + + public function test_it_logs_only_dirty_attributes_on_update(): void + { + $category = Category::factory()->create([ + 'name' => 'Old', + 'slug' => 'old', + ]); + + $category->update(['name' => 'New']); + + $activity = Activity::orderBy('id', 'desc')->first(); + + $this->assertSame('updated', $activity->description); + $this->assertArrayHasKey('name', $activity->properties['attributes']); + $this->assertArrayNotHasKey('slug', $activity->properties['attributes']); + $this->assertSame('New', $activity->properties['attributes']['name']); + $this->assertSame('Old', $activity->properties['old']['name']); + } + + public function test_it_does_not_log_when_nothing_changes(): void + { + $category = Category::factory()->create(); + + $initialCount = Activity::count(); + + $category->update(['name' => $category->name]); + + $this->assertSame($initialCount, Activity::count()); + } +} diff --git a/packages/Category/tests/Unit/Observers/CategoryObserverTest.php b/packages/Category/tests/Unit/Observers/CategoryObserverTest.php new file mode 100644 index 0000000..50419c8 --- /dev/null +++ b/packages/Category/tests/Unit/Observers/CategoryObserverTest.php @@ -0,0 +1,78 @@ +once() + ->with('category:old-slug:id'); + + Cache::shouldReceive('forget') + ->once() + ->with('category:1'); + + $category = new Category(); + $category->id = 1; + $category->slug = 'old-slug'; + $category->syncOriginal(); + + $category->slug = 'new-slug'; + + (new CategoryObserver())->updated($category); + } + + public function test_it_does_not_clear_slug_cache_if_slug_not_changed(): void + { + Cache::shouldReceive('forget') + ->once() + ->with('category:1'); + + Cache::shouldReceive('forget') + ->never() + ->with('category:slug:id'); + + $category = new Category(); + $category->id = 1; + $category->slug = 'slug'; + $category->syncOriginal(); + + (new CategoryObserver())->updated($category); + } + + public function test_update_always_clears_id_cache(): void + { + Cache::shouldReceive('forget') + ->once() + ->with('category:1'); + + $category = new Category(); + $category->id = 1; + $category->slug = 'slug'; + $category->syncOriginal(); + + (new CategoryObserver())->updated($category); + } + + public function test_it_clears_all_related_cache_on_delete(): void + { + Cache::shouldReceive('forget')->once()->with('category:slug:id'); + Cache::shouldReceive('forget')->once()->with('category:1'); + Cache::shouldReceive('forget')->once()->with('category:1:articles'); + Cache::shouldReceive('forget')->once()->with('category:1:news'); + Cache::shouldReceive('forget')->once()->with('category:1:followers'); + + $category = new Category(); + $category->id = 1; + $category->slug = 'slug'; + + (new CategoryObserver())->deleted($category); + } +} diff --git a/packages/Category/tests/Unit/Observers/CategoryProfileObserverTest.php b/packages/Category/tests/Unit/Observers/CategoryProfileObserverTest.php new file mode 100644 index 0000000..712df4b --- /dev/null +++ b/packages/Category/tests/Unit/Observers/CategoryProfileObserverTest.php @@ -0,0 +1,42 @@ +once() + ->with('category:1:profile'); + + $category = new Category(); + $category->id = 1; + + $profile = new CategoryProfile(); + $profile->setRelation('category', $category); + + (new CategoryProfileObserver())->updated($profile); + } + + public function test_it_clears_profile_cache_on_delete(): void + { + Cache::shouldReceive('forget') + ->once() + ->with('category:1:profile'); + + $category = new Category(); + $category->id = 1; + + $profile = new CategoryProfile(); + $profile->setRelation('category', $category); + + (new CategoryProfileObserver())->deleted($profile); + } +} diff --git a/packages/Category/tests/Unit/Policies/CategoryPolicyTest.php b/packages/Category/tests/Unit/Policies/CategoryPolicyTest.php new file mode 100644 index 0000000..5ef6745 --- /dev/null +++ b/packages/Category/tests/Unit/Policies/CategoryPolicyTest.php @@ -0,0 +1,156 @@ +policy = new CategoryPolicy(); + } + + public function test_view(): void + { + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('view_any_category')->andReturn(false); + $user->shouldReceive('can')->with('view_category')->andReturn(true); + $this->assertTrue($this->policy->view($user)); + + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('view_any_category')->andReturn(true); + $this->assertTrue($this->policy->view($user)); + + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('view_any_category')->andReturn(false); + $user->shouldReceive('can')->with('view_category')->andReturn(false); + $this->assertFalse($this->policy->view($user)); + } + + public function test_create(): void + { + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('create_category')->andReturn(true); + $this->assertTrue($this->policy->create($user)); + } + + public function test_update(): void + { + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('update_any_category')->andReturn(false); + $user->shouldReceive('can')->with('update_category')->andReturn(true); + $this->assertTrue($this->policy->update($user)); + + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('update_any_category')->andReturn(true); + $this->assertTrue($this->policy->update($user)); + + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('update_any_category')->andReturn(false); + $user->shouldReceive('can')->with('update_category')->andReturn(false); + $this->assertFalse($this->policy->update($user)); + } + + public function test_delete(): void + { + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('delete_any_category')->andReturn(false); + $user->shouldReceive('can')->with('delete_category')->andReturn(true); + $this->assertTrue($this->policy->delete($user)); + + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('delete_any_category')->andReturn(true); + $this->assertTrue($this->policy->delete($user)); + + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('delete_any_category')->andReturn(false); + $user->shouldReceive('can')->with('delete_category')->andReturn(false); + $this->assertFalse($this->policy->delete($user)); + } + + public function test_delete_any(): void + { + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('delete_any_category')->andReturn(true); + $this->assertTrue($this->policy->deleteAny($user)); + } + + public function test_force_delete(): void + { + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('force_delete_any_category')->andReturn(false); + $user->shouldReceive('can')->with('force_delete_category')->andReturn(true); + $this->assertTrue($this->policy->forceDelete($user)); + + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('force_delete_any_category')->andReturn(true); + $this->assertTrue($this->policy->forceDelete($user)); + + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('force_delete_any_category')->andReturn(false); + $user->shouldReceive('can')->with('force_delete_category')->andReturn(false); + $this->assertFalse($this->policy->forceDelete($user)); + } + + public function test_force_delete_any(): void + { + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('force_delete_any_category')->andReturn(true); + $this->assertTrue($this->policy->forceDeleteAny($user)); + } + + public function test_restore(): void + { + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('restore_any_category')->andReturn(false); + $user->shouldReceive('can')->with('restore_category')->andReturn(true); + $this->assertTrue($this->policy->restore($user)); + + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('restore_any_category')->andReturn(true); + $this->assertTrue($this->policy->restore($user)); + + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('restore_any_category')->andReturn(false); + $user->shouldReceive('can')->with('restore_category')->andReturn(false); + $this->assertFalse($this->policy->restore($user)); + } + + public function test_restore_any(): void + { + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('restore_any_category')->andReturn(true); + $this->assertTrue($this->policy->restoreAny($user)); + } + + public function test_replicate(): void + { + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('replicate_any_category')->andReturn(false); + $user->shouldReceive('can')->with('replicate_category')->andReturn(true); + $this->assertTrue($this->policy->replicate($user)); + + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('replicate_any_category')->andReturn(true); + $this->assertTrue($this->policy->replicate($user)); + + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('replicate_any_category')->andReturn(false); + $user->shouldReceive('can')->with('replicate_category')->andReturn(false); + $this->assertFalse($this->policy->replicate($user)); + } + + public function test_reorder(): void + { + $user = Mockery::mock(User::class); + $user->shouldReceive('can')->with('reorder_category')->andReturn(true); + $this->assertTrue($this->policy->reorder($user)); + } +} diff --git a/packages/Category/tests/Unit/Services/CategoryServiceTest.php b/packages/Category/tests/Unit/Services/CategoryServiceTest.php new file mode 100644 index 0000000..5458413 --- /dev/null +++ b/packages/Category/tests/Unit/Services/CategoryServiceTest.php @@ -0,0 +1,118 @@ +service = app(CategoryService::class); + } + + public function test_it_can_get_category_data_by_id(): void + { + $category = Category::factory()->create(); + + $data = $this->service->getData($category->id); + + $this->assertEquals($category->name, $data->name); + $this->assertEquals($category->slug, $data->slug); + $this->assertTrue(Cache::has("category:{$category->id}")); + } + + public function test_it_can_get_category_id_by_slug(): void + { + $category = Category::factory()->create(); + + $id = $this->service->getId($category->slug); + + $this->assertEquals($category->id, $id); + $this->assertTrue(Cache::has("category:{$category->slug}:id")); + } + + public function test_it_can_get_profile_data(): void + { + $category = Category::factory()->create(); + $profile = CategoryProfile::factory()->create(['category_id' => $category->id]); + + $data = $this->service->getProfileData($category->id); + + $this->assertEquals($profile->description, $data->description); + $this->assertEquals($profile->color, $data->color); + $this->assertTrue(Cache::has("category:{$category->id}:profile")); + } + + public function test_it_can_count_articles(): void + { + $category = Category::factory()->create(); + + $article = Article::factory()->create(); + $article->categories()->attach($category); + + $count = $this->service->getArticlesCount($category->id); + + $this->assertEquals(1, $count); + $this->assertTrue(Cache::has("category:{$category->id}:articles")); + } + + public function test_it_can_count_news(): void + { + $category = Category::factory()->create(); + + $news = News::factory()->create(); + $news->categories()->attach($category); + + $count = $this->service->getNewsCount($category->id); + + $this->assertEquals(1, $count); + $this->assertTrue(Cache::has("category:{$category->id}:news")); + } + + public function test_it_can_list_tags_by_category(): void + { + $category = Category::factory()->create(); + + $tagA = Tag::factory()->create(); + $profileA = TagProfile::factory()->create(['tag_id' => $tagA->id]); + $profileA->categories()->attach($category); + + $otherCategory = Category::factory()->create(); + $tagB = Tag::factory()->create(); + $profileB = TagProfile::factory()->create(['tag_id' => $tagB->id]); + $profileB->categories()->attach($otherCategory); + + $tagC = Tag::factory()->create(); + TagProfile::factory()->create(['tag_id' => $tagC->id]); + + $tags = $this->service->listTags($category->id); + + $this->assertTrue($tags->contains('slug', $tagA->slug)); + $this->assertFalse($tags->contains('slug', $tagB->slug)); + $this->assertFalse($tags->contains('slug', $tagC->slug)); + + $this->assertTrue(Cache::has("category:{$category->id}:tags")); + } + + public function test_it_can_list_related_empty_when_no_profile(): void + { + $category = Category::factory()->create(); + + $related = $this->service->listTags($category->id); + + $this->assertTrue($related->isEmpty()); + } +} diff --git a/phpunit.xml b/phpunit.xml index ec19c89..f02789f 100755 --- a/phpunit.xml +++ b/phpunit.xml @@ -7,6 +7,7 @@ packages/Tag/tests + packages/Category/tests