import { describe, expect, it } from 'vitest'; import { aufteilungAusLastzuganteil, istLastzuganteil, lastzuganteilSpanne, schwerverkehrsfaktor, } from '@/domain/rilsa/capacity'; import { HBS_LASTZUGANTEIL_BEI_UNBEKANNTER_AUFTEILUNG, HBS_PKW_GLEICHWERTE, RILSA_DEFAULTS, } from '@/domain/rilsa/constants'; import { QUELLEN } from '@/domain/rilsa/quellen'; import { settingFields } from '@/domain/rilsa/settings'; import { buildSignalPlan } from '@/domain/plan/signalPlan'; import { SCHWERVERKEHR_AUFTEILUNG_MELDESCHWELLE } from '@/domain/validation/rules'; import { validateProject } from '@/domain/validation/engine'; import { loadProject } from '@/domain/model/migrate'; import { createStandardIntersectionProject } from '@/domain/model/factory'; import { CURRENT_SCHEMA_VERSION, type Project, type TrafficDemand } from '@/domain/model/project'; import { setDemand, setLastzugAnteil } from '@/app/actions'; /** * Fassung 5.6.0 - die Aufteilung des Schwerverkehrs nach HBS 2015 Gl. 2-5. * * WORUM ES GEHT. Bis Fassung 5.5.0 kannte das Datenmodell nur einen * Gesamt-Schwerverkehrsanteil. Das Programm rechnete deshalb jeden Strom nach * Gl. 2-6 mit dem Pauschalwert 1,90 je Schwerfahrzeug - auch einen aus lauter * Lastzuegen, der nach Gl. 2-5 mit 2,50 zu rechnen ist. Bei 20 % Schwerverkehr * aus lauter Lastzuegen fiel die Saettigungsverkehrsstaerke damit 10,2 % zu * gross aus, bei reinem Lastzugverkehr 31,6 %. Der Posten war im Programm * ehrlich ausgewiesen - aber ausgewiesen ist nicht gerechnet. * * DIE BELEGE (BASt-Bericht V 400, 2025, S. 10), woertlich: * "fSV = (qLV + 1,75 * qLkw+Bus + 2,5 * qLkwK) / qKfz (2-5)" * "fSV = (qLV + 1,9 * qSV) / qKfz (2-6)" * und zur Wahl zwischen beiden: "in Abhaengigkeit von der Datenverfuegbarkeit * zur Aufteilung des Schwerverkehrs". * * DER KONSISTENZBELEG, an dem die Aufteilung haengt - V 400 zu Bild 2-1 d): * "Bei einem Anteil der Lkw mit Anhaenger und Sattel-Kfz (Fahrzeugklasse LkwK) * am Schwerverkehr von 20 % ergibt sich der Funktionsverlauf der Gleichung * (2-6)." Nachgerechnet: 1,75 * 0,8 + 2,50 * 0,2 = 1,90 exakt. Der Pauschalwert * IST Gl. 2-5 mit 20 % Lastzuganteil; die Erfassung ist eine Verfeinerung * derselben Formel und kein anderes Verfahren. Genau deshalb darf eine Altdatei * ihr Ergebnis nicht aendern. */ const DATUM = new Date('2026-01-01T00:00:00Z'); /** Grundwert je Fahrstreifen unter Standardbedingungen: 2000 Kfz/h. */ const QS_GRUND = RILSA_DEFAULTS.capacity.saturationFlow; /** * Der Knotenpunkt der Vorlage mit EINER erfassten Verkehrsstaerke an K1 * (geradeaus, ein Fahrstreifen - also Grundwert ohne Abbiegerfaktor). */ function knotenMitStrom(demand: Omit): { project: Project; groupId: string; } { const roh = createStandardIntersectionProject('Schwerverkehr', DATUM); const k1 = roh.signalGroups.find((g) => g.name === 'K1'); if (!k1) throw new Error('K1 fehlt in der Vorlage'); return { project: { ...roh, demands: [{ signalGroupId: k1.id, ...demand }] }, groupId: k1.id, }; } /** Die gerechnete Saettigungsverkehrsstaerke dieser Gruppe im Signalzeitenplan. */ function qSimPlan(project: Project, groupId: string): number { const gruppe = buildSignalPlan(project).groups.find((g) => g.groupId === groupId); if (!gruppe?.capacity) throw new Error('keine Kapazitaet gerechnet'); return gruppe.capacity.saturationFlow; } // --- Die beiden Gleichungen ------------------------------------------------- describe('Gl. 2-5 und Gl. 2-6 sind dieselbe Gleichung', () => { it('faellt bei 20 % Lastzuganteil exakt mit dem Pauschalwert zusammen', () => { /* * Die Kernaussage dieser Tests, und zugleich der schaerfste * MUTATIONSNACHWEIS: Jede Verwechslung der Bezugsgroesse in * aufteilungAusLastzuganteil (Lastzuganteil an qKfz statt am * Schwerverkehr), jeder vertauschte Pkw-Gleichwert und jedes verrutschte * Vorzeichen laesst die beiden Wege auseinanderfallen. Geprueft wird auf * zwoelf Stellen, nicht "ungefaehr gleich" - 1,75 * 0,8 + 2,50 * 0,2 = 1,90 * ist exakt und nicht gerundet. */ for (const pSV of [0, 0.03, 0.1, 0.2, 0.35, 0.5, 0.8, 1]) { const nachAufteilung = schwerverkehrsfaktor( pSV, aufteilungAusLastzuganteil(pSV, HBS_LASTZUGANTEIL_BEI_UNBEKANNTER_AUFTEILUNG), ); expect(nachAufteilung, `pSV ${pSV}`).toBeCloseTo(schwerverkehrsfaktor(pSV), 12); } }); it('haelt den belegten Pauschalanteil und seine Nachrechnung fest', () => { expect(HBS_LASTZUGANTEIL_BEI_UNBEKANNTER_AUFTEILUNG).toBe(0.2); const nachgerechnet = HBS_PKW_GLEICHWERTE.lkwUndBus * (1 - HBS_LASTZUGANTEIL_BEI_UNBEKANNTER_AUFTEILUNG) + HBS_PKW_GLEICHWERTE.lkwMitAnhaenger * HBS_LASTZUGANTEIL_BEI_UNBEKANNTER_AUFTEILUNG; expect(nachgerechnet).toBeCloseTo(HBS_PKW_GLEICHWERTE.schwerverkehrPauschal, 12); }); it('rechnet den Lastzuganteil auf die Bezugsgroesse von Gl. 2-5 um', () => { // Anteile AN qKfz, wie Gl. 2-5 sie braucht: pSV * anteil und // pSV * (1 - anteil). Ihre Summe ist genau pSV - mehr Schwerverkehr als // Schwerverkehr entsteht nicht. const aufteilung = aufteilungAusLastzuganteil(0.3, 0.4); expect(aufteilung).toEqual({ lkwUndBus: 0.3 * 0.6, lkwMitAnhaenger: 0.3 * 0.4 }); expect(aufteilung!.lkwUndBus + aufteilung!.lkwMitAnhaenger).toBeCloseTo(0.3, 12); }); it('fuehrt die Aufteilung nicht als Kennwert in der Vorgabenverwaltung', () => { // Befund C20 gilt weiter: Waehlbar ist die Datenlage je Strom, nicht der // Pkw-Gleichwert des Regelwerks. const schluessel = settingFields().map((f) => String(f.key)); for (const verboten of ['lastzugAnteil', 'pkwGleichwertLastzug', 'schwerverkehrPauschal']) { expect(schluessel).not.toContain(verboten); } }); }); // --- Der Lastzugstrom ------------------------------------------------------- describe('Ein Strom aus lauter Lastzuegen', () => { it('kommt auf fSV 1,30 und 1538 statt 1695 Kfz/h', () => { // Das Beispiel, das seit der Fassung 5.5.0 in Unterlage, Hilfe und // Fundstellenverzeichnis steht - jetzt rechenbar statt nur benannt. const nurLastzuege = schwerverkehrsfaktor(0.2, aufteilungAusLastzuganteil(0.2, 1)); expect(nurLastzuege).toBeCloseTo(1.3, 12); expect(schwerverkehrsfaktor(0.2)).toBeCloseTo(1.18, 12); const { project, groupId } = knotenMitStrom({ volume: 600, heavyVehicleShare: 0.2, lastzugAnteil: 1, }); expect(Math.round(qSimPlan(project, groupId))).toBe(1538); // MUTATIONSNACHWEIS: Wer die Aufteilung im Signalzeitenplan nicht // durchreicht, landet wieder bei 1695 - der Zahl bis Fassung 5.5.0. const { project: ohne, groupId: id2 } = knotenMitStrom({ volume: 600, heavyVehicleShare: 0.2, }); expect(Math.round(qSimPlan(ohne, id2))).toBe(1695); }); it('beziffert beide Fehlerrichtungen des Pauschalwerts fuer einen Anteil', () => { // Bezugsgroesse ist die WAHRE Saettigungsverkehrsstaerke: qS = qS0 / fSV, // also (qS_Programm - qS_wahr) / qS_wahr = fSV_wahr / fSV_pauschal - 1. const spanne = lastzuganteilSpanne(0.2); expect(spanne.pauschal).toBeCloseTo(1.18, 12); expect(spanne.nurLastzuege).toBeCloseTo(1.3, 12); expect(spanne.ohneLastzuege).toBeCloseTo(1.15, 12); expect(spanne.hoechstensZuGross * 100).toBeCloseTo(10.169, 3); expect(spanne.hoechstensZuKlein * 100).toBeCloseTo(2.542, 3); // Bei reinem Lastzugverkehr die 31,6 %, die im Fundstellenverzeichnis // stehen - und die konservative Gegenrichtung dazu. const voll = lastzuganteilSpanne(1); expect(voll.hoechstensZuGross * 100).toBeCloseTo(31.579, 3); expect(voll.hoechstensZuKlein * 100).toBeCloseTo(7.895, 3); // Ohne Schwerverkehr gibt es keine Spanne - und keinen Grund zu melden. const leer = lastzuganteilSpanne(0); expect(leer.hoechstensZuGross).toBe(0); expect(leer.hoechstensZuKlein).toBe(0); }); }); // --- Randfaelle ------------------------------------------------------------- describe('Randfaelle des Lastzuganteils', () => { it('nimmt 0 und 1 als Angaben an', () => { expect(istLastzuganteil(0)).toBe(true); expect(istLastzuganteil(1)).toBe(true); // 0 heisst "gezaehlt, kein Lastzug dabei" - Gl. 2-5 mit 1,75 je // Schwerfahrzeug, also GUENSTIGER als der Pauschalwert. expect(schwerverkehrsfaktor(0.2, aufteilungAusLastzuganteil(0.2, 0))).toBeCloseTo(1.15, 12); expect(schwerverkehrsfaktor(0.2, aufteilungAusLastzuganteil(0.2, 1))).toBeCloseTo(1.3, 12); }); it('verwirft alles andere und faellt auf Gl. 2-6 zurueck', () => { /* * MUTATIONSNACHWEIS gegen ein Begrenzen auf 0..1: Wer -0,3 auf 0 kappt, * macht aus einer Fehleingabe die GUENSTIGSTE aller Aufteilungen (fSV * 1,150 statt 1,180) und weist den Strom danach als "Aufteilung erfasst" * aus. Beide Erwartungen unten schlagen dann fehl. */ for (const unbrauchbar of [-0.3, 1.5, Number.NaN, Number.POSITIVE_INFINITY, undefined]) { expect(istLastzuganteil(unbrauchbar), `${unbrauchbar}`).toBe(false); expect(aufteilungAusLastzuganteil(0.2, unbrauchbar), `${unbrauchbar}`).toBeUndefined(); expect( schwerverkehrsfaktor(0.2, aufteilungAusLastzuganteil(0.2, unbrauchbar)), `${unbrauchbar}`, ).toBeCloseTo(schwerverkehrsfaktor(0.2), 12); } }); it('meldet einen eingetragenen, aber unbrauchbaren Anteil im Signalzeitenplan', () => { // Ueber die Datei ist der Fall nicht erreichbar (das Schema verwirft ihn // beim Lesen), ueber Oberflaeche und Fremdwerkzeuge schon. Ohne diese // Notiz waere es eine stille Ersetzung: eingetragene Aufteilung, // gerechnet ohne sie. const { project, groupId } = knotenMitStrom({ volume: 600, heavyVehicleShare: 0.2, lastzugAnteil: 1.5, }); const plan = buildSignalPlan(project); const notiz = plan.notes.find((n) => n.code === 'lastzuganteil-ausserhalb'); expect(notiz?.severity).toBe('warnung'); expect(notiz?.signalGroupId).toBe(groupId); expect(notiz?.message).toContain('150 %'); expect(notiz?.message).toContain('1,90'); // Gerechnet wird der Pauschalwert - nicht etwa mit 1,5 als Anteil. expect(Math.round(qSimPlan(project, groupId))).toBe(1695); // Und im Pruefbericht steht sie mit Titel, Fundstelle und Rat. const bericht = validateProject(project); const befund = bericht.findings.find((f) => f.title.includes('Lastzuganteil außerhalb')); expect(befund?.severity).toBe('warnung'); expect(befund?.category).toBe('leistungsfaehigkeit'); expect(befund?.reference).toContain('HBS 2015'); expect(befund?.suggestion).toContain('entfernen'); }); }); // --- Schema und Bestandsdaten ---------------------------------------------- describe('Schemastand 13 und Bestandsdaten', () => { it('fuehrt den Lastzuganteil ueber Speichern und Laden', () => { expect(CURRENT_SCHEMA_VERSION).toBe(19); const { project, groupId } = knotenMitStrom({ volume: 600, heavyVehicleShare: 0.25, lastzugAnteil: 0.6, }); const geladen = loadProject(JSON.parse(JSON.stringify(project))); expect(geladen.issues.filter((i) => i.path.includes('lastzugAnteil'))).toEqual([]); expect(geladen.project.schemaVersion).toBe(19); expect(geladen.project.demands[0]?.lastzugAnteil).toBe(0.6); // Und die Rechnung ueberlebt die Rundreise. expect(qSimPlan(geladen.project, groupId)).toBeCloseTo(qSimPlan(project, groupId), 9); }); it('laesst eine Altdatei ohne das Feld unveraendert rechnen', () => { /* * Die Zusage dabei: Schema 12 kannte den Lastzuganteil nicht, also * darf keine Zahl einer alten Datei sich bewegen. 2000/1,180 = 1694,92 - * derselbe Wert wie in Fassung 5.5.0. * * MUTATIONSNACHWEIS: Wuerde die Migration den belegten Pauschalanteil von * 20 % vorbelegen, waere die ZAHL gleich (das ist der Konsistenzbeleg), * aber `lastzugAnteil` stuende in der Datei - und der Strom gaelte als * gezaehlt. Genau das prueft die zweite Erwartung. */ const { project, groupId } = knotenMitStrom({ volume: 600, heavyVehicleShare: 0.2 }); const alt = { ...JSON.parse(JSON.stringify(project)), schemaVersion: 12 }; const geladen = loadProject(alt); expect(geladen.project.demands[0]?.lastzugAnteil).toBeUndefined(); expect(qSimPlan(geladen.project, groupId)).toBeCloseTo(QS_GRUND / 1.18, 9); }); it('verwirft einen unlesbaren Eintrag beim Lesen - mit Meldung', () => { const { project } = knotenMitStrom({ volume: 600, heavyVehicleShare: 0.2 }); for (const eingetragen of ['viele', -0.2, 2]) { const roh = JSON.parse(JSON.stringify(project)); roh.demands[0].lastzugAnteil = eingetragen; const geladen = loadProject(roh); const meldung = geladen.issues.find((i) => i.path === 'demands[0].lastzugAnteil'); expect(meldung?.severity, `${eingetragen}`).toBe('warnung'); expect(meldung?.message, `${eingetragen}`).toContain('1,90'); expect(geladen.project.demands[0]?.lastzugAnteil, `${eingetragen}`).toBeUndefined(); } }); it('schreibt kein Feld, wo keines eingetragen wurde', () => { // Ein leeres Feld ist keine Angabe: Weder das Schema noch die Aktion // duerfen aus "nichts eingetragen" eine 0 machen - das waere ein // Schwerverkehr ohne Lastzuege und damit die unsichere Richtung. const { project, groupId } = knotenMitStrom({ volume: 600, heavyVehicleShare: 0.2 }); const mitAnteil = setLastzugAnteil(project, groupId, 0.5); expect(mitAnteil.demands[0]?.lastzugAnteil).toBe(0.5); const wiederOhne = setLastzugAnteil(mitAnteil, groupId, null); expect('lastzugAnteil' in (wiederOhne.demands[0] ?? {})).toBe(false); expect(JSON.stringify(wiederOhne.demands[0])).not.toContain('lastzugAnteil'); // Die Verkehrsstaerke selbst bleibt dabei stehen. expect(wiederOhne.demands[0]?.volume).toBe(600); // Und die Zahl ist wieder die des Pauschalwerts. expect(qSimPlan(wiederOhne, groupId)).toBeCloseTo(QS_GRUND / 1.18, 9); }); it('ruehrt die uebrigen Angaben der Verkehrsstaerke nicht an', () => { const { project, groupId } = knotenMitStrom({ volume: 600, heavyVehicleShare: 0.2 }); const geaendert = setDemand(setLastzugAnteil(project, groupId, 0.4), groupId, { volume: 900 }); expect(geaendert.demands[0]).toEqual({ signalGroupId: groupId, volume: 900, heavyVehicleShare: 0.2, lastzugAnteil: 0.4, }); }); }); // --- Der Pruefbericht ------------------------------------------------------- describe('Der Pruefbericht zur fehlenden Aufteilung', () => { const REGEL = 'leistungsfaehigkeit.schwerverkehr-ohne-aufteilung'; it('schweigt, wo die Aufteilung erfasst ist', () => { // Zweig (a): Es gibt keine Annahme zu benennen - der Strom rechnet nach // Gl. 2-5. Auch dann, wenn der eingetragene Anteil genau der // Pauschalannahme entspricht: Gezaehlt ist gezaehlt. for (const anteil of [0, 0.2, 1]) { const { project } = knotenMitStrom({ volume: 600, heavyVehicleShare: 0.4, lastzugAnteil: anteil, }); const bericht = validateProject(project); expect( bericht.findings.filter((f) => f.rule === REGEL), `${anteil}`, ).toEqual([]); } }); it('meldet oberhalb der Schwelle mit Annahme und Fehlerrichtung', () => { // Zweig (b). 25 % Schwerverkehr: 2000/1,225 = 1633 Kfz/h gerechnet, // 2000/1,375 = 1455 Kfz/h bei lauter Lastzuegen (12,2 % zu gross), // 2000/1,1875 = 1684 Kfz/h ohne Lastzuege (3,1 % zu klein). const { project, groupId } = knotenMitStrom({ volume: 600, heavyVehicleShare: 0.25 }); const befund = validateProject(project).findings.find((f) => f.rule === REGEL); expect(befund?.severity).toBe('hinweis'); expect(befund?.category).toBe('leistungsfaehigkeit'); expect(befund?.target).toEqual({ kind: 'signalgruppe', id: groupId, label: 'K1' }); // Die Annahme steht da, mit ihrer Nachrechnung. expect(befund?.message).toContain('20 %'); expect(befund?.message).toContain('1,75 · 0,80 + 2,50 · 0,20 = 1,90'); // Und die Zahlen sind die DIESES Stroms, nicht die des Handbuchbeispiels. expect(befund?.message).toContain('1633 Kfz/h'); expect(befund?.message).toContain('1455 Kfz/h'); expect(befund?.message).toContain('12,2 % ZU GROSS'); expect(befund?.message).toContain('1684 Kfz/h'); expect(befund?.message).toContain('3,1 % zu klein'); expect(befund?.message).not.toContain('10,2 %'); expect(befund?.reference).toContain('2-5'); expect(befund?.suggestion).toContain('Lastzüge'); }); it('schweigt unterhalb der Schwelle', () => { /* * Die Schwelle ist ein Programmwert und begruendet: Bei 10 % * Schwerverkehr betraegt die moegliche Ueberschaetzung 5,5 %, bei 5 % nur * 2,9 % - darunter liegt sie unter der Genauigkeit einer Zaehlung. Die * Vorlage mit ihren 5 % soll keinen Hinweis erzeugen. */ expect(SCHWERVERKEHR_AUFTEILUNG_MELDESCHWELLE).toBe(0.1); expect(lastzuganteilSpanne(0.1).hoechstensZuGross * 100).toBeCloseTo(5.505, 3); expect(lastzuganteilSpanne(0.05).hoechstensZuGross * 100).toBeCloseTo(2.871, 3); // Die uebrigen Zahlen der Begruendung an der Meldeschwelle - sie stehen im // Kommentar und muessen dort stimmen. expect(lastzuganteilSpanne(0.25).hoechstensZuGross * 100).toBeCloseTo(12.245, 3); expect(lastzuganteilSpanne(0.5).hoechstensZuGross * 100).toBeCloseTo(20.69, 2); for (const pSV of [0, 0.05, 0.1]) { const { project } = knotenMitStrom({ volume: 600, heavyVehicleShare: pSV }); expect( validateProject(project).findings.filter((f) => f.rule === REGEL), `${pSV}`, ).toEqual([]); } // Knapp darueber kommt sie. const { project } = knotenMitStrom({ volume: 600, heavyVehicleShare: 0.11 }); expect(validateProject(project).findings.filter((f) => f.rule === REGEL)).toHaveLength(1); }); it('nennt den Anteil, mit dem gerechnet wird - nicht den eingetragenen', () => { /* * BEFUND (Fassung 5.6.0): Der Meldungstext nahm `demand.heavyVehicleShare` * roh, waehrend `lastzuganteilSpanne` intern auf 0 bis 1 begrenzt. Eine * Datei mit 150 % Schwerverkehr (ueber das Schema nicht erreichbar, ueber * Fremdwerkzeuge sehr wohl) ergab damit eine Ueberschrift "... (150 %)" * ueber Kfz/h-Zahlen, die fuer 100 % gelten - und derselbe Bericht meldet * den Wert daneben als begrenzt. * * Gerechnet wird mit 100 %: fSV = 1,90, also 2000/1,90 = 1053 Kfz/h; bei * lauter Lastzuegen 2000/2,50 = 800 Kfz/h (31,6 % zu gross), ohne * Lastzuege 2000/1,75 = 1143 Kfz/h (7,9 % zu klein). */ const { project } = knotenMitStrom({ volume: 600, heavyVehicleShare: 1.5 }); const befund = validateProject(project).findings.find((f) => f.rule === REGEL); expect(befund?.title).toContain('(100 %)'); expect(befund?.title).not.toContain('150'); expect(befund?.message).toContain('100 % Schwerverkehr'); expect(befund?.message).not.toContain('150 %'); expect(befund?.message).toContain('1053 Kfz/h'); expect(befund?.message).toContain('800 Kfz/h'); expect(befund?.message).toContain('31,6 % ZU GROSS'); expect(befund?.message).toContain('1143 Kfz/h'); expect(befund?.message).toContain('7,9 % zu klein'); }); it('schweigt ohne Verkehrsstaerke', () => { // Ohne sie gibt es keinen Auslastungsgrad, und die Unterlage druckt an // dieser Stelle einen Strich statt eines Faktors. const { project } = knotenMitStrom({ volume: 0, heavyVehicleShare: 0.4 }); expect(validateProject(project).findings.filter((f) => f.rule === REGEL)).toEqual([]); }); it('haelt sich an die Kennwerte des Plans, nicht an 2000 Kfz/h', () => { /* * MUTATIONSNACHWEIS gegen eine fest verdrahtete 2000 im Meldungstext: Mit * einem geaenderten Grundwert muss die Meldung mitwandern, sonst nennt * der Bericht eine Zahl, die im selben Bericht anders steht. */ const { project } = knotenMitStrom({ volume: 600, heavyVehicleShare: 0.25 }); const mitVorgabe: Project = { ...project, settings: { ...project.settings, rilsa: { ...project.settings.rilsa, saturationFlow: 1800 } }, }; const befund = validateProject(mitVorgabe).findings.find((f) => f.rule === REGEL); // 1800/1,225 = 1469 Kfz/h - die Prozentzahlen bleiben, sie haengen allein // am Schwerverkehrsanteil. expect(befund?.message).toContain('1469 Kfz/h'); expect(befund?.message).toContain('12,2 % ZU GROSS'); }); }); // --- Fundstellenverzeichnis ------------------------------------------------- describe('Das Fundstellenverzeichnis nach P14', () => { const hinweis = QUELLEN['hbs-kapazitaet'].hinweis ?? ''; it('sagt nicht mehr, das Programm rechne immer nach Gl. 2-6', () => { // Der Satz war bis Fassung 5.5.0 richtig und ist es jetzt nicht mehr. expect(hinweis).not.toContain('erfasst keine Aufteilung des Schwerverkehrs'); expect(hinweis).not.toContain('IMMER mit der zweiten Gleichung'); expect(hinweis).toContain('Datenverfügbarkeit'); }); it('fuehrt den Konsistenzbeleg mit seiner Nachrechnung', () => { expect(hinweis).toContain('Funktionsverlauf der Gleichung (2-6)'); expect(hinweis).toContain('1,75 · 0,80 + 2,5 · 0,20 = 1,9'); }); it('haelt den unsicheren Posten fest - jetzt begrenzt auf Ströme ohne Aufteilung', () => { expect(hinweis).toContain('10,2 %'); expect(hinweis).toContain('31,6 %'); expect(hinweis).toContain('ohne erfasste Aufteilung'); // Die Gegenrichtung war bisher nirgends beziffert. expect(hinweis).toContain('2,5 % zu klein'); // Und die Grenzen der Rechnung stehen weiter da. expect(hinweis).toContain('Standardbedingungen'); expect(hinweis).toContain('Mischfahrstreifen'); expect(hinweis).toContain('HCM 2010'); }); });