Files
atlas-seller-kit/apps/api/test/watermark-image-size.unit.test.ts

154 lines
7.3 KiB
TypeScript

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,
} } } });
});
});