Files
usher-manage-stack/tests/Unit/MemberTest.php
2025-11-20 23:21:05 +08:00

267 lines
8.9 KiB
PHP

<?php
namespace Tests\Unit;
use App\Models\Member;
use App\Models\User;
use App\Models\MembershipPayment;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class MemberTest extends TestCase
{
use RefreshDatabase;
protected function setUp(): void
{
parent::setUp();
$this->artisan('db:seed', ['--class' => 'RoleSeeder']);
}
public function test_member_has_required_fillable_fields(): void
{
$member = Member::factory()->create([
'full_name' => 'Test Member',
'email' => 'test@example.com',
'phone' => '0912345678',
]);
$this->assertEquals('Test Member', $member->full_name);
$this->assertEquals('test@example.com', $member->email);
$this->assertEquals('0912345678', $member->phone);
}
public function test_member_belongs_to_user(): void
{
$user = User::factory()->create();
$member = Member::factory()->create(['user_id' => $user->id]);
$this->assertInstanceOf(User::class, $member->user);
$this->assertEquals($user->id, $member->user->id);
}
public function test_member_has_many_payments(): void
{
$member = Member::factory()->create();
$payment1 = MembershipPayment::factory()->create(['member_id' => $member->id]);
$payment2 = MembershipPayment::factory()->create(['member_id' => $member->id]);
$this->assertCount(2, $member->payments);
$this->assertTrue($member->payments->contains($payment1));
$this->assertTrue($member->payments->contains($payment2));
}
public function test_has_paid_membership_returns_true_when_active_with_future_expiry(): void
{
$member = Member::factory()->create([
'membership_status' => Member::STATUS_ACTIVE,
'membership_started_at' => now()->subMonth(),
'membership_expires_at' => now()->addYear(),
]);
$this->assertTrue($member->hasPaidMembership());
}
public function test_has_paid_membership_returns_false_when_pending(): void
{
$member = Member::factory()->create([
'membership_status' => Member::STATUS_PENDING,
'membership_started_at' => null,
'membership_expires_at' => null,
]);
$this->assertFalse($member->hasPaidMembership());
}
public function test_has_paid_membership_returns_false_when_expired(): void
{
$member = Member::factory()->create([
'membership_status' => Member::STATUS_ACTIVE,
'membership_started_at' => now()->subYear()->subMonth(),
'membership_expires_at' => now()->subMonth(),
]);
$this->assertFalse($member->hasPaidMembership());
}
public function test_has_paid_membership_returns_false_when_suspended(): void
{
$member = Member::factory()->create([
'membership_status' => Member::STATUS_SUSPENDED,
'membership_started_at' => now()->subMonth(),
'membership_expires_at' => now()->addYear(),
]);
$this->assertFalse($member->hasPaidMembership());
}
public function test_can_submit_payment_returns_true_when_pending_and_no_pending_payment(): void
{
$member = Member::factory()->create([
'membership_status' => Member::STATUS_PENDING,
]);
$this->assertTrue($member->canSubmitPayment());
}
public function test_can_submit_payment_returns_false_when_already_has_pending_payment(): void
{
$member = Member::factory()->create([
'membership_status' => Member::STATUS_PENDING,
]);
MembershipPayment::factory()->create([
'member_id' => $member->id,
'status' => MembershipPayment::STATUS_PENDING,
]);
$this->assertFalse($member->canSubmitPayment());
}
public function test_can_submit_payment_returns_false_when_active(): void
{
$member = Member::factory()->create([
'membership_status' => Member::STATUS_ACTIVE,
]);
$this->assertFalse($member->canSubmitPayment());
}
public function test_get_pending_payment_returns_pending_payment(): void
{
$member = Member::factory()->create();
$pendingPayment = MembershipPayment::factory()->create([
'member_id' => $member->id,
'status' => MembershipPayment::STATUS_PENDING,
]);
$approvedPayment = MembershipPayment::factory()->create([
'member_id' => $member->id,
'status' => MembershipPayment::STATUS_APPROVED_CHAIR,
]);
$result = $member->getPendingPayment();
$this->assertNotNull($result);
$this->assertEquals($pendingPayment->id, $result->id);
}
public function test_get_pending_payment_returns_null_when_no_pending_payments(): void
{
$member = Member::factory()->create();
MembershipPayment::factory()->create([
'member_id' => $member->id,
'status' => MembershipPayment::STATUS_APPROVED_CHAIR,
]);
$this->assertNull($member->getPendingPayment());
}
public function test_national_id_encryption_and_decryption(): void
{
$member = Member::factory()->create([
'full_name' => 'Test Member',
]);
$nationalId = 'A123456789';
$member->national_id = $nationalId;
$member->save();
// Refresh from database
$member->refresh();
// Check encrypted value is different from plain text
$this->assertNotEquals($nationalId, $member->national_id_encrypted);
// Check decryption works
$this->assertEquals($nationalId, $member->national_id);
}
public function test_national_id_hash_created_for_search(): void
{
$member = Member::factory()->create();
$nationalId = 'A123456789';
$member->national_id = $nationalId;
$member->save();
$member->refresh();
// Check hash was created
$this->assertNotNull($member->national_id_hash);
// Check hash matches SHA256
$expectedHash = hash('sha256', $nationalId);
$this->assertEquals($expectedHash, $member->national_id_hash);
}
public function test_is_pending_returns_true_when_status_is_pending(): void
{
$member = Member::factory()->create(['membership_status' => Member::STATUS_PENDING]);
$this->assertTrue($member->isPending());
}
public function test_is_active_returns_true_when_status_is_active(): void
{
$member = Member::factory()->create(['membership_status' => Member::STATUS_ACTIVE]);
$this->assertTrue($member->isActive());
}
public function test_is_expired_returns_true_when_status_is_expired(): void
{
$member = Member::factory()->create(['membership_status' => Member::STATUS_EXPIRED]);
$this->assertTrue($member->isExpired());
}
public function test_is_suspended_returns_true_when_status_is_suspended(): void
{
$member = Member::factory()->create(['membership_status' => Member::STATUS_SUSPENDED]);
$this->assertTrue($member->isSuspended());
}
public function test_membership_status_label_returns_chinese_text(): void
{
$member = Member::factory()->create(['membership_status' => Member::STATUS_PENDING]);
$this->assertEquals('待繳費', $member->membership_status_label);
$member->membership_status = Member::STATUS_ACTIVE;
$this->assertEquals('已啟用', $member->membership_status_label);
$member->membership_status = Member::STATUS_EXPIRED;
$this->assertEquals('已過期', $member->membership_status_label);
$member->membership_status = Member::STATUS_SUSPENDED;
$this->assertEquals('已暫停', $member->membership_status_label);
}
public function test_membership_type_label_returns_chinese_text(): void
{
$member = Member::factory()->create(['membership_type' => Member::TYPE_REGULAR]);
$this->assertEquals('一般會員', $member->membership_type_label);
$member->membership_type = Member::TYPE_STUDENT;
$this->assertEquals('學生會員', $member->membership_type_label);
$member->membership_type = Member::TYPE_HONORARY;
$this->assertEquals('榮譽會員', $member->membership_type_label);
$member->membership_type = Member::TYPE_LIFETIME;
$this->assertEquals('終身會員', $member->membership_type_label);
}
public function test_membership_status_badge_returns_correct_css_class(): void
{
$member = Member::factory()->create(['membership_status' => Member::STATUS_PENDING]);
$badge = $member->membership_status_badge;
$this->assertStringContainsString('待繳費', $badge);
$this->assertStringContainsString('bg-yellow', $badge);
$member->membership_status = Member::STATUS_ACTIVE;
$badge = $member->membership_status_badge;
$this->assertStringContainsString('bg-green', $badge);
}
}