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>
168 lines
5.1 KiB
PHP
168 lines
5.1 KiB
PHP
<?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"]');
|
|
});
|
|
}
|
|
}
|