246 lines
7.2 KiB
PHP
246 lines
7.2 KiB
PHP
<?php
|
|
|
|
require_once __DIR__.'/TestHelpers.php';
|
|
|
|
use App\Enums\ArticleStatus;
|
|
use App\Livewire\Studio\Manage\Article\Index;
|
|
use App\Models\Article;
|
|
use App\Models\User;
|
|
use Database\Seeders\RolePermissionSeeder;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Livewire\Livewire;
|
|
use Spatie\Permission\Models\Role;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
beforeEach(function () {
|
|
$this->seed(RolePermissionSeeder::class);
|
|
|
|
$this->user = User::factory()
|
|
->active()
|
|
->has(\App\Models\Employee::factory())
|
|
->create();
|
|
|
|
$this->ownerRole = Role::where('name', 'Owner')->first();
|
|
$this->user->roles()->attach($this->ownerRole->id);
|
|
|
|
$this->article = Article::factory()->create([
|
|
'author_id' => $this->user->id,
|
|
'status' => ArticleStatus::PUBLISHED,
|
|
]);
|
|
});
|
|
|
|
function mountIndexComponent(User $user): \Livewire\Features\SupportTesting\Testable
|
|
{
|
|
return Livewire::actingAs($user)->test(Index::class);
|
|
}
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Component Rendering & Mount
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
it('renders page successfully', function () {
|
|
mountIndexComponent($this->user)
|
|
->assertViewIs('livewire.studio.manage.article.index')
|
|
->assertViewHas('pageTitle', 'Artikel');
|
|
});
|
|
|
|
it('mounts successfully', function () {
|
|
$component = mountIndexComponent($this->user);
|
|
|
|
expect($component->instance())->toBeInstanceOf(Index::class);
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Component Properties
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
it('has title attribute set', function () {
|
|
$reflection = new ReflectionClass(Index::class);
|
|
$attributes = $reflection->getAttributes();
|
|
|
|
$titleAttribute = collect($attributes)->first(function ($attribute) {
|
|
return $attribute->getName() === 'Livewire\\Attributes\\Title';
|
|
});
|
|
|
|
expect($titleAttribute)->not->toBeNull();
|
|
expect($titleAttribute->getArguments()[0])->toBe('Artikel');
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Delete Functionality
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
it('deletes article successfully', function () {
|
|
$articleToDelete = Article::factory()->create([
|
|
'author_id' => $this->user->id,
|
|
'status' => ArticleStatus::DRAFT,
|
|
]);
|
|
|
|
mountIndexComponent($this->user)
|
|
->call('delete', $articleToDelete)
|
|
->assertDispatched('refreshDatatable');
|
|
|
|
// Verify article is soft deleted
|
|
expect($articleToDelete->fresh()->trashed())->toBeTrue();
|
|
});
|
|
|
|
it('soft deletes article', function () {
|
|
$articleToDelete = Article::factory()->create([
|
|
'author_id' => $this->user->id,
|
|
'status' => ArticleStatus::DRAFT,
|
|
]);
|
|
|
|
mountIndexComponent($this->user)
|
|
->call('delete', $articleToDelete);
|
|
|
|
// Check if article exists with trashed
|
|
$deletedArticle = Article::withTrashed()->find($articleToDelete->id);
|
|
expect($deletedArticle)->not->toBeNull();
|
|
expect($deletedArticle->trashed())->toBeTrue();
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Delete Authorization
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
it('allows deletion with delete permission', function () {
|
|
$articleToDelete = Article::factory()->create([
|
|
'author_id' => $this->user->id,
|
|
'status' => ArticleStatus::DRAFT,
|
|
]);
|
|
|
|
mountIndexComponent($this->user)
|
|
->call('delete', $articleToDelete);
|
|
|
|
expect(Article::withTrashed()->find($articleToDelete->id)->trashed())->toBeTrue();
|
|
});
|
|
|
|
it('handles deletion of non-existent article gracefully', function () {
|
|
$nonExistentArticle = new Article;
|
|
$nonExistentArticle->id = 99999;
|
|
|
|
mountIndexComponent($this->user)
|
|
->call('delete', $nonExistentArticle)
|
|
->assertDispatched('refreshDatatable');
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Component Events
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
it('dispatches refreshDatatable event on delete', function () {
|
|
$articleToDelete = Article::factory()->create([
|
|
'author_id' => $this->user->id,
|
|
'status' => ArticleStatus::DRAFT,
|
|
]);
|
|
|
|
mountIndexComponent($this->user)
|
|
->call('delete', $articleToDelete)
|
|
->assertDispatched('refreshDatatable');
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Toast Messages
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
// Toast messages are tested functionally through the delete method
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Flux Modal Handling
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
it('closes flux modal after deletion', function () {
|
|
$articleToDelete = Article::factory()->create([
|
|
'author_id' => $this->user->id,
|
|
'status' => ArticleStatus::DRAFT,
|
|
]);
|
|
|
|
mountIndexComponent($this->user)
|
|
->call('delete', $articleToDelete);
|
|
|
|
// This would typically test Flux modal closure
|
|
// For now, we verify the method completes
|
|
expect(true)->toBeTrue();
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Traits Usage
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
it('uses WithConfirmation trait', function () {
|
|
$component = new Index;
|
|
|
|
expect(in_array('App\Traits\WithConfirmation', class_uses_recursive($component)))->toBeTrue();
|
|
});
|
|
|
|
it('uses WithSubscribeNotification trait', function () {
|
|
$component = new Index;
|
|
|
|
expect(in_array('App\Traits\Notification\WithSubscribeNotification', class_uses_recursive($component)))->toBeTrue();
|
|
});
|
|
|
|
it('uses WithToast trait', function () {
|
|
$component = new Index;
|
|
|
|
expect(in_array('App\Traits\WithToast', class_uses_recursive($component)))->toBeTrue();
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Render Method
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
it('has render method', function () {
|
|
$component = new Index;
|
|
|
|
expect(method_exists($component, 'render'))->toBeTrue();
|
|
});
|
|
|
|
it('render method returns correct view', function () {
|
|
$component = new Index;
|
|
|
|
$view = $component->render();
|
|
|
|
expect($view->getName())->toBe('livewire.studio.manage.article.index');
|
|
expect($view->getData()['pageTitle'])->toBe('Artikel');
|
|
});
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Component Structure
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
it('has delete method', function () {
|
|
$component = new Index;
|
|
|
|
expect(method_exists($component, 'delete'))->toBeTrue();
|
|
});
|
|
|
|
it('delete method requires article parameter', function () {
|
|
$component = new Index;
|
|
$reflection = new ReflectionMethod($component, 'delete');
|
|
$parameters = $reflection->getParameters();
|
|
|
|
expect(count($parameters))->toBe(1);
|
|
expect($parameters[0]->getType()->getName())->toBe(Article::class);
|
|
});
|