import { test } from 'node:test' import assert from 'node:assert/strict' import { h } from '../public/shop-dom.js' import { initShop, vergissAuswahl } from '../public/shop.js' import { AUSGESCHLOSSEN } from '../public/shop-anfrage.js' import { KEIN_PREIS, einschaltenAttrappe, hoereAufKn, mitDom, routen } from './support/modulAbo.js' // Webshop im Abo-Modell (P4 Task 5): Anfrage ohne Unternehmer-Haken und ohne Preis, Satz über dem Knopf, Hinweis für Privatkunden, // nach der Zusage der Ablauf des Einschaltens statt der Bestellseite. Ohne modell === 'abo' bleibt alles wie heute. const ANFRAGE = { warenart: 'kleidung', beschreibung: 'Handgemachte Mützen und Schals.', artikelzahl: 'bis20', versand: true, abholung: false, unternehmer: true, keineAusgeschlossenen: true, nachricht: '' } const funk = (state, kopf = {}) => ({ projects: [{ projectId: 'p1', projectName: 'Mein Laden', features: { shop: { state } } }], features: { shop: { priceLabel: '299 €', consent: { version: 'v', knopf: 'Zahlungspflichtig bestellen · 299 €', items: [] } } }, ustHinweis: 'einmalig, ohne Umsatzsteuer gemäß § 19 UStG', legal: { shop: {} }, shop: { verfuegbar: true }, ...kopf, }) async function oeffne(fx, { kopf = {}, state = 'off', anfrage = null, einschalten } = {}) { vergissAuswahl() routen(fx, { 'GET /api/funktionen': { body: funk(state, kopf) }, 'GET /api/shop/status?projectId=p1': { body: { verfuegbar: true, state, ticketWoid: null, anfrage } }, 'POST /api/shop/anfrage': { body: { anfrage: {} } }, }) const root = h('div') document.body.append(root) await initShop(root, { projectId: 'p1', einschalten }) await fx.ruhe() return root } const ZUGESAGT = { status: 'angenommen', anfrage: ANFRAGE, at: '2026-10-05T10:30:00.000Z' } test('Abo, Betrieb: Anfrage ohne Unternehmer-Haken, Satz S2 über dem Knopf, kein Preis; Körper ohne unternehmer', mitDom(async (fx) => { const root = await oeffne(fx, { kopf: { modell: 'abo', kundenart: 'unternehmen' } }) assert.ok(fx.finde(root, '[data-feld="unternehmer"]') === null) assert.ok(fx.finde(root, '[data-feld="keineAusgeschlossenen"]') === null) const satz = fx.finde(root, '[data-satz="ausgeschlossen"]') assert.equal(fx.text(satz), `Mit „Anfrage senden“ bestätigst du, dass du keine ausgeschlossenen Waren verkaufst (${AUSGESCHLOSSEN}).`) const knoten = fx.alle(root, '*') assert.ok(knoten.indexOf(satz) < knoten.indexOf(fx.finde(root, '[data-aktion="anfrage-senden"]')), 'Satz steht über dem Knopf') const erklaerung = fx.text(fx.finde(root, '.sh-erklaerung')) assert.match(erklaerung, /Im Wartungs-Abo enthalten\./) assert.match(erklaerung, /Wir sehen uns deine Anfrage kurz an\. Erst nach unserer Zusage kannst du einschalten\./) assert.doesNotMatch(erklaerung, KEIN_PREIS) assert.doesNotMatch(erklaerung, /bestellen/) assert.doesNotMatch(fx.text(root), KEIN_PREIS) await fx.setze(fx.finde(root, '[data-feld="warenart"]'), 'kleidung') await fx.setze(fx.finde(root, '[data-feld="beschreibung"]'), 'Handgemachte Mützen und Schals.') await fx.setze(fx.finde(root, '[data-feld="artikelzahl"]'), 'bis20') await fx.klick(fx.finde(root, '[data-feld="versand"]')) await fx.klick(fx.finde(root, '[data-aktion="anfrage-senden"]')) assert.deepEqual(fx.fetchLog.find((a) => a.method === 'POST').body, { projectId: 'p1', anfrage: { warenart: 'kleidung', beschreibung: 'Handgemachte Mützen und Schals.', artikelzahl: 'bis20', versand: true, abholung: false, keineAusgeschlossenen: true, nachricht: '' }, }) })) test('Abo, privat oder Kundenart leer/fehlend: Hinweis S3 mit Chat, nie das Formular, kein POST, leere Reiterliste', mitDom(async (fx) => { const k = hoereAufKn(fx) for (const kundenart of ['privat', '', undefined]) { const root = await oeffne(fx, { kopf: { modell: 'abo', kundenart } }) assert.ok(fx.finde(root, 'form') === null, String(kundenart)) assert.match(fx.text(root), /Der Webshop ist für Betriebe/) assert.match(fx.text(root), /Für Privatpersonen gibt es den Webshop leider nicht\. Stimmt das nicht\? Schreib uns im Chat\./) assert.ok(fx.finde(root, 'button[data-view="chat"]')) } assert.equal(fx.fetchLog.filter((a) => a.method === 'POST').length, 0) assert.deepEqual(k.reiter.at(-1).eintraege, []) })) test('Abo, privat mit bestehendem Shop (active): die fünf Reiter bleiben', mitDom(async (fx) => { const k = hoereAufKn(fx) await oeffne(fx, { kopf: { modell: 'abo', kundenart: 'privat' }, state: 'active' }) assert.equal(k.reiter.at(-1).eintraege.length, 5) })) test('Abo, Anfrage angenommen: Gruppe B1 und Ablauf key shop statt Bestellseite; onFertig lädt neu', mitDom(async (fx) => { const a = einschaltenAttrappe() const root = await oeffne(fx, { kopf: { modell: 'abo', kundenart: 'unternehmen' }, anfrage: ZUGESAGT, einschalten: a.fn }) assert.equal(a.aufrufe[0].key, 'shop') assert.equal(a.aufrufe[0].projectId, 'p1') assert.equal(fx.text(fx.finde(root, '.tm-bestellen-gruppe h4')), 'Deine Anfrage') assert.ok(fx.finde(root, '[data-aktion="bestellen"]') === null) assert.doesNotMatch(fx.text(root), KEIN_PREIS) a.fertig(0) await fx.ruhe() assert.equal(fx.fetchLog.filter((x) => x.url === '/api/shop/status?projectId=p1').length, 2) })) test('Abo, Anfrage angenommen, ohne Funktion einschalten: Fehlerkarte E4', mitDom(async (fx) => { const root = await oeffne(fx, { kopf: { modell: 'abo', kundenart: 'unternehmen' }, anfrage: ZUGESAGT }) assert.match(fx.text(root), /Das Einschalten ist gerade nicht verfügbar\./) })) test('Ohne modell (fehlt, „Abo“): Formular mit Unternehmer-Haken und 299 €, nach der Zusage die Bestellseite, der Ablauf wird nie gerufen', mitDom(async (fx) => { for (const modell of [undefined, 'Abo']) { const a = einschaltenAttrappe() const kopf = modell ? { modell } : {} const formular = await oeffne(fx, { kopf, einschalten: a.fn }) assert.ok(fx.finde(formular, '[data-feld="unternehmer"]')) assert.ok(fx.finde(formular, '[data-feld="keineAusgeschlossenen"]')) assert.match(fx.text(formular), /299 € einmalig/) const zugesagt = await oeffne(fx, { kopf, anfrage: ZUGESAGT, einschalten: a.fn }) assert.ok(fx.finde(zugesagt, '[data-aktion="bestellen"]')) assert.equal(a.aufrufe.length, 0) } })) test('Abo, Kundenansicht der Mitarbeiter (window.KbView.id): der Ablauf bekommt viewAs true', mitDom(async (fx) => { fx.window.KbView = { id: () => 'view1' } const a = einschaltenAttrappe() await oeffne(fx, { kopf: { modell: 'abo', kundenart: 'unternehmen' }, anfrage: ZUGESAGT, einschalten: a.fn }) assert.equal(a.aufrufe[0].viewAs, true) }))