Files
portal/app/tests/Feature/Bot/GuardCardContractTest.php
T

111 lines
5.8 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
/**
* СВЯЗКА между генератором карточки (ClientFacts) и сторожом (AnswerGuard).
*
* AnswerGuardTest.php ловит перепутанные цифры на карточке, написанной ВРУЧНУЮ в самом
* тесте (trapCard()) — она устроена так, как сторож ЕЁ понимает, но не проверяет, что
* сторож понимает НАСТОЯЩУЮ карточку, которую строит ClientFacts::card() на реальных
* данных. Если кто-то поменяет формулировку в ClientFacts («Баланс:» → «Ваш баланс:»),
* сторож молча перестанет находить факты — и пропустит враньё про цифры клиента.
* Ручной тест этого не заметит, а этот — обязан.
*
* 🔴 Если этот тест УПАЛ после правки текста в ClientFacts — это значит сторож ОСЛЕП,
* а не что тест «слишком строгий». Чинить нужно разбор в AnswerGuard::parseCardFacts()
* (синхронно с новой формулировкой), а НЕ подгонять этот тест под новый текст.
*/
use App\Models\Deal;
use App\Models\PricingTier;
use App\Models\Project;
use App\Models\Tenant;
use App\Models\User;
use App\Services\Bot\AnswerGuard;
use App\Services\Bot\ClientFacts;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
/**
* Те же две ступени, что в ClientFactsTest::tiers() — имя своё (guardContract*), чтобы
* не столкнуться с глобальной функцией `tiers()` из ClientFactsTest.php при общем прогоне.
*/
function guardContractPricingTiers(): void
{
PricingTier::factory()->create(['tier_no' => 1, 'leads_in_tier' => 300, 'price_per_lead_kopecks' => 5000]);
PricingTier::factory()->create(['tier_no' => 2, 'leads_in_tier' => null, 'price_per_lead_kopecks' => 4000]);
}
/**
* Строит НАСТОЯЩУЮ карточку через ClientFacts::card() на нарочно подобранных данных:
* баланс 2 000 ₽ по 50 ₽/заявку (1-я ступень) = РОВНО 40 заявок — число нарочно совпадает
* с «получено в этом месяце» (12) не будучи им, чтобы ловушка «перепутанные местами
* цифры» была видна: 40 в карточке РЕАЛЬНО есть (баланс), но не как «получено в этом
* месяце»; 12 — другое число (месяц), не «сегодня»; 3 — третье число (сегодня).
*/
function guardContractRealCard(): string
{
guardContractPricingTiers();
$tenant = Tenant::factory()->create(['balance_rub' => '2000.00', 'delivered_in_month' => 12]);
$project = Project::factory()->create([
'tenant_id' => $tenant->id, 'is_active' => true, 'daily_limit_target' => 10,
]);
Project::factory()->create([
'tenant_id' => $tenant->id, 'is_active' => true, 'daily_limit_target' => 5,
]);
$user = User::factory()->create(['tenant_id' => $tenant->id]);
// Сегодня — 3 заявки (received_at внутри текущего месяца — партиции deals помесячные).
Deal::factory()->count(3)->create([
'tenant_id' => $tenant->id,
'project_id' => $project->id,
'received_at' => now()->startOfDay()->addHours(9),
]);
$card = app(ClientFacts::class)->card((int) $user->id);
expect($card)->not->toBeNull();
// Проверяем саму ловушку ДО сторожа: если это условие не выполняется — подстроенные
// данные сломались, а не сторож (иначе тесты ниже могли бы пройти по случайной причине).
expect($card)->toContain('40 заявок')
->and($card)->toContain('получено в этом месяце 12')
->and($card)->toContain('Заявки: сегодня 3');
return (string) $card;
}
it('а) враньё режется: «получено 40» — число из ДРУГОГО факта настоящей карточки (баланс)', function () {
$card = guardContractRealCard();
$guard = app(AnswerGuard::class);
expect($guard->clean('В этом месяце получено 40 заявок.', $card))->toBe('');
});
it('б) враньё режется: «сегодня 12» — число из ДРУГОГО факта настоящей карточки (месяц)', function () {
$card = guardContractRealCard();
$guard = app(AnswerGuard::class);
expect($guard->clean('Сегодня пришло 12 заявок.', $card))->toBe('');
});
it('в) честное остаётся: «получено 12» — ровно то число, что в настоящей карточке', function () {
$card = guardContractRealCard();
$guard = app(AnswerGuard::class);
expect($guard->clean('В этом месяце получено 12 заявок.', $card))
->toBe('В этом месяце получено 12 заявок.');
});
it('г) честное остаётся: «сегодня 3» — ровно то число, что в настоящей карточке', function () {
$card = guardContractRealCard();
$guard = app(AnswerGuard::class);
expect($guard->clean('Сегодня пришло 3 заявки.', $card))
->toBe('Сегодня пришло 3 заявки.');
});