Features: - Implement two fee types: entrance fee and annual fee (both NT$1,000) - Add 50% discount for disability certificate holders - Add disability certificate upload in member profile - Integrate disability verification into cashier approval workflow - Add membership fee settings in system admin Document permissions: - Fix hard-coded role logic in Document model - Use permission-based authorization instead of role checks Additional features: - Add announcements, general ledger, and trial balance modules - Add income management and accounting entries - Add comprehensive test suite with factories - Update UI translations to Traditional Chinese 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
212 lines
5.7 KiB
PHP
212 lines
5.7 KiB
PHP
<?php
|
|
|
|
namespace Tests\Browser;
|
|
|
|
use App\Models\Member;
|
|
use App\Models\MembershipPayment;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
|
use Illuminate\Support\Facades\Hash;
|
|
use Laravel\Dusk\Browser;
|
|
use Tests\DuskTestCase;
|
|
|
|
/**
|
|
* Member Dashboard Browser Tests
|
|
*
|
|
* Tests the member dashboard user interface and user experience.
|
|
*/
|
|
class MemberDashboardBrowserTest extends DuskTestCase
|
|
{
|
|
use DatabaseMigrations;
|
|
|
|
protected User $memberUser;
|
|
|
|
protected Member $member;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->artisan('db:seed', ['--class' => 'FinancialWorkflowPermissionsSeeder']);
|
|
}
|
|
|
|
/**
|
|
* Create a member user for testing
|
|
*/
|
|
protected function createMemberUser(): User
|
|
{
|
|
$user = User::factory()->create([
|
|
'email' => 'member@test.com',
|
|
'password' => Hash::make('password'),
|
|
]);
|
|
|
|
Member::factory()->create([
|
|
'user_id' => $user->id,
|
|
'membership_status' => Member::STATUS_ACTIVE,
|
|
]);
|
|
|
|
return $user;
|
|
}
|
|
|
|
/**
|
|
* Test member can view dashboard
|
|
*/
|
|
public function test_member_can_view_dashboard(): void
|
|
{
|
|
$user = $this->createMemberUser();
|
|
|
|
$this->browse(function (Browser $browser) use ($user) {
|
|
$browser->loginAs($user)
|
|
->visit(route('member.dashboard'))
|
|
->assertSee('會員')
|
|
->assertSee('儀表板');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test member sees membership status
|
|
*/
|
|
public function test_member_sees_membership_status(): void
|
|
{
|
|
$user = $this->createMemberUser();
|
|
|
|
$this->browse(function (Browser $browser) use ($user) {
|
|
$browser->loginAs($user)
|
|
->visit(route('member.dashboard'))
|
|
->assertSee('會員狀態');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test member can navigate to payment page
|
|
*/
|
|
public function test_member_can_navigate_to_payment_page(): void
|
|
{
|
|
$user = $this->createMemberUser();
|
|
|
|
$this->browse(function (Browser $browser) use ($user) {
|
|
$browser->loginAs($user)
|
|
->visit(route('member.dashboard'))
|
|
->clickLink('繳費')
|
|
->assertPathIs('/member/payments*');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test member can view payment history
|
|
*/
|
|
public function test_member_can_view_payment_history(): void
|
|
{
|
|
$user = $this->createMemberUser();
|
|
$member = $user->member;
|
|
|
|
MembershipPayment::factory()->count(3)->create([
|
|
'member_id' => $member->id,
|
|
'status' => MembershipPayment::STATUS_APPROVED_CHAIR,
|
|
]);
|
|
|
|
$this->browse(function (Browser $browser) use ($user) {
|
|
$browser->loginAs($user)
|
|
->visit(route('member.payments.index'))
|
|
->assertSee('繳費紀錄');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test member can submit new payment
|
|
*/
|
|
public function test_member_can_submit_new_payment(): void
|
|
{
|
|
$user = $this->createMemberUser();
|
|
|
|
$this->browse(function (Browser $browser) use ($user) {
|
|
$browser->loginAs($user)
|
|
->visit(route('member.payments.create'))
|
|
->assertSee('提交繳費')
|
|
->assertPresent('input[name="amount"]')
|
|
->assertPresent('input[type="file"]');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test member sees pending payment status
|
|
*/
|
|
public function test_member_sees_pending_payment_status(): void
|
|
{
|
|
$user = $this->createMemberUser();
|
|
$member = $user->member;
|
|
|
|
MembershipPayment::factory()->create([
|
|
'member_id' => $member->id,
|
|
'status' => MembershipPayment::STATUS_PENDING,
|
|
]);
|
|
|
|
$this->browse(function (Browser $browser) use ($user) {
|
|
$browser->loginAs($user)
|
|
->visit(route('member.payments.index'))
|
|
->assertSee('待審核');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test member can update profile
|
|
*/
|
|
public function test_member_can_update_profile(): void
|
|
{
|
|
$user = $this->createMemberUser();
|
|
|
|
$this->browse(function (Browser $browser) use ($user) {
|
|
$browser->loginAs($user)
|
|
->visit(route('member.profile.edit'))
|
|
->assertPresent('input[name="phone"]')
|
|
->assertPresent('input[name="address"]');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test member dashboard shows expiry date
|
|
*/
|
|
public function test_member_dashboard_shows_expiry_date(): void
|
|
{
|
|
$user = $this->createMemberUser();
|
|
$user->member->update([
|
|
'membership_expires_at' => now()->addYear(),
|
|
]);
|
|
|
|
$this->browse(function (Browser $browser) use ($user) {
|
|
$browser->loginAs($user)
|
|
->visit(route('member.dashboard'))
|
|
->assertSee('到期');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test logout functionality
|
|
*/
|
|
public function test_logout_functionality(): void
|
|
{
|
|
$user = $this->createMemberUser();
|
|
|
|
$this->browse(function (Browser $browser) use ($user) {
|
|
$browser->loginAs($user)
|
|
->visit(route('member.dashboard'))
|
|
->click('@user-menu')
|
|
->clickLink('登出')
|
|
->assertPathIs('/');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test member cannot access admin pages
|
|
*/
|
|
public function test_member_cannot_access_admin_pages(): void
|
|
{
|
|
$user = $this->createMemberUser();
|
|
|
|
$this->browse(function (Browser $browser) use ($user) {
|
|
$browser->loginAs($user)
|
|
->visit('/admin/dashboard')
|
|
->assertPathIsNot('/admin/dashboard');
|
|
});
|
|
}
|
|
}
|