diff --git a/app/Livewire/Backend/Article/Form.php b/app/Livewire/Backend/Article/Form.php index 7fbeba14..efd8d320 100644 --- a/app/Livewire/Backend/Article/Form.php +++ b/app/Livewire/Backend/Article/Form.php @@ -33,16 +33,16 @@ class Form extends Component 'articleData.meta.image_url' => 'nullable|url', ]; - public function mount(?Article $article = null): void + public function mount($article = null): void { - if ($article->id) { + if ($article?->id) { $this->originalArticle = $article; $this->articleData = $article->toArray(); $this->articleData['keywords'] = $article->keywords->pluck('name')->implode(' '); $this->articleData['meta'] = $article->meta ?: []; } - $this->method = $article->id ? 'put' : 'post'; + $this->method = $article?->id ? 'put' : 'post'; } public function render(): View @@ -75,7 +75,7 @@ protected function store(array $articleData): void $newArticle = Article::query()->create($articleData); //add keywords - $keywordsToAttach = array_unique(explode(' ', Arr::get($this->article, 'keywords'))); + $keywordsToAttach = array_unique(explode(' ', Arr::get($this->articleData, 'keywords'))); foreach ($keywordsToAttach as $keywordToAttach) { if (empty($keywordToAttach)) { diff --git a/database/factories/ArticleFactory.php b/database/factories/ArticleFactory.php index accecf85..28e9115a 100644 --- a/database/factories/ArticleFactory.php +++ b/database/factories/ArticleFactory.php @@ -3,6 +3,7 @@ namespace Database\Factories; use App\Models\Article; +use App\Models\Category; use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Support\Str; @@ -26,7 +27,7 @@ public function definition(): array 'user_id' => null, 'language' => $language = $this->faker->randomElement(['ben', 'eng']), 'slug' => Str::slug($heading, '-', $language), - 'category_id' => null, + 'category_id' => Category::factory()->create()->id, ]; } diff --git a/tests/Feature/Livewire/Backend/Article/FormTest.php b/tests/Feature/Livewire/Backend/Article/FormTest.php new file mode 100644 index 00000000..c7a7b224 --- /dev/null +++ b/tests/Feature/Livewire/Backend/Article/FormTest.php @@ -0,0 +1,135 @@ +assertStatus(Response::HTTP_OK) + ->assertViewIs('livewire.backend.article.form') + ->assertViewHas('categories'); + } + + public function test_initializes_correctly_without_article() + { + Livewire::test(Form::class) + ->assertSet('method', 'post') + ->assertSet('articleData', []); + } + + public function test_initializes_correctly_with_article() + { + $article = Article::factory()->create(); + Livewire::test(Form::class, ['article' => $article]) + ->assertSet('method', 'put') + ->assertSet('articleData.heading', $article->heading) + ->assertSet('articleData.slug', $article->slug) + ->assertSet('articleData.category_id', $article->category_id); + } + + public function test_generates_slug_when_heading_changes() + { + Livewire::test(Form::class) + ->set('articleData.heading', 'New Article') + ->set('articleData.language', 'en') + ->assertSet('articleData.slug', Str::slug('New Article')); + } + + public function test_validates_article_data_correctly() + { + Livewire::test(Form::class) + ->set('articleData.heading', '') + ->set('articleData.slug', '') + ->set('articleData.category_id', null) + ->set('articleData.content', '') + ->set('articleData.language', '') + ->call('submit') + ->assertHasErrors([ + 'articleData.heading' => 'required', + 'articleData.slug' => 'required', + 'articleData.category_id' => 'required', + 'articleData.content' => 'required', + 'articleData.language' => 'required', + ]); + } + + public function test_stores_a_new_article_correctly() + { + Mail::fake(); + Auth::loginUsingId(User::factory()->create()->id); + + $category = Category::factory()->create(); + $data = [ + 'heading' => 'Test Article', + 'slug' => 'test-article', + 'category_id' => $category->id, + 'content' => 'This is a test article.', + 'language' => 'en', + 'is_comment_enabled' => true, + 'meta' => [ + 'description' => 'Test description', + 'image_url' => 'http://example.com/image.jpg', + ], + 'keywords' => 'test article', + ]; + + Livewire::test(Form::class, ['article' => null]) + ->set('articleData', $data) + ->call('submit') + ->assertSessionHas('success', 'Article published successfully!'); + + $this->assertDatabaseHas('articles', ['heading' => 'Test Article']); + $this->assertDatabaseHas('keywords', ['name' => 'test']); + $this->assertDatabaseHas('keywords', ['name' => 'article']); + Mail::assertQueued(NotifySubscriberForNewArticle::class); + } + + public function test_updates_an_existing_article_correctly() + { + Mail::fake(); + Auth::loginUsingId(User::factory()->create()->id); + + $article = Article::factory()->create(); + $data = [ + 'heading' => 'Updated Article', + 'slug' => 'updated-article', + 'category_id' => $article->category_id, + 'content' => 'This is an updated article.', + 'language' => 'en', + 'is_comment_enabled' => true, + 'meta' => [ + 'description' => 'Updated description', + 'image_url' => 'http://example.com/updated-image.jpg', + ], + 'keywords' => 'updated article', + ]; + + Livewire::test(Form::class, ['article' => $article]) + ->set('articleData', $data) + ->call('submit') + ->assertSessionHas('successMsg', 'Article updated successfully!'); + + $this->assertDatabaseHas('articles', [ + 'id' => $article->id, + 'heading' => 'Updated Article' + ]); + $this->assertDatabaseHas('keywords', ['name' => 'updated']); + $this->assertDatabaseHas('keywords', ['name' => 'article']); + } +} diff --git a/tests/Feature/Livewire/Backend/Article/IndexTest.php b/tests/Feature/Livewire/Backend/Article/IndexTest.php new file mode 100644 index 00000000..e3a8a46e --- /dev/null +++ b/tests/Feature/Livewire/Backend/Article/IndexTest.php @@ -0,0 +1,76 @@ +create(); + $author = Role::findOrCreate('author'); + $user->assignRole($author); + Auth::loginUsingId($user->id); + } + public function testItRendersCorrectly() + { + Auth::loginUsingId(User::factory()->create()->id); + + Livewire::test(Index::class) + ->assertStatus(200) + ->assertViewIs('livewire.backend.article.index'); + } + + public function testItFiltersArticlesBasedOnCategory() + { + $category = Category::factory()->create(); + Article::factory()->count(3)->create(['category_id' => $category->id]); + Article::factory()->count(2)->create(); // Articles in different categories + + Livewire::test(Index::class) + ->set('category', $category->id) + ->assertSeeInOrder([$category->name], 'category') + ->assertViewHas('articles', function ($articles) use ($category) { + return $articles->every(fn($article) => $article->category_id === $category->id); + }); + } + + public function testItFiltersArticlesBasedOnKeyword() + { + $keyword = Keyword::factory()->create(); + $articleWithKeyword = Article::factory()->create(); + $articleWithKeyword->keywords()->attach($keyword); + + Article::factory()->count(2)->create(); // Articles without the keyword + + Livewire::test(Index::class) + ->set('keyword', $keyword->name) + ->assertSeeInOrder([$keyword->name], 'keywords') + ->assertViewHas('articles', function ($articles) use ($keyword) { + return $articles->every(fn($article) => $article->keywords->contains($keyword)); + }); + } + + public function testItFiltersArticlesBasedOnSearchQuery() + { + $query = 'Unique Title'; + Article::factory()->create(['heading' => $query]); + Article::factory()->count(2)->create(['heading' => 'Other Title']); + + Livewire::test(Index::class) + ->set('query', $query) + ->assertViewHas('articles', function ($articles) use ($query) { + return $articles->every(fn($article) => stripos($article->heading, $query) !== false); + }); + } +}