createDefinitionWithMailChannel('welcome', 'core.auth', 'core', 'core', [ 'subject' => ['ko' => '[{app_name}] 환영합니다', 'en' => '[{app_name}] Welcome'], 'body' => ['ko' => '
{name}님 환영합니다
', 'en' => 'Welcome {name}
'], ]); $user = User::factory()->create(['name' => '홍길동', 'email' => 'hong@example.com']); $notification = new GenericNotification('welcome', 'core.auth', [ 'name' => $user->name, 'app_name' => config('app.name'), 'action_url' => config('app.url') . '/login', 'site_url' => config('app.url'), ]); $mailable = $notification->toMail($user); $this->assertInstanceOf(DbTemplateMail::class, $mailable); $this->assertEquals('welcome', $mailable->getTemplateType()); $this->assertFalse($mailable->isSkipped()); } /** * welcome 알림의 DbTemplateMail에 수신자가 설정됨 */ public function test_welcome_notification_sets_recipient(): void { $this->createDefinitionWithMailChannel('welcome', 'core.auth', 'core', 'core', [ 'subject' => ['ko' => '환영', 'en' => 'Welcome'], 'body' => ['ko' => '환영
', 'en' => 'Welcome
'], ]); $user = User::factory()->create(['name' => '홍길동', 'email' => 'hong@example.com']); $notification = new GenericNotification('welcome', 'core.auth', [ 'name' => '홍길동', 'app_name' => 'G7 Test', 'action_url' => 'https://g7.test/login', 'site_url' => 'https://g7.test', ]); $mailable = $notification->toMail($user); $to = collect($mailable->to)->first(); $this->assertEquals('hong@example.com', $to['address']); $this->assertEquals('홍길동', $to['name']); } /** * welcome 알림이 템플릿 미존재 시 스킵 인스턴스 반환 */ public function test_welcome_notification_returns_skipped_when_no_template(): void { $user = User::factory()->create(['email' => 'notemplate@example.com']); $notification = new GenericNotification('welcome', 'core.auth', [ 'name' => $user->name ?? '', 'app_name' => 'G7 Test', 'action_url' => 'https://g7.test/login', 'site_url' => 'https://g7.test', ]); $mailable = $notification->toMail($user); $this->assertInstanceOf(DbTemplateMail::class, $mailable); $this->assertTrue($mailable->isSkipped()); } // ======================================================================== // Reset Password 알림 + DbTemplateMail // ======================================================================== /** * reset_password 알림이 활성 템플릿으로 DbTemplateMail 생성 */ public function test_reset_password_notification_creates_db_template_mail(): void { $this->createDefinitionWithMailChannel('reset_password', 'core.auth', 'core', 'core', [ 'subject' => ['ko' => '비밀번호 재설정', 'en' => 'Password Reset'], 'body' => ['ko' => '{name}님, 비밀번호 재설정
', 'en' => 'Reset password, {name}
'], ]); $user = User::factory()->create(); $notification = new GenericNotification('reset_password', 'core.auth', [ 'name' => $user->name ?? '', 'app_name' => 'G7 Test', 'action_url' => 'https://g7.test/reset-password?token=abc', 'expire_minutes' => '60', 'site_url' => 'https://g7.test', ]); $mailable = $notification->toMail($user); $this->assertInstanceOf(DbTemplateMail::class, $mailable); $this->assertEquals('reset_password', $mailable->getTemplateType()); } // ======================================================================== // Password Changed 알림 + DbTemplateMail // ======================================================================== /** * password_changed 알림이 활성 템플릿으로 DbTemplateMail 생성 */ public function test_password_changed_notification_creates_db_template_mail(): void { $this->createDefinitionWithMailChannel('password_changed', 'core.auth', 'core', 'core', [ 'subject' => ['ko' => '비밀번호 변경', 'en' => 'Password Changed'], 'body' => ['ko' => '{name}님, 비밀번호 변경됨
', 'en' => 'Password changed, {name}
'], ]); $user = User::factory()->create(); $notification = new GenericNotification('password_changed', 'core.auth', [ 'name' => $user->name ?? '', 'app_name' => 'G7 Test', 'action_url' => 'https://g7.test/login', 'site_url' => 'https://g7.test', ]); $mailable = $notification->toMail($user); $this->assertInstanceOf(DbTemplateMail::class, $mailable); $this->assertEquals('password_changed', $mailable->getTemplateType()); } /** * password_changed 알림이 비활성 템플릿에서 스킵 반환 */ public function test_password_changed_notification_returns_skipped_when_inactive(): void { $this->createDefinitionWithMailChannel('password_changed', 'core.auth', 'core', 'core', [ 'subject' => ['ko' => '비밀번호 변경', 'en' => 'Password Changed'], 'body' => ['ko' => '변경됨
', 'en' => 'Changed
'], ], templateActive: false); $user = User::factory()->create(['email' => 'changed@example.com']); $notification = new GenericNotification('password_changed', 'core.auth', [ 'name' => $user->name ?? '', 'app_name' => 'G7 Test', 'action_url' => 'https://g7.test/login', 'site_url' => 'https://g7.test', ]); $mailable = $notification->toMail($user); $this->assertInstanceOf(DbTemplateMail::class, $mailable); $this->assertTrue($mailable->isSkipped()); } // ======================================================================== // 헬퍼 메서드 // ======================================================================== /** * NotificationDefinition + NotificationTemplate(mail 채널) 생성 헬퍼. * * @param string $type * @param string $hookPrefix * @param string $extensionType * @param string $extensionIdentifier * @param array $templateData ['subject' => [...], 'body' => [...]] * @param bool $templateActive * @return NotificationDefinition */ private function createDefinitionWithMailChannel( string $type, string $hookPrefix, string $extensionType, string $extensionIdentifier, array $templateData, bool $templateActive = true, ): NotificationDefinition { $definition = NotificationDefinition::create([ 'type' => $type, 'hook_prefix' => $hookPrefix, 'extension_type' => $extensionType, 'extension_identifier' => $extensionIdentifier, 'name' => ['ko' => $type, 'en' => $type], 'variables' => [], 'channels' => ['mail'], 'hooks' => [], 'is_active' => true, 'is_default' => true, ]); NotificationTemplate::create([ 'definition_id' => $definition->id, 'channel' => 'mail', 'subject' => $templateData['subject'], 'body' => $templateData['body'], 'is_active' => $templateActive, 'is_default' => true, ]); app(NotificationDefinitionService::class)->invalidateCache($type); app(NotificationTemplateService::class)->invalidateCache($type, 'mail'); return $definition; } }