Files
portal/app/tests/Feature/Sales/SmsRecipientSelectorTest.php
T

94 lines
3.6 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
use App\Models\SalesAdAudiencePhone;
use App\Models\SalesSmsMessage;
use App\Models\SalesSmsOptout;
use App\Services\Sms\Providers\FakeSmsProvider;
use App\Services\Sms\SmsRecipientSelector;
use App\Services\Sms\SmsRouter;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\Concerns\SharesSupplierPdo;
/**
* Отбор получателей СМС (Task 6). Все отсевы — ДО списания денег.
*
* SharesSupplierPdo обязателен: SalesAdAudiencePhone/SalesSmsOptout прибиты к
* pgsql_supplier (отдельный PDO), без шаринга DatabaseTransactions откатывал бы
* только соединение по умолчанию — номера 7999000000179990000006 утекали бы из
* прогона в прогон и второй запуск падал бы на unique violation.
* Образец — app/tests/Feature/Sales/AdAudienceScreenTest.php:27.
*/
uses(DatabaseTransactions::class, SharesSupplierPdo::class);
/** Отборщик с заглушкой-универсалом. Функцией, а не $this-> — PHPStan не понимает
* привязку $this в Pest и ругается на каждое обращение. */
function sms_selector(): SmsRecipientSelector
{
return new SmsRecipientSelector(new SmsRouter([new FakeSmsProvider]));
}
function sms_phone(string $phone, array $overrides = []): SalesAdAudiencePhone
{
return SalesAdAudiencePhone::create(array_merge([
'phone' => $phone,
'expires_at' => now()->addDays(30),
'state' => 'active',
'operator' => 'МТС',
'phone_type' => 'mobile',
], $overrides));
}
it('годный номер попадает в отправку', function () {
sms_phone('79990000001');
$plan = sms_selector()->build(['79990000001']);
expect($plan->sendable)->toHaveCount(1)
->and($plan->skipped)->toBeEmpty();
});
it('номер из стоп-листа не отправляется никогда', function () {
sms_phone('79990000002');
SalesSmsOptout::create(['phone' => '79990000002', 'reason' => 'manual', 'created_at' => now()]);
$plan = sms_selector()->build(['79990000002']);
expect($plan->sendable)->toBeEmpty()
->and($plan->skipped)->toBe(['79990000002' => SalesSmsMessage::SKIP_OPTOUT]);
});
it('городской номер не отправляется — деньги сгорели бы впустую', function () {
sms_phone('79990000003', ['phone_type' => 'landline']);
$plan = sms_selector()->build(['79990000003']);
expect($plan->skipped)->toBe(['79990000003' => SalesSmsMessage::SKIP_NOT_MOBILE]);
});
it('погашенный номер не отправляется', function () {
sms_phone('79990000004', ['removed_at' => now()]);
$plan = sms_selector()->build(['79990000004']);
expect($plan->skipped)->toBe(['79990000004' => SalesSmsMessage::SKIP_INACTIVE]);
});
it('дубль внутри одного запуска считается один раз', function () {
sms_phone('79990000005');
$plan = sms_selector()->build(['79990000005', '79990000005']);
expect($plan->sendable)->toHaveCount(1);
});
it('без подходящего провайдера номер помечается без маршрута', function () {
sms_phone('79990000006');
$selector = new SmsRecipientSelector(new SmsRouter([]));
$plan = $selector->build(['79990000006']);
expect($plan->skipped)->toBe(['79990000006' => SalesSmsMessage::SKIP_NO_ROUTE]);
});