Files
makelore/tests/unit/game-asset-review-recovery.test.ts
2026-07-29 17:22:35 +08:00

61 lines
2.1 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { AppError } from '@/lib/error-model';
import {
classifyGameAssetReviewLoadFailure,
isGameAssetReviewResponse,
} from '@/pages/Chat/game-asset-review-recovery';
const validReview = {
invocationId: 'review-1',
candidateIds: ['hero'],
decisions: {},
status: 'pending',
pendingAssetIds: ['hero'],
approvedAssetIds: [],
discardedAssetIds: [],
};
const validAsset = {
id: 'hero',
name: '主角',
category: 'visual',
status: 'candidate',
purpose: '玩家角色',
source: 'Kenney',
license: 'CC0',
mediaKind: 'image',
manifest: [],
};
describe('game asset review recovery', () => {
it.each([400, 403, 404, 409, 410, 422])('classifies HTTP %s as stale', (status) => {
const error = new AppError('UNKNOWN', 'hidden technical error', undefined, { status });
expect(classifyGameAssetReviewLoadFailure(error)).toBe('stale');
});
it.each([500, 502, 503])('classifies HTTP %s as retryable', (status) => {
const error = new AppError('UNKNOWN', 'hidden technical error', undefined, { status });
expect(classifyGameAssetReviewLoadFailure(error)).toBe('retryable');
});
it('classifies network and timeout errors as retryable', () => {
expect(classifyGameAssetReviewLoadFailure(new AppError('NETWORK', 'fetch failed'))).toBe('retryable');
expect(classifyGameAssetReviewLoadFailure(new AppError('TIMEOUT', 'timed out'))).toBe('retryable');
});
it('accepts the current response contract', () => {
expect(isGameAssetReviewResponse({ review: validReview, assets: [validAsset] })).toBe(true);
});
it.each([
{ review: validReview },
{ review: { ...validReview, pendingAssetIds: undefined }, assets: [validAsset] },
{ review: validReview, assets: [{ ...validAsset, manifest: undefined }] },
{ review: validReview, assets: [{ ...validAsset, status: { unsafe: true } }] },
{ review: validReview, assets: [{ ...validAsset, previewDataUrl: 42 }] },
{ review: { ...validReview, decisions: { hero: 'corrupt' } }, assets: [validAsset] },
])('rejects malformed response %#', (response) => {
expect(isGameAssetReviewResponse(response)).toBe(false);
});
});