artisan('db:seed', ['--class' => 'RoleSeeder']); } public function test_public_registration_form_is_accessible(): void { $response = $this->get(route('register.member')); $response->assertStatus(200); $response->assertSee('Register'); $response->assertSee('Full Name'); $response->assertSee('Email'); $response->assertSee('Password'); } public function test_can_register_with_valid_data(): void { Mail::fake(); $response = $this->post(route('register.member.store'), [ 'full_name' => 'John Doe', 'email' => 'john@example.com', 'password' => 'Password123!', 'password_confirmation' => 'Password123!', 'phone' => '0912345678', 'address_line_1' => '123 Test St', 'city' => 'Taipei', 'postal_code' => '100', 'emergency_contact_name' => 'Jane Doe', 'emergency_contact_phone' => '0987654321', 'terms_accepted' => true, ]); $response->assertRedirect(route('member.dashboard')); $response->assertSessionHas('status'); // Verify user created $this->assertDatabaseHas('users', [ 'email' => 'john@example.com', ]); // Verify member created $this->assertDatabaseHas('members', [ 'full_name' => 'John Doe', 'email' => 'john@example.com', 'phone' => '0912345678', 'membership_status' => Member::STATUS_PENDING, ]); } public function test_user_and_member_records_created(): void { Mail::fake(); $this->post(route('register.member.store'), [ 'full_name' => 'John Doe', 'email' => 'john@example.com', 'password' => 'Password123!', 'password_confirmation' => 'Password123!', 'phone' => '0912345678', 'terms_accepted' => true, ]); $user = User::where('email', 'john@example.com')->first(); $member = Member::where('email', 'john@example.com')->first(); $this->assertNotNull($user); $this->assertNotNull($member); $this->assertEquals($user->id, $member->user_id); $this->assertTrue(Hash::check('Password123!', $user->password)); } public function test_user_is_auto_logged_in_after_registration(): void { Mail::fake(); $response = $this->post(route('register.member.store'), [ 'full_name' => 'John Doe', 'email' => 'john@example.com', 'password' => 'Password123!', 'password_confirmation' => 'Password123!', 'terms_accepted' => true, ]); $this->assertAuthenticated(); $user = User::where('email', 'john@example.com')->first(); $this->assertEquals($user->id, auth()->id()); } public function test_welcome_email_is_sent(): void { Mail::fake(); $this->post(route('register.member.store'), [ 'full_name' => 'John Doe', 'email' => 'john@example.com', 'password' => 'Password123!', 'password_confirmation' => 'Password123!', 'terms_accepted' => true, ]); Mail::assertQueued(MemberRegistrationWelcomeMail::class, function ($mail) { return $mail->hasTo('john@example.com'); }); } public function test_validation_fails_with_invalid_email(): void { $response = $this->post(route('register.member.store'), [ 'full_name' => 'John Doe', 'email' => 'invalid-email', 'password' => 'Password123!', 'password_confirmation' => 'Password123!', 'terms_accepted' => true, ]); $response->assertSessionHasErrors('email'); $this->assertDatabaseCount('users', 0); $this->assertDatabaseCount('members', 0); } public function test_validation_fails_with_duplicate_email(): void { // Create existing user User::factory()->create(['email' => 'existing@example.com']); $response = $this->post(route('register.member.store'), [ 'full_name' => 'John Doe', 'email' => 'existing@example.com', 'password' => 'Password123!', 'password_confirmation' => 'Password123!', 'terms_accepted' => true, ]); $response->assertSessionHasErrors('email'); } public function test_validation_fails_with_duplicate_email_in_members(): void { // Create existing member without user Member::factory()->create(['email' => 'existing@example.com', 'user_id' => null]); $response = $this->post(route('register.member.store'), [ 'full_name' => 'John Doe', 'email' => 'existing@example.com', 'password' => 'Password123!', 'password_confirmation' => 'Password123!', 'terms_accepted' => true, ]); $response->assertSessionHasErrors('email'); } public function test_password_confirmation_required(): void { $response = $this->post(route('register.member.store'), [ 'full_name' => 'John Doe', 'email' => 'john@example.com', 'password' => 'Password123!', 'password_confirmation' => 'DifferentPassword', 'terms_accepted' => true, ]); $response->assertSessionHasErrors('password'); $this->assertDatabaseCount('users', 0); } public function test_terms_acceptance_required(): void { $response = $this->post(route('register.member.store'), [ 'full_name' => 'John Doe', 'email' => 'john@example.com', 'password' => 'Password123!', 'password_confirmation' => 'Password123!', 'terms_accepted' => false, ]); $response->assertSessionHasErrors('terms_accepted'); $this->assertDatabaseCount('users', 0); } public function test_registration_creates_audit_log(): void { Mail::fake(); $this->post(route('register.member.store'), [ 'full_name' => 'John Doe', 'email' => 'john@example.com', 'password' => 'Password123!', 'password_confirmation' => 'Password123!', 'terms_accepted' => true, ]); $this->assertDatabaseHas('audit_logs', [ 'action' => 'member.self_registered', ]); } public function test_member_status_is_pending_after_registration(): void { Mail::fake(); $this->post(route('register.member.store'), [ 'full_name' => 'John Doe', 'email' => 'john@example.com', 'password' => 'Password123!', 'password_confirmation' => 'Password123!', 'terms_accepted' => true, ]); $member = Member::where('email', 'john@example.com')->first(); $this->assertEquals(Member::STATUS_PENDING, $member->membership_status); $this->assertEquals(Member::TYPE_REGULAR, $member->membership_type); } public function test_required_fields_validation(): void { $response = $this->post(route('register.member.store'), []); $response->assertSessionHasErrors(['full_name', 'email', 'password', 'terms_accepted']); } public function test_optional_fields_can_be_null(): void { Mail::fake(); $response = $this->post(route('register.member.store'), [ 'full_name' => 'John Doe', 'email' => 'john@example.com', 'password' => 'Password123!', 'password_confirmation' => 'Password123!', 'terms_accepted' => true, // Optional fields omitted ]); $response->assertRedirect(route('member.dashboard')); $member = Member::where('email', 'john@example.com')->first(); $this->assertNull($member->phone); $this->assertNull($member->address_line_1); } }