Files
atlas-seller-kit/apps/api/test/product-editor-processed-media.unit.test.ts

63 lines
3.3 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest';
import { ProductEditorService } from '../src/product-editor/product-editor.service.js';
const productId = '733d0d73-3d39-4a98-ac0a-5c0e521d8998';
const variantId = '50ea00b7-6675-4cc7-b7a2-d45f05c07100';
const assetId = '664d0d73-3d39-4a98-ac0a-5c0e521d8998';
function mediaTransaction(processed: boolean, library?: 'upload' | 'import', owner = productId) {
const query = vi.fn(async (sql: string, values?: unknown[]) => {
if (sql.includes('FROM atlas.product_variant_platform_listings'))
return { rows: [{ id: 'listing-id', product_variant_id: variantId }] };
if (sql.includes('FROM atlas.media_assets'))
return { rows: [{ id: assetId, content_type: 'image/jpeg', byte_size: '1200', width_px: 1200, height_px: 1600 }] };
if (sql.includes('FROM atlas.media_upload_intents') || sql.includes('FROM atlas.product_image_imports')) {
expect(values).toEqual([productId, [assetId]]);
expect(sql).toContain('product_id = $1');
const matches = library === 'upload' ? sql.includes('media_upload_intents') : library === 'import' && sql.includes('product_image_imports');
return { rows: matches && owner === productId ? [{ asset_id: assetId }] : [] };
}
if (sql.includes('FROM atlas.media_aspect_ratio_derivatives')) {
expect(values).toEqual([productId, [assetId]]);
return { rows: processed ? [{ asset_id: assetId }] : [] };
}
return { rows: [] };
});
return { query };
}
describe('SKU 图片处理结果的保存资格', () => {
const input = {
product: { id: productId, collection_item_id: 'collection-id', source_snapshot_revision: 1 },
profile: { id: 'profile-id' },
variants: [{ variantId, assetIds: [assetId] }],
};
const service = new ProductEditorService(
{} as ConstructorParameters<typeof ProductEditorService>[0],
{} as ConstructorParameters<typeof ProductEditorService>[1],
{ pricingAllowDraftRates: false } as ConstructorParameters<typeof ProductEditorService>[2],
) as unknown as {
persistListingMedia: (tx: ReturnType<typeof mediaTransaction>, value: typeof input) => Promise<void>;
};
it.each(['upload', 'import'] as const)('%s 图片仅允许所属商品保存', async (library) => {
await service.persistListingMedia(mediaTransaction(false, library), input);
await expect(service.persistListingMedia(mediaTransaction(false, library, '其他商品'), input)).rejects.toMatchObject({
status: 422, response: { error: { code: 'LISTING_MEDIA_NOT_SELECTABLE' } },
});
});
it('当前商品的成功处理结果可加入 SKU 并保存', async () => {
const tx = mediaTransaction(true);
await service.persistListingMedia(tx, input);
expect(tx.query.mock.calls.some(([sql]) => String(sql).includes('INSERT INTO atlas.product_variant_listing_media'))).toBe(true);
});
it('其他商品或未成功的处理结果仍不能加入 SKU', async () => {
const tx = mediaTransaction(false);
await expect(service.persistListingMedia(tx, input)).rejects.toMatchObject({
status: 422, response: { error: { code: 'LISTING_MEDIA_NOT_SELECTABLE' } },
});
});
});