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

110 lines
4.5 KiB
PHP

<?php
declare(strict_types=1);
use App\Jobs\SyncVkAudienceJob;
use App\Models\SalesAdAudienceFirm;
use App\Models\SalesAdAudiencePhone;
use App\Models\SalesAdAudienceState;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Http;
use Tests\Concerns\SharesSupplierPdo;
uses(DatabaseTransactions::class, SharesSupplierPdo::class);
beforeEach(function () {
// Реклама по умолчанию выключена (enabled=false в схеме). Каждый тест канала
// включает её явно — иначе джоб честно выходит на общем рубильнике и мы бы
// проверяли не то, что думаем.
SalesAdAudienceState::current()->update(['enabled' => true]);
});
it('когда реклама выключена рубильником, джоб вообще не работает', function () {
// 🔴 Выключатель «Реклама» обязан гасить ОБЕ площадки. Иначе владелец
// выключает рекламу, Яндекс встаёт, а ВК продолжает тратить деньги.
//
// 🪤 Проверять здесь Http::assertNothingSent() БЕСПОЛЕЗНО: при трёх номерах
// джоб и без рубильника не дошёл бы до обращения к ВК, и тест был бы зелёным
// в любом случае (проверено 19.07 — первая редакция теста проходила и с
// вырезанной защитой). Наблюдаемая разница одна: с рубильником джоб выходит
// сразу и статус канала остаётся нетронутым, без рубильника — он успевает
// проставить 'waiting_volume'.
SalesAdAudienceState::current()->update(['enabled' => false, 'vk_status' => 'no_access']);
config(['services.vk_ads.token' => 'test-token']);
vkFirmWithPhones(3);
SyncVkAudienceJob::dispatchSync();
expect(SalesAdAudienceState::current()->vk_status)->toBe('no_access');
});
/** Заводит фирму для ВК с нужным числом номеров. */
function vkFirmWithPhones(int $count): SalesAdAudienceFirm
{
$firm = SalesAdAudienceFirm::create([
'firm_name' => 'Тестовая стоматология',
'warmup_started_at' => now(),
'ch_vk' => true,
]);
for ($i = 1; $i <= $count; $i++) {
SalesAdAudiencePhone::create([
'phone' => '7999'.str_pad((string) $i, 7, '0', STR_PAD_LEFT),
'firm_id' => $firm->id,
'expires_at' => now()->addDays(30),
'state' => 'active',
]);
}
return $firm;
}
it('без ключей доступа не трогает ВК и пишет «нет доступа»', function () {
config(['services.vk_ads.token' => '']);
vkFirmWithPhones(3);
Http::fake();
SyncVkAudienceJob::dispatchSync();
Http::assertNothingSent();
expect(SalesAdAudienceState::current()->vk_status)->toBe('no_access');
});
it('пока номеров меньше двух тысяч, не делает ни одного обращения к ВК', function () {
// 🔴 Порог 2000 — требование самого ВК к загрузке списка программой.
// Обращаться раньше бессмысленно и опасно: ВК считает попытки.
config(['services.vk_ads.token' => 'test-token']);
vkFirmWithPhones(3);
Http::fake();
SyncVkAudienceJob::dispatchSync();
Http::assertNothingSent();
$state = SalesAdAudienceState::current();
expect($state->vk_status)->toBe('waiting_volume')
->and($state->vk_last_error)->toBeNull();
});
it('фирмы, помеченные только Яндексом, в счёт для ВК не идут', function () {
config(['services.vk_ads.token' => 'test-token']);
$yandexOnly = SalesAdAudienceFirm::create([
'firm_name' => 'Только Яндекс', 'warmup_started_at' => now(), 'ch_yandex' => true,
]);
SalesAdAudiencePhone::create([
'phone' => '79990000001', 'firm_id' => $yandexOnly->id,
'expires_at' => now()->addDays(30), 'state' => 'active',
]);
Http::fake();
SyncVkAudienceJob::dispatchSync();
Http::assertNothingSent();
expect(SalesAdAudienceState::current()->vk_status)->toBe('waiting_volume');
});