diff --git a/assets/icons/4c81a955-e90c-44e6-b702-458e53525e14.jpg b/assets/icons/4c81a955-e90c-44e6-b702-458e53525e14.jpg deleted file mode 100644 index fc368f9..0000000 Binary files a/assets/icons/4c81a955-e90c-44e6-b702-458e53525e14.jpg and /dev/null differ diff --git a/assets/icons/610931c7-7481-468b-a0bb-fedb223c3fd1.jpg b/assets/icons/610931c7-7481-468b-a0bb-fedb223c3fd1.jpg deleted file mode 100644 index 25dc8b1..0000000 Binary files a/assets/icons/610931c7-7481-468b-a0bb-fedb223c3fd1.jpg and /dev/null differ diff --git a/assets/icons/ChatGPT Image 6. Dez. 2025, 09_38_05.png b/assets/icons/ChatGPT Image 6. Dez. 2025, 09_38_05.png deleted file mode 100644 index 80db816..0000000 Binary files a/assets/icons/ChatGPT Image 6. Dez. 2025, 09_38_05.png and /dev/null differ diff --git a/assets/icons/IMG_2709.JPG b/assets/icons/IMG_2709.JPG deleted file mode 100644 index 2eb8e56..0000000 Binary files a/assets/icons/IMG_2709.JPG and /dev/null differ diff --git a/assets/icons/IMG_2710.JPG b/assets/icons/IMG_2710.JPG deleted file mode 100644 index d8dc6b4..0000000 Binary files a/assets/icons/IMG_2710.JPG and /dev/null differ diff --git a/assets/icons/IMG_2711.PNG b/assets/icons/IMG_2711.PNG deleted file mode 100644 index 3ff132f..0000000 Binary files a/assets/icons/IMG_2711.PNG and /dev/null differ diff --git a/assets/icons/IMG_2712.PNG b/assets/icons/IMG_2712.PNG deleted file mode 100644 index e83715b..0000000 Binary files a/assets/icons/IMG_2712.PNG and /dev/null differ diff --git a/assets/icons/ad017699-a59f-43c1-a101-60d51d5f6eca.jpg b/assets/icons/ad017699-a59f-43c1-a101-60d51d5f6eca.jpg deleted file mode 100644 index 1ca3dff..0000000 Binary files a/assets/icons/ad017699-a59f-43c1-a101-60d51d5f6eca.jpg and /dev/null differ diff --git a/assets/icons/dead4a07-3cd3-4527-a9ba-a704cabb56e3.jpg b/assets/icons/dead4a07-3cd3-4527-a9ba-a704cabb56e3.jpg deleted file mode 100644 index 5334049..0000000 Binary files a/assets/icons/dead4a07-3cd3-4527-a9ba-a704cabb56e3.jpg and /dev/null differ diff --git a/services/__tests__/useGameFeedback.test.ts b/services/__tests__/useGameFeedback.test.ts new file mode 100644 index 0000000..10ace92 --- /dev/null +++ b/services/__tests__/useGameFeedback.test.ts @@ -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)); + }); +}); diff --git a/services/useGameFeedback.ts b/services/useGameFeedback.ts index ef42445..b2b66ee 100644 --- a/services/useGameFeedback.ts +++ b/services/useGameFeedback.ts @@ -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) {