Add membership fee system with disability discount and fix document permissions
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>
This commit is contained in:
167
tests/Browser/MemberRegistrationBrowserTest.php
Normal file
167
tests/Browser/MemberRegistrationBrowserTest.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser;
|
||||
|
||||
use App\Models\Member;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
use Laravel\Dusk\Browser;
|
||||
use Tests\DuskTestCase;
|
||||
|
||||
/**
|
||||
* Member Registration Browser Tests
|
||||
*
|
||||
* Tests the member registration user interface and user experience.
|
||||
*/
|
||||
class MemberRegistrationBrowserTest extends DuskTestCase
|
||||
{
|
||||
use DatabaseMigrations;
|
||||
|
||||
/**
|
||||
* Test registration page loads correctly
|
||||
*/
|
||||
public function test_registration_page_loads_correctly(): void
|
||||
{
|
||||
$this->browse(function (Browser $browser) {
|
||||
$browser->visit(route('register.member'))
|
||||
->assertSee('會員註冊')
|
||||
->assertPresent('input[name="full_name"]')
|
||||
->assertPresent('input[name="email"]')
|
||||
->assertPresent('input[name="password"]');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test form validation messages display
|
||||
*/
|
||||
public function test_form_validation_messages_display(): void
|
||||
{
|
||||
$this->browse(function (Browser $browser) {
|
||||
$browser->visit(route('register.member'))
|
||||
->press('註冊')
|
||||
->assertSee('必填');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test successful registration redirects correctly
|
||||
*/
|
||||
public function test_successful_registration_redirects(): void
|
||||
{
|
||||
$this->artisan('db:seed', ['--class' => 'FinancialWorkflowPermissionsSeeder']);
|
||||
|
||||
$this->browse(function (Browser $browser) {
|
||||
$browser->visit(route('register.member'))
|
||||
->type('full_name', '測試會員')
|
||||
->type('email', 'test@example.com')
|
||||
->type('password', 'password123')
|
||||
->type('password_confirmation', 'password123')
|
||||
->type('national_id', 'A123456789')
|
||||
->type('birthday', '1990-01-01')
|
||||
->type('phone', '0912345678')
|
||||
->type('address', '台北市信義區')
|
||||
->press('註冊')
|
||||
->waitForLocation('/member/dashboard')
|
||||
->assertPathIs('/member/dashboard');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test email field validation
|
||||
*/
|
||||
public function test_email_field_validation(): void
|
||||
{
|
||||
$this->browse(function (Browser $browser) {
|
||||
$browser->visit(route('register.member'))
|
||||
->type('email', 'invalid-email')
|
||||
->press('註冊')
|
||||
->assertSee('電子郵件');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test password confirmation validation
|
||||
*/
|
||||
public function test_password_confirmation_validation(): void
|
||||
{
|
||||
$this->browse(function (Browser $browser) {
|
||||
$browser->visit(route('register.member'))
|
||||
->type('password', 'password123')
|
||||
->type('password_confirmation', 'different')
|
||||
->press('註冊')
|
||||
->assertSee('密碼');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test national ID format validation
|
||||
*/
|
||||
public function test_national_id_format_validation(): void
|
||||
{
|
||||
$this->browse(function (Browser $browser) {
|
||||
$browser->visit(route('register.member'))
|
||||
->type('national_id', 'invalid')
|
||||
->press('註冊')
|
||||
->assertSee('身分證');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test duplicate email detection
|
||||
*/
|
||||
public function test_duplicate_email_detection(): void
|
||||
{
|
||||
User::factory()->create(['email' => 'existing@example.com']);
|
||||
|
||||
$this->browse(function (Browser $browser) {
|
||||
$browser->visit(route('register.member'))
|
||||
->type('email', 'existing@example.com')
|
||||
->press('註冊')
|
||||
->assertSee('電子郵件');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test file upload for ID photo
|
||||
*/
|
||||
public function test_file_upload_for_id_photo(): void
|
||||
{
|
||||
$this->browse(function (Browser $browser) {
|
||||
$browser->visit(route('register.member'))
|
||||
->assertPresent('input[type="file"]');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test form preserves input on validation error
|
||||
*/
|
||||
public function test_form_preserves_input_on_validation_error(): void
|
||||
{
|
||||
$this->browse(function (Browser $browser) {
|
||||
$browser->visit(route('register.member'))
|
||||
->type('full_name', '測試會員')
|
||||
->type('email', 'test@example.com')
|
||||
->press('註冊')
|
||||
->assertInputValue('full_name', '測試會員')
|
||||
->assertInputValue('email', 'test@example.com');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test registration form is responsive
|
||||
*/
|
||||
public function test_registration_form_is_responsive(): void
|
||||
{
|
||||
$this->browse(function (Browser $browser) {
|
||||
// Test on mobile viewport
|
||||
$browser->resize(375, 667)
|
||||
->visit(route('register.member'))
|
||||
->assertPresent('input[name="full_name"]');
|
||||
|
||||
// Test on desktop viewport
|
||||
$browser->resize(1920, 1080)
|
||||
->visit(route('register.member'))
|
||||
->assertPresent('input[name="full_name"]');
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user