feat(ai-image): AI生图开发
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { createWatermarkTemplateRequestSchema } from '@atlas/contracts';
|
||||
import { WatermarksService } from '../src/watermarks/watermarks.service.js';
|
||||
|
||||
const templateId = '46ea1f9c-28d0-4b32-92e1-3d4e74ad7757';
|
||||
const assetId = '54799515-028d-4320-80a2-f53fd13fb588';
|
||||
|
||||
const imageRow = (size: number, radius: number, version = 1) => ({
|
||||
id: templateId,
|
||||
name: '图片水印',
|
||||
kind: 'image' as const,
|
||||
current_version: version,
|
||||
created_at: new Date('2026-09-26T00:00:00Z'),
|
||||
updated_at: new Date('2026-09-26T00:00:00Z'),
|
||||
revision: version,
|
||||
text_content: null,
|
||||
image_asset_id: assetId,
|
||||
font_code: null,
|
||||
font_size_px: null,
|
||||
opacity: '0.2600',
|
||||
scale_ratio: '0.5556',
|
||||
image_size_px: size,
|
||||
border_radius_px: radius,
|
||||
position: 'bottom_right',
|
||||
position_x: '1.0000',
|
||||
position_y: '1.0000',
|
||||
});
|
||||
|
||||
const serviceWith = (query: ReturnType<typeof vi.fn>) => {
|
||||
const run = vi.fn(async (_input: unknown, work: (tx: { query: typeof query }) => Promise<unknown>) =>
|
||||
work({ query }));
|
||||
return new WatermarksService(
|
||||
{ run } as unknown as ConstructorParameters<typeof WatermarksService>[0],
|
||||
{} as ConstructorParameters<typeof WatermarksService>[1],
|
||||
);
|
||||
};
|
||||
|
||||
describe('图片水印像素尺寸和圆角', () => {
|
||||
it('创建契约接收像素尺寸并约束尺寸和圆角范围,同时兼容旧比例', () => {
|
||||
const base = {
|
||||
name: '图片水印', kind: 'image',
|
||||
config: { image_asset_id: assetId, opacity: '0.26', position_x: 1, position_y: 1 },
|
||||
};
|
||||
expect(createWatermarkTemplateRequestSchema.safeParse({
|
||||
...base, config: { ...base.config, image_size_px: 80, border_radius_px: 12 },
|
||||
}).success).toBe(true);
|
||||
expect(createWatermarkTemplateRequestSchema.safeParse({
|
||||
...base, config: { ...base.config, image_size_px: 10 },
|
||||
}).success).toBe(true);
|
||||
expect(createWatermarkTemplateRequestSchema.safeParse({
|
||||
...base, config: { ...base.config, scale_ratio: '0.25' },
|
||||
}).success).toBe(true);
|
||||
expect(createWatermarkTemplateRequestSchema.safeParse(base).success).toBe(false);
|
||||
expect(createWatermarkTemplateRequestSchema.safeParse({
|
||||
...base, config: { ...base.config, image_size_px: 9 },
|
||||
}).success).toBe(false);
|
||||
expect(createWatermarkTemplateRequestSchema.safeParse({
|
||||
...base, config: { ...base.config, image_size_px: 201 },
|
||||
}).success).toBe(false);
|
||||
expect(createWatermarkTemplateRequestSchema.safeParse({
|
||||
...base, config: { ...base.config, image_size_px: 80, border_radius_px: 101 },
|
||||
}).success).toBe(false);
|
||||
});
|
||||
|
||||
it('创建时保存绝对尺寸和圆角,并保留旧比例字段', async () => {
|
||||
let inserted: unknown[] = [];
|
||||
const query = vi.fn(async (sql: string, args?: unknown[]) => {
|
||||
if (sql.includes('SELECT id FROM atlas.media_assets')) return { rows: [{ id: assetId }] };
|
||||
if (sql.includes('INSERT INTO atlas.watermark_templates')) return { rows: [{ id: templateId }] };
|
||||
if (sql.includes('INSERT INTO atlas.watermark_template_versions')) {
|
||||
inserted = args ?? [];
|
||||
return { rows: [] };
|
||||
}
|
||||
if (sql.includes('SELECT template.id')) return { rows: [imageRow(Number(inserted[13]), Number(inserted[14]))] };
|
||||
throw new Error(`未知 SQL: ${sql}`);
|
||||
});
|
||||
const result = await serviceWith(query).create('workspace', 'user', 'key', {
|
||||
name: '图片水印', kind: 'image',
|
||||
config: { image_asset_id: assetId, image_size_px: 80, border_radius_px: 12,
|
||||
opacity: '0.26', position_x: 1, position_y: 1 },
|
||||
});
|
||||
expect(inserted[8]).toBe('0.5556');
|
||||
expect(inserted.slice(13, 15)).toEqual([80, 12]);
|
||||
expect(result).toMatchObject({ body: { data: { config: {
|
||||
image_size_px: 80, border_radius_px: 12,
|
||||
} } } });
|
||||
});
|
||||
|
||||
it('旧版比例输入换算为像素尺寸,圆角默认为零', async () => {
|
||||
let inserted: unknown[] = [];
|
||||
const query = vi.fn(async (sql: string, args?: unknown[]) => {
|
||||
if (sql.includes('SELECT id FROM atlas.media_assets')) return { rows: [{ id: assetId }] };
|
||||
if (sql.includes('INSERT INTO atlas.watermark_templates')) return { rows: [{ id: templateId }] };
|
||||
if (sql.includes('INSERT INTO atlas.watermark_template_versions')) {
|
||||
inserted = args ?? [];
|
||||
return { rows: [] };
|
||||
}
|
||||
if (sql.includes('SELECT template.id')) return { rows: [imageRow(36, 0)] };
|
||||
throw new Error(`未知 SQL: ${sql}`);
|
||||
});
|
||||
await serviceWith(query).create('workspace', 'user', 'key', {
|
||||
name: '图片水印', kind: 'image',
|
||||
config: { image_asset_id: assetId, scale_ratio: '0.25',
|
||||
opacity: '0.26', position_x: 1, position_y: 1 },
|
||||
});
|
||||
expect(inserted[8]).toBe('0.25');
|
||||
expect(inserted.slice(13, 15)).toEqual([36, 0]);
|
||||
});
|
||||
|
||||
it('10px 尺寸原值保存,兼容比例保持旧版允许的最小值', async () => {
|
||||
let inserted: unknown[] = [];
|
||||
const query = vi.fn(async (sql: string, args?: unknown[]) => {
|
||||
if (sql.includes('SELECT id FROM atlas.media_assets')) return { rows: [{ id: assetId }] };
|
||||
if (sql.includes('INSERT INTO atlas.watermark_templates')) return { rows: [{ id: templateId }] };
|
||||
if (sql.includes('INSERT INTO atlas.watermark_template_versions')) {
|
||||
inserted = args ?? [];
|
||||
return { rows: [] };
|
||||
}
|
||||
if (sql.includes('SELECT template.id')) return { rows: [imageRow(10, 0)] };
|
||||
throw new Error(`未知 SQL: ${sql}`);
|
||||
});
|
||||
await serviceWith(query).create('workspace', 'user', 'key', {
|
||||
name: '图片水印', kind: 'image',
|
||||
config: { image_asset_id: assetId, image_size_px: 10,
|
||||
opacity: '0.26', position_x: 1, position_y: 1 },
|
||||
});
|
||||
expect(inserted[8]).toBe('0.1');
|
||||
expect(inserted[13]).toBe(10);
|
||||
});
|
||||
|
||||
it('只修改圆角时保留图片尺寸并创建新版本', async () => {
|
||||
let inserted: unknown[] = [];
|
||||
const query = vi.fn(async (sql: string, args?: unknown[]) => {
|
||||
if (sql.includes('SELECT template.id') && sql.includes('FOR UPDATE')) return { rows: [imageRow(80, 0)] };
|
||||
if (sql.includes('SELECT id FROM atlas.media_assets')) return { rows: [{ id: assetId }] };
|
||||
if (sql.includes('UPDATE atlas.watermark_templates')) return { rows: [] };
|
||||
if (sql.includes('INSERT INTO atlas.watermark_template_versions')) {
|
||||
inserted = args ?? [];
|
||||
return { rows: [] };
|
||||
}
|
||||
if (sql.includes('SELECT template.id')) return { rows: [imageRow(80, 16, 2)] };
|
||||
throw new Error(`未知 SQL: ${sql}`);
|
||||
});
|
||||
const result = await serviceWith(query).update(
|
||||
'workspace', 'user', templateId, 'key', 1, { config: { border_radius_px: 16 } },
|
||||
);
|
||||
expect(inserted[13]).toBe(80);
|
||||
expect(inserted[14]).toBe(16);
|
||||
expect(result).toMatchObject({ body: { data: { current_version: 2, config: {
|
||||
image_size_px: 80, border_radius_px: 16,
|
||||
} } } });
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user