Files
kochwas/tests/unit/ingredient.test.ts

105 lines
3.7 KiB
TypeScript
Raw Permalink Normal View History

import { describe, it, expect } from 'vitest';
import { parseIngredient } from '../../src/lib/server/parsers/ingredient';
describe('parseIngredient', () => {
it.each([
['200 g Mehl', { quantity: 200, unit: 'g', name: 'Mehl' }],
['1 kg Kartoffeln', { quantity: 1, unit: 'kg', name: 'Kartoffeln' }],
['500 ml Milch', { quantity: 500, unit: 'ml', name: 'Milch' }],
['1 TL Salz', { quantity: 1, unit: 'TL', name: 'Salz' }],
['2 EL Olivenöl', { quantity: 2, unit: 'EL', name: 'Olivenöl' }],
['3 Eier', { quantity: 3, unit: null, name: 'Eier' }],
['1/2 Zitrone', { quantity: 0.5, unit: null, name: 'Zitrone' }],
['1,5 l Wasser', { quantity: 1.5, unit: 'l', name: 'Wasser' }]
] as const)('parses %s', (input, expected) => {
const parsed = parseIngredient(input);
expect(parsed.quantity).toBe(expected.quantity);
expect(parsed.unit).toBe(expected.unit);
expect(parsed.name).toBe(expected.name);
expect(parsed.raw_text).toBe(input);
});
it('handles notes', () => {
const p = parseIngredient('200 g Mehl (Type 550)');
expect(p.quantity).toBe(200);
expect(p.name).toBe('Mehl');
expect(p.note).toBe('Type 550');
});
it('falls back to raw_text when unparsable', () => {
const p = parseIngredient('etwas frischer Pfeffer');
expect(p.quantity).toBeNull();
expect(p.unit).toBeNull();
expect(p.name).toBe('etwas frischer Pfeffer');
expect(p.raw_text).toBe('etwas frischer Pfeffer');
});
it('handles ranges by taking the lower bound', () => {
const p = parseIngredient('2-3 Tomaten');
expect(p.quantity).toBe(2);
expect(p.name).toBe('Tomaten');
});
describe('Unicode-Bruchzeichen', () => {
it.each([
['½ TL Salz', 0.5, 'TL', 'Salz'],
['¼ kg Zucker', 0.25, 'kg', 'Zucker'],
['¾ l Milch', 0.75, 'l', 'Milch'],
['⅓ Tasse Mehl', 1 / 3, 'Tasse', 'Mehl'],
['⅔ TL Pfeffer', 2 / 3, 'TL', 'Pfeffer'],
['⅛ TL Muskat', 0.125, 'TL', 'Muskat']
] as const)('%s', (input, qty, unit, name) => {
const p = parseIngredient(input);
expect(p.quantity).toBeCloseTo(qty, 5);
expect(p.unit).toBe(unit);
expect(p.name).toBe(name);
});
it('Unicode-Bruch ohne Unit', () => {
const p = parseIngredient('½ Zitrone');
expect(p.quantity).toBeCloseTo(0.5, 5);
expect(p.unit).toBe(null);
expect(p.name).toBe('Zitrone');
});
});
describe('Mengen-Plausibilitaet (Bounds)', () => {
it('weist 0 als Menge ab → quantity null', () => {
const p = parseIngredient('0 g Mehl');
expect(p.quantity).toBe(null);
// name bleibt das was nach der "0" kommt — Importer muss das nicht
// perfekt rekonstruieren, der raw_text bleibt erhalten.
expect(p.raw_text).toBe('0 g Mehl');
});
it('weist negative Menge ab', () => {
// "-1 EL Öl" — Minus führt regex direkt ins Fallback (kein \d am Start),
// also bleibt name = full text.
const p = parseIngredient('-1 EL Öl');
expect(p.quantity).toBe(null);
});
it('weist Menge > 10000 ab', () => {
const p = parseIngredient('99999 g Hokuspokus');
expect(p.quantity).toBe(null);
});
it('akzeptiert die Obergrenze 10000 selbst', () => {
const p = parseIngredient('10000 g Mehl');
expect(p.quantity).toBe(10000);
});
it('akzeptiert führende Null bei Dezimalbrüchen', () => {
const p = parseIngredient('0.5 kg Salz');
expect(p.quantity).toBe(0.5);
expect(p.unit).toBe('kg');
});
it('akzeptiert deutsche führende Null', () => {
const p = parseIngredient('0,25 l Wasser');
expect(p.quantity).toBe(0.25);
expect(p.unit).toBe('l');
});
});
});