Files
chatroom/tests/Feature/ChatAppointmentControllerTest.php
2026-04-14 22:41:33 +08:00

156 lines
5.1 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* 文件功能:聊天室快捷任命控制器测试
*
* 验证聊天室用户名片中的任命/撤销操作会给目标用户写入带右下角提示的私聊消息。
*/
namespace Tests\Feature;
use App\Jobs\SaveMessageJob;
use App\Models\Department;
use App\Models\Position;
use App\Models\Room;
use App\Models\User;
use App\Models\UserPosition;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Facades\Redis;
use Tests\TestCase;
/**
* 聊天室快捷任命控制器测试类。
*/
class ChatAppointmentControllerTest extends TestCase
{
use RefreshDatabase;
/**
* 每个测试前清空 Redis避免跨用例的聊天室消息污染断言。
*/
protected function setUp(): void
{
parent::setUp();
Redis::flushall();
}
/**
* 测试任命职务后会给目标用户写入带 toast 的私聊提示。
*/
public function test_appoint_pushes_private_toast_notification_to_target(): void
{
Queue::fake();
[$admin, $target, $room, $position] = $this->createAppointmentActors();
$response = $this->actingAs($admin)->postJson(route('chat.appoint.appoint'), [
'username' => $target->username,
'position_id' => $position->id,
'remark' => '聊天室快速任命',
'room_id' => $room->id,
]);
$response->assertOk()->assertJson([
'status' => 'success',
'message' => "已成功将【{$target->username}】任命为【{$position->name}】。",
]);
$privateMessage = $this->findPrivateSystemMessage($room->id, $target->username, '已任命你为');
$this->assertNotNull($privateMessage);
$this->assertSame('✨ 职务任命通知', $privateMessage['toast_notification']['title'] ?? null);
$this->assertSame('✨', $privateMessage['toast_notification']['icon'] ?? null);
$this->assertSame('#a855f7', $privateMessage['toast_notification']['color'] ?? null);
Queue::assertPushed(SaveMessageJob::class, 1);
}
/**
* 测试撤销职务后会给目标用户写入带 toast 的私聊提示。
*/
public function test_revoke_pushes_private_toast_notification_to_target(): void
{
Queue::fake();
[$admin, $target, $room, $position] = $this->createAppointmentActors();
UserPosition::create([
'user_id' => $target->id,
'position_id' => $position->id,
'appointed_by_user_id' => $admin->id,
'appointed_at' => now()->subDay(),
'remark' => '已有职务',
'is_active' => true,
]);
$target->update(['user_level' => $position->level]);
$response = $this->actingAs($admin)->postJson(route('chat.appoint.revoke'), [
'username' => $target->username,
'remark' => '聊天室快速撤销',
'room_id' => $room->id,
]);
$response->assertOk()->assertJson([
'status' => 'success',
]);
$privateMessage = $this->findPrivateSystemMessage($room->id, $target->username, '已撤销你的');
$this->assertNotNull($privateMessage);
$this->assertSame('📋 职务变动通知', $privateMessage['toast_notification']['title'] ?? null);
$this->assertSame('📋', $privateMessage['toast_notification']['icon'] ?? null);
$this->assertSame('#6b7280', $privateMessage['toast_notification']['color'] ?? null);
Queue::assertPushed(SaveMessageJob::class, 1);
}
/**
* 创建任命测试共用的操作者、目标用户、房间与职务。
*
* @return array{0: User, 1: User, 2: Room, 3: Position}
*/
private function createAppointmentActors(): array
{
$admin = User::factory()->create([
'id' => 1,
'user_level' => 100,
]);
$target = User::factory()->create([
'user_level' => 1,
]);
$room = Room::create([
'room_name' => '职务操作房',
]);
$department = Department::create([
'name' => '办公厅',
'rank' => 90,
]);
$position = Position::create([
'department_id' => $department->id,
'name' => '巡查员',
'icon' => '✨',
'rank' => 50,
'level' => 20,
]);
return [$admin, $target, $room, $position];
}
/**
* 从房间消息缓存中定位目标用户收到的系统私聊提示。
*
* @return array<string, mixed>|null
*/
private function findPrivateSystemMessage(int $roomId, string $targetUsername, string $needle): ?array
{
$messages = Redis::lrange("room:{$roomId}:messages", 0, -1);
return collect($messages)
->map(fn (string $item) => json_decode($item, true))
->first(fn (array $item) => ($item['from_user'] ?? null) === '系统'
&& ($item['to_user'] ?? null) === $targetUsername
&& str_contains((string) ($item['content'] ?? ''), $needle));
}
}