Skip to content

Commit c5cf97f

Browse files
added streaks.test.js
1 parent 14751b0 commit c5cf97f

2 files changed

Lines changed: 106 additions & 2 deletions

File tree

package.json

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,20 @@
77
"@testing-library/jest-dom": "^6.9.1",
88
"@testing-library/react": "^16.3.0",
99
"@testing-library/user-event": "^13.5.0",
10-
"date-fns": "^4.1.0",
1110
"framer-motion": "^12.23.22",
1211
"lucide-react": "^0.544.0",
1312
"react": "^19.2.0",
1413
"react-dom": "^19.2.0",
1514
"react-scripts": "5.0.1",
1615
"react-swipeable": "^7.0.2",
17-
"web-vitals": "^2.1.4"
16+
"web-vitals": "^2.1.4",
17+
"date-fns": "^4.1.0"
1818
},
1919
"scripts": {
2020
"start": "react-scripts start",
2121
"build": "react-scripts build",
2222
"test": "react-scripts test",
23+
"test:coverage": "react-scripts test --coverage",
2324
"eject": "react-scripts eject"
2425
},
2526
"eslintConfig": {
@@ -39,5 +40,15 @@
3940
"last 1 firefox version",
4041
"last 1 safari version"
4142
]
43+
},
44+
"jest": {
45+
"collectCoverageFrom": [
46+
"src/hooks/useAchievements.js"
47+
],
48+
"testMatch": [
49+
"<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
50+
"<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}",
51+
"<rootDir>/tests/**/*.{spec,test}.{js,jsx,ts,tsx}"
52+
]
4253
}
4354
}

src/tests/streaks.test.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import {
2+
calculateStreak,
3+
checkAndAwardAchievements,
4+
} from "../hooks/useAchievements";
5+
6+
describe("Streak and Achievement Tests (mocked dates)", () => {
7+
const makeHabitWithDays = (numDays, achievements = []) => {
8+
const completions = [];
9+
const today = new Date();
10+
today.setHours(0, 0, 0, 0);
11+
12+
for (let i = 0; i < numDays; i++) {
13+
const d = new Date(today.getTime() - i * 24 * 60 * 60 * 1000);
14+
completions.push(d);
15+
}
16+
17+
return { completions, achievements };
18+
};
19+
20+
describe("calculateStreak", () => {
21+
test("empty completions → streak = 0", () => {
22+
expect(calculateStreak({ completions: [], achievements: [] })).toBe(0);
23+
});
24+
25+
test("single completion → streak = 1", () => {
26+
expect(calculateStreak(makeHabitWithDays(1))).toBe(1);
27+
});
28+
29+
test("consecutive 3-day streak", () => {
30+
expect(calculateStreak(makeHabitWithDays(3))).toBe(3);
31+
});
32+
33+
test("streak breaks with gap", () => {
34+
const today = new Date();
35+
today.setHours(0, 0, 0, 0);
36+
const habit = {
37+
completions: [
38+
today,
39+
new Date(today.getTime() - 24 * 60 * 60 * 1000),
40+
new Date(today.getTime() - 3 * 24 * 60 * 60 * 1000),
41+
],
42+
achievements: [],
43+
};
44+
expect(calculateStreak(habit)).toBe(2);
45+
});
46+
47+
test("unordered completions still counted", () => {
48+
const today = new Date();
49+
today.setHours(0, 0, 0, 0);
50+
const habit = {
51+
completions: [new Date(today.getTime() - 24 * 60 * 60 * 1000), today],
52+
achievements: [],
53+
};
54+
expect(calculateStreak(habit)).toBe(2);
55+
});
56+
});
57+
58+
describe("checkAndAwardAchievements", () => {
59+
test("awards streak7 for 7-day streak", () => {
60+
const habit = makeHabitWithDays(7);
61+
const result = checkAndAwardAchievements(habit);
62+
expect(result.achievements).toContain("streak7");
63+
expect(result.newUnlocked).toContain("streak7");
64+
});
65+
66+
test("awards streak30 for 30-day streak", () => {
67+
const habit = makeHabitWithDays(30);
68+
const result = checkAndAwardAchievements(habit);
69+
expect(result.achievements).toContain("streak30");
70+
expect(result.newUnlocked).toContain("streak30");
71+
});
72+
73+
test("awards streak100 for 100-day streak", () => {
74+
const habit = makeHabitWithDays(100);
75+
const result = checkAndAwardAchievements(habit);
76+
expect(result.achievements).toContain("streak100");
77+
expect(result.newUnlocked).toContain("streak100");
78+
});
79+
80+
test("does not re-award existing achievements", () => {
81+
const habit = makeHabitWithDays(7, ["streak7"]);
82+
const result = checkAndAwardAchievements(habit);
83+
expect(result.achievements.filter((a) => a === "streak7").length).toBe(1);
84+
});
85+
86+
test("handles habits with no completions safely", () => {
87+
const habit = { completions: [], achievements: [] };
88+
const result = checkAndAwardAchievements(habit);
89+
expect(result.achievements).toEqual([]);
90+
expect(result.newUnlocked).toEqual([]);
91+
});
92+
});
93+
});

0 commit comments

Comments
 (0)