Files
portal/app/tests/Frontend/AdminAutopodborPricingView.spec.ts
T
Дмитрий 793b20a39c feat(конкурентное поле): доводка фронта до прототипа — F1/F2/F3 + чистка M2
Сверка прототипа с реализацией показала расхождения — закрыты по TDD (dev, фронт):

- F1: экран «Предложения» (FieldProposalsScreen) переписан под вид «Поля» —
  карточки-плитки field-shared, тип+«предложение», крупная похожесть, Сайт +
  Справочник 2ГИС·Яндекс, править/удалять в карточке, массовый перенос; кнопка
  «Собрать конкурентов» открывает единое окно сбора 300 ₽ вместо старого autoform.
- F2: новый дружелюбный админ-экран AdminAutopodborPricingView (правка цен
  доп.услуг через PUT /api/admin/system-settings/{key} с обоснованием для аудита,
  сетка лидов для справки) + маршрут /admin/autopodbor-pricing + пункт меню.
- F3: колонка «когда списывается» в панели доп.услуг биллинга.
- M2: удалён мёртвый экран FieldManualCompetitorScreen (+ спека) — на него не
  было переходов; ручное добавление живёт окном на «Поле».

Тесты автоподбор+админ 43/43 зелёные, продакшен-вёрстка eslint-чистая, vite build .
НЕ на проде. M1 (18:00/21:00 МСК) — не баг, реальный инвариант продукта, не трогал.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 04:57:58 +03:00

82 lines
3.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { mount } from '@vue/test-utils';
import { createVuetify } from 'vuetify';
vi.mock('../../resources/js/api/admin');
import AdminAutopodborPricingView from '../../resources/js/views/admin/AdminAutopodborPricingView.vue';
import { listSystemSettings, updateSystemSetting, getPricingTiers } from '../../resources/js/api/admin';
const vuetify = createVuetify();
function settings(search = '300', study = '50') {
return [
{ key: 'autopodbor_price_search_rub', value: search, type: 'decimal', description: null, updated_at: '', updated_by: null },
{ key: 'autopodbor_price_study_rub', value: study, type: 'decimal', description: null, updated_at: '', updated_by: null },
{ key: 'other_key', value: '1', type: 'int', description: null, updated_at: '', updated_by: null },
];
}
function tiers() {
return {
active: [{ tier_no: 1, leads_in_tier: 100, price_per_lead_kopecks: 50000, effective_from: '2026-06-01' }],
scheduled: {},
};
}
function mountV() {
return mount(AdminAutopodborPricingView, { global: { plugins: [vuetify] } });
}
describe('AdminAutopodborPricingView', () => {
beforeEach(() => {
vi.clearAllMocks();
vi.mocked(listSystemSettings).mockResolvedValue(settings() as any);
vi.mocked(getPricingTiers).mockResolvedValue(tiers() as any);
vi.mocked(updateSystemSetting).mockResolvedValue({} as any);
});
it('грузит текущие тарифы доп.услуг из system-settings', async () => {
const w = mountV();
await new Promise((r) => setTimeout(r, 0));
expect(listSystemSettings).toHaveBeenCalled();
expect((w.vm as any).searchPrice).toBe('300');
expect((w.vm as any).studyPrice).toBe('50');
});
it('показывает сетку лидов для справки', async () => {
const w = mountV();
await new Promise((r) => setTimeout(r, 0));
expect(w.text()).toContain('Тариф на лиды');
expect(w.text()).toContain('500'); // 50000 коп = 500 ₽
});
it('сохранение изменённой цены зовёт updateSystemSetting с value и reason', async () => {
const w = mountV();
await new Promise((r) => setTimeout(r, 0));
(w.vm as any).searchPrice = '350';
await (w.vm as any).save();
expect(updateSystemSetting).toHaveBeenCalledWith(
'autopodbor_price_search_rub',
expect.objectContaining({ value: '350' }),
);
expect(updateSystemSetting).not.toHaveBeenCalledWith('autopodbor_price_study_rub', expect.anything());
});
it('причина короче 30 символов блокирует сохранение', async () => {
const w = mountV();
await new Promise((r) => setTimeout(r, 0));
(w.vm as any).searchPrice = '350';
(w.vm as any).reason = 'мало';
await (w.vm as any).save();
expect(updateSystemSetting).not.toHaveBeenCalled();
expect((w.vm as any).errorMessage).toContain('30');
});
it('без изменений не зовёт сохранение', async () => {
const w = mountV();
await new Promise((r) => setTimeout(r, 0));
await (w.vm as any).save();
expect(updateSystemSetting).not.toHaveBeenCalled();
expect((w.vm as any).errorMessage).toBeTruthy();
});
});