x', ); $cands = (new CandidateBuilder)->build([$site], []); $byNum = collect($cands)->keyBy('number'); expect($byNum)->toHaveKey('73912920000'); expect($byNum['73912920000']['kind'])->toBe('code'); expect($byNum['73912920000']['url'])->toBe('https://k.ru/'); expect($byNum['73912920000']['tracker'])->toBeTrue(); // roistat найден expect($byNum['73912920000']['label'])->toBe('в коде сайта'); }); it('достроенный короткий локальный номер становится кандидатом code', function () { // КрасЛомбард-кейс: на странице полный 391-номер + короткие локальные без кода города. // Короткие НЕ теряем — достраиваем кодом 391 со страницы. $site = new FetchedSite( url: 'https://k.ru/', rawHtml: 'главный' .'филиал-1' .'филиал-2', ); $cands = (new CandidateBuilder)->build([$site], []); $byNum = collect($cands)->keyBy('number'); expect($byNum)->toHaveKey('73912713333'); // 271-33-33 достроен expect($byNum)->toHaveKey('73912828828'); // 2-828-828 достроен expect($byNum['73912713333']['kind'])->toBe('code'); }); it('короткий номер без определимого кода города попадает в кандидаты «требует проверки»', function () { $site = new FetchedSite( url: 'https://k.ru/', rawHtml: 'единственный, без полного номера', ); $cands = (new CandidateBuilder)->build([$site], []); $byNum = collect($cands)->keyBy('number'); expect($byNum)->toHaveKey('2713333'); // не потеряли expect($byNum['2713333']['kind'])->toBe('uncertain'); }); it('размечает видимый подменный и скрытый пул при активном трекере', function () { $site = new FetchedSite( url: 'https://k.ru/', rawHtml: '' .'8 (391) 111-22-33' // видимый подменный (нет в tel:/schema) .'8(391)700-00-01 8(391)700-00-01', // пул: 2 вхождения, не код, не видимый visiblePhones: ['8 (391) 111-22-33'], ); $cands = (new CandidateBuilder)->build([$site], []); $byNum = collect($cands)->keyBy('number'); expect($byNum['73911112233']['kind'])->toBe('displayed'); expect($byNum['73917000001']['kind'])->toBe('pool'); }); it('из страницы контактов делает кандидатов с офисом', function () { $site = new FetchedSite( url: 'https://k.ru/', rawHtml: 'пусто', contactsNumbers: [ ['number' => '8(391)281-70-70', 'office' => 'Кр. рабочий, 61'], ['number' => '8(391)250-00-00', 'office' => 'Калинина, 185'], ], ); $cands = (new CandidateBuilder)->build([$site], []); $byNum = collect($cands)->keyBy('number'); expect($byNum['73912817070']['kind'])->toBe('contacts'); expect($byNum['73912817070']['office'])->toBe('Кр. рабочий, 61'); expect($byNum['73912817070']['label'])->toBe('страница «Контакты»'); }); it('из карточек справочника делает кандидатов directory', function () { $cards = [ new DirectoryCard(number: '8(391)292-00-00', office: 'Единая справочная', url: 'https://2gis.ru/firm/1', source: '2ГИС'), new DirectoryCard(number: '8(391)250-00-00', office: 'Калинина, 185', url: 'https://yandex.ru/maps/9', source: 'Яндекс.Карты'), ]; $cands = (new CandidateBuilder)->build([], $cards); $byNum = collect($cands)->keyBy('number'); expect($byNum['73912920000']['kind'])->toBe('directory'); expect($byNum['73912920000']['label'])->toBe('2ГИС'); expect($byNum['73912920000']['url'])->toBe('https://2gis.ru/firm/1'); expect($byNum['73912500000']['office'])->toBe('Калинина, 185'); });