Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed assets/icons/IMG_2709.JPG
Binary file not shown.
Binary file removed assets/icons/IMG_2710.JPG
Binary file not shown.
Binary file removed assets/icons/IMG_2711.PNG
Binary file not shown.
Binary file removed assets/icons/IMG_2712.PNG
Binary file not shown.
Binary file not shown.
Binary file not shown.
62 changes: 62 additions & 0 deletions services/__tests__/useGameFeedback.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* useGameFeedback Hook Tests
*/
import { renderHook, waitFor } from '@testing-library/react-native';

jest.mock('../StorageManager', () => ({
__esModule: true,
default: {
getSetting: jest.fn().mockResolvedValue(true),
getGallery: jest.fn().mockResolvedValue([]),
getProgress: jest.fn().mockResolvedValue({ levels: {}, totalLevelsCompleted: 0 }),
},
}));

jest.mock('../SoundManager', () => ({
__esModule: true,
default: { playCelebration: jest.fn() },
}));

jest.mock('../StreakManager', () => ({
getStreakData: jest.fn().mockResolvedValue({ currentStreak: 0 }),
}));

const mockCheckAndUnlock = jest.fn().mockResolvedValue([]);
jest.mock('../AchievementManager', () => ({
checkAndUnlock: (...args: unknown[]) => mockCheckAndUnlock(...args),
}));

import SoundManager from '../SoundManager';
import { useGameFeedback } from '../useGameFeedback';

describe('useGameFeedback', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('feiert und prüft Abzeichen auch bei gleicher Sternzahl in der nächsten Runde', async () => {
const { rerender } = renderHook(({ rating }: { rating: number }) => useGameFeedback(rating), {
initialProps: { rating: 0 },
});

rerender({ rating: 5 });
await waitFor(() => expect(mockCheckAndUnlock).toHaveBeenCalledTimes(1));
expect(SoundManager.playCelebration).toHaveBeenCalledTimes(1);

// Nächste Runde: Rating wird zurückgesetzt, dann wieder 5 Sterne
rerender({ rating: 0 });
rerender({ rating: 5 });
await waitFor(() => expect(mockCheckAndUnlock).toHaveBeenCalledTimes(2));
expect(SoundManager.playCelebration).toHaveBeenCalledTimes(2);
});

it('prüft dieselbe Bewertung innerhalb einer Runde nur einmal', async () => {
const { rerender } = renderHook(({ rating }: { rating: number }) => useGameFeedback(rating), {
initialProps: { rating: 3 },
});
await waitFor(() => expect(mockCheckAndUnlock).toHaveBeenCalledTimes(1));

rerender({ rating: 3 });
await waitFor(() => expect(mockCheckAndUnlock).toHaveBeenCalledTimes(1));
});
});
8 changes: 7 additions & 1 deletion services/useGameFeedback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,13 @@ export function useGameFeedback(userRating: number) {
}, []);

useEffect(() => {
if (userRating === 0 || userRating === lastCheckedRatingRef.current) return;
// Neue Runde (Rating zurück auf 0): Merker zurücksetzen, sonst würde dieselbe
// Sternzahl in der nächsten Runde als "schon geprüft" übersprungen
if (userRating === 0) {
lastCheckedRatingRef.current = 0;
return;
}
if (userRating === lastCheckedRatingRef.current) return;
lastCheckedRatingRef.current = userRating;

if (userRating >= 4 && FeatureFlags.ENABLE_CONFETTI && celebrationEnabled) {
Expand Down
Loading