Files
portal/app/tests/Unit/Advertising/YandexDirectClientTest.php
T
Дмитрий a1567ff545 fix реклама Яндекса: сегмент Аудиторий указывается с приставкой 20 — без неё Директ отвечает «объект не найден»
Настоящая причина, по которой портал не мог завести кампанию. Прежний диагноз «сегменту
нужно не меньше 1000 опознанных людей» оказался ВЫДУМКОЙ: он был построен на статьях,
а не на замере, и увёл в ожидание, которое ничего не решало.

Что происходит. Сегмент Аудиторий указывается в условии ретаргетинга не своим номером,
а номером с приставкой 20: сегмент 58034825 уходит как ExternalId 2058034825. Без приставки
Директ ищет цель Метрики с таким номером и честно отвечает 8800 «Object not found» — тем же
отказом, что и на несуществующий сегмент. Поэтому поломка выглядела как «аудитория не готова».

Замер на боевом кабинете 30.07 на одном и том же ГОТОВОМ сегменте:
   ExternalId 58034825   -> отказ 8800 «Object not found»
   ExternalId 2058034825 -> условие создано, № 41678818
После починки то же самое кодом портала: условие № 41678854 создано и убрано за собой.

Приставку показал сам Яндекс: у уже существующего в кабинете условия на этот сегмент
retargetinglists.get возвращает ровно "ExternalId": 2058034825. Документация про приставки
говорит глухо и только «для интересов» — живой ответ кабинета оказался надёжнее документации.

Попутно снят ложный «дефект продукта». Порога в 1000 человек НЕ существует: сегмент годится
для Директа при 134 опознанных людях из 151 номера. Минимум портала менять не нужно.

Ещё один замер, важный на будущее: статус is_processed у сегмента — это НЕ «готов»,
у готового статус processed, заполнены matched_quantity и cookies_matched_quantity,
и стоит can_create_dependent. Судить о готовности только по can_create_dependent.

Тестов на приставку было ДВА, и оба закрепляли поломку: проверяли, что уходит номер БЕЗ
приставки. Оба были зелёные всё время. Тест, написанный по нашему представлению о правде,
а не по ответу живой системы, охраняет баг и делает его невидимым. Теперь оба проверяют
приставку и падают без неё; реклама портала 43 из 43.

Вместе с починкой ложатся три промта смен: 29.07 сведение телеграма и прокси, 29.07 робот
креативов в работу и 30.07 состояние после живой приёмки. В последнем ложный диагноз про
порог в 1000 человек помечен как неверный прямо в шапке — чтобы следующая смена не пошла
по нему второй раз.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 10:57:38 +03:00

38 lines
1.7 KiB
PHP

<?php
declare(strict_types=1);
use App\Services\Advertising\YandexDirectClient;
use Illuminate\Support\Facades\Http;
use Tests\TestCase;
uses(TestCase::class);
it('adds a retargeting list referencing an audience segment', function () {
Http::fake([
'*/json/v5/retargetinglists' => Http::response(['result' => ['AddResults' => [['Id' => 777]]]], 200),
]);
$client = new YandexDirectClient('https://api-sandbox.direct.yandex.com', 'TESTTOKEN');
$id = $client->addRetargetingList('Лидерра кампания #5', 58034825);
expect($id)->toBe(777);
Http::assertSent(function ($req) {
$body = $req->data();
return str_ends_with($req->url(), '/json/v5/retargetinglists')
&& $req->hasHeader('Authorization', 'Bearer TESTTOKEN')
&& $body['method'] === 'add'
&& $body['params']['RetargetingLists'][0]['Type'] === 'AUDIENCE'
&& $body['params']['RetargetingLists'][0]['Rules'][0]['Operator'] === 'ALL'
// Сегмент Аудиторий указывается с приставкой «20» — см. addRetargetingList().
&& $body['params']['RetargetingLists'][0]['Rules'][0]['Arguments'][0]['ExternalId'] === 2058034825;
});
});
it('surfaces an API error as RuntimeException', function () {
Http::fake(['*/json/v5/campaigns' => Http::response(['error' => ['error_string' => 'Нет доступа к API', 'error_code' => 53]], 200)]);
$client = new YandexDirectClient('https://api-sandbox.direct.yandex.com', 'T');
expect(fn () => $client->addCpmBannerCampaign('C', '2026-08-01', '2026-08-14', 72000000, 90000000, 3, 14))->toThrow(RuntimeException::class);
});