get(route('admin.accounts.index')); $response->assertRedirect(route('login')); } public function test_regular_player_cannot_open_admin_accounts_page(): void { $response = $this->actingAs($this->makeUser(0))->get(route('admin.accounts.index')); $response->assertForbidden(); } public function test_admin_can_open_accounts_page(): void { $this->mock(AzerothCoreAccountService::class, function (MockInterface $mock): void { $mock->shouldReceive('listAccounts') ->once() ->with(null) ->andReturn(new Collection([ [ 'id' => 1, 'username' => 'ADMIN', 'email' => 'ADMIN@EXAMPLE.COM', 'reg_mail' => 'ADMIN@EXAMPLE.COM', 'gm_level' => 3, 'access_label' => 'Администратор', 'locked' => false, 'online' => false, 'joined_at' => '12.03.2026 12:00', 'last_login_at' => '13.03.2026 18:00', 'characters' => new Collection([ [ 'name' => 'Stormmage', 'race' => 'Человек', 'class' => 'Маг', 'level' => 80, 'online' => false, ], ]), ], ])); }); $this->mock(InviteCodeService::class, function (MockInterface $mock): void { $mock->shouldReceive('latest') ->once() ->andReturn(new Collection()); $mock->shouldReceive('stats') ->once() ->andReturn(['total' => 0, 'available' => 0, 'redeemed' => 0]); }); $response = $this->actingAs($this->makeUser(3))->get(route('admin.accounts.index')); $response->assertOk(); $response->assertSee('Stormmage'); $response->assertSee('Аккаунты и персонажи'); $response->assertSee('Управление инвайт-кодами'); } public function test_admin_can_update_access_level(): void { $this->mock(AzerothCoreAccountService::class, function (MockInterface $mock): void { $mock->shouldReceive('findUserById') ->once() ->with(12) ->andReturn($this->makeUser(0)); $mock->shouldReceive('updateAccessLevel') ->once() ->with(12, 2); }); $response = $this->from(route('admin.accounts.index')) ->actingAs($this->makeUser(3)) ->patch(route('admin.accounts.access.update', 12), [ 'gmlevel' => 2, ]); $response->assertRedirect(route('admin.accounts.index')); $response->assertSessionHas('status', 'Уровень доступа обновлён.'); } public function test_admin_can_create_invite_codes(): void { $admin = $this->makeUser(3); $this->mock(InviteCodeService::class, function (MockInterface $mock) use ($admin): void { $mock->shouldReceive('createCodes') ->once() ->with(3, $admin) ->andReturn(new Collection([1, 2, 3])); }); $response = $this->from(route('admin.accounts.index')) ->actingAs($admin) ->post(route('admin.invite-codes.store'), [ 'quantity' => 3, ]); $response->assertRedirect(route('admin.accounts.index')); $response->assertSessionHas('status', 'Создано инвайт-кодов: 3.'); } private function makeUser(int $gmLevel): GameAccountUser { return new GameAccountUser( id: 1, username: 'ADMIN', email: 'ADMIN@EXAMPLE.COM', regMail: 'ADMIN@EXAMPLE.COM', gmLevel: $gmLevel, locked: false, lastLoginAt: '2026-03-13 18:00:00', joinedAt: '2026-03-12 12:00:00', saltHex: str_repeat('AA', 32), verifierHex: str_repeat('BB', 32), ); } }