Files
portal/app/tests/Unit/YandexAudienceClientTest.php
T
Дмитрий 9bc587c2de fix(sales): реальный телефон директора убран из тестов и планов; клиент Яндекс.Аудиторий возвращён в main
Коммит d2c2ec43 от 19.07 оторвался от main (dangling, ни в одной ветке):
чистка ПДн и YandexAudienceClient в основную ветку так и не попали.
Номера заменены на фиктивные 7999000000X, клиент и его тесты внесены заново.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 10:24:21 +03:00

101 lines
4.0 KiB
PHP

<?php
declare(strict_types=1);
use App\Services\Sales\YandexAudienceClient;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Http;
use Tests\TestCase;
// tests/Unit (кроме Unit/Autopodbor) не привязан к TestCase в Pest.php —
// фасад Http без контейнера Laravel не поднимется.
uses(TestCase::class);
it('создаёт сегмент из CSV с заголовком phone', function () {
Http::fake([
'api-audience.yandex.ru/*' => Http::response(['segment' => ['id' => 58029600, 'status' => 'uploaded']], 200),
]);
$id = (new YandexAudienceClient('test-token'))->createSegment('Кандидаты', ['79990000001', '79990000002']);
expect($id)->toBe(58029600);
Http::assertSent(function (Request $r) {
expect($r->url())->toContain('/v1/management/segments/upload_csv_file');
expect($r->hasHeader('Authorization', 'OAuth test-token'))->toBeTrue();
expect($r->isMultipart())->toBeTrue();
// Тело multipart: имя файла, имя сегмента и сам CSV c заголовком phone.
// Раскладываем в плоские массивы явно — иначе статанализ видит здесь mixed.
/** @var array<string, string> $filenames */
$filenames = [];
/** @var array<string, string> $contents */
$contents = [];
foreach ($r->data() as $part) {
if (! is_array($part) || ! isset($part['name']) || ! is_string($part['name'])) {
continue;
}
$filenames[$part['name']] = is_string($part['filename'] ?? null) ? $part['filename'] : '';
$contents[$part['name']] = is_string($part['contents'] ?? null) ? $part['contents'] : '';
}
expect($filenames)->toHaveKey('file');
expect($filenames['file'])->toBe('phones.csv');
expect($contents['file'])->toBe("phone\n79990000001\n79990000002\n");
expect($contents['name'])->toBe('Кандидаты');
return true;
});
});
it('не считает повторную заливку того же файла аварией', function () {
Http::fake([
'api-audience.yandex.ru/*' => Http::response(['errors' => [['error_type' => 'no_changes']]], 400),
]);
$result = (new YandexAudienceClient('test-token'))->modifyData(58029600, ['79990000001'], 'addition');
expect($result)->toBe('no_changes');
Http::assertSent(function (Request $r) {
expect($r->url())->toContain('/v1/management/segment/58029600/modify_data');
expect($r->url())->toContain('modification_type=addition');
return true;
});
});
it('бросает исключение на настоящей ошибке заливки', function () {
Http::fake([
'api-audience.yandex.ru/*' => Http::response(['errors' => [['error_type' => 'invalid_file']]], 400),
]);
(new YandexAudienceClient('test-token'))->modifyData(58029600, ['79990000001'], 'addition');
})->throws(RuntimeException::class);
it('читает охват и статус сегмента по id', function () {
Http::fake([
'api-audience.yandex.ru/*' => Http::response(['segments' => [
['id' => 111, 'name' => 'Чужой', 'status' => 'processed'],
['id' => 58029600, 'name' => 'Кандидаты', 'status' => 'processed', 'matched_quantity' => 4200],
]], 200),
]);
$segment = (new YandexAudienceClient('test-token'))->segment(58029600);
expect($segment['status'])->toBe('processed');
expect($segment['matched_quantity'])->toBe(4200);
Http::assertSent(fn (Request $r) => str_contains($r->url(), '/v1/management/segments')
&& $r->hasHeader('Authorization', 'OAuth test-token'));
});
it('отдаёт пустой массив, если сегмента нет в списке', function () {
Http::fake([
'api-audience.yandex.ru/*' => Http::response(['segments' => []], 200),
]);
expect((new YandexAudienceClient('test-token'))->segment(58029600))->toBe([]);
});