tenant = Tenant::factory()->create(); $this->user = User::factory()->create(['tenant_id' => $this->tenant->id]); $this->actingAs($this->user); }); test('GET /api/api-keys возвращает активные ключи тенанта', function () { ApiKey::factory()->create(['tenant_id' => $this->tenant->id, 'user_id' => $this->user->id]); $response = $this->getJson('/api/api-keys'); $response->assertOk(); expect($response->json('data'))->toHaveCount(1); expect($response->json('data.0'))->toHaveKeys(['id', 'name', 'key_prefix', 'last_used_at', 'created_at']); expect($response->json('data.0'))->not->toHaveKey('key_hash'); }); test('GET /api/api-keys без auth: 401', function () { auth()->logout(); $this->getJson('/api/api-keys')->assertStatus(401); }); test('GET /api/api-keys изолирован по тенанту', function () { $otherTenant = Tenant::factory()->create(); $otherUser = User::factory()->create(['tenant_id' => $otherTenant->id]); ApiKey::factory()->create(['tenant_id' => $otherTenant->id, 'user_id' => $otherUser->id]); $response = $this->getJson('/api/api-keys'); $response->assertOk(); expect($response->json('data'))->toHaveCount(0); }); test('GET /api/api-keys не возвращает истёкшие ключи', function () { ApiKey::factory()->create([ 'tenant_id' => $this->tenant->id, 'user_id' => $this->user->id, 'is_active' => true, 'expires_at' => now()->subDay(), ]); ApiKey::factory()->create([ 'tenant_id' => $this->tenant->id, 'user_id' => $this->user->id, 'is_active' => true, 'expires_at' => now()->addYear(), ]); $response = $this->getJson('/api/api-keys'); $response->assertOk(); expect($response->json('data'))->toHaveCount(1); }); test('POST /api/api-keys/regenerate создаёт ключ и возвращает plaintext один раз', function () { $response = $this->postJson('/api/api-keys/regenerate'); $response->assertStatus(201); expect($response->json('key'))->toStartWith('lpkapi_'); expect($response->json('key_prefix'))->toBe(substr($response->json('key'), 0, 10)); expect($response->json())->toHaveKeys(['id', 'name', 'key', 'key_prefix']); $row = ApiKey::query()->where('tenant_id', $this->tenant->id)->where('is_active', true)->first(); expect($row)->not->toBeNull(); expect($row->key_hash)->not->toBe($response->json('key')); expect(Hash::check($response->json('key'), $row->key_hash))->toBeTrue(); }); test('POST /api/api-keys/regenerate деактивирует предыдущий активный ключ', function () { $old = ApiKey::factory()->create([ 'tenant_id' => $this->tenant->id, 'user_id' => $this->user->id, 'is_active' => true, ]); $this->postJson('/api/api-keys/regenerate')->assertStatus(201); $old->refresh(); expect($old->is_active)->toBeFalse(); expect(ApiKey::query()->where('tenant_id', $this->tenant->id)->where('is_active', true)->count())->toBe(1); }); test('POST /api/api-keys/regenerate без auth: 401', function () { auth()->logout(); $this->postJson('/api/api-keys/regenerate')->assertStatus(401); });