'superlevel'], ['body' => '100']); } /** * 方法功能:验证普通用户不能发送礼包。 */ public function test_normal_user_cannot_send_red_packet(): void { $user = User::factory()->create(['user_level' => 10]); $response = $this->actingAs($user)->postJson(route('command.red_packet.send'), [ 'room_id' => 1, 'type' => 'gold', ]); $response->assertStatus(403); $response->assertJson(['status' => 'error']); } /** * 方法功能:验证高等级但无职务权限的用户仍不能发送礼包。 */ public function test_high_level_user_without_red_packet_permission_cannot_send_red_packet(): void { $user = User::factory()->create(['user_level' => 100]); $response = $this->actingAs($user)->postJson(route('command.red_packet.send'), [ 'room_id' => 1, 'type' => 'gold', ]); $response->assertStatus(403); } /** * 方法功能:验证站长没有在职职务时也不能绕过礼包权限。 */ public function test_site_owner_without_position_cannot_send_red_packet(): void { $admin = $this->createSiteOwner(); $response = $this->actingAs($admin)->postJson(route('command.red_packet.send'), [ 'room_id' => 1, 'type' => 'gold', ]); $response->assertStatus(403); } /** * 方法功能:验证礼包弹窗配置接口会读取当前职务的数据库配置。 */ public function test_red_packet_config_uses_position_packet_config(): void { $user = $this->createUserWithPermissions([ PositionPermissionRegistry::ROOM_RED_PACKET, ], redPacketAmount: 2468, redPacketCount: 8); $response = $this->actingAs($user)->getJson(route('command.red_packet.config')); $response->assertOk() ->assertJson([ 'status' => 'success', 'amount' => 2468, 'count' => 8, 'expire_seconds' => 300, ]); } /** * 方法功能:验证没有礼包权限时不能读取发包弹窗配置。 */ public function test_user_without_red_packet_permission_cannot_read_packet_config(): void { $user = $this->createUserWithPermissions([]); $response = $this->actingAs($user)->getJson(route('command.red_packet.config')); $response->assertStatus(403) ->assertJson(['status' => 'error']); } /** * 方法功能:验证拥有礼包权限的职务用户会按职务配置发出礼包。 */ public function test_position_user_with_red_packet_permission_uses_position_packet_config(): void { $user = $this->createUserWithPermissions([ PositionPermissionRegistry::ROOM_RED_PACKET, ], redPacketAmount: 1234, redPacketCount: 7); $response = $this->actingAs($user)->postJson(route('command.red_packet.send'), [ 'room_id' => 1, 'type' => 'gold', ]); $response->assertOk() ->assertJsonPath('status', 'success'); $this->assertDatabaseHas('red_packet_envelopes', [ 'sender_id' => $user->id, 'room_id' => 1, 'type' => 'gold', 'total_amount' => 1234, 'total_count' => 7, 'status' => 'active', ]); $envelope = RedPacketEnvelope::first(); $amounts = array_map('intval', Redis::lrange("red_packet:{$envelope->id}:amounts", 0, -1)); $this->assertCount(7, $amounts); $this->assertSame(1234, array_sum($amounts)); } /** * 方法功能:验证拥有礼包权限的职务用户可以发礼包。 */ public function test_position_user_with_red_packet_permission_can_send_red_packet(): void { $user = $this->createUserWithPermissions([ PositionPermissionRegistry::ROOM_RED_PACKET, ], redPacketAmount: 4321, redPacketCount: 6); $response = $this->actingAs($user)->postJson(route('command.red_packet.send'), [ 'room_id' => 1, 'type' => 'exp', ]); $response->assertOk()->assertJson([ 'status' => 'success', ]); $this->assertDatabaseHas('red_packet_envelopes', [ 'sender_id' => $user->id, 'type' => 'exp', 'total_amount' => 4321, 'total_count' => 6, ]); } /** * 方法功能:验证同一房间内不可重复发送未结束的礼包。 */ public function test_cannot_send_multiple_active_packets_in_same_room(): void { $admin = $this->createUserWithPermissions([ PositionPermissionRegistry::ROOM_RED_PACKET, ]); $this->actingAs($admin)->postJson(route('command.red_packet.send'), [ 'room_id' => 1, 'type' => 'gold', ]); $response = $this->actingAs($admin)->postJson(route('command.red_packet.send'), [ 'room_id' => 1, 'type' => 'gold', ]); $response->assertStatus(422); } /** * 方法功能:验证用户可以领取礼包并增加金币余额。 */ public function test_user_can_claim_red_packet(): void { $admin = $this->createUserWithPermissions([ PositionPermissionRegistry::ROOM_RED_PACKET, ]); $user = User::factory()->create(['jjb' => 100]); // Send packet $this->actingAs($admin)->postJson(route('command.red_packet.send'), [ 'room_id' => 1, 'type' => 'gold', ]); $envelope = RedPacketEnvelope::first(); // Claim packet $response = $this->actingAs($user)->postJson(route('red_packet.claim', ['envelopeId' => $envelope->id]), [ 'room_id' => 1, ]); $response->assertStatus(200); $response->assertJson(['status' => 'success']); $this->assertDatabaseHas('red_packet_claims', [ 'envelope_id' => $envelope->id, 'user_id' => $user->id, ]); // Verify currency incremented $this->assertGreaterThan(100, $user->fresh()->jjb); } /** * 方法功能:验证领取成功后会返回并广播最新剩余份数。 */ public function test_claim_red_packet_returns_and_broadcasts_remaining_count(): void { Event::fake([RedPacketClaimed::class]); $admin = $this->createUserWithPermissions([ PositionPermissionRegistry::ROOM_RED_PACKET, ]); $user = User::factory()->create(['jjb' => 100]); $this->actingAs($admin)->postJson(route('command.red_packet.send'), [ 'room_id' => 1, 'type' => 'gold', ]); $envelope = RedPacketEnvelope::query()->firstOrFail(); $response = $this->actingAs($user)->postJson(route('red_packet.claim', ['envelopeId' => $envelope->id]), [ 'room_id' => 1, ]); $response->assertOk(); $response->assertJson([ 'status' => 'success', 'remaining_count' => 9, ]); Event::assertDispatched(RedPacketClaimed::class, function (RedPacketClaimed $event) use ($user, $envelope): bool { return $event->claimer->is($user) && $event->envelopeId === $envelope->id && $event->roomId === 1 && $event->remainingCount === 9 && $event->type === 'gold'; }); $messages = Redis::lrange('room:1:messages', 0, -1); $publicMessage = collect($messages) ->map(fn (string $item) => json_decode($item, true)) ->first(fn (array $item) => ($item['to_user'] ?? null) === '大家' && ($item['toast_notification']['title'] ?? null) === '🧧 有人领取红包' && str_contains((string) ($item['toast_notification']['message'] ?? ''), $user->username)); $this->assertNotNull($publicMessage); $this->assertFalse((bool) ($publicMessage['is_secret'] ?? true)); $this->assertStringContainsString('金币礼包', (string) ($publicMessage['toast_notification']['message'] ?? '')); $this->assertSame('🧧', $publicMessage['toast_notification']['icon'] ?? null); } /** * 方法功能:验证同一用户不能重复领取同一个礼包。 */ public function test_user_cannot_claim_same_packet_twice(): void { $admin = $this->createUserWithPermissions([ PositionPermissionRegistry::ROOM_RED_PACKET, ]); $user = User::factory()->create(); $this->actingAs($admin)->postJson(route('command.red_packet.send'), [ 'room_id' => 1, 'type' => 'gold', ]); $envelope = RedPacketEnvelope::first(); // First claim $this->actingAs($user)->postJson(route('red_packet.claim', ['envelopeId' => $envelope->id]), [ 'room_id' => 1, ]); // Second claim $response = $this->actingAs($user)->postJson(route('red_packet.claim', ['envelopeId' => $envelope->id]), [ 'room_id' => 1, ]); $response->assertStatus(422); $response->assertJson(['message' => '您已经领过这个礼包了']); } /** * 方法功能:验证可以查询礼包状态并识别当前用户是否已领取。 */ public function test_can_check_packet_status(): void { $admin = $this->createUserWithPermissions([ PositionPermissionRegistry::ROOM_RED_PACKET, ]); $user = User::factory()->create(); $this->actingAs($admin)->postJson(route('command.red_packet.send'), [ 'room_id' => 1, 'type' => 'gold', ]); $envelope = RedPacketEnvelope::first(); $response = $this->actingAs($user)->getJson(route('red_packet.status', ['envelopeId' => $envelope->id])); $response->assertStatus(200); $response->assertJson([ 'status' => 'success', 'has_claimed' => false, 'is_expired' => false, ]); // Claim it $this->actingAs($user)->postJson(route('red_packet.claim', ['envelopeId' => $envelope->id]), [ 'room_id' => 1, ]); $response2 = $this->actingAs($user)->getJson(route('red_packet.status', ['envelopeId' => $envelope->id])); $response2->assertJson([ 'status' => 'success', 'has_claimed' => true, ]); } /** * 创建站长账号。 */ private function createSiteOwner(): User { return User::factory()->create([ 'id' => 1, 'user_level' => 100, ]); } /** * 创建带指定聊天室权限的在职职务用户。 * * @param list $permissions */ private function createUserWithPermissions(array $permissions, int $redPacketAmount = 8888, int $redPacketCount = 10): User { $user = User::factory()->create([ 'user_level' => 80, ]); $department = Department::create([ 'name' => '红包权限部'.$user->id, 'rank' => 80, 'color' => '#dc2626', 'sort_order' => 1, 'description' => '红包权限测试', ]); $position = Position::create([ 'department_id' => $department->id, 'name' => '红包权限职务'.$user->id, 'icon' => '🧧', 'rank' => 80, 'level' => 80, 'sort_order' => 1, 'permissions' => $permissions, 'red_packet_amount' => $redPacketAmount, 'red_packet_count' => $redPacketCount, ]); UserPosition::create([ 'user_id' => $user->id, 'position_id' => $position->id, 'appointed_by_user_id' => null, 'appointed_at' => now(), 'remark' => '红包权限测试', 'is_active' => true, ]); return $user->fresh(); } }