'Full Administrator', 'guard_name' => 'admin']); $this->admin = User::factory()->create(); $this->admin->assignRole('Full Administrator'); $this->customer = Customer::factory()->create(['fullname' => 'Nguyễn Văn A']); $this->template = Template::create([ 'type_id' => 0, 'format' => 'html', 'name' => 'Khuyến mãi', 'subject' => 'Chào {{client_name}}', 'message' => '
Xin chào {{$client_name}}, mã {{promo_code}}
', 'metadata' => [ 'variables' => [ ['key' => 'client_name', 'label' => 'Tên', 'type' => 'string', 'example' => 'Quý khách'], ['key' => 'promo_code', 'label' => 'Mã', 'type' => 'string', 'example' => 'TGS10'], ], 'mail' => ['cc' => ['sale@example.com']], ], 'status' => 1, ]); } public function test_preview_renders_template_for_customer(): void { $this->actingAs($this->admin, 'admin') ->postJson("/api/v1/administrator/customers/{$this->customer->uuid}/email-preview", [ 'template_id' => $this->template->id, ]) ->assertOk() ->assertJsonPath('data.subject', 'Chào Nguyễn Văn A') ->assertJsonPath('data.html', 'Xin chào Nguyễn Văn A, mã TGS10
') ->assertJsonPath('data.cc', ['sale@example.com']); } public function test_send_uses_edited_html_without_template_cc(): void { Mail::fake(); $this->actingAs($this->admin, 'admin') ->postJson("/api/v1/administrator/customers/{$this->customer->uuid}/send-email", [ 'template_id' => $this->template->id, 'subject' => 'Tiêu đề đã sửa', 'message' => 'Nội dung đã sửa
', 'to' => $this->customer->email, ]) ->assertOk(); Mail::assertSent(GenericTemplateMail::class, fn (GenericTemplateMail $mail) => $mail->hasTo($this->customer->email) && $mail->renderedSubject === 'Tiêu đề đã sửa' && $mail->renderedHtml === 'Nội dung đã sửa
' && !array_key_exists('cc', $mail->mailConfig)); $this->assertDatabaseHas('mail', ['customer_id' => $this->customer->id, 'message' => 'Nội dung đã sửa
']); } public function test_email_layout_wraps_content_with_header_and_footer(): void { $html = $this->actingAs($this->admin, 'admin') ->postJson("/api/v1/administrator/customers/{$this->customer->uuid}/email-layout", [ 'message' => 'Xin chào {{client_name}}
', ]) ->assertOk() ->json('data.html'); $this->assertStringContainsString('Xin chào Nguyễn Văn A
', $html); $this->assertStringContainsString('class="Header"', $html); $this->assertStringContainsString('class="Footer"', $html); } public function test_manual_email_with_inserted_layout_is_not_wrapped_again(): void { Mail::fake(); $this->actingAs($this->admin, 'admin') ->postJson("/api/v1/administrator/customers/{$this->customer->uuid}/send-email", [ 'subject' => 'Thông báo', 'message' => 'Nội dung
', 'to' => $this->customer->email, 'with_layout' => false, ]) ->assertOk(); Mail::assertQueued(ManualCustomerEmail::class, function (ManualCustomerEmail $mail) { $html = $mail->render(); return substr_count($html, 'class="Header"') === 1 && str_contains($html, 'Nội dung
'); }); } public function test_sent_emails_are_listed_with_sender_and_bcc(): void { Mail::fake(); $base = "/api/v1/administrator/customers/{$this->customer->uuid}"; $this->actingAs($this->admin, 'admin')->postJson("{$base}/send-email", [ 'subject' => 'Thông tin VPS', 'message' => 'Thông tin
', 'to' => $this->customer->email, 'bcc' => 'audit@example.com', ])->assertOk(); $item = $this->getJson("{$base}/emails") ->assertOk() ->assertJsonPath('data.total', 1) ->assertJsonPath('data.items.0.bcc', 'audit@example.com') ->assertJsonPath('data.items.0.to', $this->customer->email) ->assertJsonPath('data.items.0.sent_by', $this->admin->name ?: $this->admin->username) ->assertJsonMissingPath('data.items.0.html') ->json('data.items.0'); $this->getJson("{$base}/emails/{$item['id']}") ->assertOk() ->assertJsonPath('data.html', 'Thông tin
'); $other = Customer::factory()->create(); $this->getJson("/api/v1/administrator/customers/{$other->uuid}/emails/{$item['id']}")->assertNotFound(); } public function test_send_reports_error_when_mail_is_disabled(): void { \App\Models\Setting::updateOrCreate(['key' => 'email_settings'], ['value' => json_encode(['mail_enabled' => false])]); $this->actingAs($this->admin, 'admin') ->postJson("/api/v1/administrator/customers/{$this->customer->uuid}/send-email", [ 'subject' => 'Thông báo', 'message' => 'Nội dung
', ]) ->assertStatus(422); $this->assertDatabaseMissing('mail', ['customer_id' => $this->customer->id]); } public function test_send_attaches_uploaded_files(): void { Mail::fake(); Storage::fake('local'); $base = "/api/v1/administrator/customers/{$this->customer->uuid}/send-email"; $this->actingAs($this->admin, 'admin') ->post($base, [ 'subject' => 'Hợp đồng', 'message' => 'Gửi hợp đồng
', 'to' => $this->customer->email, 'attachments' => [ UploadedFile::fake()->create('hop-dong.pdf', 100, 'application/pdf'), UploadedFile::fake()->create('phu-luc.docx', 50), ], ], ['Accept' => 'application/json']) ->assertOk(); Mail::assertQueued(ManualCustomerEmail::class, function (ManualCustomerEmail $mail) { $names = array_map(fn ($attachment) => $attachment->as, $mail->attachments()); return $names === ['hop-dong.pdf', 'phu-luc.docx']; }); $this->assertCount(2, Storage::disk('local')->allFiles("customer-emails/{$this->customer->id}")); $this->post($base, [ 'subject' => 'Hợp đồng', 'message' => 'Gửi hợp đồng
', 'attachments' => [UploadedFile::fake()->create('script.php', 1)], ], ['Accept' => 'application/json'])->assertStatus(422); } }