feat: večeře (extra meal slot)
CI / Generate TypeScript types (pull_request) Successful in 11s
CI / Generate TypeScript types (push) Successful in 36s
CI / Server unit tests (pull_request) Successful in 25s
CI / Build client (pull_request) Successful in 37s
CI / Server unit tests (push) Successful in 22s
CI / Build server (push) Successful in 1m0s
CI / Build client (push) Successful in 37s
CI / Build server (pull_request) Successful in 3m14s
CI / Playwright E2E tests (push) Successful in 1m18s
CI / Build and push Docker image (push) Has been skipped
CI / Notify (push) Successful in 2s
CI / Playwright E2E tests (pull_request) Successful in 10m34s
CI / Build and push Docker image (pull_request) Has been skipped
CI / Notify (pull_request) Has been skipped

- Nová stránka /vecere pro evidenci extra jídla (večeře/pozdní oběd)
- MealSlot enum (obed/extra), oddělený storage namespace YYYY-MM-DD_extra
- slot parametr na všech food endpointech a GET /api/data
- Push reminder: přechod na 60min cooldown, login v payloadu místo endpointu
- server: slot?: string → slot?: MealSlot, enum konstanty místo literálů
- Jest testy izolace extra/obed storage namespace
- Aktualizace changelogů (saláty, SINGLE_PAYMENT, večeře)
This commit is contained in:
2026-05-06 20:37:39 +02:00
parent 5f903797f1
commit 774be3df6d
22 changed files with 441 additions and 107 deletions
+60
View File
@@ -0,0 +1,60 @@
const mockStorageData = new Map<string, any>();
jest.mock('../storage', () => ({
__esModule: true,
default: () => ({
hasData: async (key: string) => mockStorageData.has(key),
getData: async <T>(key: string) => mockStorageData.get(key) as T,
setData: async <T>(key: string, val: T) => void mockStorageData.set(key, val),
}),
storageReady: Promise.resolve(),
}));
import { addChoice, getData } from '../service';
import { LunchChoice, MealSlot } from '../../../types/gen/types.gen';
const TODAY = new Date('2025-01-10');
const TODAY_STR = '2025-01-10';
const TODAY_EXTRA_STR = '2025-01-10_extra';
describe('MealSlot storage isolation', () => {
beforeEach(() => {
mockStorageData.clear();
jest.useFakeTimers();
jest.setSystemTime(TODAY);
});
afterEach(() => {
jest.useRealTimers();
});
test('addChoice slot=extra writes only to _extra key, not to obed key, and returns slot=EXTRA', async () => {
const result = await addChoice('user1', false, LunchChoice.OBJEDNAVAM, undefined, TODAY, MealSlot.EXTRA);
expect(result.slot).toBe(MealSlot.EXTRA);
expect(mockStorageData.has(TODAY_EXTRA_STR)).toBe(true);
expect(mockStorageData.has(TODAY_STR)).toBe(false);
const extraData = mockStorageData.get(TODAY_EXTRA_STR);
expect(extraData.choices.OBJEDNAVAM?.['user1']).toBeDefined();
});
test('getData slot=extra returns slot===MealSlot.EXTRA and no menus', async () => {
await addChoice('user1', false, LunchChoice.OBJEDNAVAM, undefined, TODAY, MealSlot.EXTRA);
const result = await getData(TODAY, MealSlot.EXTRA);
expect(result.slot).toBe(MealSlot.EXTRA);
expect(result.menus).toBeUndefined();
});
test('addChoice slot=extra does not modify obed data even when obed has PIZZA choice', async () => {
mockStorageData.set(TODAY_STR, {
choices: { PIZZA: { user1: { selectedFoods: [0], trusted: false } } },
todayDayIndex: 4,
date: '10. 1. 2025',
isWeekend: false,
dayIndex: 4,
});
await addChoice('user1', false, LunchChoice.OBJEDNAVAM, undefined, TODAY, MealSlot.EXTRA);
const obed = mockStorageData.get(TODAY_STR);
expect(obed.choices.PIZZA?.['user1']).toBeDefined();
});
});