Dashboard-Abschnitt view-webshop, shop.css und Platzhalter shop.js, app.js (Hash, Refresher, Label, Elternansicht), Kachel in funktionen.js nach shop.verfuegbar, GET /api/funktionen liefert shop.verfuegbar, funktion-bestellen.js nimmt key/name/zusammenfassung (Standard: Terminplaner unverändert). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
83 lines
4.4 KiB
JavaScript
83 lines
4.4 KiB
JavaScript
import { test } from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import { installFakeDom } from './support/fakeDom.js'
|
|
import { h } from '../public/termine-dom.js'
|
|
import * as bestellen from '../public/funktion-bestellen.js'
|
|
|
|
// public/funktion-bestellen.js, Task G1: Checkout-Pfad und Zusammenfassung sind Parameter (key, zusammenfassung); ohne sie bleibt alles
|
|
// beim Terminplaner. Ohne Server und ohne den schweren Fragebogen-Test: die Bestellung ist von Hand gebaut.
|
|
|
|
const URL_ZAHLUNG = 'https://checkout.stripe.test/c/pay/cs_test_9'
|
|
const mitDom = (optionen, fn) => async () => {
|
|
const fx = installFakeDom(optionen)
|
|
try {
|
|
await fn(fx)
|
|
} finally {
|
|
fx.restore()
|
|
}
|
|
}
|
|
const bestellung = () => ({
|
|
preis: '299 €',
|
|
preisHinweis: 'einmalig, ohne Umsatzsteuer gemäß § 19 UStG',
|
|
consent: { version: 'v-shop', knopf: 'Zahlungspflichtig bestellen', items: [{ id: 'a', text: 'Ich stimme zu.', haken: true }, { id: 'b', text: 'Hinweis', haken: false }] },
|
|
})
|
|
const daten = () => ({ kundenansicht: false, offen: [], bestellung: bestellung(), einstellung: {}, fragebogen: {}, branchen: [] })
|
|
|
|
async function bestelleUndGibLog(fx, optionen) {
|
|
const wurzel = h('div')
|
|
document.body.append(wurzel)
|
|
bestellen.renderBestellen(wurzel, { ctx: { projectId: 'p1', aktuell: () => true }, daten: daten(), ...optionen })
|
|
await fx.klick(fx.finde(wurzel, 'input[type="checkbox"]'))
|
|
await fx.klick(fx.finde(wurzel, '[data-aktion="bestellen"]'))
|
|
await fx.ruhe()
|
|
return { wurzel, log: fx.fetchLog }
|
|
}
|
|
|
|
test('renderBestellen mit key "shop": Checkout geht an /api/funktionen/shop/checkout, Körper unverändert', mitDom({ antworten: [{ body: { url: URL_ZAHLUNG } }] }, async (fx) => {
|
|
const { log } = await bestelleUndGibLog(fx, { key: 'shop' })
|
|
assert.deepEqual(log, [{ method: 'POST', url: '/api/funktionen/shop/checkout', body: { projectId: 'p1', zustimmung: { version: 'v-shop', haken: ['a'] } } }])
|
|
assert.equal(fx.window.location.href, URL_ZAHLUNG)
|
|
}))
|
|
|
|
test('renderBestellen ohne key: weiter /api/funktionen/termine/checkout; ein unzulässiger key fällt darauf zurück', mitDom({ antworten: [{ body: { url: URL_ZAHLUNG } }] }, async (fx) => {
|
|
const { log } = await bestelleUndGibLog(fx, {})
|
|
assert.equal(log[0].url, '/api/funktionen/termine/checkout')
|
|
}))
|
|
test('renderBestellen: ein key mit Pfadzeichen wird nie in den Pfad übernommen', mitDom({ antworten: [{ body: { url: URL_ZAHLUNG } }] }, async (fx) => {
|
|
const { log } = await bestelleUndGibLog(fx, { key: '../abo/x?y' })
|
|
assert.equal(log[0].url, '/api/funktionen/termine/checkout')
|
|
}))
|
|
|
|
test('renderBestellen: ohne Zusammenfassungsfunktion (key shop) kein Zusammenfassungsblock; mit Funktion werden ihre Gruppen gezeichnet', mitDom({}, async (fx) => {
|
|
const ohne = h('div')
|
|
document.body.append(ohne)
|
|
bestellen.renderBestellen(ohne, { ctx: { projectId: 'p1' }, daten: daten(), key: 'shop' })
|
|
assert.equal(fx.finde(ohne, '.tm-bestellen-zusammenfassung'), null)
|
|
assert.ok(fx.finde(ohne, '[data-aktion="bestellen"]'), 'Preis, Zustimmungen und Knopf bleiben')
|
|
|
|
const mit = h('div')
|
|
document.body.append(mit)
|
|
const aufrufe = []
|
|
bestellen.renderBestellen(mit, {
|
|
ctx: { projectId: 'p1' }, daten: daten(), key: 'shop',
|
|
zusammenfassung: (...args) => { aufrufe.push(args.length); return [{ schritt: 'artikel', titel: 'Artikel', zeilen: ['3 Artikel'] }] },
|
|
})
|
|
assert.equal(aufrufe.length, 1)
|
|
assert.ok(fx.finde(mit, '.tm-bestellen-zusammenfassung'))
|
|
assert.match(fx.text(fx.finde(mit, '.tm-bestellen-gruppe')), /Artikel/)
|
|
}))
|
|
|
|
test('statusKarte: key und name steuern Fortsetzen-Pfad und Texte; ohne Angaben bleibt es der Terminplaner', mitDom({ antworten: [{ body: { url: URL_ZAHLUNG } }] }, async (fx) => {
|
|
const shop = bestellen.statusKarte({ projekt: { projectId: 'p1' }, bestellung: { state: 'setup' }, key: 'shop', name: 'Webshop' })
|
|
assert.match(fx.text(shop), /Wir richten deinen Webshop ein/)
|
|
assert.doesNotMatch(fx.text(shop), /Terminplaner/)
|
|
const termine = bestellen.statusKarte({ projekt: { projectId: 'p1' }, bestellung: { state: 'setup' } })
|
|
assert.match(fx.text(termine), /Wir richten deinen Terminplaner ein/)
|
|
|
|
const offen = bestellen.statusKarte({ projekt: { projectId: 'p1' }, bestellung: { state: 'ordered' }, key: 'shop', name: 'Webshop' })
|
|
document.body.append(offen)
|
|
await fx.klick(fx.finde(offen, '[data-aktion="fortsetzen"]'))
|
|
await fx.ruhe()
|
|
assert.deepEqual(fx.fetchLog, [{ method: 'POST', url: '/api/funktionen/shop/checkout', body: { projectId: 'p1', fortsetzen: true } }])
|
|
}))
|