626 lines
22 KiB
PHP
626 lines
22 KiB
PHP
<?php
|
||
|
||
/**
|
||
* 文件功能:聊天室控制器功能测试
|
||
*
|
||
* 覆盖进房、发言、图片消息、权限限制与广播范围等关键聊天流程。
|
||
*/
|
||
|
||
namespace Tests\Feature;
|
||
|
||
use App\Events\MessageSent;
|
||
use App\Models\Room;
|
||
use App\Models\User;
|
||
use Illuminate\Broadcasting\PresenceChannel;
|
||
use Illuminate\Broadcasting\PrivateChannel;
|
||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Http\UploadedFile;
|
||
use Illuminate\Support\Facades\Broadcast;
|
||
use Illuminate\Support\Facades\Redis;
|
||
use Illuminate\Support\Facades\Storage;
|
||
use Illuminate\Support\Facades\URL;
|
||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||
use Tests\TestCase;
|
||
|
||
/**
|
||
* 类功能:验证聊天室核心控制器的关键行为。
|
||
*/
|
||
class ChatControllerTest extends TestCase
|
||
{
|
||
use RefreshDatabase;
|
||
|
||
/**
|
||
* 每个测试前清空 Redis,避免跨用例污染在线状态与消息缓存。
|
||
*/
|
||
protected function setUp(): void
|
||
{
|
||
parent::setUp();
|
||
Redis::flushall();
|
||
}
|
||
|
||
/**
|
||
* 测试用户可以正常进入聊天室页面。
|
||
*/
|
||
public function test_can_view_room(): void
|
||
{
|
||
$room = Room::create(['room_name' => 'testroom']);
|
||
$user = User::factory()->create();
|
||
|
||
$response = $this->actingAs($user)->get(route('chat.room', $room->id));
|
||
|
||
$response->assertStatus(200);
|
||
$response->assertViewIs('chat.frame');
|
||
|
||
// Assert user was added to room in redis
|
||
$this->assertEquals(1, Redis::hexists("room:{$room->id}:users", $user->username));
|
||
}
|
||
|
||
/**
|
||
* 测试关闭房间会拒绝普通用户直接进入。
|
||
*/
|
||
public function test_cannot_view_closed_room_without_bypass_permission(): void
|
||
{
|
||
$room = Room::create([
|
||
'room_name' => 'closed',
|
||
'door_open' => false,
|
||
]);
|
||
$user = User::factory()->create([
|
||
'user_level' => 1,
|
||
]);
|
||
|
||
$response = $this->actingAs($user)->get(route('chat.room', $room->id));
|
||
|
||
$response->assertForbidden();
|
||
$this->assertSame(0, Redis::hexists("room:{$room->id}:users", $user->username));
|
||
}
|
||
|
||
/**
|
||
* 测试等级不足的用户不能进入受限房间。
|
||
*/
|
||
public function test_cannot_view_room_when_level_is_below_permit_level(): void
|
||
{
|
||
$room = Room::create([
|
||
'room_name' => 'viprm',
|
||
'permit_level' => 10,
|
||
'door_open' => true,
|
||
]);
|
||
$user = User::factory()->create([
|
||
'user_level' => 5,
|
||
]);
|
||
|
||
$response = $this->actingAs($user)->get(route('chat.room', $room->id));
|
||
|
||
$response->assertForbidden();
|
||
$this->assertSame(0, Redis::hexists("room:{$room->id}:users", $user->username));
|
||
}
|
||
|
||
/**
|
||
* 测试只有已成功进入房间的用户才可通过 Presence 频道鉴权。
|
||
*/
|
||
public function test_room_presence_channel_requires_room_access_and_join_state(): void
|
||
{
|
||
$room = Room::create([
|
||
'room_name' => 'guard',
|
||
'door_open' => true,
|
||
]);
|
||
$user = User::factory()->create();
|
||
$channelCallback = Broadcast::driver()->getChannels()->get('room.{roomId}');
|
||
|
||
$this->assertIsCallable($channelCallback);
|
||
$this->assertFalse($channelCallback($user, (string) $room->id));
|
||
|
||
$this->actingAs($user)->get(route('chat.room', $room->id));
|
||
|
||
$authorizedPayload = $channelCallback($user, (string) $room->id);
|
||
$this->assertIsArray($authorizedPayload);
|
||
$this->assertSame($user->id, $authorizedPayload['id'] ?? null);
|
||
|
||
Redis::del("room:{$room->id}:users");
|
||
$this->assertFalse($channelCallback($user, (string) $room->id));
|
||
}
|
||
|
||
/**
|
||
* 测试主干默认聊天室页面不会渲染虚拟形象挂载点和配置。
|
||
*/
|
||
public function test_room_view_does_not_render_avatar_widget_or_config_by_default(): void
|
||
{
|
||
$room = Room::create(['room_name' => 'avguard']);
|
||
$user = User::factory()->create();
|
||
|
||
$response = $this->actingAs($user)->get(route('chat.room', $room->id));
|
||
|
||
$response->assertOk();
|
||
$response->assertDontSee('chat-avatar-widget');
|
||
$response->assertDontSee('chatAvatarWidget');
|
||
}
|
||
|
||
/**
|
||
* 测试聊天室输入区会渲染系统播报屏蔽按钮与对应选项。
|
||
*/
|
||
public function test_room_view_renders_block_system_sender_controls(): void
|
||
{
|
||
$room = Room::create(['room_name' => 'blockmenu']);
|
||
$user = User::factory()->create();
|
||
|
||
$response = $this->actingAs($user)->get(route('chat.room', $room->id));
|
||
|
||
$response->assertOk();
|
||
$response->assertSee('🔕 屏蔽', false);
|
||
$response->assertSee('🔇 禁音', false);
|
||
$response->assertSee('钓鱼播报');
|
||
$response->assertSee('星海小博士');
|
||
$response->assertSee('百家乐');
|
||
$response->assertSee('跑马');
|
||
$response->assertSee('神秘箱子');
|
||
$response->assertSee('chat_blocked_system_senders');
|
||
$response->assertSee('toggleBlockedSystemSender');
|
||
}
|
||
|
||
/**
|
||
* 测试用户可以发送普通文本消息。
|
||
*/
|
||
public function test_can_send_message(): void
|
||
{
|
||
$room = Room::create(['room_name' => 'test_send']);
|
||
$user = User::factory()->create();
|
||
|
||
// 进房
|
||
$this->actingAs($user)->get(route('chat.room', $room->id));
|
||
|
||
$response = $this->actingAs($user)->postJson(route('chat.send', $room->id), [
|
||
'to_user' => '大家',
|
||
'content' => '测试消息',
|
||
'is_secret' => false,
|
||
'font_color' => '#000000',
|
||
'action' => '微笑',
|
||
]);
|
||
|
||
$response->assertStatus(200);
|
||
$response->assertJson(['status' => 'success']);
|
||
|
||
// 查看 Redis 里的消息记录
|
||
$messages = Redis::lrange("room:{$room->id}:messages", 0, -1);
|
||
$this->assertNotEmpty($messages);
|
||
|
||
$found = false;
|
||
foreach ($messages as $msgJson) {
|
||
$msg = json_decode($msgJson, true);
|
||
if ($msg['from_user'] === $user->username && $msg['content'] === '测试消息') {
|
||
$found = true;
|
||
break;
|
||
}
|
||
}
|
||
$this->assertTrue($found, 'Message not found in Redis');
|
||
}
|
||
|
||
/**
|
||
* 测试发送接口会拦截不在白名单内的危险动作值。
|
||
*/
|
||
public function test_send_message_rejects_invalid_action_value(): void
|
||
{
|
||
$room = Room::create(['room_name' => 'badact']);
|
||
$user = User::factory()->create();
|
||
|
||
$this->actingAs($user)->get(route('chat.room', $room->id));
|
||
|
||
$response = $this->actingAs($user)->postJson(route('chat.send', $room->id), [
|
||
'to_user' => '大家',
|
||
'content' => '危险动作测试',
|
||
'is_secret' => false,
|
||
'font_color' => '#000000',
|
||
'action' => '\"></span><img src=x onerror=alert(1)>',
|
||
]);
|
||
|
||
$response->assertStatus(422);
|
||
$response->assertJsonValidationErrors('action');
|
||
}
|
||
|
||
/**
|
||
* 测试定向消息仅广播到发送方与接收方私有频道。
|
||
*/
|
||
public function test_targeted_message_event_uses_private_user_channels(): void
|
||
{
|
||
$sender = User::factory()->create(['username' => 'sender-user']);
|
||
$receiver = User::factory()->create(['username' => 'receiver-user']);
|
||
|
||
$event = new MessageSent(1, [
|
||
'room_id' => 1,
|
||
'from_user' => $sender->username,
|
||
'to_user' => $receiver->username,
|
||
'content' => '只给你看',
|
||
'is_secret' => true,
|
||
'font_color' => '#000000',
|
||
'action' => '',
|
||
'sent_at' => now()->toDateTimeString(),
|
||
]);
|
||
|
||
$channels = $event->broadcastOn();
|
||
|
||
$this->assertCount(2, $channels);
|
||
$this->assertContainsOnlyInstancesOf(PrivateChannel::class, $channels);
|
||
$this->assertSame([
|
||
'private-user.'.$sender->id,
|
||
'private-user.'.$receiver->id,
|
||
], array_map(fn (PrivateChannel $channel) => $channel->name, $channels));
|
||
}
|
||
|
||
/**
|
||
* 测试公共消息仍广播到房间 Presence 频道。
|
||
*/
|
||
public function test_public_message_event_still_uses_room_presence_channel(): void
|
||
{
|
||
$event = new MessageSent(3, [
|
||
'room_id' => 3,
|
||
'from_user' => 'tester',
|
||
'to_user' => '大家',
|
||
'content' => '公开消息',
|
||
'is_secret' => false,
|
||
'font_color' => '#000000',
|
||
'action' => '',
|
||
'sent_at' => now()->toDateTimeString(),
|
||
]);
|
||
|
||
$channels = $event->broadcastOn();
|
||
|
||
$this->assertCount(1, $channels);
|
||
$this->assertInstanceOf(PresenceChannel::class, $channels[0]);
|
||
$this->assertSame('presence-room.3', $channels[0]->name);
|
||
}
|
||
|
||
/**
|
||
* 测试文本内容为字符串 0 时仍可正常发送。
|
||
*/
|
||
public function test_can_send_zero_message_content(): void
|
||
{
|
||
$room = Room::create(['room_name' => 'send0']);
|
||
$user = User::factory()->create();
|
||
|
||
$this->actingAs($user)->get(route('chat.room', $room->id));
|
||
|
||
$response = $this->actingAs($user)->postJson(route('chat.send', $room->id), [
|
||
'to_user' => '大家',
|
||
'content' => '0',
|
||
'is_secret' => false,
|
||
'font_color' => '#000000',
|
||
'action' => '',
|
||
]);
|
||
|
||
$response->assertOk();
|
||
$response->assertJson(['status' => 'success']);
|
||
|
||
$messages = Redis::lrange("room:{$room->id}:messages", 0, -1);
|
||
$found = false;
|
||
|
||
foreach ($messages as $msgJson) {
|
||
$msg = json_decode($msgJson, true);
|
||
|
||
if ($msg['from_user'] === $user->username && $msg['content'] === '0') {
|
||
$found = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
$this->assertTrue($found, 'Zero message not found in Redis');
|
||
}
|
||
|
||
/**
|
||
* 测试用户可以发送带缩略图的图片消息。
|
||
*/
|
||
public function test_can_send_image_message(): void
|
||
{
|
||
Storage::fake('public');
|
||
|
||
$room = Room::create(['room_name' => 'imgsend']);
|
||
$user = User::factory()->create();
|
||
|
||
$this->actingAs($user)->get(route('chat.room', $room->id));
|
||
|
||
$response = $this->actingAs($user)->post(route('chat.send', $room->id), [
|
||
'to_user' => '大家',
|
||
'content' => '图片说明',
|
||
'font_color' => '#000000',
|
||
'action' => '',
|
||
'image' => UploadedFile::fake()->image('chat-picture.png', 1280, 960),
|
||
], [
|
||
'Accept' => 'application/json',
|
||
]);
|
||
|
||
$response->assertOk();
|
||
$response->assertJson(['status' => 'success']);
|
||
|
||
$messages = Redis::lrange("room:{$room->id}:messages", 0, -1);
|
||
$payload = collect($messages)
|
||
->map(fn (string $item) => json_decode($item, true))
|
||
->first(fn (array $item) => ($item['from_user'] ?? null) === $user->username && ($item['message_type'] ?? null) === 'image');
|
||
|
||
$this->assertNotNull($payload);
|
||
$this->assertSame('image', $payload['message_type'] ?? null);
|
||
$this->assertNotEmpty($payload['image_path'] ?? null);
|
||
$this->assertNotEmpty($payload['image_thumb_path'] ?? null);
|
||
$this->assertNotEmpty($payload['image_url'] ?? null);
|
||
$this->assertNotEmpty($payload['image_thumb_url'] ?? null);
|
||
Storage::disk('public')->assertExists($payload['image_path']);
|
||
Storage::disk('public')->assertExists($payload['image_thumb_path']);
|
||
}
|
||
|
||
/**
|
||
* 测试聊天室发送接口在 419 场景下会返回稳定的 JSON 提示。
|
||
*/
|
||
public function test_chat_send_http_419_exception_renders_json_response(): void
|
||
{
|
||
$request = Request::create('/room/1/send', 'POST', server: [
|
||
'HTTP_ACCEPT' => 'application/json',
|
||
]);
|
||
|
||
$response = $this->app->make(\Illuminate\Contracts\Debug\ExceptionHandler::class)
|
||
->render($request, new HttpException(419, 'Page Expired'));
|
||
|
||
\Illuminate\Testing\TestResponse::fromBaseResponse($response)->assertStatus(419)->assertJson([
|
||
'status' => 'error',
|
||
'message' => '页面已过期,请刷新后重试。',
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 测试超过保留期的聊天图片会被命令清理并改成过期占位消息。
|
||
*/
|
||
public function test_purge_command_cleans_expired_chat_images(): void
|
||
{
|
||
Storage::fake('public');
|
||
|
||
Storage::disk('public')->put('chat-images/2026-04-08/sample_original.png', 'original');
|
||
Storage::disk('public')->put('chat-images/2026-04-08/sample_thumb.png', 'thumb');
|
||
|
||
$message = \App\Models\Message::create([
|
||
'room_id' => 1,
|
||
'from_user' => 'tester',
|
||
'to_user' => '大家',
|
||
'content' => '历史图片',
|
||
'is_secret' => false,
|
||
'font_color' => '#000000',
|
||
'action' => '',
|
||
'message_type' => 'image',
|
||
'image_path' => 'chat-images/2026-04-08/sample_original.png',
|
||
'image_thumb_path' => 'chat-images/2026-04-08/sample_thumb.png',
|
||
'image_original_name' => 'sample.png',
|
||
'sent_at' => now()->subDays(4),
|
||
]);
|
||
|
||
$this->artisan('messages:purge', [
|
||
'--days' => 30,
|
||
'--image-days' => 3,
|
||
])->assertExitCode(0);
|
||
|
||
$message->refresh();
|
||
|
||
$this->assertSame('expired_image', $message->message_type);
|
||
$this->assertNull($message->image_path);
|
||
$this->assertNull($message->image_thumb_path);
|
||
$this->assertNull($message->image_original_name);
|
||
$this->assertStringContainsString('图片已过期', $message->content);
|
||
Storage::disk('public')->assertMissing('chat-images/2026-04-08/sample_original.png');
|
||
Storage::disk('public')->assertMissing('chat-images/2026-04-08/sample_thumb.png');
|
||
}
|
||
|
||
/**
|
||
* 测试心跳接口可以正常返回成功响应。
|
||
*/
|
||
public function test_can_trigger_heartbeat()
|
||
{
|
||
$room = Room::create(['room_name' => 'test_hb']);
|
||
$user = User::factory()->create(['exp_num' => 0]);
|
||
|
||
$response = $this->actingAs($user)->postJson(route('chat.heartbeat', $room->id));
|
||
|
||
$response->assertStatus(200);
|
||
$response->assertJsonFragment(['status' => 'success']);
|
||
|
||
$user->refresh();
|
||
$this->assertGreaterThanOrEqual(0, $user->exp_num); // Might be 1 depending on sysparam
|
||
}
|
||
|
||
/**
|
||
* 测试显式退房会清理 Redis 在线状态。
|
||
*/
|
||
public function test_can_leave_room()
|
||
{
|
||
$room = Room::create(['room_name' => 'test_leave']);
|
||
$user = User::factory()->create();
|
||
|
||
// 进房
|
||
$this->actingAs($user)->get(route('chat.room', $room->id));
|
||
$this->assertEquals(1, Redis::hexists("room:{$room->id}:users", $user->username));
|
||
|
||
// 显式退房
|
||
$response = $this->actingAs($user)->postJson(route('chat.leave', $room->id).'?explicit=1');
|
||
|
||
$response->assertStatus(200);
|
||
|
||
// 缓存中被移除
|
||
$this->assertEquals(0, Redis::hexists("room:{$room->id}:users", $user->username));
|
||
}
|
||
|
||
/**
|
||
* 测试签名退房链接同样可以正常清理在线状态。
|
||
*/
|
||
public function test_can_leave_room_through_signed_expired_route(): void
|
||
{
|
||
$room = Room::create(['room_name' => 'leave2']);
|
||
$user = User::factory()->create();
|
||
|
||
$this->actingAs($user)->get(route('chat.room', $room->id));
|
||
$this->assertEquals(1, Redis::hexists("room:{$room->id}:users", $user->username));
|
||
|
||
$url = URL::temporarySignedRoute('chat.leave.expired', now()->addMinutes(5), [
|
||
'id' => $room->id,
|
||
'user' => $user->id,
|
||
]);
|
||
|
||
$response = $this->getJson($url);
|
||
|
||
$response->assertStatus(200);
|
||
$this->assertEquals(0, Redis::hexists("room:{$room->id}:users", $user->username));
|
||
}
|
||
|
||
/**
|
||
* 测试双击名片赠金币会写入私聊消息,且只有赠送双方能看到历史记录。
|
||
*/
|
||
public function test_gift_gold_creates_secret_message_visible_only_to_participants(): void
|
||
{
|
||
$room = Room::create(['room_name' => 'gift-gold']);
|
||
$sender = User::factory()->create(['jjb' => 500]);
|
||
$receiver = User::factory()->create(['jjb' => 100]);
|
||
$outsider = User::factory()->create();
|
||
|
||
$response = $this->actingAs($sender)->postJson(route('gift.gold'), [
|
||
'to_user' => $receiver->username,
|
||
'room_id' => $room->id,
|
||
'amount' => 88,
|
||
]);
|
||
|
||
$response->assertOk();
|
||
$response->assertJsonFragment([
|
||
'status' => 'success',
|
||
'message' => "赠送成功!已向 {$receiver->username} 赠送 88 金币。",
|
||
]);
|
||
|
||
// 余额应同步完成转移,确保消息不是“通知成功但金额未变”。
|
||
$this->assertSame(412, $sender->fresh()->jjb);
|
||
$this->assertSame(188, $receiver->fresh()->jjb);
|
||
|
||
$messages = Redis::lrange("room:{$room->id}:messages", 0, -1);
|
||
$giftMessage = collect($messages)
|
||
->map(fn (string $item) => json_decode($item, true))
|
||
->first(fn (array $item) => ($item['from_user'] ?? null) === $sender->username
|
||
&& ($item['to_user'] ?? null) === $receiver->username
|
||
&& ($item['content'] ?? null) === '赠送了你 88 金币!💝');
|
||
|
||
$this->assertNotNull($giftMessage);
|
||
$this->assertTrue((bool) ($giftMessage['is_secret'] ?? false));
|
||
$this->assertSame('💰 赠金币到账', $giftMessage['toast_notification']['title'] ?? null);
|
||
$this->assertSame('💰', $giftMessage['toast_notification']['icon'] ?? null);
|
||
$this->assertSame('#f59e0b', $giftMessage['toast_notification']['color'] ?? null);
|
||
|
||
// 赠送方查看房间历史时,应保留这条私聊通知。
|
||
$senderHistory = $this->actingAs($sender)
|
||
->get(route('chat.room', $room->id))
|
||
->viewData('historyMessages');
|
||
$this->assertTrue(collect($senderHistory)->contains(
|
||
fn (array $item) => ($item['from_user'] ?? null) === $sender->username
|
||
&& ($item['to_user'] ?? null) === $receiver->username
|
||
&& ($item['content'] ?? null) === '赠送了你 88 金币!💝'
|
||
));
|
||
|
||
// 接收方查看房间历史时,也应看到这条私聊通知。
|
||
$receiverHistory = $this->actingAs($receiver)
|
||
->get(route('chat.room', $room->id))
|
||
->viewData('historyMessages');
|
||
$this->assertTrue(collect($receiverHistory)->contains(
|
||
fn (array $item) => ($item['from_user'] ?? null) === $sender->username
|
||
&& ($item['to_user'] ?? null) === $receiver->username
|
||
&& ($item['content'] ?? null) === '赠送了你 88 金币!💝'
|
||
));
|
||
|
||
// 旁观者不应在历史消息里看到别人的赠金币私聊。
|
||
$outsiderHistory = $this->actingAs($outsider)
|
||
->get(route('chat.room', $room->id))
|
||
->viewData('historyMessages');
|
||
$this->assertFalse(collect($outsiderHistory)->contains(
|
||
fn (array $item) => ($item['from_user'] ?? null) === $sender->username
|
||
&& ($item['to_user'] ?? null) === $receiver->username
|
||
&& ($item['content'] ?? null) === '赠送了你 88 金币!💝'
|
||
));
|
||
}
|
||
|
||
/**
|
||
* 测试会员用户首次进房时会把专属欢迎主题写入历史消息。
|
||
*/
|
||
public function test_vip_user_join_message_uses_presence_theme_payload(): void
|
||
{
|
||
$room = Room::create(['room_name' => 'viproom']);
|
||
$vipLevel = \App\Models\VipLevel::factory()->create([
|
||
'join_effect' => 'lightning',
|
||
'join_banner_style' => 'storm',
|
||
'allow_custom_messages' => true,
|
||
]);
|
||
$user = User::factory()->create([
|
||
'vip_level_id' => $vipLevel->id,
|
||
'hy_time' => now()->addDays(30),
|
||
'custom_join_message' => '{username} 带着风暴王座闪耀降临',
|
||
'has_received_new_gift' => true,
|
||
]);
|
||
|
||
$response = $this->actingAs($user)->get(route('chat.room', $room->id));
|
||
|
||
$response->assertStatus(200);
|
||
$history = $response->viewData('historyMessages');
|
||
$presenceMessage = collect($history)->first(fn (array $message) => ($message['action'] ?? '') === 'vip_presence');
|
||
|
||
$this->assertNotNull($presenceMessage);
|
||
$this->assertSame('join', $presenceMessage['presence_type']);
|
||
$this->assertSame('lightning', $presenceMessage['presence_effect']);
|
||
$this->assertSame('storm', $presenceMessage['presence_banner_style']);
|
||
$this->assertStringContainsString($user->username, $presenceMessage['presence_text']);
|
||
}
|
||
|
||
/**
|
||
* 测试可以获取所有房间的在线人数状态。
|
||
*/
|
||
public function test_can_get_rooms_online_status()
|
||
{
|
||
$user = User::factory()->create();
|
||
$room1 = Room::create(['room_name' => 'room1']);
|
||
$room2 = Room::create(['room_name' => 'room2']);
|
||
|
||
$this->actingAs($user)->get(route('chat.room', $room1->id));
|
||
|
||
$response = $this->actingAs($user)->getJson(route('chat.rooms-online-status'));
|
||
|
||
$response->assertStatus(200);
|
||
|
||
// Assert room1 has 1 online, room2 has 0
|
||
$response->assertJsonFragment([
|
||
'id' => $room1->id,
|
||
'online' => 1,
|
||
]);
|
||
$response->assertJsonFragment([
|
||
'id' => $room2->id,
|
||
'online' => 0,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 测试管理员可以设置房间公告。
|
||
*/
|
||
public function test_can_set_announcement()
|
||
{
|
||
$user = User::factory()->create(['user_level' => 100]); // superadmin
|
||
$room = Room::create(['room_name' => 'test_ann', 'room_owner' => 'someone']);
|
||
|
||
$response = $this->actingAs($user)->postJson(route('chat.announcement', $room->id), [
|
||
'announcement' => 'This is a new test announcement',
|
||
]);
|
||
|
||
$response->assertStatus(200);
|
||
|
||
$room->refresh();
|
||
$this->assertStringContainsString('This is a new test announcement', $room->announcement);
|
||
}
|
||
|
||
/**
|
||
* 测试无权限用户不能设置房间公告。
|
||
*/
|
||
public function test_cannot_set_announcement_without_permission()
|
||
{
|
||
$user = User::factory()->create(['user_level' => 0]);
|
||
$room = Room::create(['room_name' => 'test_ann2', 'room_owner' => 'someone']);
|
||
|
||
$response = $this->actingAs($user)->postJson(route('chat.announcement', $room->id), [
|
||
'announcement' => 'This is a new test announcement',
|
||
]);
|
||
|
||
$response->assertStatus(403);
|
||
}
|
||
}
|