e280edd431
4 files reformatted (import list expansion, line-length wrapping). Vitest 88/683+3sk green. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
180 lines
6.8 KiB
TypeScript
180 lines
6.8 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||
|
||
vi.mock('../../resources/js/api/client', () => ({
|
||
apiClient: {
|
||
get: vi.fn(),
|
||
post: vi.fn(),
|
||
patch: vi.fn(),
|
||
delete: vi.fn(),
|
||
},
|
||
ensureCsrfCookie: vi.fn(),
|
||
}));
|
||
|
||
import {
|
||
createDeal,
|
||
bulkDeleteDeals,
|
||
bulkRestoreDeals,
|
||
updateDeal,
|
||
transitionDeals,
|
||
exportDeals,
|
||
exportDealsXlsx,
|
||
getDeal,
|
||
listDeals,
|
||
listManagers,
|
||
listProjects,
|
||
} from '../../resources/js/api/deals';
|
||
import { apiClient, ensureCsrfCookie } from '../../resources/js/api/client';
|
||
|
||
const FAKE_DEAL = {
|
||
id: 1,
|
||
tenant_id: 1,
|
||
project_id: 1,
|
||
project_name: 'Test',
|
||
phone: '+79161234567',
|
||
contact_name: 'X',
|
||
status: 'new',
|
||
manager_id: null,
|
||
manager_name: null,
|
||
manager_initials: null,
|
||
received_at: null,
|
||
comment: null,
|
||
assigned_at: null,
|
||
};
|
||
|
||
describe('api/deals', () => {
|
||
beforeEach(() => vi.clearAllMocks());
|
||
|
||
it('createDeal() POSTs /api/deals + ensureCsrfCookie + unwraps data.deal', async () => {
|
||
vi.mocked(apiClient.post).mockResolvedValue({ data: { deal: FAKE_DEAL, message: 'ok' } });
|
||
const r = await createDeal({ tenant_id: 1, project_name: 'P', phone: '+79161234567' });
|
||
expect(ensureCsrfCookie).toHaveBeenCalledOnce();
|
||
expect(apiClient.post).toHaveBeenCalledWith('/api/deals', {
|
||
tenant_id: 1,
|
||
project_name: 'P',
|
||
phone: '+79161234567',
|
||
});
|
||
expect(r.id).toBe(1);
|
||
});
|
||
|
||
it('bulkDeleteDeals() DELETE /api/deals с data payload', async () => {
|
||
vi.mocked(apiClient.delete).mockResolvedValue({ data: { deleted: 3, requested: 4 } });
|
||
const r = await bulkDeleteDeals({ tenant_id: 1, ids: [1, 2, 3, 4] });
|
||
expect(ensureCsrfCookie).toHaveBeenCalledOnce();
|
||
expect(apiClient.delete).toHaveBeenCalledWith('/api/deals', { data: { tenant_id: 1, ids: [1, 2, 3, 4] } });
|
||
expect(r.deleted).toBe(3);
|
||
});
|
||
|
||
it('bulkRestoreDeals() POSTs /api/deals/restore', async () => {
|
||
vi.mocked(apiClient.post).mockResolvedValue({ data: { restored: 2, requested: 2 } });
|
||
await bulkRestoreDeals({ tenant_id: 1, ids: [1, 2] });
|
||
expect(ensureCsrfCookie).toHaveBeenCalledOnce();
|
||
expect(apiClient.post).toHaveBeenCalledWith('/api/deals/restore', { tenant_id: 1, ids: [1, 2] });
|
||
});
|
||
|
||
it('updateDeal() PATCH /api/deals/{id} c partial payload', async () => {
|
||
vi.mocked(apiClient.patch).mockResolvedValue({ data: { deal: FAKE_DEAL } });
|
||
await updateDeal(42, { tenant_id: 1, comment: 'new' });
|
||
expect(ensureCsrfCookie).toHaveBeenCalledOnce();
|
||
expect(apiClient.patch).toHaveBeenCalledWith('/api/deals/42', { tenant_id: 1, comment: 'new' });
|
||
});
|
||
|
||
it('transitionDeals() POSTs /api/deals/transition с status', async () => {
|
||
vi.mocked(apiClient.post).mockResolvedValue({ data: { updated: 5, requested: 5, status: 'won' } });
|
||
const r = await transitionDeals({ tenant_id: 1, ids: [1, 2, 3, 4, 5], status: 'won' });
|
||
expect(apiClient.post).toHaveBeenCalledWith('/api/deals/transition', {
|
||
tenant_id: 1,
|
||
ids: [1, 2, 3, 4, 5],
|
||
status: 'won',
|
||
});
|
||
expect(r.status).toBe('won');
|
||
});
|
||
|
||
it('exportDeals() POSTs /api/deals/export с format=csv + responseType=text', async () => {
|
||
vi.mocked(apiClient.post).mockResolvedValue({ data: 'id,phone\n1,+79..' });
|
||
const r = await exportDeals({ tenant_id: 1, ids: [1] });
|
||
expect(ensureCsrfCookie).toHaveBeenCalledOnce();
|
||
expect(apiClient.post).toHaveBeenCalledWith(
|
||
'/api/deals/export',
|
||
{ tenant_id: 1, ids: [1], format: 'csv' },
|
||
{ responseType: 'text' },
|
||
);
|
||
expect(typeof r).toBe('string');
|
||
});
|
||
|
||
it('exportDealsXlsx() POSTs /api/deals/export с format=xlsx + responseType=blob', async () => {
|
||
const blob = new Blob(['fake'], { type: 'application/octet-stream' });
|
||
vi.mocked(apiClient.post).mockResolvedValue({ data: blob });
|
||
const r = await exportDealsXlsx({ tenant_id: 1, ids: [1, 2] });
|
||
expect(apiClient.post).toHaveBeenCalledWith(
|
||
'/api/deals/export',
|
||
{ tenant_id: 1, ids: [1, 2], format: 'xlsx' },
|
||
{ responseType: 'blob' },
|
||
);
|
||
expect(r).toBeInstanceOf(Blob);
|
||
});
|
||
|
||
it('getDeal() GET /api/deals/{id} с tenant_id param', async () => {
|
||
vi.mocked(apiClient.get).mockResolvedValue({ data: { deal: FAKE_DEAL, events: [] } });
|
||
const r = await getDeal(7, 1);
|
||
expect(apiClient.get).toHaveBeenCalledWith('/api/deals/7', { params: { tenant_id: 1 } });
|
||
expect(r.events).toEqual([]);
|
||
});
|
||
|
||
it('listDeals() GET /api/deals с маппингом camelCase→snake_case + onlyDeleted flag', async () => {
|
||
vi.mocked(apiClient.get).mockResolvedValue({
|
||
data: { deals: [], total: 0, limit: 50, offset: 0 },
|
||
});
|
||
await listDeals({
|
||
tenantId: 1,
|
||
statusIn: ['new', 'in_progress'],
|
||
projectId: 2,
|
||
managerId: 3,
|
||
search: 'q',
|
||
limit: 50,
|
||
offset: 0,
|
||
onlyDeleted: true,
|
||
});
|
||
expect(apiClient.get).toHaveBeenCalledWith('/api/deals', {
|
||
params: {
|
||
tenant_id: 1,
|
||
status_in: ['new', 'in_progress'],
|
||
project_id: 2,
|
||
manager_id: 3,
|
||
search: 'q',
|
||
limit: 50,
|
||
offset: 0,
|
||
only_deleted: 'true',
|
||
},
|
||
});
|
||
});
|
||
|
||
it('listDeals() без onlyDeleted → only_deleted=undefined', async () => {
|
||
vi.mocked(apiClient.get).mockResolvedValue({ data: { deals: [], total: 0, limit: 50, offset: 0 } });
|
||
await listDeals({ tenantId: 1 });
|
||
expect(apiClient.get).toHaveBeenCalledWith(
|
||
'/api/deals',
|
||
expect.objectContaining({ params: expect.objectContaining({ only_deleted: undefined }) }),
|
||
);
|
||
});
|
||
|
||
it('listManagers() GET /api/managers + unwraps data.managers', async () => {
|
||
vi.mocked(apiClient.get).mockResolvedValue({
|
||
data: {
|
||
managers: [{ id: 1, email: 'm@x.ru', first_name: 'M', last_name: 'X', name: 'M X', initials: 'MX' }],
|
||
},
|
||
});
|
||
const r = await listManagers(1);
|
||
expect(apiClient.get).toHaveBeenCalledWith('/api/managers', { params: { tenant_id: 1 } });
|
||
expect(r).toHaveLength(1);
|
||
});
|
||
|
||
it('listProjects() GET /api/projects + unwraps data.projects', async () => {
|
||
vi.mocked(apiClient.get).mockResolvedValue({
|
||
data: { projects: [{ id: 1, name: 'P', tag: 'site', type: 'webhook' }] },
|
||
});
|
||
const r = await listProjects(1);
|
||
expect(apiClient.get).toHaveBeenCalledWith('/api/projects', { params: { tenant_id: 1 } });
|
||
expect(r[0].name).toBe('P');
|
||
});
|
||
});
|