Tests nach der Freigabe: Wortlaut-Status freigegeben, Rückfall "PDF fehlt" per Test-Weiche
Seit die PDFs der Fassung 6 im Repo liegen, stellt knUnterlagenFehlen den Fall "Fassung 6 ohne PDF" mit setAnhangPfadFuerTests nach (vertragsAnhang.js, nur für Tests, Vorgabe aus). Vier Nachweis-Tests erwarten jetzt wortlaut: 'freigegeben'. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5d0adf12c9
commit
99d9b280f5
6 files changed
+34
-13
No files matched your search
@@ -11,6 +11,16 @@ import { access, readFile } from 'node:fs/promises'
|
|||||||
import { contractAttachmentFor } from './products.js'
|
import { contractAttachmentFor } from './products.js'
|
||||||
import { istNeueFassung } from './vertragsNachweis.js'
|
import { istNeueFassung } from './vertragsNachweis.js'
|
||||||
|
|
||||||
|
/** Nur für Tests: lenkt den Pfad des PDFs um (fn(pfad, termsVersion) -> pfad; null = normal), um „PDF fehlt“ nachzustellen. */
|
||||||
|
let pfadFuerTests = null
|
||||||
|
export function setAnhangPfadFuerTests(fn) {
|
||||||
|
pfadFuerTests = typeof fn === 'function' ? fn : null
|
||||||
|
}
|
||||||
|
function anhangVon(termsVersion) {
|
||||||
|
const a = contractAttachmentFor(termsVersion)
|
||||||
|
return pfadFuerTests ? { ...a, path: pfadFuerTests(a.path, termsVersion) } : a
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} termsVersion zugestimmte Fassung (die Fassung der Zustimmung, nicht die des Abos)
|
* @param {string} termsVersion zugestimmte Fassung (die Fassung der Zustimmung, nicht die des Abos)
|
||||||
* @param {string} tag Kennung fuer das Log, z. B. 'abo'
|
* @param {string} tag Kennung fuer das Log, z. B. 'abo'
|
||||||
@@ -18,7 +28,7 @@ import { istNeueFassung } from './vertragsNachweis.js'
|
|||||||
* fehlt: nur bei Fassung 6 und nicht lesbarer Datei
|
* fehlt: nur bei Fassung 6 und nicht lesbarer Datei
|
||||||
*/
|
*/
|
||||||
export async function ladeVertragsAnhang(termsVersion, tag) {
|
export async function ladeVertragsAnhang(termsVersion, tag) {
|
||||||
const { filename, path } = contractAttachmentFor(termsVersion)
|
const { filename, path } = anhangVon(termsVersion)
|
||||||
const content = await readFile(path).catch((err) => {
|
const content = await readFile(path).catch((err) => {
|
||||||
console.error(`[${tag}] Vertragsunterlagen ${filename} nicht lesbar:`, err.message)
|
console.error(`[${tag}] Vertragsunterlagen ${filename} nicht lesbar:`, err.message)
|
||||||
return null
|
return null
|
||||||
@@ -29,6 +39,6 @@ export async function ladeVertragsAnhang(termsVersion, tag) {
|
|||||||
/** Fehlen die PDFs der Fassung 6 (ohne Log, ohne Lesen der Datei)? Für ein später gesendetes T12; ältere Fassungen: nie. */
|
/** Fehlen die PDFs der Fassung 6 (ohne Log, ohne Lesen der Datei)? Für ein später gesendetes T12; ältere Fassungen: nie. */
|
||||||
export async function anhangFehlt(termsVersion) {
|
export async function anhangFehlt(termsVersion) {
|
||||||
if (!istNeueFassung(termsVersion)) return false
|
if (!istNeueFassung(termsVersion)) return false
|
||||||
const { path } = contractAttachmentFor(termsVersion)
|
const { path } = anhangVon(termsVersion)
|
||||||
return access(path).then(() => false, () => true)
|
return access(path).then(() => false, () => true)
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ seedFixtures(aw)
|
|||||||
test('Pilot-Kunde bekommt Fassung 6 und den Wortlaut', async () => {
|
test('Pilot-Kunde bekommt Fassung 6 und den Wortlaut', async () => {
|
||||||
const neu = await get('/api/abo', { cookie: customerCookie('c1') })
|
const neu = await get('/api/abo', { cookie: customerCookie('c1') })
|
||||||
assert.equal(neu.termsVersion, config.abo.termsVersionNeu)
|
assert.equal(neu.termsVersion, config.abo.termsVersionNeu)
|
||||||
assert.deepEqual([neu.bestelltexte.status, neu.bestelltexte.fassung, neu.bestelltexte.knopf], ['entwurf', config.abo.termsVersionNeu, 'Zahlungspflichtig bestellen'])
|
assert.deepEqual([neu.bestelltexte.status, neu.bestelltexte.fassung, neu.bestelltexte.knopf], ['freigegeben', config.abo.termsVersionNeu, 'Zahlungspflichtig bestellen'])
|
||||||
assert.equal(neu.bestelltexte.abo.linkzeile.urls[0], termsDocFor(config.abo.termsVersionNeu).url)
|
assert.equal(neu.bestelltexte.abo.linkzeile.urls[0], termsDocFor(config.abo.termsVersionNeu).url)
|
||||||
assert.match(neu.bestelltexte.abo.linkzeile.text, new RegExp(`Fassung ${config.abo.termsVersionNeu}\\)`))
|
assert.match(neu.bestelltexte.abo.linkzeile.text, new RegExp(`Fassung ${config.abo.termsVersionNeu}\\)`))
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ test('Betrieb: sofort ohne Häkchen, Fassung 6 in den Metadaten, Nachweis ohne B
|
|||||||
const [z] = zeilen().slice(n0)
|
const [z] = zeilen().slice(n0)
|
||||||
assert.deepEqual([z.customerId, z.projectId, z.kundenart, z.stripeSessionId], ['c3', '', 'unternehmen', ''])
|
assert.deepEqual([z.customerId, z.projectId, z.kundenart, z.stripeSessionId], ['c3', '', 'unternehmen', ''])
|
||||||
assert.deepEqual(ids(z), ['bestellung', 'linkzeile', 'knopf', 'kundenart'])
|
assert.deepEqual(ids(z), ['bestellung', 'linkzeile', 'knopf', 'kundenart'])
|
||||||
assert.deepEqual(JSON.parse(z.fassungen), { zustimmung: NEU(), bezug: 'wartung', wortlaut: 'entwurf' })
|
assert.deepEqual(JSON.parse(z.fassungen), { zustimmung: NEU(), bezug: 'wartung', wortlaut: 'freigegeben' })
|
||||||
assert.match(JSON.parse(z.texte)[0].text, /^Wartungs-Abo: 50,00 € pro Monat .*Beginn sofort/)
|
assert.match(JSON.parse(z.texte)[0].text, /^Wartungs-Abo: 50,00 € pro Monat .*Beginn sofort/)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ test('Fassung 6: Nachweis mit dem Satz und dem Knopf, Kundenart aus dem Dokument
|
|||||||
const [z] = zeilen().slice(n0)
|
const [z] = zeilen().slice(n0)
|
||||||
assert.deepEqual([z.kundenart, z.projectId, z.stripeSessionId, z.customerId], ['unternehmen', '', '', 'c1'])
|
assert.deepEqual([z.kundenart, z.projectId, z.stripeSessionId, z.customerId], ['unternehmen', '', '', 'c1'])
|
||||||
assert.deepEqual(JSON.parse(z.texte), nachweisTexte('gutschrift', {}))
|
assert.deepEqual(JSON.parse(z.texte), nachweisTexte('gutschrift', {}))
|
||||||
assert.deepEqual(JSON.parse(z.fassungen), { zustimmung: '2026-09-30', bezug: '', wortlaut: 'entwurf' })
|
assert.deepEqual(JSON.parse(z.fassungen), { zustimmung: '2026-09-30', bezug: '', wortlaut: 'freigegeben' })
|
||||||
assert.equal(config.takeover.conditionsVersion, '2026-09-30')
|
assert.equal(config.takeover.conditionsVersion, '2026-09-30')
|
||||||
assert.equal(aw.docs('takeoverCredits').get(res.body.request.id).conditionsVersion, '2026-09-30')
|
assert.equal(aw.docs('takeoverCredits').get(res.body.request.id).conditionsVersion, '2026-09-30')
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { useTestEnv } from './support/testEnv.js'
|
|||||||
import { schemaKeys } from './support/schema.js'
|
import { schemaKeys } from './support/schema.js'
|
||||||
import { mailSink } from './support/mailSink.js'
|
import { mailSink } from './support/mailSink.js'
|
||||||
|
|
||||||
// Abschlussprüfung F5: Fassung 6 ohne PDF. Fehlt der Anhang, behaupten K01, K12 und K13 kein „im Anhang“, und das Team bekommt in T02, T12 bzw. T13
|
// Abschlussprüfung F5: Fassung 6 ohne PDF. Seit der Freigabe (28.10.2026) liegen die PDFs im Repo; ohnePdf() stellt den Rückfall nach. Fehlt der Anhang, behaupten K01, K12 und K13 kein „im Anhang“, und das Team bekommt in T02, T12 bzw. T13
|
||||||
// den Block anhang_fehlt (Muster K38/T24). Alte Fassungen bleiben unverändert (Hash-Pins auf die Wiedergabe der alten Vorlagen).
|
// den Block anhang_fehlt (Muster K38/T24). Alte Fassungen bleiben unverändert (Hash-Pins auf die Wiedergabe der alten Vorlagen).
|
||||||
const aw = await startAppwriteMock({
|
const aw = await startAppwriteMock({
|
||||||
schema: {
|
schema: {
|
||||||
@@ -30,6 +30,7 @@ const { listContractEvents } = await import('../server/services/contractEvents.j
|
|||||||
const { deleteDocument } = await import('../server/services/appwriteAdmin.js')
|
const { deleteDocument } = await import('../server/services/appwriteAdmin.js')
|
||||||
const { setMailTransportForTests } = await import('../server/services/mailer.js')
|
const { setMailTransportForTests } = await import('../server/services/mailer.js')
|
||||||
const { loadTemplate, renderMail } = await import('../server/services/mailTemplates.js')
|
const { loadTemplate, renderMail } = await import('../server/services/mailTemplates.js')
|
||||||
|
const { setAnhangPfadFuerTests } = await import('../server/services/vertragsAnhang.js')
|
||||||
|
|
||||||
const app = await startTestApp({ '/api/abo': aboRoutes })
|
const app = await startTestApp({ '/api/abo': aboRoutes })
|
||||||
const mails = mailSink()
|
const mails = mailSink()
|
||||||
@@ -63,6 +64,16 @@ async function mitNeuFassung(fassung, fn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Fassung 6 ohne PDF: der Pfad zeigt während fn auf eine nicht vorhandene Datei. */
|
||||||
|
async function ohnePdf(fn) {
|
||||||
|
setAnhangPfadFuerTests((p) => `${p}.fehlt`)
|
||||||
|
try {
|
||||||
|
return await fn()
|
||||||
|
} finally {
|
||||||
|
setAnhangPfadFuerTests(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------- Vorlagen
|
// ---------------------------------------------------------------- Vorlagen
|
||||||
test('Vorlagen: K01, K12 und K13 kennen anhang und ohne_anhang, T02, T12 und T13 den Block anhang_fehlt', () => {
|
test('Vorlagen: K01, K12 und K13 kennen anhang und ohne_anhang, T02, T12 und T13 den Block anhang_fehlt', () => {
|
||||||
for (const id of ['K01', 'K12', 'K13']) assert.deepEqual(['anhang', 'ohne_anhang'].filter((b) => !loadTemplate(id).blocks.includes(b)), [], id)
|
for (const id of ['K01', 'K12', 'K13']) assert.deepEqual(['anhang', 'ohne_anhang'].filter((b) => !loadTemplate(id).blocks.includes(b)), [], id)
|
||||||
@@ -136,7 +147,7 @@ async function k01(termsVersion) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test('K01: Fassung 6 ohne PDF behauptet keinen Anhang, T02 sagt es dem Team', async () => {
|
test('K01: Fassung 6 ohne PDF behauptet keinen Anhang, T02 sagt es dem Team', async () => {
|
||||||
const { kunde, team } = await k01(NEU)
|
const { kunde, team } = await ohnePdf(() => k01(NEU))
|
||||||
assert.equal(kunde.attachments.length, 0)
|
assert.equal(kunde.attachments.length, 0)
|
||||||
assert.doesNotMatch(kunde.text, /Anhang|beigefügt/i)
|
assert.doesNotMatch(kunde.text, /Anhang|beigefügt/i)
|
||||||
assert.match(kunde.text, /senden wir Ihnen gesondert zu/)
|
assert.match(kunde.text, /senden wir Ihnen gesondert zu/)
|
||||||
@@ -169,7 +180,7 @@ async function k12(termsVersion) {
|
|||||||
return { kunde: mails.sent.find((m) => m.subject === 'Ihr Wechsel ins WEBklar Wartungs-Abo – Bestätigung'), team: mails.sent.find((m) => m.subject.startsWith('[Abo] Wechsel ins Wartungs-Abo')) }
|
return { kunde: mails.sent.find((m) => m.subject === 'Ihr Wechsel ins WEBklar Wartungs-Abo – Bestätigung'), team: mails.sent.find((m) => m.subject.startsWith('[Abo] Wechsel ins Wartungs-Abo')) }
|
||||||
}
|
}
|
||||||
test('K12: Fassung 6 ohne PDF behauptet keinen Anhang, T12 sagt es dem Team; mit PDF und alte Fassung wie bisher', async () => {
|
test('K12: Fassung 6 ohne PDF behauptet keinen Anhang, T12 sagt es dem Team; mit PDF und alte Fassung wie bisher', async () => {
|
||||||
const ohne = await k12(NEU)
|
const ohne = await ohnePdf(() => k12(NEU))
|
||||||
assert.equal(ohne.kunde.attachments.length, 0)
|
assert.equal(ohne.kunde.attachments.length, 0)
|
||||||
assert.doesNotMatch(ohne.kunde.text, /Anhang|beigefügt/i)
|
assert.doesNotMatch(ohne.kunde.text, /Anhang|beigefügt/i)
|
||||||
assert.match(ohne.kunde.text, /senden wir Ihnen gesondert zu/)
|
assert.match(ohne.kunde.text, /senden wir Ihnen gesondert zu/)
|
||||||
@@ -195,13 +206,13 @@ async function k13({ units, paidUnits, ziel, termsVersion }) {
|
|||||||
return { kunde: mails.sent.find((m) => m.subject === 'Ihr E-Mail-Zusatzspeicher – Bestätigung'), team: mails.sent.find((m) => m.subject.startsWith('[Speicher]')) }
|
return { kunde: mails.sent.find((m) => m.subject === 'Ihr E-Mail-Zusatzspeicher – Bestätigung'), team: mails.sent.find((m) => m.subject.startsWith('[Speicher]')) }
|
||||||
}
|
}
|
||||||
test('K13: Fassung 6 ohne PDF behauptet keinen Anhang, T13 sagt es dem Team (auch ohne Aufgabe); mit PDF und alte Fassung wie bisher', async () => {
|
test('K13: Fassung 6 ohne PDF behauptet keinen Anhang, T13 sagt es dem Team (auch ohne Aufgabe); mit PDF und alte Fassung wie bisher', async () => {
|
||||||
const ohne = await k13({ units: 0, paidUnits: 0, ziel: 2, termsVersion: NEU })
|
const ohne = await ohnePdf(() => k13({ units: 0, paidUnits: 0, ziel: 2, termsVersion: NEU }))
|
||||||
assert.equal(ohne.kunde.attachments.length, 0)
|
assert.equal(ohne.kunde.attachments.length, 0)
|
||||||
assert.doesNotMatch(ohne.kunde.text, /Anhang|beigefügt/i)
|
assert.doesNotMatch(ohne.kunde.text, /Anhang|beigefügt/i)
|
||||||
assert.match(ohne.kunde.text, /senden wir Ihnen gesondert zu/)
|
assert.match(ohne.kunde.text, /senden wir Ihnen gesondert zu/)
|
||||||
assert.match(ohne.team.text, new RegExp(HINWEIS))
|
assert.match(ohne.team.text, new RegExp(HINWEIS))
|
||||||
// Plus nur bis zur schon bezahlten Menge: keine Aufgabe, aber die Unterlagen müssen nachgesendet werden
|
// Plus nur bis zur schon bezahlten Menge: keine Aufgabe, aber die Unterlagen müssen nachgesendet werden
|
||||||
const bezahlt = await k13({ units: 1, paidUnits: 3, ziel: 3, termsVersion: NEU })
|
const bezahlt = await ohnePdf(() => k13({ units: 1, paidUnits: 3, ziel: 3, termsVersion: NEU }))
|
||||||
assert.equal(bezahlt.kunde.attachments.length, 0)
|
assert.equal(bezahlt.kunde.attachments.length, 0)
|
||||||
assert.ok(bezahlt.team, 'T13 geht auch ohne Aufgabe raus, wenn der Anhang fehlt')
|
assert.ok(bezahlt.team, 'T13 geht auch ohne Aufgabe raus, wenn der Anhang fehlt')
|
||||||
assert.match(bezahlt.team.text, new RegExp(HINWEIS))
|
assert.match(bezahlt.team.text, new RegExp(HINWEIS))
|
||||||
@@ -218,7 +229,7 @@ test('K13: Fassung 6 ohne PDF behauptet keinen Anhang, T13 sagt es dem Team (auc
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Karte mit Bestätigung bei der Bank: K12 geht beim Klick, T12 "wirksam" erst mit pending_update_applied; auch dieses T12 sagt, dass die PDFs fehlen
|
// Karte mit Bestätigung bei der Bank: K12 geht beim Klick, T12 "wirksam" erst mit pending_update_applied; auch dieses T12 sagt, dass die PDFs fehlen
|
||||||
test('T12 beim späteren Wirksamwerden (Karte, pending_update_applied) trägt anhang_fehlt, solange die PDFs der Fassung 6 fehlen', async () => {
|
test('T12 beim späteren Wirksamwerden (Karte, pending_update_applied) trägt anhang_fehlt, solange die PDFs der Fassung 6 fehlen', () => ohnePdf(async () => {
|
||||||
await resetHosting()
|
await resetHosting()
|
||||||
const nowU = nowUnix()
|
const nowU = nowUnix()
|
||||||
st.nextSubscriptionUpdate = {
|
st.nextSubscriptionUpdate = {
|
||||||
@@ -234,4 +245,4 @@ test('T12 beim späteren Wirksamwerden (Karte, pending_update_applied) trägt an
|
|||||||
const t12 = mails.sent.filter((m) => m.subject.startsWith('[Abo] Wechsel ins Wartungs-Abo'))
|
const t12 = mails.sent.filter((m) => m.subject.startsWith('[Abo] Wechsel ins Wartungs-Abo'))
|
||||||
assert.equal(t12.length, 1)
|
assert.equal(t12.length, 1)
|
||||||
assert.match(t12[0].text, new RegExp(HINWEIS))
|
assert.match(t12[0].text, new RegExp(HINWEIS))
|
||||||
})
|
}))
|
||||||
@@ -57,7 +57,7 @@ test('speichereVertragsNachweis schreibt eine Zeile ohne Projekt, mit Kundenart,
|
|||||||
const texte = nachweisTexte('abo', { kundenart: 'privat', fassung: FASSUNG, bestellung: 'Zeile', beginnGehakt: true })
|
const texte = nachweisTexte('abo', { kundenart: 'privat', fassung: FASSUNG, bestellung: 'Zeile', beginnGehakt: true })
|
||||||
const d = await speichereVertragsNachweis({ customerId: 'c3', art: 'abo', bezug: 'wartung', texte, fassungen: { zustimmung: FASSUNG }, kundenart: 'privat', req: req('k3@example.invalid'), at: '2026-10-17T08:00:00.000Z' })
|
const d = await speichereVertragsNachweis({ customerId: 'c3', art: 'abo', bezug: 'wartung', texte, fassungen: { zustimmung: FASSUNG }, kundenart: 'privat', req: req('k3@example.invalid'), at: '2026-10-17T08:00:00.000Z' })
|
||||||
assert.deepEqual([d.featureKey, d.projectId, d.stripeSessionId, d.kundenart, d.konto, d.ip, d.userAgent], ['abo', '', '', 'privat', 'Kunde Drei <k3@example.invalid>', '203.0.113.9', 'UA/1'])
|
assert.deepEqual([d.featureKey, d.projectId, d.stripeSessionId, d.kundenart, d.konto, d.ip, d.userAgent], ['abo', '', '', 'privat', 'Kunde Drei <k3@example.invalid>', '203.0.113.9', 'UA/1'])
|
||||||
assert.deepEqual(JSON.parse(d.fassungen), { zustimmung: FASSUNG, bezug: 'wartung', wortlaut: 'entwurf' })
|
assert.deepEqual(JSON.parse(d.fassungen), { zustimmung: FASSUNG, bezug: 'wartung', wortlaut: 'freigegeben' })
|
||||||
assert.deepEqual(JSON.parse(d.texte), texte)
|
assert.deepEqual(JSON.parse(d.texte), texte)
|
||||||
assert.equal(d.textHash, texteHash(texte))
|
assert.equal(d.textHash, texteHash(texte))
|
||||||
assert.equal(d.acceptedAt, '2026-10-17T08:00:00.000Z')
|
assert.equal(d.acceptedAt, '2026-10-17T08:00:00.000Z')
|
||||||
|
|||||||
Reference in new issue
Block a user