refactor observers, fix policy, add feature tests
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Activity;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ActivityObserverTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
private User $user;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->user = User::factory()->create();
|
||||
$this->actingAs($this->user);
|
||||
}
|
||||
|
||||
private function makeActivity(string $status = 'draft'): Activity
|
||||
{
|
||||
return Activity::create([
|
||||
'title' => 'Test Kegiatan',
|
||||
'start_date' => now()->toDateString(),
|
||||
'end_date' => now()->addDay()->toDateString(),
|
||||
'created_by' => $this->user->id,
|
||||
'status' => $status,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_draft_can_transition_to_pending(): void
|
||||
{
|
||||
$activity = $this->makeActivity('draft');
|
||||
$activity->update(['status' => 'pending']);
|
||||
|
||||
$this->assertSame('pending', $activity->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_draft_cannot_skip_to_approved(): void
|
||||
{
|
||||
$activity = $this->makeActivity('draft');
|
||||
$activity->update(['status' => 'approved']);
|
||||
|
||||
$this->assertSame('draft', $activity->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_pending_can_transition_to_approved(): void
|
||||
{
|
||||
$activity = $this->makeActivity('pending');
|
||||
$activity->update(['status' => 'approved']);
|
||||
|
||||
$this->assertSame('approved', $activity->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_pending_can_transition_to_rejected(): void
|
||||
{
|
||||
$activity = $this->makeActivity('pending');
|
||||
$activity->update(['status' => 'rejected']);
|
||||
|
||||
$this->assertSame('rejected', $activity->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_approved_cannot_revert_to_draft(): void
|
||||
{
|
||||
$activity = $this->makeActivity('approved');
|
||||
$activity->update(['status' => 'draft']);
|
||||
|
||||
$this->assertSame('approved', $activity->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_large_budget_pending_creates_vote(): void
|
||||
{
|
||||
$activity = $this->makeActivity('draft');
|
||||
$activity->budget = 3_000_000;
|
||||
$activity->save();
|
||||
|
||||
$activity->update(['status' => 'pending']);
|
||||
|
||||
$this->assertDatabaseHas('votes', [
|
||||
'related_type' => Activity::class,
|
||||
'related_id' => $activity->id,
|
||||
'type' => 'finance',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Approval;
|
||||
use App\Models\CashCategory;
|
||||
use App\Models\CashRecord;
|
||||
use App\Models\User;
|
||||
use App\Models\Vote;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class CashRecordObserverTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
private User $user;
|
||||
private CashCategory $category;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->user = User::factory()->create();
|
||||
$this->category = CashCategory::create(['name' => 'Umum']);
|
||||
$this->actingAs($this->user);
|
||||
}
|
||||
|
||||
private function makeRecord(int $amount): CashRecord
|
||||
{
|
||||
return CashRecord::create([
|
||||
'amount' => $amount,
|
||||
'category_id' => $this->category->id,
|
||||
'description' => 'Test',
|
||||
'date' => now()->toDateString(),
|
||||
'created_by' => $this->user->id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_small_transaction_creates_no_approval_or_vote(): void
|
||||
{
|
||||
$record = $this->makeRecord(100_000);
|
||||
|
||||
$this->assertDatabaseMissing('approvals', ['model_id' => $record->id]);
|
||||
$this->assertDatabaseMissing('votes', ['related_id' => $record->id]);
|
||||
}
|
||||
|
||||
public function test_mid_transaction_creates_approval(): void
|
||||
{
|
||||
$record = $this->makeRecord(1_000_000);
|
||||
|
||||
$this->assertDatabaseHas('approvals', [
|
||||
'model_type' => CashRecord::class,
|
||||
'model_id' => $record->id,
|
||||
'status' => 'pending',
|
||||
]);
|
||||
$this->assertDatabaseMissing('votes', ['related_id' => $record->id]);
|
||||
}
|
||||
|
||||
public function test_mid_transaction_does_not_duplicate_approval(): void
|
||||
{
|
||||
$record = $this->makeRecord(1_000_000);
|
||||
// Simulate retry — observer called again
|
||||
(new \App\Observers\CashRecordObserver)->created($record);
|
||||
|
||||
$this->assertSame(1, Approval::where('model_id', $record->id)->count());
|
||||
}
|
||||
|
||||
public function test_large_transaction_creates_vote(): void
|
||||
{
|
||||
$record = $this->makeRecord(3_000_000);
|
||||
|
||||
$this->assertDatabaseHas('votes', [
|
||||
'related_type' => CashRecord::class,
|
||||
'related_id' => $record->id,
|
||||
'type' => 'finance',
|
||||
]);
|
||||
$this->assertDatabaseMissing('approvals', ['model_id' => $record->id]);
|
||||
}
|
||||
|
||||
public function test_verified_record_cannot_be_deleted(): void
|
||||
{
|
||||
$record = $this->makeRecord(100_000);
|
||||
$record->update(['verified_by' => $this->user->id, 'verified_at' => now()]);
|
||||
|
||||
$this->expectException(\Illuminate\Auth\Access\AuthorizationException::class);
|
||||
|
||||
$record->delete();
|
||||
}
|
||||
}
|
||||
+9
-1
@@ -3,8 +3,16 @@
|
||||
namespace Tests;
|
||||
|
||||
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
abstract class TestCase extends BaseTestCase
|
||||
{
|
||||
//
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
// Seed roles yang dibutuhkan observer
|
||||
foreach (['anggota', 'ketua', 'bendahara', 'pengurus', 'auditor', 'super_admin'] as $role) {
|
||||
Role::firstOrCreate(['name' => $role, 'guard_name' => 'web']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user