61 lines
2.1 KiB
TypeScript
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);
|
|
});
|
|
});
|