CI / Generate TypeScript types (push) Failing after 13m15s
CI / Server unit tests (push) Has been skipped
CI / Build server (push) Has been skipped
CI / Build client (push) Has been skipped
CI / Playwright E2E tests (push) Has been skipped
CI / Build and push Docker image (push) Has been skipped
CI / Notify (push) Successful in 2s
160 lines
6.1 KiB
TypeScript
160 lines
6.1 KiB
TypeScript
import * as fs from 'fs';
|
||
import * as path from 'path';
|
||
import axios from 'axios';
|
||
import { getMenuSladovnicka, getMenuTechTower, getMenuSenkSerikova, StaleWeekError } from '../restaurants';
|
||
|
||
jest.mock('axios');
|
||
const mockedAxios = axios as jest.Mocked<typeof axios>;
|
||
|
||
const fixturesDir = path.join(__dirname, 'fixtures');
|
||
const loadFixture = (name: string) => fs.readFileSync(path.join(fixturesDir, name), 'utf-8');
|
||
|
||
// Pondělí 12.5.2025
|
||
const MONDAY = new Date('2025-05-12');
|
||
|
||
beforeEach(() => {
|
||
jest.resetAllMocks();
|
||
});
|
||
|
||
describe('Sladovnicka parser', () => {
|
||
beforeEach(() => {
|
||
mockedAxios.get = jest.fn().mockResolvedValue({ data: loadFixture('sladovnicka.html') });
|
||
});
|
||
|
||
test('vrátí pole o délce 5 (jeden záznam na každý pracovní den)', async () => {
|
||
const menu = await getMenuSladovnicka(MONDAY);
|
||
expect(menu).toHaveLength(5);
|
||
});
|
||
|
||
test('pondělní menu obsahuje aspoň jedno jídlo', async () => {
|
||
const menu = await getMenuSladovnicka(MONDAY);
|
||
expect(menu[0].length).toBeGreaterThan(0);
|
||
});
|
||
|
||
test('první položka pondělního dne je polévka (isSoup=true)', async () => {
|
||
const menu = await getMenuSladovnicka(MONDAY);
|
||
expect(menu[0][0].isSoup).toBe(true);
|
||
});
|
||
|
||
test('jídla mají name, price a amount', async () => {
|
||
const menu = await getMenuSladovnicka(MONDAY);
|
||
const jidlo = menu[0][1];
|
||
expect(jidlo.name).toBeTruthy();
|
||
expect(jidlo.price).toBeTruthy();
|
||
expect(jidlo.amount).toBeTruthy();
|
||
});
|
||
|
||
test('alergeny jsou naparsovány jako čísla', async () => {
|
||
const menu = await getMenuSladovnicka(MONDAY);
|
||
const polievka = menu[0][0];
|
||
expect(Array.isArray(polievka.allergens)).toBe(true);
|
||
expect(polievka.allergens!.length).toBeGreaterThan(0);
|
||
expect(typeof polievka.allergens![0]).toBe('number');
|
||
});
|
||
});
|
||
|
||
describe('TechTower parser', () => {
|
||
beforeEach(() => {
|
||
mockedAxios.get = jest.fn().mockResolvedValue({ data: loadFixture('techtower.html') });
|
||
});
|
||
|
||
test('vrátí pole o délce 5', async () => {
|
||
const menu = await getMenuTechTower(MONDAY);
|
||
expect(menu).toHaveLength(5);
|
||
});
|
||
|
||
test('pondělní menu obsahuje polévku a hlavní jídla', async () => {
|
||
const menu = await getMenuTechTower(MONDAY);
|
||
expect(menu[0].some(f => f.isSoup)).toBe(true);
|
||
expect(menu[0].some(f => !f.isSoup)).toBe(true);
|
||
});
|
||
|
||
test('TechTower hodí StaleWeekError, pokud datum v hlavičce neodpovídá', async () => {
|
||
// Fixture obsahuje "12.5.-16.5.2025" – jiný týden = stale
|
||
const jinaStreda = new Date('2025-04-14');
|
||
await expect(getMenuTechTower(jinaStreda)).rejects.toBeInstanceOf(StaleWeekError);
|
||
});
|
||
|
||
test('StaleWeekError obsahuje naparsovaná data', async () => {
|
||
const jinaStreda = new Date('2025-04-14');
|
||
try {
|
||
await getMenuTechTower(jinaStreda);
|
||
} catch (e) {
|
||
expect(e).toBeInstanceOf(StaleWeekError);
|
||
const err = e as StaleWeekError;
|
||
expect(err.food).toHaveLength(5);
|
||
}
|
||
});
|
||
});
|
||
|
||
describe('TechTower parser – nový formát 07/2026', () => {
|
||
// Pondělí 6.7.2026 (pondělí je svátek, hlavička začíná úterým "7. 7.-10. 7.")
|
||
const MONDAY_2026 = new Date('2026-07-06');
|
||
|
||
beforeEach(() => {
|
||
mockedAxios.get = jest.fn().mockResolvedValue({ data: loadFixture('techtower-2026-07.html') });
|
||
});
|
||
|
||
test('vrátí pole o délce 5', async () => {
|
||
const menu = await getMenuTechTower(MONDAY_2026);
|
||
expect(menu).toHaveLength(5);
|
||
});
|
||
|
||
test('středeční menu obsahuje polévku a hlavní jídla s cenou', async () => {
|
||
const menu = await getMenuTechTower(MONDAY_2026);
|
||
// index 2 = středa (Boršč + hlavní jídla)
|
||
expect(menu[2].some(f => f.isSoup)).toBe(true);
|
||
expect(menu[2].some(f => !f.isSoup && f.price.includes('Kč'))).toBe(true);
|
||
});
|
||
|
||
test('cena i alergeny jsou správně odděleny od názvu jídla', async () => {
|
||
const menu = await getMenuTechTower(MONDAY_2026);
|
||
const polevka = menu[2].find(f => f.isSoup);
|
||
expect(polevka).toBeDefined();
|
||
// "Boršč 1,7,9 — 45 Kč" → název bez ceny a bez alergenů, cena a alergeny zvlášť
|
||
expect(polevka!.name).not.toMatch(/Kč/);
|
||
expect(polevka!.name).not.toMatch(/\d/);
|
||
expect(polevka!.price).toContain('Kč');
|
||
expect(Array.isArray(polevka!.allergens)).toBe(true);
|
||
expect(polevka!.allergens!.length).toBeGreaterThan(0);
|
||
});
|
||
|
||
test('nehodí StaleWeekError pro aktuální týden, i když pondělí je svátek', async () => {
|
||
await expect(getMenuTechTower(MONDAY_2026)).resolves.toHaveLength(5);
|
||
});
|
||
|
||
test('hodí StaleWeekError pro jiný týden', async () => {
|
||
const jinyTyden = new Date('2026-06-01');
|
||
await expect(getMenuTechTower(jinyTyden)).rejects.toBeInstanceOf(StaleWeekError);
|
||
});
|
||
});
|
||
|
||
describe('SenkSerikova parser', () => {
|
||
beforeEach(() => {
|
||
// SenkSerikova parsuje arraybuffer – musíme vrátit Buffer, ne string
|
||
mockedAxios.get = jest.fn().mockResolvedValue({
|
||
data: Buffer.from(loadFixture('senkserikova.html')),
|
||
headers: {}
|
||
});
|
||
});
|
||
|
||
test('parser provede HTTP request a vrátí pole', async () => {
|
||
const menu = await getMenuSenkSerikova(MONDAY);
|
||
expect(mockedAxios.get).toHaveBeenCalledTimes(1);
|
||
expect(Array.isArray(menu)).toBe(true);
|
||
});
|
||
|
||
test('výsledné dny s obsahem mají správnou strukturu (name, price, isSoup)', async () => {
|
||
const menu = await getMenuSenkSerikova(MONDAY);
|
||
// Protože MONDAY je v minulosti, parser vrátí placeholdery pro všechny pracovní
|
||
// dny a .menicka elementy přidá za ně – hledáme aspoň jeden den s reálnými daty
|
||
const denSJidlem = menu.find(den =>
|
||
den.length > 0 && den[0].name !== 'Pro tento den není uveřejněna nabídka jídel'
|
||
);
|
||
if (denSJidlem) {
|
||
expect(typeof denSJidlem[0].name).toBe('string');
|
||
expect(typeof denSJidlem[0].isSoup).toBe('boolean');
|
||
}
|
||
});
|
||
});
|