397 lines
12 KiB
TypeScript
397 lines
12 KiB
TypeScript
import { render, screen } from '@testing-library/react';
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { AchievementGrid } from './AchievementGrid';
|
|
|
|
// Mock the AchievementDisplay module
|
|
vi.mock('@/lib/display-objects/AchievementDisplay', () => ({
|
|
AchievementDisplay: {
|
|
getRarityVariant: vi.fn((rarity) => {
|
|
const rarityMap = {
|
|
common: { text: 'low', surface: 'rarity-common', iconIntent: 'low' },
|
|
rare: { text: 'primary', surface: 'rarity-rare', iconIntent: 'primary' },
|
|
epic: { text: 'primary', surface: 'rarity-epic', iconIntent: 'primary' },
|
|
legendary: { text: 'warning', surface: 'rarity-legendary', iconIntent: 'warning' },
|
|
};
|
|
return rarityMap[rarity as keyof typeof rarityMap] || rarityMap.common;
|
|
}),
|
|
},
|
|
}));
|
|
|
|
describe('AchievementGrid', () => {
|
|
const mockAchievements = [
|
|
{
|
|
id: '1',
|
|
title: 'First Victory',
|
|
description: 'Win your first race',
|
|
icon: 'trophy',
|
|
rarity: 'common',
|
|
earnedAtLabel: 'Jan 15, 2024',
|
|
},
|
|
{
|
|
id: '2',
|
|
title: 'Speed Demon',
|
|
description: 'Reach 200 mph',
|
|
icon: 'zap',
|
|
rarity: 'rare',
|
|
earnedAtLabel: 'Feb 20, 2024',
|
|
},
|
|
{
|
|
id: '3',
|
|
title: 'Champion',
|
|
description: 'Win 10 races',
|
|
icon: 'crown',
|
|
rarity: 'epic',
|
|
earnedAtLabel: 'Mar 10, 2024',
|
|
},
|
|
{
|
|
id: '4',
|
|
title: 'Legend',
|
|
description: 'Win 100 races',
|
|
icon: 'star',
|
|
rarity: 'legendary',
|
|
earnedAtLabel: 'Apr 5, 2024',
|
|
},
|
|
];
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe('Rendering', () => {
|
|
it('renders the header with correct title', () => {
|
|
render(<AchievementGrid achievements={mockAchievements} />);
|
|
|
|
expect(screen.getByText('Achievements')).toBeDefined();
|
|
});
|
|
|
|
it('renders the correct count of achievements', () => {
|
|
render(<AchievementGrid achievements={mockAchievements} />);
|
|
|
|
expect(screen.getByText('4 earned')).toBeDefined();
|
|
});
|
|
|
|
it('renders all achievement items', () => {
|
|
render(<AchievementGrid achievements={mockAchievements} />);
|
|
|
|
mockAchievements.forEach((achievement) => {
|
|
expect(screen.getByText(achievement.title)).toBeDefined();
|
|
expect(screen.getByText(achievement.description)).toBeDefined();
|
|
expect(screen.getByText(achievement.earnedAtLabel)).toBeDefined();
|
|
});
|
|
});
|
|
|
|
it('renders achievement icons correctly', () => {
|
|
render(<AchievementGrid achievements={mockAchievements} />);
|
|
|
|
// Check that the icon mapping works
|
|
expect(screen.getByText('First Victory')).toBeDefined();
|
|
expect(screen.getByText('Speed Demon')).toBeDefined();
|
|
expect(screen.getByText('Champion')).toBeDefined();
|
|
expect(screen.getByText('Legend')).toBeDefined();
|
|
});
|
|
|
|
it('renders achievement rarities correctly', () => {
|
|
render(<AchievementGrid achievements={mockAchievements} />);
|
|
|
|
expect(screen.getByText('common')).toBeDefined();
|
|
expect(screen.getByText('rare')).toBeDefined();
|
|
expect(screen.getByText('epic')).toBeDefined();
|
|
expect(screen.getByText('legendary')).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('Empty states', () => {
|
|
it('renders with empty achievements array', () => {
|
|
render(<AchievementGrid achievements={[]} />);
|
|
|
|
expect(screen.getByText('Achievements')).toBeDefined();
|
|
expect(screen.getByText('0 earned')).toBeDefined();
|
|
});
|
|
|
|
it('renders with single achievement', () => {
|
|
const singleAchievement = [mockAchievements[0]];
|
|
|
|
render(<AchievementGrid achievements={singleAchievement} />);
|
|
|
|
expect(screen.getByText('Achievements')).toBeDefined();
|
|
expect(screen.getByText('1 earned')).toBeDefined();
|
|
expect(screen.getByText('First Victory')).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('Icon mapping', () => {
|
|
it('maps trophy icon correctly', () => {
|
|
const trophyAchievement = {
|
|
id: '1',
|
|
title: 'Trophy Achievement',
|
|
description: 'Test description',
|
|
icon: 'trophy',
|
|
rarity: 'common',
|
|
earnedAtLabel: 'Jan 15, 2024',
|
|
};
|
|
|
|
render(<AchievementGrid achievements={[trophyAchievement]} />);
|
|
|
|
expect(screen.getByText('Trophy Achievement')).toBeDefined();
|
|
});
|
|
|
|
it('maps medal icon correctly', () => {
|
|
const medalAchievement = {
|
|
id: '2',
|
|
title: 'Medal Achievement',
|
|
description: 'Test description',
|
|
icon: 'medal',
|
|
rarity: 'common',
|
|
earnedAtLabel: 'Jan 15, 2024',
|
|
};
|
|
|
|
render(<AchievementGrid achievements={[medalAchievement]} />);
|
|
|
|
expect(screen.getByText('Medal Achievement')).toBeDefined();
|
|
});
|
|
|
|
it('maps star icon correctly', () => {
|
|
const starAchievement = {
|
|
id: '3',
|
|
title: 'Star Achievement',
|
|
description: 'Test description',
|
|
icon: 'star',
|
|
rarity: 'common',
|
|
earnedAtLabel: 'Jan 15, 2024',
|
|
};
|
|
|
|
render(<AchievementGrid achievements={[starAchievement]} />);
|
|
|
|
expect(screen.getByText('Star Achievement')).toBeDefined();
|
|
});
|
|
|
|
it('maps crown icon correctly', () => {
|
|
const crownAchievement = {
|
|
id: '4',
|
|
title: 'Crown Achievement',
|
|
description: 'Test description',
|
|
icon: 'crown',
|
|
rarity: 'common',
|
|
earnedAtLabel: 'Jan 15, 2024',
|
|
};
|
|
|
|
render(<AchievementGrid achievements={[crownAchievement]} />);
|
|
|
|
expect(screen.getByText('Crown Achievement')).toBeDefined();
|
|
});
|
|
|
|
it('maps target icon correctly', () => {
|
|
const targetAchievement = {
|
|
id: '5',
|
|
title: 'Target Achievement',
|
|
description: 'Test description',
|
|
icon: 'target',
|
|
rarity: 'common',
|
|
earnedAtLabel: 'Jan 15, 2024',
|
|
};
|
|
|
|
render(<AchievementGrid achievements={[targetAchievement]} />);
|
|
|
|
expect(screen.getByText('Target Achievement')).toBeDefined();
|
|
});
|
|
|
|
it('maps zap icon correctly', () => {
|
|
const zapAchievement = {
|
|
id: '6',
|
|
title: 'Zap Achievement',
|
|
description: 'Test description',
|
|
icon: 'zap',
|
|
rarity: 'common',
|
|
earnedAtLabel: 'Jan 15, 2024',
|
|
};
|
|
|
|
render(<AchievementGrid achievements={[zapAchievement]} />);
|
|
|
|
expect(screen.getByText('Zap Achievement')).toBeDefined();
|
|
});
|
|
|
|
it('defaults to award icon for unknown icon', () => {
|
|
const unknownIconAchievement = {
|
|
id: '7',
|
|
title: 'Unknown Icon Achievement',
|
|
description: 'Test description',
|
|
icon: 'unknown',
|
|
rarity: 'common',
|
|
earnedAtLabel: 'Jan 15, 2024',
|
|
};
|
|
|
|
render(<AchievementGrid achievements={[unknownIconAchievement]} />);
|
|
|
|
expect(screen.getByText('Unknown Icon Achievement')).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('Rarity display', () => {
|
|
it('applies correct rarity variant for common', () => {
|
|
const commonAchievement = {
|
|
id: '1',
|
|
title: 'Common Achievement',
|
|
description: 'Test description',
|
|
icon: 'trophy',
|
|
rarity: 'common',
|
|
earnedAtLabel: 'Jan 15, 2024',
|
|
};
|
|
|
|
render(<AchievementGrid achievements={[commonAchievement]} />);
|
|
|
|
expect(screen.getByText('common')).toBeDefined();
|
|
});
|
|
|
|
it('applies correct rarity variant for rare', () => {
|
|
const rareAchievement = {
|
|
id: '2',
|
|
title: 'Rare Achievement',
|
|
description: 'Test description',
|
|
icon: 'trophy',
|
|
rarity: 'rare',
|
|
earnedAtLabel: 'Jan 15, 2024',
|
|
};
|
|
|
|
render(<AchievementGrid achievements={[rareAchievement]} />);
|
|
|
|
expect(screen.getByText('rare')).toBeDefined();
|
|
});
|
|
|
|
it('applies correct rarity variant for epic', () => {
|
|
const epicAchievement = {
|
|
id: '3',
|
|
title: 'Epic Achievement',
|
|
description: 'Test description',
|
|
icon: 'trophy',
|
|
rarity: 'epic',
|
|
earnedAtLabel: 'Jan 15, 2024',
|
|
};
|
|
|
|
render(<AchievementGrid achievements={[epicAchievement]} />);
|
|
|
|
expect(screen.getByText('epic')).toBeDefined();
|
|
});
|
|
|
|
it('applies correct rarity variant for legendary', () => {
|
|
const legendaryAchievement = {
|
|
id: '4',
|
|
title: 'Legendary Achievement',
|
|
description: 'Test description',
|
|
icon: 'trophy',
|
|
rarity: 'legendary',
|
|
earnedAtLabel: 'Jan 15, 2024',
|
|
};
|
|
|
|
render(<AchievementGrid achievements={[legendaryAchievement]} />);
|
|
|
|
expect(screen.getByText('legendary')).toBeDefined();
|
|
});
|
|
|
|
it('handles unknown rarity gracefully', () => {
|
|
const unknownRarityAchievement = {
|
|
id: '5',
|
|
title: 'Unknown Rarity Achievement',
|
|
description: 'Test description',
|
|
icon: 'trophy',
|
|
rarity: 'unknown',
|
|
earnedAtLabel: 'Jan 15, 2024',
|
|
};
|
|
|
|
render(<AchievementGrid achievements={[unknownRarityAchievement]} />);
|
|
|
|
expect(screen.getByText('unknown')).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('Multiple achievements', () => {
|
|
it('renders multiple achievements with different rarities', () => {
|
|
render(<AchievementGrid achievements={mockAchievements} />);
|
|
|
|
// Check all titles are rendered
|
|
mockAchievements.forEach((achievement) => {
|
|
expect(screen.getByText(achievement.title)).toBeDefined();
|
|
});
|
|
|
|
// Check all descriptions are rendered
|
|
mockAchievements.forEach((achievement) => {
|
|
expect(screen.getByText(achievement.description)).toBeDefined();
|
|
});
|
|
|
|
// Check all earned labels are rendered
|
|
mockAchievements.forEach((achievement) => {
|
|
expect(screen.getByText(achievement.earnedAtLabel)).toBeDefined();
|
|
});
|
|
});
|
|
|
|
it('renders achievements in order', () => {
|
|
render(<AchievementGrid achievements={mockAchievements} />);
|
|
|
|
// The component should render achievements in the order they are provided
|
|
const titles = screen.getAllByText(/Achievement|Victory|Demon|Champion|Legend/);
|
|
expect(titles.length).toBe(4);
|
|
});
|
|
});
|
|
|
|
describe('Edge cases', () => {
|
|
it('handles achievements with long titles', () => {
|
|
const longTitleAchievement = {
|
|
id: '1',
|
|
title: 'This is an extremely long achievement title that should still be displayed correctly without breaking the layout',
|
|
description: 'Test description',
|
|
icon: 'trophy',
|
|
rarity: 'common',
|
|
earnedAtLabel: 'Jan 15, 2024',
|
|
};
|
|
|
|
render(<AchievementGrid achievements={[longTitleAchievement]} />);
|
|
|
|
expect(screen.getByText(longTitleAchievement.title)).toBeDefined();
|
|
});
|
|
|
|
it('handles achievements with long descriptions', () => {
|
|
const longDescriptionAchievement = {
|
|
id: '1',
|
|
title: 'Achievement',
|
|
description: 'This is a very long description that spans multiple lines and contains detailed information about the achievement and its requirements',
|
|
icon: 'trophy',
|
|
rarity: 'common',
|
|
earnedAtLabel: 'Jan 15, 2024',
|
|
};
|
|
|
|
render(<AchievementGrid achievements={[longDescriptionAchievement]} />);
|
|
|
|
expect(screen.getByText(longDescriptionAchievement.description)).toBeDefined();
|
|
});
|
|
|
|
it('handles achievements with special characters in title', () => {
|
|
const specialTitleAchievement = {
|
|
id: '1',
|
|
title: 'Champion\'s Trophy #1!',
|
|
description: 'Test description',
|
|
icon: 'trophy',
|
|
rarity: 'common',
|
|
earnedAtLabel: 'Jan 15, 2024',
|
|
};
|
|
|
|
render(<AchievementGrid achievements={[specialTitleAchievement]} />);
|
|
|
|
expect(screen.getByText(specialTitleAchievement.title)).toBeDefined();
|
|
});
|
|
|
|
it('handles achievements with unicode characters in icon', () => {
|
|
const unicodeIconAchievement = {
|
|
id: '1',
|
|
title: 'Unicode Achievement',
|
|
description: 'Test description',
|
|
icon: '🌟',
|
|
rarity: 'common',
|
|
earnedAtLabel: 'Jan 15, 2024',
|
|
};
|
|
|
|
render(<AchievementGrid achievements={[unicodeIconAchievement]} />);
|
|
|
|
expect(screen.getByText('Unicode Achievement')).toBeDefined();
|
|
});
|
|
});
|
|
});
|