/** * pluginData API 契约测试 */ import { describe, it, expect, vi, beforeEach } from 'vitest' const mockGet = vi.fn() const mockPost = vi.fn() const mockPut = vi.fn() const mockPatch = vi.fn() const mockDelete = vi.fn() vi.mock('./client', () => ({ default: { get: (...args: unknown[]) => mockGet(...args), post: (...args: unknown[]) => mockPost(...args), put: (...args: unknown[]) => mockPut(...args), patch: (...args: unknown[]) => mockPatch(...args), delete: (...args: unknown[]) => mockDelete(...args), }, })) import * as pluginDataApi from './pluginData' beforeEach(() => { vi.clearAllMocks() }) describe('pluginData CRUD', () => { const fakeRes = { data: { success: true, data: {} } } it('listPluginData 应调用 GET /plugins/:pid/:entity 并传递分页和过滤参数', async () => { mockGet.mockResolvedValue(fakeRes) await pluginDataApi.listPluginData('crm', 'customer', 1, 20, { filter: { status: 'active' }, search: '张', sort_by: 'name', sort_order: 'asc', }) expect(mockGet).toHaveBeenCalledWith('/plugins/crm/customer', { params: expect.objectContaining({ page: '1', page_size: '20', search: '张', sort_by: 'name', sort_order: 'asc', }), }) }) it('getPluginData 应调用 GET /plugins/:pid/:entity/:id', async () => { mockGet.mockResolvedValue(fakeRes) await pluginDataApi.getPluginData('crm', 'customer', 'rec-001') expect(mockGet).toHaveBeenCalledWith('/plugins/crm/customer/rec-001') }) it('createPluginData 应调用 POST /plugins/:pid/:entity 并包裹 data', async () => { mockPost.mockResolvedValue(fakeRes) const recordData = { name: '客户A', phone: '13800138000' } await pluginDataApi.createPluginData('crm', 'customer', recordData) expect(mockPost).toHaveBeenCalledWith('/plugins/crm/customer', { data: recordData }) }) it('updatePluginData 应调用 PUT /plugins/:pid/:entity/:id', async () => { mockPut.mockResolvedValue(fakeRes) const recordData = { name: '客户A(更新)' } await pluginDataApi.updatePluginData('crm', 'customer', 'rec-001', recordData, 2) expect(mockPut).toHaveBeenCalledWith('/plugins/crm/customer/rec-001', { data: recordData, version: 2, }) }) it('deletePluginData 应调用 DELETE /plugins/:pid/:entity/:id', async () => { mockDelete.mockResolvedValue(undefined) await pluginDataApi.deletePluginData('crm', 'customer', 'rec-001') expect(mockDelete).toHaveBeenCalledWith('/plugins/crm/customer/rec-001') }) }) describe('pluginData 高级查询', () => { const fakeRes = { data: { success: true, data: {} } } it('countPluginData 应调用 GET /plugins/:pid/:entity/count', async () => { mockGet.mockResolvedValue(fakeRes) await pluginDataApi.countPluginData('crm', 'customer', { filter: { status: 'active' } }) expect(mockGet).toHaveBeenCalledWith('/plugins/crm/customer/count', { params: expect.objectContaining({ filter: '{"status":"active"}', }), }) }) it('aggregatePluginData 应调用 GET /plugins/:pid/:entity/aggregate', async () => { mockGet.mockResolvedValue(fakeRes) await pluginDataApi.aggregatePluginData('crm', 'customer', 'status') expect(mockGet).toHaveBeenCalledWith('/plugins/crm/customer/aggregate', { params: { group_by: 'status' }, }) }) it('batchPluginData 应调用 POST /plugins/:pid/:entity/batch', async () => { mockPost.mockResolvedValue(fakeRes) const req = { action: 'delete', ids: ['rec-1', 'rec-2'] } await pluginDataApi.batchPluginData('crm', 'customer', req) expect(mockPost).toHaveBeenCalledWith('/plugins/crm/customer/batch', req) }) it('resolveRefLabels 应调用 POST /plugins/:pid/:entity/resolve-labels', async () => { mockPost.mockResolvedValue(fakeRes) const fields = { customer_tag_id: ['tag-1', 'tag-2'] } await pluginDataApi.resolveRefLabels('crm', 'customer', fields) expect(mockPost).toHaveBeenCalledWith('/plugins/crm/customer/resolve-labels', { fields }) }) it('importPluginData 应调用 POST /plugins/:pid/:entity/import', async () => { mockPost.mockResolvedValue(fakeRes) const rows = [{ name: '客户A' }, { name: '客户B' }] await pluginDataApi.importPluginData('crm', 'customer', rows) expect(mockPost).toHaveBeenCalledWith('/plugins/crm/customer/import', { rows }) }) })