import { describe, expect, it, vi } from 'vitest'; import { WatermarkDerivativeService } from '../src/media/watermark-derivative.service.js'; const workspaceId = '30cf54b7-06a3-4e5f-a5fc-d74165115094'; const sourceAssetId = '664d0d73-3d39-4a98-ac0a-5c0e521d8998'; const templateId = '0878262e-6c38-4f3b-953a-2084ef297a33'; const derivativeId = '68db226f-3fcb-4579-ab9e-4932b1d84067'; const productId = '733d0d73-3d39-4a98-ac0a-5c0e521d8998'; function serviceWithQuery(query: ReturnType) { const run = vi.fn(async (_input: unknown, work: (tx: { query: typeof query }) => Promise) => work({ query })); const service = new WatermarkDerivativeService( {} as ConstructorParameters[0], { run } as unknown as ConstructorParameters[1], {} as ConstructorParameters[2], ); return { service, run }; } describe('水印派生任务', () => { it('固定当前模板版本,并在同一个事务创建任务、操作和 Outbox', async () => { const statements: string[] = []; const query = vi.fn(async (sql: string) => { statements.push(sql); if (sql.includes('SELECT id FROM atlas.media_assets')) return { rows: [{ id: sourceAssetId }] }; if (sql.includes('FROM atlas.watermark_templates')) return { rows: [{ id: templateId, current_version: 4 }] }; if (sql.includes('RETURNING id')) return { rows: [{ id: derivativeId }] }; return { rows: [] }; }); const { service, run } = serviceWithQuery(query); const result = await service.create(workspaceId, 'user-id', sourceAssetId, 'idempotency-key', { watermark_template_id: templateId }); expect(result).toMatchObject({ status: 202, body: { data: { id: derivativeId, watermark_template_id: templateId, watermark_template_version: 4, } } }); expect(run).toHaveBeenCalledOnce(); expect(statements.some((sql) => sql.includes('INSERT INTO atlas.media_watermark_derivatives'))).toBe(true); expect(statements.some((sql) => sql.includes('INSERT INTO atlas.operations'))).toBe(true); expect(statements.some((sql) => sql.includes('INSERT INTO atlas.outbox_events'))).toBe(true); }); it('拒绝不可用模板且不创建派生任务', async () => { const query = vi.fn(async (sql: string) => sql.includes('SELECT id FROM atlas.media_assets') ? { rows: [{ id: sourceAssetId }] } : { rows: [] }); const { service } = serviceWithQuery(query); await expect(service.create(workspaceId, 'user-id', sourceAssetId, 'idempotency-key', { watermark_template_id: templateId })).rejects.toMatchObject({ status: 404 }); expect(query.mock.calls.every(([sql]) => !String(sql).includes('INSERT INTO'))).toBe(true); }); it('将当前工作空间的商品关联到水印结果', async () => { const query = vi.fn(async (sql: string, values?: unknown[]) => { if (sql.includes('SELECT id FROM atlas.media_assets')) return { rows: [{ id: sourceAssetId }] }; if (sql.includes('SELECT id FROM atlas.products')) return { rows: [{ id: productId }] }; if (sql.includes('FROM atlas.watermark_templates')) return { rows: [{ id: templateId, current_version: 4 }] }; if (sql.includes('INSERT INTO atlas.media_watermark_derivatives')) { expect(values).toEqual([productId, sourceAssetId, templateId, 4, 'user-id']); return { rows: [{ id: derivativeId }] }; } return { rows: [] }; }); const { service } = serviceWithQuery(query); await service.create(workspaceId, 'user-id', sourceAssetId, 'key', { watermark_template_id: templateId, product_id: productId }); expect(query.mock.calls.some(([sql]) => String(sql).includes('INSERT INTO atlas.media_watermark_derivatives'))).toBe(true); }); });