feat(notice): NoticeSended 事件与登录提醒内置监听

This commit is contained in:
augushong
2026-10-12 12:09:01 +00:00
parent 02f77f4eca
commit 7aba2d02fe
6 changed files with 233 additions and 0 deletions

View File

@@ -0,0 +1,163 @@
<?php
declare(strict_types=1);
namespace tests\Feature;
use app\admin\model\SystemAdmin;
use app\common\event\AdminLoginSuccess\NoticeEvent;
use app\common\service\NoticeService;
use app\common\test\TestCase;
use think\facade\Cache;
use think\facade\Db;
use think\facade\Event;
/**
* 事件层集成测试.
*
* 覆盖:
* 1. send 触发 NoticeSended 事件,payload = [$notice(模型), $targets(投递行数组)]
* 2. 登录提醒开关开启时 NoticeEvent 落 admin_login 通知(inmail 行直接成功终态)
* 3. 开关默认关闭(无配置行)时不发
*
* fixture 均为事务内自造数据,tearDown 自动回滚;sysconfig 缓存显式清理
* (Cache 不受事务回滚影响,非 '0' 值会缓存 3600 秒)。
*/
class NoticeEventTest extends TestCase
{
// =========================================================================
// 1. NoticeSended 事件触发
// =========================================================================
public function test_send_triggers_notice_sended_event_with_notice_and_targets(): void
{
$adminId = $this->createAdmin();
// 临时注入收集器监听器(容器内与框架注册的 NoticeSended LogEvent 并存,互不影响)
$captured = [];
Event::listen('NoticeSended', function ($payload) use (&$captured) {
$captured[] = $payload;
});
$noticeId = NoticeService::send([$adminId], '事件测试', '内容');
$this->assertCount(1, $captured, 'send 应触发一次 NoticeSended 事件');
[$notice, $targets] = $captured[0];
$this->assertSame($noticeId, (int) $notice->id, 'payload[0] 应为本次创建的 notice 模型');
$this->assertIsArray($targets, 'payload[1] 应为投递行数组');
$this->assertCount(1, $targets);
$this->assertSame($adminId, (int) $targets[0]['admin_id']);
$this->assertSame('inmail', $targets[0]['channel']);
}
// =========================================================================
// 2. 登录提醒开关开启:NoticeEvent 落 admin_login 通知
// =========================================================================
public function test_login_notice_sent_when_scene_switch_on(): void
{
$adminId = $this->createAdmin(['username' => 'lgn_' . uniqid()]);
$admin = SystemAdmin::find($adminId);
$this->assertNotNull($admin, 'SystemAdmin 模型应能取到监听器入参形态');
$this->setLoginSceneSwitch('1');
(new NoticeEvent())->handle($admin);
$row = Db::name('system_notice')
->where('scene', 'admin_login')
->where('send_admin_id', 0)
->find();
$this->assertNotNull($row, '开关开启时应产生 admin_login 通知主体');
$this->assertSame('登录提醒', $row['title']);
// 文案含登录时间(Y-m-d H:i),跨分钟竞态下按正则断言而非逐字相等
$pattern = '/^账号 ' . preg_quote((string) $admin->username, '/') . ' 于 \d{4}-\d{2}-\d{2} \d{2}:\d{2} 登录成功$/u';
$this->assertMatchesRegularExpression($pattern, (string) $row['content']);
// inmail 行直接成功终态(无 email 地址的管理员 email 渠道被跳过)
$this->assertDatabaseHas('system_notice_target', [
'notice_id' => $row['id'],
'admin_id' => $adminId,
'channel' => 'inmail',
'status' => 2,
]);
$this->assertSame(
1,
Db::name('system_notice_target')->where('notice_id', $row['id'])->count(),
'无 email 管理员应仅展开 inmail 一行'
);
}
// =========================================================================
// 3. 登录提醒开关默认关闭
// =========================================================================
public function test_login_notice_skipped_when_scene_switch_absent(): void
{
$adminId = $this->createAdmin(['username' => 'lgn_' . uniqid()]);
$admin = SystemAdmin::find($adminId);
// 无配置行 = 默认关;清理可能被前序用例缓存的非 '0' 值
$this->clearLoginSceneSwitch();
(new NoticeEvent())->handle($admin);
$this->assertSame(
0,
Db::name('system_notice')->where('scene', 'admin_login')->where('send_admin_id', 0)->count(),
'开关缺省(无配置行)时不应产生 admin_login 通知'
);
}
// =========================================================================
// fixture 工厂(事务内运行,tearDown 自动回滚)
// =========================================================================
/**
* 造启用管理员.
*/
private function createAdmin(array $overrides = []): int
{
$data = array_merge([
'username' => 'evt_' . uniqid(),
'password' => 'not-a-real-password',
'nickname' => '事件测试用户',
'email' => '',
'status' => 1,
'create_time' => time(),
'update_time' => time(),
'delete_time' => 0,
], $overrides);
return (int) Db::name('system_admin')->insertGetId($data);
}
/**
* 写 notify 组登录提醒开关配置行并清缓存(缓存不受事务回滚影响).
*/
private function setLoginSceneSwitch(string $value): void
{
Db::name('system_config')->insert([
'name' => 'notify_login_scene_enable',
'group' => 'notify',
'value' => $value,
'remark' => 'NoticeEventTest fixture',
'sort' => 100,
'create_time' => time(),
'update_time' => time(),
]);
Cache::tag('sysconfig')->clear();
}
/**
* 删除 notify 组登录提醒开关配置行并清缓存.
*/
private function clearLoginSceneSwitch(): void
{
Db::name('system_config')
->where('group', 'notify')
->where('name', 'notify_login_scene_enable')
->delete();
Cache::tag('sysconfig')->clear();
}
}