df83fa836c
Шаг 1 «Конкурентное поле» — чекпоинт: - Финальный проход «Найти и объединить дубли» на поле и предложениях; клиент решает по каждой группе, ничего не склеиваем молча. - Тихая склейка только по сайту и коду справочника; телефон и людный номер у более чем 4 фирм — на решение клиента. - Колонка phones jsonb; телефон-дубли видны уже на «Предложениях». - Sonar даёт только имя и тип, сайт всегда через EXA; вскрываем все карточки без гейта «есть сайт». - Яндекс-карточки через локальный Playwright параллельно; рубрика из заголовка идёт в описание. - Фикс рекламных номеров: 2ГИС-парсер разбирает телефоны пообъектно и выкидывает рекламные кнопки с platforms/caption чужих фирм. Тесты: автоподбор 224/224 unit, 105/105 feature; фронт-спеки зелёные. Времянки app/scripts/diag-*/probe-* в гит не входят. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
79 lines
3.3 KiB
TypeScript
79 lines
3.3 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
import { mount } from '@vue/test-utils';
|
|
import { setActivePinia, createPinia } from 'pinia';
|
|
|
|
vi.mock('../../resources/js/api/autopodbor', async (importOriginal) => {
|
|
const actual = await importOriginal<typeof import('../../resources/js/api/autopodbor')>();
|
|
return { ...actual, fetchCompetitor: vi.fn() };
|
|
});
|
|
import * as api from '../../resources/js/api/autopodbor';
|
|
import { useAutopodborStore } from '../../resources/js/stores/autopodborStore';
|
|
import FieldCompetitorScreen from '../../resources/js/views/autopodbor/screens/FieldCompetitorScreen.vue';
|
|
|
|
const makeNav = (competitorId = 10) => ({
|
|
go: vi.fn(),
|
|
ctx: { competitorId, editProjectId: null, selectedSourceIds: [] },
|
|
screen: { value: 'field-competitor' },
|
|
});
|
|
|
|
// Источник-предложение (box 'proposal', без проекта).
|
|
const makeProposal = (id: number) => ({
|
|
id,
|
|
competitor_id: 10,
|
|
signal_type: 'site' as const,
|
|
identifier: `prop-${id}.ru`,
|
|
phone_kind: null,
|
|
phone_type: null,
|
|
box: 'proposal' as const,
|
|
provenance_url: null,
|
|
provenance_label: null,
|
|
created_project_id: null,
|
|
project: null,
|
|
});
|
|
|
|
async function mountWithProposals() {
|
|
(api.fetchCompetitor as ReturnType<typeof vi.fn>).mockResolvedValue({
|
|
competitor: { id: 10, name: 'Окна', is_federal: false, relevance_pct: 90, origin: 'auto', box: 'field', site_url: 'okna.ru', directory_urls: [], studied_at: '2026-01-01', study_run_id: 1, search_run_id: 1, description: '' },
|
|
sources: [makeProposal(1), makeProposal(2)],
|
|
});
|
|
const store = useAutopodborStore();
|
|
await store.loadCompetitor(10);
|
|
const wrapper = mount(FieldCompetitorScreen, {
|
|
global: { provide: { autopodborNav: makeNav() }, stubs: { Transition: false } },
|
|
});
|
|
await new Promise((r) => setTimeout(r, 50));
|
|
return { wrapper, store };
|
|
}
|
|
|
|
beforeEach(() => {
|
|
setActivePinia(createPinia());
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe('FieldCompetitorScreen — массовые действия на вкладке «Предложения» (Баг 1)', () => {
|
|
it('при 2+ выбранных предложениях показывается панель массового переноса', async () => {
|
|
const { wrapper } = await mountWithProposals();
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const vm = wrapper.vm as any;
|
|
vm.switchTab('sugg');
|
|
vm.selected = [1, 2];
|
|
await wrapper.vm.$nextTick();
|
|
expect(wrapper.find('.ld-bulkbar').exists()).toBe(true);
|
|
expect(wrapper.text()).toContain('Перенести выбранные в источники');
|
|
});
|
|
|
|
it('bulkMoveToWork переносит каждый выбранный источник в box field', async () => {
|
|
const { wrapper, store } = await mountWithProposals();
|
|
const spy = vi.spyOn(store, 'moveSourceToBox').mockResolvedValue();
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const vm = wrapper.vm as any;
|
|
vm.switchTab('sugg');
|
|
vm.selected = [1, 2];
|
|
await wrapper.vm.$nextTick();
|
|
await vm.bulkMoveToWork();
|
|
expect(spy).toHaveBeenCalledWith(10, 1, 'field');
|
|
expect(spy).toHaveBeenCalledWith(10, 2, 'field');
|
|
expect(spy).toHaveBeenCalledTimes(2);
|
|
});
|
|
});
|