Files
portal/app/tests/Feature/Billing/TopupControllerTest.php
T
Дмитрий 7bee35768d fix(billing): topup save() rationale comment + cross-tenant test (Task 1 review)
Code-quality review fixups: документирующий комментарий про безопасность
Eloquent save() для bcmath-строки (расхождение с LedgerService raw-update);
cross-tenant isolation тест на /api/billing/topup; balance_rub_after в
assertDatabaseHas.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 07:00:19 +03:00

80 lines
3.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
declare(strict_types=1);
use App\Models\Tenant;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTransactions;
uses(DatabaseTransactions::class);
beforeEach(function () {
$this->tenant = Tenant::factory()->create(['balance_rub' => '500.00', 'balance_leads' => 12]);
$this->user = User::factory()->create(['tenant_id' => $this->tenant->id]);
$this->actingAs($this->user);
});
test('POST /api/billing/topup кредитует баланс и возвращает 201', function () {
$response = $this->postJson('/api/billing/topup', ['amount_rub' => 250]);
$response->assertStatus(201)
->assertJsonPath('balance_rub', '750.00')
->assertJsonPath('transaction.type', 'topup')
->assertJsonPath('transaction.amount_rub', '250.00');
expect((string) $this->tenant->fresh()->balance_rub)->toBe('750.00');
});
test('POST /api/billing/topup пишет строку balance_transactions с user_id', function () {
$this->postJson('/api/billing/topup', ['amount_rub' => 100])->assertStatus(201);
$this->assertDatabaseHas('balance_transactions', [
'tenant_id' => $this->tenant->id,
'user_id' => $this->user->id,
'type' => 'topup',
'amount_rub' => '100.00',
'balance_rub_after' => '600.00',
]);
});
test('POST /api/billing/topup использует bcmath-точность', function () {
$this->tenant->update(['balance_rub' => '0.10']);
$this->postJson('/api/billing/topup', ['amount_rub' => 100.20])->assertStatus(201);
expect((string) $this->tenant->fresh()->balance_rub)->toBe('100.30');
});
test('POST /api/billing/topup не затрагивает баланс чужого тенанта', function () {
$otherTenant = Tenant::factory()->create(['balance_rub' => '777.00']);
$this->postJson('/api/billing/topup', ['amount_rub' => 100])->assertStatus(201);
// Топап эндпоинт не принимает tenant_id — резолвит из auth-пользователя;
// баланс чужого тенанта неприкосновенен (defense-in-depth, паттерн проекта).
expect((string) $otherTenant->fresh()->balance_rub)->toBe('777.00');
});
test('POST /api/billing/topup отклоняет сумму ниже минимума 100 ₽', function () {
$this->postJson('/api/billing/topup', ['amount_rub' => 50])
->assertStatus(422)
->assertJsonValidationErrors('amount_rub');
});
test('POST /api/billing/topup отклоняет отсутствующую сумму', function () {
$this->postJson('/api/billing/topup', [])
->assertStatus(422)
->assertJsonValidationErrors('amount_rub');
});
test('POST /api/billing/topup отклоняет более 2 знаков после запятой', function () {
$this->postJson('/api/billing/topup', ['amount_rub' => 100.123])
->assertStatus(422)
->assertJsonValidationErrors('amount_rub');
});
test('POST /api/billing/topup без auth: 401', function () {
auth()->logout();
$this->postJson('/api/billing/topup', ['amount_rub' => 100])->assertStatus(401);
});