This commit is contained in:
91
src/components/CharacterAnimator.test.tsx
Normal file
91
src/components/CharacterAnimator.test.tsx
Normal file
@@ -0,0 +1,91 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { AnimationState, type Character } from '../types';
|
||||
import { CharacterAnimator } from './CharacterAnimator';
|
||||
|
||||
vi.mock('../hooks/useResolvedAssetReadUrl', () => ({
|
||||
useResolvedAssetReadUrl: vi.fn((source: string | null | undefined) => ({
|
||||
resolvedUrl: source?.trim() ?? '',
|
||||
isResolving: false,
|
||||
shouldResolve: false,
|
||||
})),
|
||||
}));
|
||||
|
||||
function buildCharacter(overrides: Partial<Character> = {}): Character {
|
||||
return {
|
||||
id: 'generated-role',
|
||||
name: '沈砺',
|
||||
title: '守灯人',
|
||||
description: '',
|
||||
backstory: '',
|
||||
avatar: '/generated/portrait.png',
|
||||
portrait: '/generated/portrait.png',
|
||||
assetFolder: 'custom-world',
|
||||
assetVariant: 'generated',
|
||||
attributes: {} as Character['attributes'],
|
||||
personality: '',
|
||||
skills: [],
|
||||
adventureOpenings: {},
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe('CharacterAnimator portrait fallbacks', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('keeps idle fallback static on the portrait when idle animation is missing', () => {
|
||||
render(
|
||||
<CharacterAnimator
|
||||
state={AnimationState.IDLE}
|
||||
character={buildCharacter()}
|
||||
/>,
|
||||
);
|
||||
|
||||
const image = screen.getByRole('img', {
|
||||
name: /沈砺 idle animation/i,
|
||||
}) as HTMLImageElement;
|
||||
|
||||
expect(image.getAttribute('src')).toBe('/generated/portrait.png');
|
||||
expect(image.style.transform).toBe('');
|
||||
});
|
||||
|
||||
it('uses a fallen portrait fallback when death animation is missing', () => {
|
||||
render(
|
||||
<CharacterAnimator
|
||||
state={AnimationState.DIE}
|
||||
character={buildCharacter()}
|
||||
/>,
|
||||
);
|
||||
|
||||
const image = screen.getByRole('img', {
|
||||
name: /沈砺 die animation/i,
|
||||
}) as HTMLImageElement;
|
||||
|
||||
expect(image.getAttribute('src')).toBe('/generated/portrait.png');
|
||||
expect(image.style.animation).toContain(
|
||||
'character-animator-portrait-death-fall',
|
||||
);
|
||||
expect(image.style.transform).toContain('rotate(-90deg)');
|
||||
expect(image.style.transform).toContain('scaleX(-1)');
|
||||
});
|
||||
|
||||
it('uses generated portrait for movement when generated animation is missing', () => {
|
||||
render(
|
||||
<CharacterAnimator
|
||||
state={AnimationState.RUN}
|
||||
character={buildCharacter({generatedVisualAssetId: 'assetobj-role-main'})}
|
||||
/>,
|
||||
);
|
||||
|
||||
const image = screen.getByRole('img', {
|
||||
name: /沈砺 run animation/i,
|
||||
}) as HTMLImageElement;
|
||||
|
||||
expect(image.getAttribute('src')).toBe('/generated/portrait.png');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user