buildTemplateContext( [ 'name' => 'John Doe', 'last_date' => '2026-03-01', ], [ 'parent_name' => 'Jane Doe', 'phone' => '555-1212', ] ); $this->assertSame('Jane Doe', $context['{{parent_name}}']); $this->assertSame('John Doe', $context['{{student_name}}']); $this->assertSame('2026-03-01', $context['{{incident_date}}']); $this->assertSame('555-1212', $context['{{voicemail_phone}}']); } public function test_render_template_uses_model_get_template(): void { $model = Mockery::mock(AttendanceEmailTemplate::class); $model->shouldReceive('getTemplate') ->once() ->with('ABS_1', 'default') ->andReturn([ 'subject' => 'Notice for {{student_name}}', 'body_html' => '

Date: {{incident_date}}

', ]); $service = new AttendanceEmailComposerService($model); $rendered = $service->renderTemplate('ABS_1', 'default', [ '{{student_name}}' => 'John Doe', '{{incident_date}}' => '2026-03-01', ]); $this->assertSame( ['Notice for John Doe', '

Date: 2026-03-01

'], $rendered ); } public function test_pick_variant_returns_override_when_present(): void { $model = Mockery::mock(AttendanceEmailTemplate::class); $service = new AttendanceEmailComposerService($model); $this->assertSame('custom_variant', $service->pickVariant('ABS_2', 'custom_variant')); } public function test_pick_variant_returns_no_answer_for_abs_2(): void { $model = Mockery::mock(AttendanceEmailTemplate::class); $service = new AttendanceEmailComposerService($model); $this->assertSame('no_answer', $service->pickVariant('ABS_2')); } public function test_pick_variant_returns_default_for_other_codes(): void { $model = Mockery::mock(AttendanceEmailTemplate::class); $service = new AttendanceEmailComposerService($model); $this->assertSame('default', $service->pickVariant('ABS_1')); } public function test_normalize_body_to_html_keeps_html_when_tags_present(): void { $model = Mockery::mock(AttendanceEmailTemplate::class); $service = new AttendanceEmailComposerService($model); $body = '

Hello

'; $this->assertSame($body, $service->normalizeBodyToHtml($body)); } public function test_normalize_body_to_html_converts_plain_text_to_br_html(): void { $model = Mockery::mock(AttendanceEmailTemplate::class); $service = new AttendanceEmailComposerService($model); $result = $service->normalizeBodyToHtml("Hello\nWorld"); $this->assertStringContainsString('Hello', $result); $this->assertStringContainsString('assertStringContainsString('World', $result); } public function test_build_fallback_auto_email_returns_subject_and_body(): void { $model = Mockery::mock(AttendanceEmailTemplate::class); $service = new AttendanceEmailComposerService($model); [$subject, $body] = $service->buildFallbackAutoEmail('ABS_1', [ 'name' => 'John Doe', 'violation' => '1 Unreported Absence', 'last_date' => '2026-03-01', ], 'Jane Doe'); $this->assertSame('Attendance Notice: Unreported Absence', $subject); $this->assertStringContainsString('John Doe', $body); $this->assertStringContainsString('2026-03-01', $body); $this->assertStringContainsString('Jane Doe', $body); } }