diff --git a/src/lib/server/parsers/json-ld-recipe.ts b/src/lib/server/parsers/json-ld-recipe.ts new file mode 100644 index 0000000..0ffeed1 --- /dev/null +++ b/src/lib/server/parsers/json-ld-recipe.ts @@ -0,0 +1,159 @@ +import { parseHTML } from 'linkedom'; +import { parseIso8601Duration } from './iso8601-duration'; +import { parseIngredient } from './ingredient'; +import type { Recipe, Step } from '$lib/types'; + +type JsonLdNode = Record; + +function unwrapGraph(node: unknown): JsonLdNode[] { + if (Array.isArray(node)) return node.flatMap(unwrapGraph); + if (node && typeof node === 'object') { + const obj = node as JsonLdNode; + if (obj['@graph']) return unwrapGraph(obj['@graph']); + return [obj]; + } + return []; +} + +function isRecipeType(t: unknown): boolean { + if (typeof t === 'string') return t === 'Recipe' || t.endsWith('/Recipe'); + if (Array.isArray(t)) return t.some(isRecipeType); + return false; +} + +function toText(v: unknown): string | null { + if (typeof v === 'string') return v.trim() || null; + if (Array.isArray(v) && v.length > 0) return toText(v[0]); + if (v && typeof v === 'object') { + const o = v as JsonLdNode; + if (typeof o.name === 'string') return o.name.trim(); + if (typeof o.text === 'string') return o.text.trim(); + } + return null; +} + +function toImageUrl(v: unknown): string | null { + if (typeof v === 'string') return v; + if (Array.isArray(v) && v.length > 0) return toImageUrl(v[0]); + if (v && typeof v === 'object') { + const o = v as JsonLdNode; + if (typeof o.url === 'string') return o.url; + } + return null; +} + +function toStringArray(v: unknown): string[] { + if (Array.isArray(v)) return v.map((x) => toText(x)).filter((x): x is string => x !== null); + if (typeof v === 'string') return v.split(',').map((s) => s.trim()).filter(Boolean); + return []; +} + +function toSteps(v: unknown): Step[] { + const out: Step[] = []; + const walk = (x: unknown): void => { + if (Array.isArray(x)) { + for (const item of x) walk(item); + return; + } + if (typeof x === 'string') { + if (x.trim()) out.push({ position: out.length + 1, text: x.trim() }); + return; + } + if (x && typeof x === 'object') { + const obj = x as JsonLdNode; + if (obj['@type'] === 'HowToSection' && obj.itemListElement) { + walk(obj.itemListElement); + return; + } + if (obj['@type'] === 'HowToStep' && typeof obj.text === 'string') { + if (obj.text.trim()) out.push({ position: out.length + 1, text: obj.text.trim() }); + return; + } + if (typeof obj.text === 'string' && obj.text.trim()) { + out.push({ position: out.length + 1, text: obj.text.trim() }); + } + } + }; + walk(v); + return out; +} + +function toServings(v: unknown): number | null { + if (typeof v === 'number' && Number.isFinite(v)) return Math.trunc(v); + if (typeof v === 'string') { + const m = /(\d+)/.exec(v); + if (m) return parseInt(m[1], 10); + } + if (Array.isArray(v) && v.length > 0) return toServings(v[0]); + return null; +} + +function findRecipeNode(html: string): JsonLdNode | null { + const { document } = parseHTML(html); + const scripts = document.querySelectorAll('script[type="application/ld+json"]'); + for (const script of scripts) { + const raw = script.textContent; + if (!raw) continue; + try { + const parsed = JSON.parse(raw); + for (const node of unwrapGraph(parsed)) { + if (isRecipeType(node['@type'])) return node; + } + } catch { + // malformed JSON-LD, keep scanning + } + } + return null; +} + +export function extractRecipeFromHtml(html: string): Recipe | null { + const node = findRecipeNode(html); + if (!node) return null; + + const title = toText(node.name) ?? ''; + if (!title) return null; + + const ingredients = Array.isArray(node.recipeIngredient) + ? (node.recipeIngredient as unknown[]) + .map((x, i) => (typeof x === 'string' ? parseIngredient(x, i + 1) : null)) + .filter((x): x is NonNullable => x !== null) + : []; + + const steps = toSteps(node.recipeInstructions); + const imageUrl = toImageUrl(node.image); + + const prep = parseIso8601Duration( + typeof node.prepTime === 'string' ? node.prepTime : undefined + ); + const cook = parseIso8601Duration( + typeof node.cookTime === 'string' ? node.cookTime : undefined + ); + const total = parseIso8601Duration( + typeof node.totalTime === 'string' ? node.totalTime : undefined + ); + + const tags = new Set([ + ...toStringArray(node.recipeCategory), + ...toStringArray(node.recipeCuisine), + ...toStringArray(node.keywords) + ]); + + return { + id: null, + title, + description: toText(node.description), + source_url: typeof node.url === 'string' ? node.url : null, + source_domain: null, + image_path: imageUrl, + servings_default: toServings(node.recipeYield), + servings_unit: null, + prep_time_min: prep, + cook_time_min: cook, + total_time_min: total, + cuisine: toText(node.recipeCuisine), + category: toText(node.recipeCategory), + ingredients, + steps, + tags: [...tags] + }; +} diff --git a/tests/fixtures/chefkoch-schupfnudeln.html b/tests/fixtures/chefkoch-schupfnudeln.html new file mode 100644 index 0000000..aa333f5 --- /dev/null +++ b/tests/fixtures/chefkoch-schupfnudeln.html @@ -0,0 +1,122 @@ + + +Selbstgemachte Schupfnudeln von Chefkoch_Viki + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Selbstgemachte Schupfnudeln

Originalrezept von Viki Fuchs

Durchschnittliche Bewertung: 4,7 von 5 Sternen von 5 Sternen(35 Bewertungen)
2 / 16 alaKatinka
3 / 16 Silviafuss
6 / 16 ellik
8 / 16 Superpenno
time
40 Min.
Arbeitszeit
difficulty_level
Simpel
Schwierigkeit
veggi_vegan
Vegetarisch
Ernährung
calendar_month
26.1.2022
Erstellt am

Zutaten

Für 4 Portionen
500 g
Kartoffeln, vorwiegend festkochendeoder aufgewärmte Pellkartoffeln vom Vortag
150 g
Weizenmehl
1
Ei(er)
1
Eigelb
Salz
Muskatnuss
Weizenmehlzum Bearbeiten
2 EL
Butter

Zubereitung

1 Std. 10 Min.
Gesamtzeit
40 Min.
Arbeitszeit
30 Min.
Koch-/Backzeit
1

Für den Schupfnudelteig die Kartoffeln in der Schale ca. 25 Minuten in reichlich Salzwasser gar kochen und zum leichteren Pellen mit kaltem Wasser abschrecken. Für die Schupfnudeln einen großen Topf mit Wasser aufstellen.

2

Die noch warmen Kartoffeln pellen und sofort durch eine Kartoffelpresse drücken. Mit Salz und frisch geriebener Muskatnuss würzen und mit Mehl, Ei und Eigelb zügig zu einem geschmeidigen Teig verarbeiten.

3

Den Teig auf einer mit Mehl bestäubten Arbeitsfläche in vier Teile teilen und zu gleichmäßigen Strängen rollen (ca. 1,5 cm dick). Anschließend mit einem Messer oder einer Teigkarte ca. 2 cm große Teigstücke von der Rolle schneiden und mit den Händen zu Kugeln rollen. Aus diesen Kugeln werden die Schupfnudeln geformt. Die Stücke werden „geschupft”, sprich sie werden zwischen den Handinnenflächen oder auf einem Holzbrett mit einer leicht gewölbten Hand in die typische Schupfnudel-Form gerollt.

4

Die fertigen Schupfnudeln in reichlich kochendem Salzwasser ca. 5 Minuten garen, bis sie an die Oberfläche steigen und dann die Temperatur herunterstellen und noch 2 Minuten ziehen lassen. Mit einer Schaumkelle herausnehmen, auf ein geöltes Blech geben und erkalten lassen. Das Öl verhindert, dass die Schupfnudeln zusammenkleben.

5

Die Schupfnudeln in aufgeschäumter Butter kurz anbraten, leicht salzen und sofort servieren.

Rezeptautor:in

Bild von Chefkoch_Viki
Chefkoch_Viki

Kommentare

Top-Kommentare

Neu
Für mich war das Rezept ein absoluter Albtraum. Der Teig ist eine klebrige Masse und nach der angegebenen Kochzeit erhalte ich wässrige zerfallene Pampe - trotz Ei + Eigelb wie im Rezept. Ich liebe Schupfnudeln, aber dies war für mich verschwendete Zeit in der Küche. Die Angabe "simpel" hat sich für mich nicht bewahrheitet.
Beliebt
Ich habe heute Schupfnudeln nach diesem Rezept gemacht (doppelte Masse) und der Teig ließ sich super verarbeiten, obwohl ich ihn vermutlich sogar zu lange geknetet habe. +Meine Änderungen/Tipps/Hinweise: +- 500g rohe, vorwiegend festkochende Erdäpfel - habe sie erst nach dem Kochen geschält und dann durch eine Presse gedrückt +- 150g Mehl, wie im Rezept angegeben: Hälfte glattes Dinkelmehl, Hälfte griffiges Weizenmehl (Typ W700 in AT, Typ 550 in DE) + ein bisschen Dinkelmehl zum Rollen/Formen - das nächste Mal werde ich es nur mit Dinkelmehl versuchen +- Ich habe nur ein ganzes Ei benutzt (also insg. 2 für die doppelte Masse, Größe L oder XL), das extra Eigelb habe ich weggelassen +- Am besten zuerst mit einem Teigschaber mischen und erst ganz am Ende die Hände benutzen, denn durch die Körperwärme wird der Teig womöglich klebrig.
Beliebt
Man muss unbedingt mehlig kochende Kartoffeln verwenden, mit anderen (wie in der Zutatenliste angegeben) funktioniert es nicht, oder man müsste viel mehr Mehl zugeben. + +Versuch mal dieses Rezept: +https://www.chefkoch.de/rezepte/1299261235040786/Mickys-Schupfnudeln.html + +Nach meinem ersten Schupfnudel-Fiasko mit falschen Kartoffeln und falschem Rezept hab ich mich ewig nicht mehr getraut, Schupfnudeln selber zu machen, bis ich obiges Rezept gefunden hatte. Das klappt. + +Liebe Grüßle vom schwobamädle
Wurst mit Senf

Gib deinen Senf dazu!

Schreibe den ersten Kommentar zu diesem Rezept.
+ + \ No newline at end of file diff --git a/tests/fixtures/emmi-bolognese.html b/tests/fixtures/emmi-bolognese.html new file mode 100644 index 0000000..a0f7114 --- /dev/null +++ b/tests/fixtures/emmi-bolognese.html @@ -0,0 +1,1941 @@ + + + + + + + + + + + + Bolognese-Rezept – das Original + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+
+ +
+
+
+
+
+ + + +
+
+

Bolognese-Rezept – das Original

+
+

Die original Bolognese-Soße schmeckt wie in Italien. Der Klassiker lässt sich einfacher zubereiten als man denkt.

+
+ + +
+ +
+ Bolognese-Rezept
+ +
+
+ +
+

Das klassische Bolognese-Rezept hat reichlich Aroma und Tradition. Sie hat nichts mit der gemeinen Hackfleischsoße zu tun. Mit den richtigen Zutaten und etwas Zeit entfaltet sie den vollen Geschmack.

Meine Bolognese-Soße ist einfach: Sind alle Zutaten im Topf, köchelt das beliebte Familienessen auf dem Herd in Ruhe vor sich hin. Ein echter Klassiker der italienischen Küche.

Bolognese-Rezept

Diese Zutaten brauchst du für mein Bolognese-Rezept

Hackfleisch ist die Hauptzutat der Sauce Bolognese. Ich empfehle dir gemischtes Hackfleisch aus Rind und Schwein, frisch vom Metzger. Das gemischte Hack hat am meisten Aroma.

    +
  • Pancetta ist die italienische Variante des deutschen Schweinebauchspecks. Er ist luftgetrocknet und gesalzen, nicht geräuchert und deshalb milder im Geschmack.
  • +
  • Frische Zwiebeln, Möhren und Stangensellerie sind die original italienische Saucenbasis, die auch Soffritto genannt wird.
  • +
  • Passierte Tomaten und Tomatenmark sorgen für eine intensive fruchtige Geschmacksnote.
  • +
  • Vollmilch macht die Soße cremig und das Hackfleisch schön zart.
  • +
  • Gewürze: Lorbeerblatt, Muskatnuss, Salz und Pfeffer verleihen der Bolognese-Soße noch etwas Würze.
  • +

In Italien wird die original Bolognese-Soße traditionell mit breiten Bandnudeln wie Tagliatelle oder Pappardelle gegessen. Ich verwende Spaghetti für den Klassiker „Spaghetti Bolognese“. Du kannst die Soße nach meinem Bolognese-Rezept aber vielfältig verwenden, auch in Lasagne.

Zutaten für Bolognese-Soße

Darum muss Bolognese so lange köcheln

Du möchtest Bolognese selber machen, fragst dich aber, warum sie so lange köcheln muss? Ist die Soße nach einer kurzen Vorbereitungszeit im Kochtopf, brauchst du etwas Geduld. In Italien nimmt die Kochzeit häufig mehrere Stunden in Anspruch. Mein Bolognese-Rezept ist so gestaltet, dass sich die Aromen voll entwickeln – in deutlich kürzerer Zeit. Ich verzichte außerdem auf den Wein, zwar verkocht der Alkohol, doch Kinder mögen den Geschmack einfach nicht so gerne. Das Rezept passt gut in die Feierabend- und Familienküche: zeitlich, in puncto Portionen und es ist familienfreundlich.

Die Sauce länger ziehen zu lassen schadet jedoch nicht. Wähle eine niedrige Herdstufe, damit die Sauce bei geringer Hitze nicht noch einmal zu kochen beginnt. Die Aromen der Zutaten entwickeln sich weiter und erhalten eine wohlschmeckende Tiefe. Der entscheidende Unterschied zu einer gewöhnlichen Hackfleischsoße ist die Zugabe von Bauchspeck. Ein Muss! Er sorgt für die besondere würzige Note in der Bolognese.

Original italienische Bolognese

Warum du mein Bolognese-Rezept lieben wirst

    +
  • Soulfood: Meine Bolognese ist eine köstliche, kräftige Sauce mit Gemüse und Gehacktem, die jede Nudel krönt.
  • +
  • Du kannst die Bolognese-Soße gut in einer größeren Menge zubereiten und bei Bedarf aufwärmen.
  • +
  • Die deftige Soße lässt sich super einfrieren, am besten portionsweise. Sie hält bis zu neun Monate.
  • +
  • Alle Zutaten erhältst du saisonunabhängig.
  • +
  • Bolognese ist einfach selber zu machen, durch die kurze Vorbereitungszeit – den Rest macht dein Herd.
  • +
  • Mein klassisches Bolognese-Rezept ist vielfältig. Du kannst dazu die Nudeln kombinieren, die dir am besten schmecken.
  • +
  • Meine Variante kommt ohne Wein aus und ist somit familienfreundlich.
  • +

Italienischer Soßen-Klassiker

Du bist wie ich ein großer Fan von Pasta-Rezepten? Auf meinem Foodblog findest du noch mehr italienische Rezepte, wie meine Spaghetti Carbonara, Penne Arrabiata, meine Lasagne und Tortellini alla Panna. Buon appetito!

+
Bolognese-Rezept
+
+
+

Bolognese-Rezept – das Original

+
+
260 Bewertungen
+
+
+

Sterne anklicken zum Bewerten

+
+
Die Bolognese-Soße schmeckt wie in Italien. Der beliebte Klassiker kann prima vorbereitet und wieder aufgewärmt werden.
+
+ Rezept ausdrucken + +
+
+
+ +
VORBEREITUNG20 Minuten
ZUBEREITUNG40 Minuten
ZEIT GESAMT1 Stunde
+
PORTIONEN4 Personen
+ + + +
+

ZUTATEN

  • 500 g gemischtes Hackfleisch - halb Rind und halb Schwein
  • 400 g Nudeln nach Wahl - z.B. Spaghetti oder Tagliatelle
  • 400 g passierte Tomaten - aus dem Glas oder Dose
  • 100 g Bauchspeck - idealerweise Pancetta, wenn erhältlich
  • 150 g Zwiebeln - ca. 2-3 Stück
  • 50 g Möhre - ca. 1 Möhre
  • 50 g Stangensellerie (geputzt) - ca. 1 Stange
  • 200 ml Vollmilch
  • 40 g Butter
  • 1 EL Pflanzenöl, neutral - z.B. Sonnenblumen- oder Rapsöl
  • 1 EL Tomatenmark
  • 1 Lorbeerblatt, getrocknet
  • 1 Msp. Muskatnuss, gerieben
  • Salz und schwarzer Pfeffer aus der Mühle

ANLEITUNG

  • Die 100 g Bauchspeck (Pancetta) schneidest du in sehr kleine Würfel.
    Pancetta-Bauchspeck für die Bolognese würfeln
  • Die 50 g Möhre schälst du und schneidest sie in sehr feine Würfel. Von der 1 Selleriestange entfernst du das Grün sowie evtl. noch Fäden, wäschst sie gut, wiegst 50 g ab und schneidest sie in sehr feine Würfel. Die 150 g Zwiebeln schälst du und schneidest sie ebenfalls in feine Würfel.
    Karotte, Sellerie und Zwiebel schälen und schneiden
  • Nun erhitzt du 1 EL Pflanzenöl in einem Topf und dünstest darin zuerst die Bauchspeck-Würfel (Pancetta) alleine für 1-2 Minuten an.
    Gewürfelten Bauchspeck andünsten
  • Im Anschluss gibst du die 40 g Butter, die Zwiebel-, Sellerie- und Möhrenwürfel in den Topf und lässt alles auf mittlerer Stufe ca. 3 Minuten dünsten. Gut umrühren, damit das Gemüse gut mit Fett überzogen wird.
    Butter und Gemüse im Topf für die Bolognese andünsten
  • Im Anschluss gibst du die 500 g Hackfleisch in den Topf und würzt mit 1 TL Salz und einem 1/4 TL schwarzen Pfeffer aus der Mühle. Das Fleisch zerkrümelst du mit einem Holzlöffel und lässt es so lange auf mittlerer Stufe garen, bis es nicht mehr roh und rot aussieht.
    TIPP: Das Fleisch wird NICHT auf hoher Stufe angebraten, damit es nicht trocken wird.
    Hackfleisch mit Bauchspeck und Gemüse im Topf
  • Im Anschluss rührst du noch 1 EL Tomatenmark unter.
    Tomatenmark zur Bolognese-Mischung hinzugeben
  • Nun löschst du mit 200 ml Vollmilch ab und lässt diese so lange köcheln, bis sie nahezu verdampft ist. Dabei fügst du eine Messerspitze geriebene Muskatnuss dazu. Ab und zu umrühren.
    TIPP: Ich gebe wegen meines Sohnes keinen Rotwein in die Bolognese-Soße. Wenn du Rotwein verwenden möchtest, kannst du 125 ml nach der Milch hinzugießen und einköcheln lassen.
    Mischung für die Bolognese-Soße mit Vollmilch ablöschen
  • Jetzt gibst du noch 400 g passierte Tomaten in den Topf sowie 1 Lorbeerblatt. Im Anschluss verrührst du alles gut miteinander.
    TIPP: Das Lorbeerblatt mit der Schere einschneiden, dann entfalten sich die Aromen in der Bolognese besser.
    Loorbeerblatt für Aromen in der Bolognese
  • Bei mittlerer bis kleiner Hitze lässt du die Bolognese mit halb geöffnetem Deckel für ca. 40 Minuten köcheln. Dabei ab und zu umrühren und falls die Bolognese zu trocken wird immer etwas Milch oder Wasser esslöffelweise hinzugeben. (Wichtig zu wissen: Ein original Ragù alla Bolognese ist niemals eine flüssige Soße). Zum Schluss noch mit Salz und schwarzem Pfeffer aus der Mühle abschmecken.
    TIPP: In der italienischen Küche wird ein Ragù alla Bolognese mindestens 3 Stunden geköchelt bzw. blubbert so vor sich hin. Je länger sie köchelt, umso mehr Geschmacksaromen entwickeln sich, da es sich um ein Schmorgericht handelt. Wenn du also richtig Zeit hast, kannst du auch mein Rezept einfach länger blubbern lassen, ab und zu nachsehen, umrühren und etwas Milch oder Wasser hinzufügen.
  • Rechtzeitig die 400 g Nudeln nach Packungsanweisung in Salzwasser zubereiten.
    TIPP: In Italien wird ein original Ragù alla Bolognese übrigens mit Eiernudeln wie Tagliatelle und nicht mit Hartweizennudeln wie Spaghetti gegessen.
    Nudeln für Spaghetti Bolognese kochen
  • Die gekochten Nudeln mit der Bolognese servieren. Dazu nach Belieben frisch geriebenen Parmesan reichen. Ich wünsche dir einen guten Appetit.
    Bolognese-Soße mit Spaghetti auf einem Teller angerichtet servieren
+ +

MEIN REZEPT-VIDEO

+

NÄHRWERTE PRO PORTION

Kalorien: 866 kcal | Kohlenhydrate: 85 g | Eiweiß: 38 g | Fett: 38 g
+

WAS MEINST DU?

Hast du mein Bolognese-Rezept einmal ausprobiert? Wie findest du es? Ich freue mich immer über Lob, freundliche Kritik oder deine Tipps und Erfahrungen damit. 
+
+
+
Hast du mein Rezept ausprobiert?Markiere mich mit @emmikochteinfach wenn du es mir zeigen möchtest

+ +
+ +
+
+ +
+ +
+ +
+ Emmi in der Küche
+ +
+

Ich ❤️ die einfache, schnörkellose Küche und möchte dir Inspiration geben, wenn du dir mal wieder die Frage stellst: „Was soll ich heute für meine Lieben und mich bloß kochen?“

+
+ +
+
+
+ +
+
+
+ + Rezept für Saltimbocca alla Romana +

+ Saltimbocca alla Romana – wie in Italien +

+ + + + +
+
+
+
+ + Der Klassiker aus Griechenland - www.emmikochteinfach.de +

+ Bifteki – Griechische Frikadellen gefüllt mit Schafskäse +

+ + + + +
+
+
+
+ + Gemüselasagne +

+ Gemüselasagne – einfaches Rezept +

+ + + + +
+
+
+ +
+
+ +
+ + + + +
+
+ +
+ +
+
+
+ 5 from 260 votes (30 ratings without comment) +
+
+
+ ICH FREUE MICH ÜBER DEINE RÜCKMELDUNG

Über eine Sterne-Bewertung bei einem Rezept würde ich mich ebenfalls sehr freuen!

+ +
+ REZEPT BEWERTUNG (BITTE DIE STERNE ANKLICKEN - 5 GEFÜLLTE STERNE BEDEUTEN "SEHR GUT") +




+
+
+
+
+

+ +

+ + + 467 Kommentare + + +
    +
  1. +
    + +
    +
    + Silvia + + 15. April 2026 - 17:08 +
    +
    +
    +

    + +
    +Ich hatte es nach mehreren anderen Rezepten schon aufgegeben ,selber Bolognese zu kochen bis ich auf dein Rezept gestoßen bin. Da ich von dir schon andere Gerichte nachgemacht und immer für super lecker empfunden habe , dachte ich mir das ich das jetzt auch mal probieren muss .Ich habe die Variante mit Rotwein gekochtund auch noch Oregano und Rinderbrühe reingemacht. +Was soll ich sagen ? Besser geht garnicht! Ich danke dir für dieses Rezept 🙂

    + + Antworten >> +
    +
    +
    + +
      +
    1. +
      +
      + Emmi +
      + +
      +
      + Emmi + + 15. April 2026 - 20:24 +
      +
      +
      +

      Liebe Silvia, es freut mich wenn alles gepasst hat💟👍. Lieben Dank und Alles Liebe💕

      + + Antworten >> +
      +
      +
      + +
    2. +
    +
  2. +
  3. +
    + +
    +
    + Carola H. + + 13. April 2026 - 16:41 +
    +
    +
    +

    + +
    +Habe etwa 80 Kochbücher zuhause…. Letztlich verlasse ich mich dann doch immer auf Emmis Empfehlungen. Die sind klassisch einfach, gut nachvollziehbar, mit guten Tipps unterstützt und das Ergebnis bringt mir immer Komplimente ein. Einfach schnörkellose Küche. Einfach für jeden Tag. Einfach, wenn man keine Lust oder Zeit hat aufwendige Einkaufszettel abzuarbeiten. Einfach Emmi. Einfach gut.

    + + Antworten >> +
    +
    +
    + +
      +
    1. +
      +
      + Emmi +
      + +
      +
      + Emmi + + 13. April 2026 - 17:05 +
      +
      +
      +

      Herzlichen Dank für dein Kompliment Carola👍❤️. Merci vielmals und viele LG

      + + Antworten >> +
      +
      +
      + +
    2. +
    +
  4. +
  5. +
    + +
    +
    + Nadine + + 8. April 2026 - 20:53 +
    +
    +
    +

    + +
    +Super lecker!! +Danke ☺️

    + + Antworten >> +
    +
    +
    + +
      +
    1. +
      +
      + Emmi +
      + +
      +
      + Emmi + + 8. April 2026 - 21:35 +
      +
      +
      +

      Merci vielmals, Nadine🤗. Wenn alles gepasst hat freut mich das sehr💕👍. Alles Liebe!

      + + Antworten >> +
      +
      +
      + +
    2. +
    +
  6. +
+ + + +
+
+
+ + +
+
+
+
+ +
+
+ + + +
+ + +
+
+
+
+ + + Meine Kochbücher
+ Überall im Buchhandel
+ + + + + Alle Infos zu meinen Büchern + + + +
+ +
+
+ Kochbücher Emmi
+
+
+
+
+ +
+
+
+
+ + + + Anmelden und nichts verpassen! + + + + +

Kostenlos meine neuesten Rezepte, Tipps und Inspirationen für die einfache und clevere Küche direkt in dein E-Mail-Postfach.

+
+ + + zum Newsletter +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/unit/json-ld-recipe.test.ts b/tests/unit/json-ld-recipe.test.ts new file mode 100644 index 0000000..fb62dd0 --- /dev/null +++ b/tests/unit/json-ld-recipe.test.ts @@ -0,0 +1,44 @@ +import { describe, it, expect } from 'vitest'; +import { readFileSync } from 'node:fs'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { extractRecipeFromHtml } from '../../src/lib/server/parsers/json-ld-recipe'; + +const here = dirname(fileURLToPath(import.meta.url)); + +function load(name: string): string { + return readFileSync(join(here, '../fixtures', name), 'utf8'); +} + +describe('extractRecipeFromHtml', () => { + it('extracts a recipe from Chefkoch HTML', () => { + const html = load('chefkoch-schupfnudeln.html'); + const r = extractRecipeFromHtml(html); + expect(r).not.toBeNull(); + expect(r!.title.toLowerCase()).toContain('schupfnudel'); + expect(r!.ingredients.length).toBeGreaterThan(2); + expect(r!.steps.length).toBeGreaterThan(0); + }); + + it('extracts a recipe from Emmi kocht einfach HTML', () => { + const html = load('emmi-bolognese.html'); + const r = extractRecipeFromHtml(html); + expect(r).not.toBeNull(); + expect(r!.title.toLowerCase()).toContain('bolognese'); + expect(r!.ingredients.length).toBeGreaterThan(0); + expect(r!.steps.length).toBeGreaterThan(0); + }); + + it('returns null when no Recipe JSON-LD present', () => { + const html = '

no recipe

'; + expect(extractRecipeFromHtml(html)).toBeNull(); + }); + + it('returns null when JSON-LD has only non-Recipe types', () => { + const html = ` + + + `; + expect(extractRecipeFromHtml(html)).toBeNull(); + }); +});