Shop Review B M-2: Widerrufsfunktion laeuft auch bei SHOP_ENABLED=off und ausserhalb des Pilotkreises

GET /:siteKey liefert dann die Widerrufsseite (nurWiderruf), POST /:siteKey/widerruf samt
Preflight geht durch, solange die Funktion active oder disabled ist. Bestellen, Pruefen, Status
und Bilder bleiben gesperrt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-10-05 09:59:58 +00:00
1 parent 08d837d690
commit b2072e4e7c
3 files changed
+84 -24

No files matched your search

+32 -5
View File
@@ -276,26 +276,53 @@ test('aktiv:false ohne Orakel: unbekannt, ungueltig, falscher Zustand, Modus off
await aufbau({ shop: null }) // kein shopConfig
await nein(`/${SITE_KEY}`)
await aufbau()
config.shop.mode = 'off'
await nein(`/${SITE_KEY}`)
config.shop.mode = 'on'
assert.equal((await api(`/${SITE_KEY}`)).body.aktiv, true)
})
test('Pilotmodus: nur Besitzer auf der Pilotliste', async () => {
test('M-2: Modus off und Pilotkreis ohne Besitzer sperren das Bestellen, nicht die Widerrufsseite: GET liefert nurWiderruf, Bestellrouten bleiben aktiv:false', async () => {
const nurWiderruf = (body) => {
assert.equal(body.aktiv, true)
assert.equal(body.offen, false)
assert.equal(body.nurWiderruf, true)
assert.ok(body.formToken && body.widerrufUrl.endsWith(`/shop/${SITE_KEY}/widerruf`))
assert.equal(body.shop.name, 'Brot & Mehr')
assert.equal(body.produkte, undefined)
assert.equal(body.rechtstexte, undefined)
}
config.shop.mode = 'off'
nurWiderruf((await api(`/${SITE_KEY}`)).body)
assert.equal((await api(`/${SITE_KEY}/bild/${BILD_ID}-s.webp`)).status, 404)
K.leereCache()
config.shop.mode = 'pilot'
config.shop.pilotEmails = ['andere@example.com']
nurWiderruf((await api(`/${SITE_KEY}`)).body)
K.leereCache()
config.shop.pilotEmails = ['inhaber@brot.example']
assert.equal((await api(`/${SITE_KEY}`)).body.nurWiderruf, undefined, 'im Pilotkreis wie gewohnt')
// unbekannter Shop und andere Zustaende bleiben aktiv:false, auch bei off
config.shop.mode = 'off'
await aufbau({ feature: { state: 'off' } })
assert.deepEqual((await api(`/${SITE_KEY}`)).body, { aktiv: false })
assert.deepEqual((await api('/zzzzzzzzzzzzzzzz')).body, { aktiv: false })
})
test('Pilotmodus: nur Besitzer auf der Pilotliste bekommen den Shop, alle anderen nur die Widerrufsseite', async () => {
config.shop.mode = 'pilot'
config.shop.pilotEmails = ['andere@example.com']
const gesperrt = (await api(`/${SITE_KEY}`)).body
assert.deepEqual([gesperrt.aktiv, gesperrt.nurWiderruf, gesperrt.produkte], [true, true, undefined])
K.leereCache()
config.shop.pilotEmails = ['inhaber@brot.example']
assert.equal((await api(`/${SITE_KEY}`)).body.aktiv, true)
assert.equal((await api(`/${SITE_KEY}`)).body.nurWiderruf, undefined)
K.leereCache()
config.shop.pilotEmails = ['*']
assert.equal((await api(`/${SITE_KEY}`)).body.aktiv, true)
assert.equal((await api(`/${SITE_KEY}`)).body.nurWiderruf, undefined)
// Kunde ohne Dokument: nie freigeschaltet
await aufbau({ kunde: null })
config.shop.pilotEmails = ['inhaber@brot.example']
assert.deepEqual((await api(`/${SITE_KEY}`)).body, { aktiv: false })
assert.equal((await api(`/${SITE_KEY}`)).body.nurWiderruf, true)
// im Pilotmodus gilt dasselbe fuer die Bilder
await aufbau()
config.shop.pilotEmails = ['andere@example.com']
+27 -11
View File
@@ -353,7 +353,7 @@ test('abgeschalteter Shop (disabled): Widerruf geht weiter', async () => {
assert.equal(outbox()[0].art, 'G12')
})
test('unbekannter siteKey, Modus off, Pilot ohne Treffer, andere Zustände: 200 { aktiv: false } ohne Origin-Prüfung', async () => {
test('unbekannter siteKey und andere Zustände: 200 { aktiv: false } ohne Origin-Prüfung', async () => {
const unbekannt = await post('/zzzzzzzzzzzzzzzz/widerruf', koerper(), { origin: 'https://fremd.example' })
assert.equal(unbekannt.status, 200)
assert.deepEqual(unbekannt.body, { aktiv: false })
@@ -362,21 +362,37 @@ test('unbekannter siteKey, Modus off, Pilot ohne Treffer, andere Zustände: 200
const ungueltig = await post('/x/widerruf', koerper())
assert.deepEqual(ungueltig.body, { aktiv: false })
config.shop.mode = 'off'
assert.deepEqual((await widerruf()).body, { aktiv: false })
config.shop.mode = 'pilot'
config.shop.pilotEmails = ['jemand@anders.example']
assert.deepEqual((await widerruf()).body, { aktiv: false })
config.shop.pilotEmails = ['inhaber@brot.example']
assert.equal((await widerruf()).body.ok, true)
await warteAufVersand()
assert.equal(widerrufe().length, 1, 'nur der Pilot-Treffer')
await aufbau({ state: 'pending' })
assert.deepEqual((await widerruf()).body, { aktiv: false })
assert.equal(widerrufe().length, 0)
})
test('M-2: der Widerruf geht auch bei SHOP_ENABLED=off und für Besitzer ausserhalb des Pilotkreises (active und disabled), Preflight ebenso', async () => {
for (const [modus, pilot] of [['off', []], ['pilot', ['jemand@anders.example']], ['pilot', []], ['on', []]]) {
config.shop.mode = modus
config.shop.pilotEmails = pilot
K.leereCache()
const vorher = widerrufe().length
const res = await widerruf()
assert.equal(res.body.ok, true, `${modus} ${pilot}`)
await warteAufVersand()
assert.equal(widerrufe().length, vorher + 1, `${modus}: Widerruf gespeichert`)
const preflight = await send('OPTIONS', `${BASIS}/${SITE_KEY}/widerruf`, { headers: { 'x-forwarded-for': ip, origin: O_LIVE, 'access-control-request-method': 'POST' } })
assert.equal(preflight.status, 204, `${modus}: Preflight`)
assert.equal(kopf(preflight, 'access-control-allow-origin'), O_LIVE)
}
// abgeschaltete Funktion: ebenfalls
config.shop.mode = 'off'
await aufbau({ state: 'disabled' })
assert.equal((await widerruf()).body.ok, true)
// aber die Bestellrouten bleiben bei off zu
const pruefen = await post(`/${SITE_KEY}/pruefen`, { positionen: [{ produktId: 'a1', menge: 1 }], lieferart: 'abholung' })
assert.deepEqual(pruefen.body, { aktiv: false })
// nicht active/disabled bleibt zu
await aufbau({ state: 'pending' })
assert.deepEqual((await widerruf()).body, { aktiv: false })
})
test('Mindestantwortzeit: auch Fehler und Fallen antworten nicht schneller als minAntwortMs', async () => {
config.shop.minAntwortMs = 250
for (const body of [koerper(), koerper({ kontakt_url: 'x' }), koerper({ formToken: 'kaputt' }), koerper({ name: '' })]) {