Skip to content

Commit d6bb37e

Browse files
authored
test(theme-glacier): verify color variables and configuration for glacier theme (JhaSourav07#3273)
## Description Fixes JhaSourav07#2321 ## Pillar - [ ] 🎨 Pillar 1 — New Theme Design - [ ] 📐 Pillar 2 — Geometric SVG Improvement - [ ] 🕐 Pillar 3 — Timezone Logic Optimization - [x] 🛠️ Other (Bug fix, refactoring, docs) ## Visual Preview No SVG changes — test-only PR. All 5 tests pass locally. ## Checklist before requesting a review: - [x] I have read the `CONTRIBUTING.md` file. - [x] I have tested these changes locally (`localhost:3000/api/streak?user=Tapasya-12`). - [x] I have run `npm run format` and `npm run lint` locally and resolved all errors (CI will fail otherwise). - [x] My commits follow the Conventional Commits format (e.g., `feat(themes): ...`, `fix(calculate): ...`). - [ ] I have updated `README.md` if I added a new theme or URL parameter. - [x] I have started the repo. - [x] I have made sure that i have only one commit to merge in this PR. - [ ] The SVG output matches the CommitPulse "premium quality" aesthetic standard (no raw elements, smooth animations, correct fonts). - [ ] (Recommended) I joined the CommitPulse Discord community for contributor discussions, mentorship, and faster PR support.
2 parents e718a2f + 43b0af7 commit d6bb37e

1 file changed

Lines changed: 124 additions & 0 deletions

File tree

lib/svg/glacier.test.ts

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { themes } from './themes';
3+
import { generateSVG } from './generator';
4+
import type { StreakStats, ContributionCalendar, BadgeParams } from '../../types/index';
5+
6+
const mockStats: StreakStats = {
7+
currentStreak: 5,
8+
longestStreak: 10,
9+
totalContributions: 120,
10+
todayDate: '2024-06-01',
11+
};
12+
13+
const mockCalendar: ContributionCalendar = {
14+
totalContributions: 120,
15+
weeks: [
16+
{
17+
contributionDays: [
18+
{ contributionCount: 3, date: '2024-05-26' },
19+
{ contributionCount: 0, date: '2024-05-27' },
20+
{ contributionCount: 5, date: '2024-05-28' },
21+
{ contributionCount: 2, date: '2024-05-29' },
22+
{ contributionCount: 4, date: '2024-05-30' },
23+
{ contributionCount: 1, date: '2024-05-31' },
24+
{ contributionCount: 6, date: '2024-06-01' },
25+
],
26+
},
27+
],
28+
};
29+
30+
const glacierAccent = Array.isArray(themes.glacier.accent)
31+
? themes.glacier.accent[0]
32+
: themes.glacier.accent;
33+
34+
const mockParams = {
35+
user: 'octocat',
36+
bg: themes.glacier.bg,
37+
text: themes.glacier.text,
38+
accent: glacierAccent,
39+
size: 'medium',
40+
scale: 'linear',
41+
grace: 1,
42+
refresh: false,
43+
hide_title: false,
44+
hide_background: false,
45+
hide_stats: false,
46+
lang: 'en',
47+
view: 'default',
48+
delta_format: 'percent',
49+
mode: 'commits',
50+
entrance: 'rise',
51+
format: 'svg',
52+
radius: 8,
53+
speed: '8s',
54+
opacity: 1.0,
55+
labels: false,
56+
shading: false,
57+
gradient: false,
58+
disable_particles: false,
59+
glow: true,
60+
} as BadgeParams;
61+
62+
const HEX_REGEX = /^[0-9a-fA-F]{3}$|^[0-9a-fA-F]{6}$/;
63+
64+
function hexToRgb(hex: string): [number, number, number] {
65+
const h = hex.replace('#', '');
66+
const full =
67+
h.length === 3
68+
? h
69+
.split('')
70+
.map((c) => c + c)
71+
.join('')
72+
: h;
73+
const n = parseInt(full, 16);
74+
return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
75+
}
76+
77+
function relativeLuminance(hex: string): number {
78+
const [r, g, b] = hexToRgb(hex).map((c) => {
79+
const s = c / 255;
80+
return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
81+
});
82+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
83+
}
84+
85+
function contrastRatio(hex1: string, hex2: string): number {
86+
const l1 = relativeLuminance(hex1);
87+
const l2 = relativeLuminance(hex2);
88+
const lighter = Math.max(l1, l2);
89+
const darker = Math.min(l1, l2);
90+
return (lighter + 0.05) / (darker + 0.05);
91+
}
92+
93+
describe('glacier theme', () => {
94+
it('exists as a key in the themes object', () => {
95+
expect(Object.hasOwn(themes, 'glacier')).toBe(true);
96+
});
97+
98+
it('has valid hex color strings for bg, text, and accent', () => {
99+
const { bg, text, accent } = themes.glacier;
100+
const accentStr = Array.isArray(accent) ? accent[0] : accent;
101+
expect(HEX_REGEX.test(bg)).toBe(true);
102+
expect(HEX_REGEX.test(text)).toBe(true);
103+
expect(HEX_REGEX.test(accentStr)).toBe(true);
104+
});
105+
106+
it('has the correct specific color values', () => {
107+
expect(themes.glacier.bg).toBe('e0f2fe');
108+
expect(themes.glacier.text).toBe('0369a1');
109+
expect(glacierAccent).toBe('06b6d4');
110+
});
111+
112+
it('meets WCAG AA contrast ratio (≥ 4.5) between bg and text', () => {
113+
const ratio = contrastRatio(themes.glacier.bg, themes.glacier.text);
114+
expect(ratio).toBeGreaterThanOrEqual(4.5);
115+
});
116+
117+
it('generates SVG output containing the glacier theme hex colors', () => {
118+
const svg = generateSVG(mockStats, mockParams, mockCalendar);
119+
expect(typeof svg).toBe('string');
120+
expect(svg.length).toBeGreaterThan(100);
121+
expect(svg).toMatch(new RegExp(`#?${glacierAccent}`, 'i'));
122+
expect(svg).toContain('<svg');
123+
});
124+
});

0 commit comments

Comments
 (0)