Files
laude/src/shared/types.test.ts
AnRil 36085f225f test: expand coverage 53 → 135 (+82 tests)
Аудит тестов выявил критические пробелы в покрытии. Расширили
существующие файлы и добавили два новых:

Новые файлы:
- src/main/validate.test.ts (59) — security-boundary IPC layer вообще
  не имел тестов. Покрывает NaN/Infinity, range edge cases, тип-
  сабверсии, partial-patch semantics, quietHours regex+dedup.
  Фиксирует контракт «strict для required, lenient для optional
  defaults» (input принимает enabled:'yes' → true, patch строгий).
- src/renderer/src/lib/icon-choices.test.ts (3) — SAMPLE_EXERCISES.icon
  ⊆ ICON_CHOICES (иначе fallback-Activity на первом запуске).

Расширения:
- format.test.ts: NaN/Infinity guard, EN-локаль.
- history.test.ts: DST-safe инвариант (unique keys, monotonic),
  plannedRepsToday, future-dated entries, mixed actions.
- i18n.test.ts: dict parity RU↔EN (с правильным skip для RU-only
  *_few CLDR-категории), regex-injection в var-значениях,
  weekday.short.* parity.

Рефакторинг:
- ICON_CHOICES вынесен в src/renderer/src/lib/icon-choices.ts
  (без JSX) — теперь whitelist импортируется из любого слоя без
  React-зависимости. icon.tsx реэкспортирует для обратной
  совместимости.
2026-05-19 18:15:37 +07:00

48 lines
1.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it } from 'vitest'
import {
DEFAULT_SETTINGS,
GAME_STATS,
SAMPLE_EXERCISES,
STAT_LABELS,
type GameStat
} from './types'
describe('DEFAULT_SETTINGS', () => {
it('uses safe defaults that do not surprise the user', () => {
expect(DEFAULT_SETTINGS.globalEnabled).toBe(true)
expect(DEFAULT_SETTINGS.notificationMode).toBe('modal')
expect(DEFAULT_SETTINGS.minimizeToTray).toBe(true)
expect(DEFAULT_SETTINGS.startWithWindows).toBe(false) // never auto-enroll
expect(DEFAULT_SETTINGS.snoozeMinutes).toBeGreaterThan(0)
})
})
describe('SAMPLE_EXERCISES', () => {
it('ships at least one enabled sample so the app is not empty on first launch', () => {
expect(SAMPLE_EXERCISES.length).toBeGreaterThan(0)
expect(SAMPLE_EXERCISES.some((e) => e.enabled)).toBe(true)
})
it('all samples have positive reps and intervals', () => {
for (const ex of SAMPLE_EXERCISES) {
expect(ex.reps, `reps for ${ex.name}`).toBeGreaterThan(0)
expect(ex.intervalMinutes, `interval for ${ex.name}`).toBeGreaterThan(0)
expect(ex.icon.length, `icon set for ${ex.name}`).toBeGreaterThan(0)
}
})
})
// NB: тест «sample icons ⊆ ICON_CHOICES» лежит в
// src/renderer/src/lib/icon-choices.test.ts — он тянет renderer-сторону
// (ICON_CHOICES), а node-tsconfig сюда не пускает renderer-импорты.
describe('STAT_LABELS', () => {
it('has a Russian label for every GameStat in every GAME_STATS bundle', () => {
for (const stats of Object.values(GAME_STATS)) {
for (const stat of stats as readonly GameStat[]) {
expect(STAT_LABELS[stat], `label for ${stat}`).toBeTruthy()
}
}
})
})