Files
Webklar-Kundenbereich/test/unterkunftWidgetFluss.test.js
T

111 lines
6.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { test } from 'node:test'
import assert from 'node:assert/strict'
import { readFileSync } from 'node:fs'
import vm from 'node:vm'
import { installFakeDom } from './support/fakeDom.js'
// Ablauf des Widgets public/embed/unterkunft.js gegen den Vertrag docs/funktionen/unterkunft-api.md (Fake-fetch, Minimal-DOM).
const QUELLE = readFileSync(new URL('../public/embed/unterkunft.js', import.meta.url), 'utf8')
const CFG = { aktiv: true, anbieter: { name: 'Haus Test', ort: 'X', datenschutzUrl: 'https://kunde.example/datenschutz' }, akzentfarbe: '#0f766e', formToken: 'tok1', unterkuenfte: [{ id: 'u1', name: 'Ferienwohnung', maxPersonen: 3, mindestNaechte: 2, checkIn: '15:00', checkOut: '11:00' }] }
const BEL = { belegt: [{ von: '2026-11-20', bis: '2026-11-25' }], heute: '2026-11-01', bisMax: '2028-04-30' }
function start(antworten) {
const fx = installFakeDom({ antworten })
fx.document.readyState = 'complete'
fx.document.currentScript = { dataset: {}, src: 'https://project.webklar.com/embed/unterkunft.js' }
const el = fx.document.createElement('div')
el.setAttribute('data-webklar-unterkunft', 'abcdefghijklmnop')
fx.document.body.appendChild(el)
vm.runInThisContext(QUELLE, { filename: 'unterkunft.js' })
return { fx, el }
}
const tag = (fx, el, t) => fx.finde(el, `[data-tag="${t}"]`)
test('Ladefehler und aktiv:false zeigen nur den Ausweichsatz', async () => {
for (const antwort of [{ status: 200, body: { aktiv: false } }, { status: 500, body: {} }]) {
const { fx, el } = start([antwort])
try {
await fx.ruhe()
assert.equal(fx.text(el), 'Anfragen gerne per Telefon oder E-Mail.')
} finally { fx.restore() }
}
})
test('Kalender, Auswahl, Mindestnaechte, Absenden mit Vertragsfeldern, Danke-Text', async () => {
const { fx, el } = start([{ status: 200, body: CFG }, { status: 200, body: BEL }, { status: 201, body: { nummer: 'A-1234' } }, { status: 200, body: BEL }])
try {
await fx.ruhe(); await fx.ruhe()
assert.match(fx.fetchLog[0].url, /^https:\/\/project\.webklar\.com\/api\/public\/unterkunft\/v1\/abcdefghijklmnop$/)
assert.match(fx.fetchLog[1].url, /\/belegung\?unterkunft=u1&von=\d{4}-\d{2}-\d{2}&bis=\d{4}-\d{2}-\d{2}$/)
assert.equal(tag(fx, el, '2026-11-10').getAttribute('aria-label'), 'Dienstag, 10. November 2026, frei')
assert.equal(tag(fx, el, '2026-11-21').getAttribute('aria-label').includes('belegt'), true)
assert.ok(fx.finde(el, '[name="kontakt_url"]'), 'Honeypot')
// ohne Zeitraum
await fx.setze(fx.finde(el, '[name="name"]'), 'Max'); await fx.setze(fx.finde(el, '[name="email"]'), 'max@example.com')
await fx.klick(fx.finde(el, 'button[type="submit"]'))
assert.match(fx.text(el), /Bitte wählen Sie Anreise und Abreise im Kalender\./)
assert.equal(fx.fetchLog.length, 2)
// Mindestnaechte (2): 1 Nacht -> Hinweis
await fx.klick(tag(fx, el, '2026-11-10')); await fx.klick(tag(fx, el, '2026-11-11'))
assert.match(fx.text(el), /Mindestaufenthalt: 2 Nächte/)
await fx.klick(tag(fx, el, '2026-11-14'))
assert.match(fx.text(el), /10\.–14\. Nov\. · 4 Nächte/)
await fx.klick(fx.finde(el, 'button[type="submit"]'))
const post = fx.fetchLog[2]
assert.equal(post.method, 'POST')
assert.match(post.url, /\/anfrage$/)
assert.deepEqual(post.body, { unterkunft: 'u1', von: '2026-11-10', bis: '2026-11-14', personen: 1, name: 'Max', firma: '', email: 'max@example.com', telefon: '', nachricht: '', formToken: 'tok1', kontakt_url: '' })
assert.match(fx.text(el), /Danke! Ihre Anfrage A-1234 ist eingegangen\. Sie erhalten gleich eine Bestätigung per E-Mail\./)
} finally { fx.restore() }
})
test('Pfeiltasten bewegen den Fokus', async () => {
const { fx, el } = start([{ status: 200, body: CFG }, { status: 200, body: BEL }])
try {
await fx.ruhe(); await fx.ruhe()
await fx.klick(tag(fx, el, '2026-11-10'))
await fx.sende(tag(fx, el, '2026-11-10'), 'keydown', { key: 'ArrowRight' })
assert.equal(fx.document.activeElement.getAttribute('data-tag'), '2026-11-11')
await fx.sende(fx.document.activeElement, 'keydown', { key: 'ArrowDown' })
assert.equal(fx.document.activeElement.getAttribute('data-tag'), '2026-11-18')
} finally { fx.restore() }
})
test('Monatsnavigation: erster Monat hat aktiven Weiter-Knopf, Fokus bleibt, Tab-Stop im gezeigten Monat, Abreisetag-Label', async () => {
const { fx, el } = start([{ status: 200, body: CFG }, { status: 200, body: BEL }])
try {
await fx.ruhe(); await fx.ruhe()
const erster = fx.finde(el, '.wku-monat')
const weiter = fx.finde(erster, '[data-nav="vor1"]')
assert.ok(weiter && !weiter.hasAttribute('disabled'))
await fx.klick(weiter)
assert.match(fx.text(el), /Dezember 2026/)
assert.equal(fx.document.activeElement.getAttribute('data-nav'), 'vor1')
assert.equal(fx.finde(el, '[data-tag][tabindex="0"]').getAttribute('data-tag'), '2026-12-01')
await fx.klick(fx.finde(el, '[data-nav="zur"]'))
assert.equal(fx.document.activeElement.getAttribute('data-nav'), 'vor1') // Zurueck ist im ersten Monat gesperrt, Fokus wechselt zum Weiter-Knopf
assert.equal(fx.finde(el, '[data-tag][tabindex="0"]').getAttribute('data-tag'), '2026-11-01')
await fx.klick(tag(fx, el, '2026-11-18'))
assert.match(tag(fx, el, '2026-11-20').getAttribute('aria-label'), /belegt – als Abreisetag möglich/)
assert.doesNotMatch(tag(fx, el, '2026-11-22').getAttribute('aria-label'), /Abreisetag möglich/)
} finally { fx.restore() }
})
test('Serverfehler: felder.zeitraum, neu_laden und mindestnaechte erscheinen mit eigenem Text', async () => {
const faelle = [
[{ status: 400, body: { fehler: 'ungueltig', felder: { zeitraum: 'Ungültiger Zeitraum.' } } }, /Ungültiger Zeitraum\./],
[{ status: 400, body: { fehler: 'neu_laden' } }, /zu lange geöffnet/],
[{ status: 400, body: { fehler: 'mindestnaechte', felder: { mindestNaechte: 3 } } }, /Mindestaufenthalt: 3 Nächte\./],
]
for (const [antwort, muster] of faelle) {
const { fx, el } = start([{ status: 200, body: CFG }, { status: 200, body: BEL }, antwort, { status: 200, body: CFG }])
try {
await fx.ruhe(); await fx.ruhe()
await fx.setze(fx.finde(el, '[name="name"]'), 'Max'); await fx.setze(fx.finde(el, '[name="email"]'), 'max@example.com')
await fx.klick(tag(fx, el, '2026-11-10')); await fx.klick(tag(fx, el, '2026-11-14'))
await fx.klick(fx.finde(el, 'button[type="submit"]'))
assert.match(fx.text(el), muster)
} finally { fx.restore() }
}
})