diff --git a/src/components/__tests__/achievements.spec.ts b/src/components/__tests__/achievements.spec.ts index e6af386..4cf451b 100644 --- a/src/components/__tests__/achievements.spec.ts +++ b/src/components/__tests__/achievements.spec.ts @@ -1,7 +1,13 @@ import {describe, it, expect} from 'vitest'; import {mount} from '@vue/test-utils'; import {useAchievements} from '@/hooks/achievements'; -import {AchievementLevel, Category, type Achievements, type Favorites} from '@/utils/types'; +import { + AchievementLevel, + Category, + type AchievementProps, + type Achievements, + type Favorites, +} from '@/utils/types'; import {take} from 'remeda'; import {ALL_VEGGIES, BEANS, FRUITS, GRAINS, LEAFIES, ROOTS, VEGETABLES} from '@/utils/constants'; @@ -40,6 +46,16 @@ const getFavorites = (amount: number = 0) => {} as Favorites, ); +const getProps = (achievementProps: Partial = {}): AchievementProps => ({ + completedChallenges: 0, + favorites: getFavorites(), + hotStreakLength: 0, + totalWeeks: 0, + uniqueVeggies: [], + veggiesThisWeek: 0, + ...achievementProps, +}); + describe('achievements', () => { it('sets initial status', async () => { const {achievements} = await withSetup(useAchievements); @@ -48,153 +64,147 @@ describe('achievements', () => { it('advances completionist', async () => { const {advanceAchievements, achievements} = await withSetup(useAchievements); - advanceAchievements(0, [...Array(39)], 0, 0, 0, getFavorites()); + advanceAchievements(getProps({uniqueVeggies: [...Array(39)]})); expect(achievements.value.completionist).toEqual(AchievementLevel.NoAchievement); - advanceAchievements(0, [...Array(40)], 0, 0, 0, getFavorites()); + advanceAchievements(getProps({uniqueVeggies: [...Array(40)]})); expect(achievements.value.completionist).toBe(AchievementLevel.Bronze); - advanceAchievements(0, [...Array(80)], 0, 0, 0, getFavorites()); + advanceAchievements(getProps({uniqueVeggies: [...Array(80)]})); expect(achievements.value.completionist).toBe(AchievementLevel.Silver); - advanceAchievements(0, [...Array(150)], 0, 0, 0, getFavorites()); + advanceAchievements(getProps({uniqueVeggies: [...Array(150)]})); expect(achievements.value.completionist).toBe(AchievementLevel.Gold); }); it('goes straight to silver', async () => { const {advanceAchievements, achievements} = await withSetup(useAchievements); - advanceAchievements(0, [...Array(80)], 0, 0, 0, getFavorites()); + advanceAchievements(getProps({uniqueVeggies: [...Array(80)]})); expect(achievements.value.completionist).toBe(AchievementLevel.Silver); }); it('completionist goes straight to gold', async () => { const {advanceAchievements, achievements} = await withSetup(useAchievements); - advanceAchievements(0, [...Array(150)], 0, 0, 0, getFavorites()); + advanceAchievements(getProps({uniqueVeggies: [...Array(150)]})); expect(achievements.value.completionist).toBe(AchievementLevel.Gold); }); it('advances experimenterFruit', async () => { const {advanceAchievements, achievements} = await withSetup(useAchievements); - advanceAchievements(0, take(FRUITS, 14), 0, 0, 0, getFavorites()); + advanceAchievements(getProps({uniqueVeggies: take(FRUITS, 14)})); expect(achievements.value.experimenterFruit).toEqual(AchievementLevel.NoAchievement); - advanceAchievements(0, take(FRUITS, 15), 0, 0, 0, getFavorites()); - expect(achievements.value.experimenterFruit).toBe(AchievementLevel.Gold); - }); - - it('experimenter goes straight to gold', async () => { - const {advanceAchievements, achievements} = await withSetup(useAchievements); - advanceAchievements(0, take(FRUITS, 15), 0, 0, 0, getFavorites()); + advanceAchievements(getProps({uniqueVeggies: take(FRUITS, 15)})); expect(achievements.value.experimenterFruit).toBe(AchievementLevel.Gold); }); it('advances experimenterVegetable', async () => { const {advanceAchievements, achievements} = await withSetup(useAchievements); - advanceAchievements(0, take(VEGETABLES, 14), 0, 0, 0, getFavorites()); + advanceAchievements(getProps({uniqueVeggies: take(VEGETABLES, 14)})); expect(achievements.value.experimenterVegetable).toEqual(AchievementLevel.NoAchievement); - advanceAchievements(0, take(VEGETABLES, 15), 0, 0, 0, getFavorites()); + advanceAchievements(getProps({uniqueVeggies: take(VEGETABLES, 15)})); expect(achievements.value.experimenterVegetable).toBe(AchievementLevel.Gold); }); it('advances experimenterLeafy', async () => { const {advanceAchievements, achievements} = await withSetup(useAchievements); - advanceAchievements(0, take(LEAFIES, 14), 0, 0, 0, getFavorites()); + advanceAchievements(getProps({uniqueVeggies: take(LEAFIES, 14)})); expect(achievements.value.experimenterLeafy).toEqual(AchievementLevel.NoAchievement); - advanceAchievements(0, take(LEAFIES, 15), 0, 0, 0, getFavorites()); + advanceAchievements(getProps({uniqueVeggies: take(LEAFIES, 15)})); expect(achievements.value.experimenterLeafy).toBe(AchievementLevel.Gold); }); it('advances experimenterBean', async () => { const {advanceAchievements, achievements} = await withSetup(useAchievements); - advanceAchievements(0, take(BEANS, 14), 0, 0, 0, getFavorites()); + advanceAchievements(getProps({uniqueVeggies: take(BEANS, 14)})); expect(achievements.value.experimenterBean).toEqual(AchievementLevel.NoAchievement); - advanceAchievements(0, take(BEANS, 15), 0, 0, 0, getFavorites()); + advanceAchievements(getProps({uniqueVeggies: take(BEANS, 15)})); expect(achievements.value.experimenterBean).toBe(AchievementLevel.Gold); }); it('advances experimenterRoot', async () => { const {advanceAchievements, achievements} = await withSetup(useAchievements); - advanceAchievements(0, take(ROOTS, 14), 0, 0, 0, getFavorites()); + advanceAchievements(getProps({uniqueVeggies: take(ROOTS, 14)})); expect(achievements.value.experimenterRoot).toEqual(AchievementLevel.NoAchievement); - advanceAchievements(0, take(ROOTS, 15), 0, 0, 0, getFavorites()); + advanceAchievements(getProps({uniqueVeggies: take(ROOTS, 15)})); expect(achievements.value.experimenterRoot).toBe(AchievementLevel.Gold); }); it('advances experimenterGrain', async () => { const {advanceAchievements, achievements} = await withSetup(useAchievements); - advanceAchievements(0, take(GRAINS, 14), 0, 0, 0, getFavorites()); + advanceAchievements(getProps({uniqueVeggies: take(GRAINS, 14)})); expect(achievements.value.experimenterGrain).toEqual(AchievementLevel.NoAchievement); - advanceAchievements(0, take(GRAINS, 15), 0, 0, 0, getFavorites()); + advanceAchievements(getProps({uniqueVeggies: take(GRAINS, 15)})); expect(achievements.value.experimenterGrain).toBe(AchievementLevel.Gold); }); it('advances hot streak', async () => { const {advanceAchievements, achievements} = await withSetup(useAchievements); - advanceAchievements(0, [], 4, 0, 0, getFavorites()); + advanceAchievements(getProps({hotStreakLength: 4})); expect(achievements.value.hotStreak).toEqual(AchievementLevel.NoAchievement); - advanceAchievements(0, [], 5, 0, 0, getFavorites()); + advanceAchievements(getProps({hotStreakLength: 5})); expect(achievements.value.hotStreak).toEqual(AchievementLevel.Bronze); - advanceAchievements(0, [], 10, 0, 0, getFavorites()); + advanceAchievements(getProps({hotStreakLength: 10})); expect(achievements.value.hotStreak).toEqual(AchievementLevel.Silver); - advanceAchievements(0, [], 20, 0, 0, getFavorites()); + advanceAchievements(getProps({hotStreakLength: 20})); expect(achievements.value.hotStreak).toEqual(AchievementLevel.Gold); }); it('advances committed', async () => { const {advanceAchievements, achievements} = await withSetup(useAchievements); - advanceAchievements(0, [], 0, 11, 0, getFavorites()); + advanceAchievements(getProps({totalWeeks: 11})); expect(achievements.value.committed).toEqual(AchievementLevel.NoAchievement); - advanceAchievements(0, [], 0, 12, 0, getFavorites()); + advanceAchievements(getProps({totalWeeks: 12})); expect(achievements.value.committed).toEqual(AchievementLevel.Bronze); - advanceAchievements(0, [], 0, 26, 0, getFavorites()); + advanceAchievements(getProps({totalWeeks: 26})); expect(achievements.value.committed).toEqual(AchievementLevel.Silver); - advanceAchievements(0, [], 0, 52, 0, getFavorites()); + advanceAchievements(getProps({totalWeeks: 52})); expect(achievements.value.committed).toEqual(AchievementLevel.Gold); }); it('advances challengeAccepted', async () => { const {advanceAchievements, achievements} = await withSetup(useAchievements); - advanceAchievements(0, [], 0, 0, 4, getFavorites()); + advanceAchievements(getProps({completedChallenges: 4})); expect(achievements.value.challengeAccepted).toEqual(AchievementLevel.NoAchievement); - advanceAchievements(0, [], 0, 0, 5, getFavorites()); + advanceAchievements(getProps({completedChallenges: 5})); expect(achievements.value.challengeAccepted).toEqual(AchievementLevel.Bronze); - advanceAchievements(0, [], 0, 0, 10, getFavorites()); + advanceAchievements(getProps({completedChallenges: 10})); expect(achievements.value.challengeAccepted).toEqual(AchievementLevel.Silver); - advanceAchievements(0, [], 0, 0, 20, getFavorites()); + advanceAchievements(getProps({completedChallenges: 20})); expect(achievements.value.challengeAccepted).toEqual(AchievementLevel.Gold); }); it('advances thirtyVeggies', async () => { const {advanceAchievements, achievements} = await withSetup(useAchievements); - advanceAchievements(29, [], 0, 0, 0, getFavorites()); + advanceAchievements(getProps({veggiesThisWeek: 29})); expect(achievements.value.thirtyVeggies).toEqual(AchievementLevel.NoAchievement); - advanceAchievements(30, [], 0, 0, 0, getFavorites()); + advanceAchievements(getProps({veggiesThisWeek: 30})); expect(achievements.value.thirtyVeggies).toBe(AchievementLevel.Gold); - advanceAchievements(40, [], 0, 0, 0, getFavorites()); + advanceAchievements(getProps({veggiesThisWeek: 40})); expect(achievements.value.thirtyVeggies).toBe(AchievementLevel.Platinum); }); it('resets thirtyVeggies', async () => { const {advanceAchievements, achievements} = await withSetup(useAchievements); - advanceAchievements(30, [], 0, 0, 0, getFavorites()); + advanceAchievements(getProps({veggiesThisWeek: 30})); expect(achievements.value.thirtyVeggies).toEqual(AchievementLevel.Gold); - advanceAchievements(0, [], 0, 0, 0, getFavorites()); + advanceAchievements(getProps({veggiesThisWeek: 0})); expect(achievements.value.thirtyVeggies).toBe(AchievementLevel.NoAchievement); - advanceAchievements(40, [], 0, 0, 0, getFavorites()); + advanceAchievements(getProps({veggiesThisWeek: 40})); expect(achievements.value.thirtyVeggies).toEqual(AchievementLevel.Platinum); - advanceAchievements(0, [], 0, 0, 0, getFavorites()); + advanceAchievements(getProps({veggiesThisWeek: 0})); expect(achievements.value.thirtyVeggies).toBe(AchievementLevel.NoAchievement); - advanceAchievements(40, [], 0, 0, 0, getFavorites()); + advanceAchievements(getProps({veggiesThisWeek: 40})); expect(achievements.value.thirtyVeggies).toEqual(AchievementLevel.Platinum); - advanceAchievements(39, [], 0, 0, 0, getFavorites()); + advanceAchievements(getProps({veggiesThisWeek: 39})); expect(achievements.value.thirtyVeggies).toBe(AchievementLevel.Gold); }); it('advances favorite', async () => { const {advanceAchievements, achievements} = await withSetup(useAchievements); - advanceAchievements(0, [], 0, 0, 0, getFavorites(4)); + advanceAchievements(getProps({favorites: getFavorites(4)})); expect(achievements.value.favorite).toEqual(AchievementLevel.NoAchievement); - advanceAchievements(0, [], 0, 0, 0, getFavorites(5)); + advanceAchievements(getProps({favorites: getFavorites(5)})); expect(achievements.value.favorite).toEqual(AchievementLevel.Bronze); - advanceAchievements(0, [], 0, 0, 0, getFavorites(20)); + advanceAchievements(getProps({favorites: getFavorites(20)})); expect(achievements.value.favorite).toEqual(AchievementLevel.Silver); - advanceAchievements(0, [], 0, 0, 0, getFavorites(50)); + advanceAchievements(getProps({favorites: getFavorites(50)})); expect(achievements.value.favorite).toEqual(AchievementLevel.Gold); }); @@ -214,7 +224,14 @@ describe('achievements', () => { thirtyVeggies: AchievementLevel.Platinum, }; const {advanceAchievements, achievements, resetAchievements} = await withSetup(useAchievements); - advanceAchievements(40, ALL_VEGGIES, 30, 52, 20, getFavorites(50)); + advanceAchievements({ + completedChallenges: 20, + favorites: getFavorites(50), + hotStreakLength: 30, + totalWeeks: 52, + uniqueVeggies: ALL_VEGGIES, + veggiesThisWeek: 40, + }); expect(achievements.value).toEqual(expectedAchievements); resetAchievements(); expect(achievements.value).toEqual(defaultAchievements); diff --git a/src/hooks/achievements.ts b/src/hooks/achievements.ts index b301dd1..e5e1ea0 100644 --- a/src/hooks/achievements.ts +++ b/src/hooks/achievements.ts @@ -3,17 +3,11 @@ import {intersection, isDeepEqual, mapValues} from 'remeda'; import {createActor, setup, type MachineContext} from 'xstate'; import type {GuardArgs} from 'xstate/guards'; import {BEANS, FRUITS, GRAINS, LEAFIES, ROOTS, VEGETABLES} from '@/utils/constants'; -import type {Achievements, Favorites} from '@/utils/types'; +import type {AchievementProps, Achievements} from '@/utils/types'; type AdvanceEvent = { type: 'ADVANCE'; - veggiesThisWeek: number; - uniqueVeggies: string[]; - completedChallenges: number; - hotStreakLength: number; - totalWeeks: number; - favorites: Favorites; -}; +} & AchievementProps; type ResetEvent = { type: 'RESET'; @@ -448,22 +442,10 @@ export function useAchievements() { return { achievements, - advanceAchievements: ( - veggiesThisWeek: number, - uniqueVeggies: string[], - hotStreakLength: number, - totalWeeks: number, - completedChallenges: number, - favorites: Favorites, - ) => + advanceAchievements: (achievementProps: AchievementProps) => actor.send({ type: 'ADVANCE', - veggiesThisWeek, - uniqueVeggies, - hotStreakLength, - totalWeeks, - completedChallenges, - favorites, + ...achievementProps, }), resetAchievements: () => actor.send({type: 'RESET'}), }; diff --git a/src/stores/appStateStore.ts b/src/stores/appStateStore.ts index d2e40d3..3f0750b 100644 --- a/src/stores/appStateStore.ts +++ b/src/stores/appStateStore.ts @@ -16,14 +16,14 @@ export const useAppStateStore = defineStore('appState', () => { storeToRefs(useActivityStore()); watchEffect(() => - advanceAchievements( - currentVeggies.value.length, - uniqueVeggies.value, - hotStreak.value, - weeks.value.length, - completedChallenges.value, - favorites.value, - ), + advanceAchievements({ + completedChallenges: completedChallenges.value, + favorites: favorites.value, + hotStreakLength: hotStreak.value, + totalWeeks: weeks.value.length, + uniqueVeggies: uniqueVeggies.value, + veggiesThisWeek: currentVeggies.value.length, + }), ); // State refs diff --git a/src/utils/types.ts b/src/utils/types.ts index f475ce6..1fa77d8 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -2,6 +2,15 @@ import type {DateTime} from 'luxon'; export type Locale = 'en' | 'fi'; +export type AchievementProps = { + completedChallenges: number; + favorites: Favorites; + hotStreakLength: number; + totalWeeks: number; + uniqueVeggies: string[]; + veggiesThisWeek: number; +}; + export enum Category { Fruit = 'Fruit', Vegetable = 'Vegetable',