2026-06-24 16:20:59 +03:00
|
|
|
|
import { describe, it, expect, vi } from 'vitest';
|
2026-05-25 06:23:59 +03:00
|
|
|
|
import { mount } from '@vue/test-utils';
|
|
|
|
|
|
import { createVuetify } from 'vuetify';
|
2026-06-24 16:20:59 +03:00
|
|
|
|
import { createRouter, createMemoryHistory } from 'vue-router';
|
2026-05-25 06:23:59 +03:00
|
|
|
|
import ProjectLimitOverloadDialog from '../../resources/js/components/projects/ProjectLimitOverloadDialog.vue';
|
|
|
|
|
|
|
2026-07-02 12:04:16 +03:00
|
|
|
|
/**
|
|
|
|
|
|
* Task 12 — переделка диалога «перегрузки лимита» в «запуск отложен».
|
|
|
|
|
|
* Billing v2 Spec C §6.2, план 2026-07-02-launch-gate-balance.md.
|
|
|
|
|
|
* Новое поле payload: topup_rub (сумма пополнения в рублях).
|
|
|
|
|
|
*/
|
2026-05-25 06:23:59 +03:00
|
|
|
|
|
|
|
|
|
|
const payload = {
|
2026-07-02 12:04:16 +03:00
|
|
|
|
current_balance_rub: '200.00',
|
|
|
|
|
|
current_capacity_leads: 4,
|
|
|
|
|
|
would_be_required_leads: 12,
|
|
|
|
|
|
deficit_leads: 8,
|
|
|
|
|
|
topup_rub: '400.00',
|
2026-05-25 06:23:59 +03:00
|
|
|
|
};
|
|
|
|
|
|
|
2026-07-02 12:04:16 +03:00
|
|
|
|
const mountDialog = (props?: Record<string, unknown>) =>
|
2026-05-25 06:23:59 +03:00
|
|
|
|
mount(ProjectLimitOverloadDialog, {
|
2026-07-02 12:04:16 +03:00
|
|
|
|
props: { modelValue: true, payload, ...props },
|
2026-05-25 06:23:59 +03:00
|
|
|
|
global: {
|
|
|
|
|
|
plugins: [createVuetify()],
|
|
|
|
|
|
stubs: { VDialog: { template: '<div><slot /></div>' } },
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-07-02 12:04:16 +03:00
|
|
|
|
describe('ProjectLimitOverloadDialog — Task 12 (запуск отложен)', () => {
|
|
|
|
|
|
it('монтируется без ошибок', () => {
|
2026-05-25 06:23:59 +03:00
|
|
|
|
const w = mountDialog();
|
2026-07-02 12:04:16 +03:00
|
|
|
|
expect(w.exists()).toBe(true);
|
2026-05-25 06:23:59 +03:00
|
|
|
|
});
|
|
|
|
|
|
|
2026-07-02 12:04:16 +03:00
|
|
|
|
it('показывает текст «не запущен»', () => {
|
2026-05-25 06:23:59 +03:00
|
|
|
|
const w = mountDialog();
|
2026-07-02 12:04:16 +03:00
|
|
|
|
expect(w.text().toLowerCase()).toContain('не запущен');
|
2026-05-25 06:23:59 +03:00
|
|
|
|
});
|
|
|
|
|
|
|
2026-07-02 12:04:16 +03:00
|
|
|
|
it('показывает сумму пополнения из topup_rub', () => {
|
2026-05-25 06:23:59 +03:00
|
|
|
|
const w = mountDialog();
|
2026-07-02 12:04:16 +03:00
|
|
|
|
expect(w.text()).toContain('400');
|
2026-05-25 06:23:59 +03:00
|
|
|
|
});
|
|
|
|
|
|
|
2026-07-02 12:04:16 +03:00
|
|
|
|
it('содержит кнопку [data-test="topup"]', () => {
|
2026-05-25 06:23:59 +03:00
|
|
|
|
const w = mountDialog();
|
2026-07-02 12:04:16 +03:00
|
|
|
|
expect(w.find('[data-test="topup"]').exists()).toBe(true);
|
2026-05-25 06:23:59 +03:00
|
|
|
|
});
|
|
|
|
|
|
|
2026-07-02 12:04:16 +03:00
|
|
|
|
it('содержит кнопку [data-test="reduce"]', () => {
|
2026-06-24 16:20:59 +03:00
|
|
|
|
const w = mountDialog();
|
2026-07-02 12:04:16 +03:00
|
|
|
|
expect(w.find('[data-test="reduce"]').exists()).toBe(true);
|
2026-06-24 16:20:59 +03:00
|
|
|
|
});
|
|
|
|
|
|
|
2026-07-02 12:04:16 +03:00
|
|
|
|
it('содержит кнопку закрытия [data-test="close"]', () => {
|
|
|
|
|
|
const w = mountDialog();
|
|
|
|
|
|
expect(w.find('[data-test="close"]').exists()).toBe(true);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it('[data-test="topup"] закрывает диалог (update:modelValue=false)', async () => {
|
|
|
|
|
|
const w = mountDialog();
|
|
|
|
|
|
await w.find('[data-test="topup"]').trigger('click');
|
|
|
|
|
|
const emitted = w.emitted('update:modelValue') as unknown[][];
|
|
|
|
|
|
expect(emitted).toBeTruthy();
|
|
|
|
|
|
expect(emitted[0][0]).toBe(false);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it('[data-test="topup"] ведёт в /billing через router.push', async () => {
|
2026-06-24 16:20:59 +03:00
|
|
|
|
const router = createRouter({
|
|
|
|
|
|
history: createMemoryHistory(),
|
|
|
|
|
|
routes: [{ path: '/billing', component: { template: '<div>billing</div>' } }],
|
|
|
|
|
|
});
|
|
|
|
|
|
const push = vi.spyOn(router, 'push');
|
|
|
|
|
|
const w = mount(ProjectLimitOverloadDialog, {
|
|
|
|
|
|
props: { modelValue: true, payload },
|
|
|
|
|
|
global: { plugins: [createVuetify(), router], stubs: { VDialog: { template: '<div><slot /></div>' } } },
|
|
|
|
|
|
});
|
2026-07-02 12:04:16 +03:00
|
|
|
|
await w.find('[data-test="topup"]').trigger('click');
|
2026-06-24 16:20:59 +03:00
|
|
|
|
expect(push).toHaveBeenCalledWith('/billing');
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-07-02 12:04:16 +03:00
|
|
|
|
it('[data-test="reduce"] эмитит set-zero', async () => {
|
|
|
|
|
|
const w = mountDialog();
|
|
|
|
|
|
await w.find('[data-test="reduce"]').trigger('click');
|
|
|
|
|
|
expect(w.emitted('set-zero')).toBeTruthy();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it('[data-test="close"] закрывает диалог (update:modelValue=false)', async () => {
|
|
|
|
|
|
const w = mountDialog();
|
|
|
|
|
|
await w.find('[data-test="close"]').trigger('click');
|
|
|
|
|
|
const emitted = w.emitted('update:modelValue') as unknown[][];
|
|
|
|
|
|
expect(emitted).toBeTruthy();
|
|
|
|
|
|
expect(emitted[0][0]).toBe(false);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it('payload=null — без падения, карточка не рендерится', () => {
|
2026-05-25 06:23:59 +03:00
|
|
|
|
const w = mount(ProjectLimitOverloadDialog, {
|
|
|
|
|
|
props: { modelValue: true, payload: null },
|
|
|
|
|
|
global: { plugins: [createVuetify()], stubs: { VDialog: { template: '<div><slot /></div>' } } },
|
|
|
|
|
|
});
|
2026-07-02 12:04:16 +03:00
|
|
|
|
expect(w.find('[data-testid="overload-dialog"]').exists()).toBe(false);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it('текст на «вы», без «ты»', () => {
|
|
|
|
|
|
const w = mountDialog();
|
|
|
|
|
|
const text = w.text();
|
|
|
|
|
|
expect(text).not.toContain('У тебя');
|
|
|
|
|
|
expect(text).not.toContain('пополни ');
|
|
|
|
|
|
expect(text).not.toContain('поставь ');
|
2026-05-25 06:23:59 +03:00
|
|
|
|
});
|
|
|
|
|
|
});
|