fix: harden reminders and state handling
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
} from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import { DEFAULT_SETTINGS } from '@shared/types'
|
||||
|
||||
/**
|
||||
* Тесты persistence-слоя. Мокаем electron.app.getPath на временную директорию
|
||||
@@ -147,6 +148,43 @@ describe('store · history cap', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('store · meal history', () => {
|
||||
it('markMealDone пишет meal-entry в историю', async () => {
|
||||
writeFileSync(
|
||||
statePath(),
|
||||
JSON.stringify({
|
||||
exercises: [],
|
||||
meals: [
|
||||
{
|
||||
id: 'm1',
|
||||
name: 'Обед',
|
||||
time: '13:00',
|
||||
icon: 'Soup',
|
||||
enabled: true,
|
||||
days: [],
|
||||
nextFireAt: Date.now() + 60_000
|
||||
}
|
||||
],
|
||||
challenges: [],
|
||||
history: []
|
||||
}),
|
||||
'utf-8'
|
||||
)
|
||||
|
||||
const { markMealDone, getHistory } = await load()
|
||||
expect(markMealDone('m1')).toBeDefined()
|
||||
expect(getHistory()).toMatchObject([
|
||||
{
|
||||
exerciseId: 'meal:m1',
|
||||
action: 'done',
|
||||
reps: 1,
|
||||
name: 'Обед',
|
||||
source: 'meal'
|
||||
}
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('store · clearHistory', () => {
|
||||
it('удаляет записи старше границы и возвращает количество', async () => {
|
||||
const ex = {
|
||||
@@ -195,4 +233,79 @@ describe('store · export / import', () => {
|
||||
expect(importState('not json at all')).toBe(false)
|
||||
expect(importState('42')).toBe(false)
|
||||
})
|
||||
|
||||
it('import сохраняет валидные части snapshot и отбрасывает повреждённые записи', async () => {
|
||||
const validExercise = {
|
||||
id: 'x1',
|
||||
name: 'Тест',
|
||||
reps: 10,
|
||||
icon: 'Activity',
|
||||
intervalMinutes: 30,
|
||||
enabled: true,
|
||||
nextFireAt: Date.now() + 1000
|
||||
}
|
||||
const validMeal = {
|
||||
id: 'm1',
|
||||
name: 'Обед',
|
||||
time: '13:00',
|
||||
icon: 'Soup',
|
||||
enabled: true,
|
||||
days: [],
|
||||
nextFireAt: Date.now() + 1000
|
||||
}
|
||||
const validChallenge = {
|
||||
id: 'c1',
|
||||
name: 'За убийства',
|
||||
gameId: 'dota2',
|
||||
stat: 'kills',
|
||||
multiplier: 1,
|
||||
exerciseName: 'Отжимания',
|
||||
icon: 'Dumbbell',
|
||||
enabled: true
|
||||
}
|
||||
|
||||
const { importState, getState, getSettings, getHistory } = await load()
|
||||
expect(
|
||||
importState(
|
||||
JSON.stringify({
|
||||
exercises: [
|
||||
validExercise,
|
||||
{ ...validExercise, id: 'bad-ex', intervalMinutes: -5 }
|
||||
],
|
||||
meals: [validMeal, { ...validMeal, id: 'bad-meal', time: '25:00' }],
|
||||
settings: {
|
||||
globalEnabled: false,
|
||||
snoozeMinutes: -1,
|
||||
language: 'xx'
|
||||
},
|
||||
challenges: [
|
||||
validChallenge,
|
||||
{ ...validChallenge, id: 'bad-challenge', gameId: 'cs2' }
|
||||
],
|
||||
gamesEnabled: { dota2: true, cs2: true },
|
||||
history: [
|
||||
{ ts: 100, exerciseId: 'x1', action: 'done', reps: 10 },
|
||||
{ ts: -1, exerciseId: 'x1', action: 'done', reps: 10 },
|
||||
{
|
||||
ts: 200,
|
||||
exerciseId: 'meal:m1',
|
||||
action: 'done',
|
||||
reps: 1,
|
||||
source: 'meal'
|
||||
}
|
||||
]
|
||||
})
|
||||
)
|
||||
).toBe(true)
|
||||
|
||||
const state = getState()
|
||||
expect(state.exercises.map((e) => e.id)).toEqual(['x1'])
|
||||
expect(state.meals.map((m) => m.id)).toEqual(['m1'])
|
||||
expect(state.challenges.map((c) => c.id)).toEqual(['c1'])
|
||||
expect(state.gamesEnabled).toEqual({ dota2: true })
|
||||
expect(getHistory().map((e) => e.ts)).toEqual([100, 200])
|
||||
expect(getSettings().globalEnabled).toBe(false)
|
||||
expect(getSettings().snoozeMinutes).toBe(DEFAULT_SETTINGS.snoozeMinutes)
|
||||
expect(getSettings().language).toBe(DEFAULT_SETTINGS.language)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user