feat: lepší generování mock dat při vývoji
CI / Generate TypeScript types (push) Successful in 11s
CI / Server unit tests (push) Successful in 25s
CI / Build server (push) Successful in 28s
CI / Build client (push) Successful in 41s
CI / Playwright E2E tests (push) Successful in 1m45s
CI / Build and push Docker image (push) Successful in 46s
CI / Notify (push) Successful in 2s

This commit is contained in:
2026-08-25 10:31:32 +02:00
parent 9027de5f8b
commit 93242b7c7e
7 changed files with 221 additions and 98 deletions
+122 -74
View File
@@ -56,106 +56,154 @@ function requireDevMode(req: any, res: any, next: any) {
router.use(requireDevMode);
/** Indexy všech pracovních dnů týdne (pondělí až pátek). */
const WEEK_DAY_INDEXES = [0, 1, 2, 3, 4];
/**
* Vygeneruje mock data pro testování.
* Vygeneruje mock data pro jeden den týdne.
* @returns počet skutečně vygenerovaných záznamů
*/
async function generateMockDataForDay(dayIndex: number, requestedCount?: number): Promise<number> {
const count = requestedCount ?? Math.floor(Math.random() * 16) + 5; // 5-20
const date = getDateForWeekIndex(dayIndex);
await initIfNeeded(date);
const dateKey = formatDate(date);
const data = await storage.getData<any>(dateKey);
// Získání menu restaurací pro vybraný den
const menus: { [key: string]: any } = {};
for (const restaurant of RESTAURANTS_WITH_MENU) {
const menu = await getRestaurantMenu(restaurant as any, date);
if (menu?.food?.length) {
menus[restaurant] = menu.food;
}
}
// Vygenerování náhodných uživatelů
const usedNames = new Set<string>();
for (let i = 0; i < count && usedNames.size < MOCK_NAMES.length; i++) {
// Vybereme náhodné jméno, které ještě nebylo použito
let name: string;
do {
name = MOCK_NAMES[Math.floor(Math.random() * MOCK_NAMES.length)];
} while (usedNames.has(name));
usedNames.add(name);
// Vybereme náhodnou volbu stravování
const choice = LUNCH_CHOICES[Math.floor(Math.random() * LUNCH_CHOICES.length)];
// Inicializace struktury pro volbu
data.choices[choice] ??= {};
const userChoice: any = {
trusted: false,
selectedFoods: [],
};
// Pokud má restaurace menu, vybereme náhodné jídlo
if (RESTAURANTS_WITH_MENU.includes(choice) && menus[choice]?.length) {
const foods = menus[choice];
// Vybereme náhodné jídlo (ne polévku)
const mainFoods = foods.filter((f: any) => !f.isSoup);
if (mainFoods.length > 0) {
const randomFoodIndex = foods.indexOf(mainFoods[Math.floor(Math.random() * mainFoods.length)]);
userChoice.selectedFoods = [randomFoodIndex];
}
}
data.choices[choice][name] = userChoice;
}
await storage.setData(dateKey, data);
return usedNames.size;
}
/** Smaže všechny volby (a pizza day) pro jeden den týdne. */
async function clearMockDataForDay(dayIndex: number): Promise<void> {
const date = getDateForWeekIndex(dayIndex);
await initIfNeeded(date);
const dateKey = formatDate(date);
const data = await storage.getData<any>(dateKey);
// Vymažeme všechny volby i aktivní pizza day
data.choices = {};
delete data.pizzaDay;
await storage.setData(dateKey, data);
}
/** Rozešle klientům aktuální data pro dané datum. */
async function broadcastDate(date: Date) {
const clientData = await getData(date);
getWebsocket().emit("message", clientData);
}
/**
* Vygeneruje mock data pro testování - pro jeden den, nebo pro celý týden.
*/
router.post("/generate", async (req: Request<{}, any, any>, res, next) => {
try {
const wholeWeek = req.body?.wholeWeek === true;
const count: number | undefined = req.body?.count;
if (wholeWeek) {
// Pro každý den generujeme zvlášť - pokud není zadán počet, bude pro každý den náhodný
const days: { dayIndex: number, count: number }[] = [];
for (const dayIndex of WEEK_DAY_INDEXES) {
days.push({ dayIndex, count: await generateMockDataForDay(dayIndex, count) });
}
// Klientům stačí poslat data dnešního dne, ostatní si dotáhnou při přepnutí
await broadcastDate(getToday());
const total = days.reduce((sum, day) => sum + day.count, 0);
return res.status(200).json({ success: true, count: total, days });
}
const dayIndex = req.body?.dayIndex ?? getDayOfWeekIndex(getToday());
const count = req.body?.count ?? Math.floor(Math.random() * 16) + 5; // 5-20
if (dayIndex < 0 || dayIndex > 4) {
return res.status(400).json({ error: 'Neplatný index dne (0-4)' });
}
const date = getDateForWeekIndex(dayIndex);
await initIfNeeded(date);
const generated = await generateMockDataForDay(dayIndex, count);
await broadcastDate(getDateForWeekIndex(dayIndex));
const dateKey = formatDate(date);
const data = await storage.getData<any>(dateKey);
// Získání menu restaurací pro vybraný den
const menus: { [key: string]: any } = {};
for (const restaurant of RESTAURANTS_WITH_MENU) {
const menu = await getRestaurantMenu(restaurant as any, date);
if (menu?.food?.length) {
menus[restaurant] = menu.food;
}
}
// Vygenerování náhodných uživatelů
const usedNames = new Set<string>();
for (let i = 0; i < count && usedNames.size < MOCK_NAMES.length; i++) {
// Vybereme náhodné jméno, které ještě nebylo použito
let name: string;
do {
name = MOCK_NAMES[Math.floor(Math.random() * MOCK_NAMES.length)];
} while (usedNames.has(name));
usedNames.add(name);
// Vybereme náhodnou volbu stravování
const choice = LUNCH_CHOICES[Math.floor(Math.random() * LUNCH_CHOICES.length)];
// Inicializace struktury pro volbu
data.choices[choice] ??= {};
const userChoice: any = {
trusted: false,
selectedFoods: [],
};
// Pokud má restaurace menu, vybereme náhodné jídlo
if (RESTAURANTS_WITH_MENU.includes(choice) && menus[choice]?.length) {
const foods = menus[choice];
// Vybereme náhodné jídlo (ne polévku)
const mainFoods = foods.filter((f: any) => !f.isSoup);
if (mainFoods.length > 0) {
const randomFoodIndex = foods.indexOf(mainFoods[Math.floor(Math.random() * mainFoods.length)]);
userChoice.selectedFoods = [randomFoodIndex];
}
}
data.choices[choice][name] = userChoice;
}
await storage.setData(dateKey, data);
// Odeslat aktualizovaná data přes WebSocket
const clientData = await getData(date);
getWebsocket().emit("message", clientData);
res.status(200).json({ success: true, count: usedNames.size, dayIndex });
res.status(200).json({ success: true, count: generated, dayIndex });
} catch (e: any) {
next(e);
}
});
/**
* Smaže všechny volby pro daný den.
* Smaže všechny volby pro daný den, nebo pro celý týden.
*/
router.post("/clear", async (req: Request<{}, any, any>, res, next) => {
try {
const wholeWeek = req.body?.wholeWeek === true;
if (wholeWeek) {
for (const dayIndex of WEEK_DAY_INDEXES) {
await clearMockDataForDay(dayIndex);
}
await broadcastDate(getToday());
return res.status(200).json({ success: true, days: WEEK_DAY_INDEXES.map(dayIndex => ({ dayIndex })) });
}
const dayIndex = req.body?.dayIndex ?? getDayOfWeekIndex(getToday());
if (dayIndex < 0 || dayIndex > 4) {
return res.status(400).json({ error: 'Neplatný index dne (0-4)' });
}
const date = getDateForWeekIndex(dayIndex);
await initIfNeeded(date);
const dateKey = formatDate(date);
const data = await storage.getData<any>(dateKey);
// Vymažeme všechny volby i aktivní pizza day
data.choices = {};
delete data.pizzaDay;
await storage.setData(dateKey, data);
// Odeslat aktualizovaná data přes WebSocket
const clientData = await getData(date);
getWebsocket().emit("message", clientData);
await clearMockDataForDay(dayIndex);
await broadcastDate(getDateForWeekIndex(dayIndex));
res.status(200).json({ success: true, dayIndex });
} catch (e: any) {