'role-' . uniqid(), 'guard_name' => 'admin']); $role->givePermissionTo(Permission::firstOrCreate(['name' => 'mail-campaign.create', 'guard_name' => 'admin'])); $admin = User::factory()->create(); $admin->assignRole($role); return $admin; } public function test_existing_customer_email_is_matched_case_insensitively(): void { $customer = Customer::factory()->create(['email' => 'Bao.Dev@Example.com']); $this->actingAs($this->admin(), 'admin') ->postJson('/api/v1/administrator/mail-campaigns/resolve-emails', [ 'emails' => [' bao.dev@example.COM ', 'new.person@example.com'], ]) ->assertOk() ->assertJsonCount(1, 'data.customers') ->assertJsonPath('data.customers.0.uuid', $customer->uuid) ->assertJsonPath('data.unregistered', ['new.person@example.com']); } public function test_invalid_emails_are_rejected_with_clear_message(): void { $this->actingAs($this->admin(), 'admin') ->postJson('/api/v1/administrator/mail-campaigns/resolve-emails', [ 'emails' => ['not-an-email'], ]) ->assertUnprocessable() ->assertJsonValidationErrors(['emails.0' => 'Email "not-an-email" không hợp lệ.']); $this->actingAs($this->admin(), 'admin') ->postJson('/api/v1/administrator/mail-campaigns/resolve-emails', ['emails' => []]) ->assertUnprocessable() ->assertJsonValidationErrors(['emails' => 'Nhập ít nhất một email.']); } public function test_store_attaches_customer_typed_as_email_with_different_case(): void { Queue::fake(); $customer = Customer::factory()->create(['email' => 'Bao.Dev@Example.com', 'email_marketing' => 1]); $this->actingAs($this->admin(), 'admin') ->postJson('/api/v1/administrator/mail-campaigns', [ 'subject' => 'Tin tức', 'message' => '

Hi

', 'recipient_type' => 'selected', 'uuids' => [$customer->uuid], 'emails' => ['bao.dev@example.com'], ]) ->assertOk() ->assertJsonPath('data.total_recipients', 1); Queue::assertPushed( SendMailCampaignRecipient::class, fn (SendMailCampaignRecipient $job) => $this->jobCustomerId($job) === $customer->id ); } private function jobCustomerId(SendMailCampaignRecipient $job): ?int { return (fn () => $this->customerId)->call($job); } }