188 lines
10 KiB
JavaScript
188 lines
10 KiB
JavaScript
import test from 'node:test'
|
||
import assert from 'node:assert/strict'
|
||
import { loadModule } from './load.mjs'
|
||
|
||
const {
|
||
KONTEN_FEHLER, AUFTRAEGE_FEHLER, ladeAuftraegeAnsicht, ansichtsZustand, kundeMitKundenart, erstelltMeldung, auftragMeldung,
|
||
} = await loadModule('src/lib/auftraegeAnsicht.js')
|
||
|
||
// Antwort von getProjektkonten (V5) mit den Feldern, die die Ansicht braucht
|
||
const konten = (extra = {}) => ({
|
||
auftraegeAktiv: false,
|
||
kunde: { id: 'k1', name: 'Anelia Wolf', kundenart: 'privat' },
|
||
konten: [{ projektId: 'p1', name: 'Website' }],
|
||
ohneProjekt: { berechnetCents: 5000, bezahltCents: 0, anzahl: 1 },
|
||
stripeOk: true,
|
||
...extra,
|
||
})
|
||
const OHNE_PROJEKT_LEER = { berechnetCents: 0, bezahltCents: 0, anzahl: 0 }
|
||
|
||
// Attrappe für getProjektkonten und listAuftraege: gibt Werte zurück, wirft Fehler und merkt sich die Aufrufe
|
||
function fakeApi({ projektkonten, auftraege } = {}) {
|
||
const calls = []
|
||
const antwort = (wert) => {
|
||
if (wert instanceof Error) throw wert
|
||
return wert
|
||
}
|
||
return {
|
||
calls,
|
||
getProjektkonten: async (id) => { calls.push(['konten', id]); return antwort(projektkonten) },
|
||
listAuftraege: async (id) => { calls.push(['auftraege', id]); return antwort(auftraege) },
|
||
}
|
||
}
|
||
|
||
test('Schalter aus: die Aufträge werden gar nicht erst abgerufen', async () => {
|
||
const api = fakeApi({ projektkonten: konten({ auftraegeAktiv: false }), auftraege: new Error('404 darf nie ankommen') })
|
||
const result = await ladeAuftraegeAnsicht('k1', api)
|
||
assert.deepEqual(api.calls, [['konten', 'k1']])
|
||
assert.equal(result.konten.auftraegeAktiv, false)
|
||
assert.equal(result.auftraege, null)
|
||
assert.equal(result.auftraegeFehler, '')
|
||
// ein fehlendes Feld gilt wie „aus“, nur true schaltet an; eine Antwort ohne Objekt wird zu {}
|
||
const fehlt = fakeApi({ projektkonten: { konten: [] } })
|
||
assert.equal((await ladeAuftraegeAnsicht('k1', fehlt)).auftraege, null)
|
||
assert.deepEqual(fehlt.calls, [['konten', 'k1']])
|
||
const nichts = await ladeAuftraegeAnsicht('k1', fakeApi({ projektkonten: null }))
|
||
assert.deepEqual(nichts, { konten: {}, auftraege: null, auftraegeFehler: '' })
|
||
})
|
||
|
||
test('Schalter an: erst die Projektkonten, dann die Aufträge des Kunden', async () => {
|
||
const liste = [{ id: 'a1', nummer: 'AB-2026-0001', status: 'versendet' }]
|
||
const api = fakeApi({ projektkonten: konten({ auftraegeAktiv: true }), auftraege: { auftraege: liste } })
|
||
const result = await ladeAuftraegeAnsicht('k1', api)
|
||
assert.deepEqual(api.calls, [['konten', 'k1'], ['auftraege', 'k1']])
|
||
assert.deepEqual(result.auftraege, liste)
|
||
assert.equal(result.auftraegeFehler, '')
|
||
// eine Antwort ohne Liste gibt eine leere Liste statt eines Absturzes
|
||
const leer = await ladeAuftraegeAnsicht('k1', fakeApi({ projektkonten: konten({ auftraegeAktiv: true }), auftraege: {} }))
|
||
assert.deepEqual(leer.auftraege, [])
|
||
})
|
||
|
||
test('Aufträge scheitern allein: die Projektkonten bleiben, der Fehler steht eigens da', async () => {
|
||
const api = fakeApi({
|
||
projektkonten: konten({ auftraegeAktiv: true }),
|
||
auftraege: Object.assign(new Error('Interner Fehler.'), { status: 500 }),
|
||
})
|
||
const result = await ladeAuftraegeAnsicht('k1', api)
|
||
assert.equal(result.konten.konten.length, 1)
|
||
assert.equal(result.auftraege, null)
|
||
assert.equal(result.auftraegeFehler, 'Interner Fehler.')
|
||
const ohneText = await ladeAuftraegeAnsicht('k1', fakeApi({ projektkonten: konten({ auftraegeAktiv: true }), auftraege: new Error('') }))
|
||
assert.equal(ohneText.auftraegeFehler, AUFTRAEGE_FEHLER)
|
||
assert.equal(AUFTRAEGE_FEHLER, 'Die Aufträge konnten nicht geladen werden.')
|
||
})
|
||
|
||
test('Projektkonten scheitern: der Fehler geht weiter, die Aufträge werden nicht abgerufen', async () => {
|
||
const fehler = Object.assign(new Error('Interner Fehler.'), { status: 500 })
|
||
const api = fakeApi({ projektkonten: fehler, auftraege: { auftraege: [] } })
|
||
await assert.rejects(ladeAuftraegeAnsicht('k1', api), (e) => e === fehler)
|
||
assert.deepEqual(api.calls, [['konten', 'k1']])
|
||
})
|
||
|
||
test('ansichtsZustand: vor der ersten Antwort „laden“, nach einem Fehler „fehler“ mit der Meldung', () => {
|
||
const laden = ansichtsZustand({ data: null, error: '' })
|
||
assert.equal(laden.projekteStatus, 'laden')
|
||
assert.equal(laden.auftraegeStatus, 'aus') // der Schalter ist noch unbekannt: kein Abschnitt, kein Flackern
|
||
assert.deepEqual(laden.konten, [])
|
||
assert.equal(ansichtsZustand().projekteStatus, 'laden')
|
||
const fehler = ansichtsZustand({ data: null, error: KONTEN_FEHLER })
|
||
assert.equal(fehler.projekteStatus, 'fehler')
|
||
assert.equal(fehler.fehler, KONTEN_FEHLER)
|
||
assert.equal(fehler.auftraegeStatus, 'aus') // ohne Projektkonten kein Schalter, also auch keine Aufträge
|
||
assert.equal(KONTEN_FEHLER, 'Die Projektübersicht konnte nicht geladen werden.')
|
||
})
|
||
|
||
test('ansichtsZustand: Schalter aus – Projekte bereit, kein Aufträge-Abschnitt', () => {
|
||
const z = ansichtsZustand({ data: { konten: konten({ auftraegeAktiv: false }), auftraege: null, auftraegeFehler: '' }, error: '' })
|
||
assert.equal(z.projekteStatus, 'bereit')
|
||
assert.equal(z.auftraegeAktiv, false)
|
||
assert.equal(z.auftraegeStatus, 'aus')
|
||
assert.equal(z.konten.length, 1)
|
||
assert.deepEqual(z.ohneProjekt, { berechnetCents: 5000, bezahltCents: 0, anzahl: 1 })
|
||
assert.equal(z.stripeOk, true)
|
||
assert.deepEqual(z.kunde, { id: 'k1', name: 'Anelia Wolf', kundenart: 'privat' })
|
||
assert.equal(z.nachladeFehler, '')
|
||
})
|
||
|
||
test('ansichtsZustand: Schalter an – Aufträge bereit oder mit eigenem Fehler, die Projekte bleiben', () => {
|
||
const liste = [{ id: 'a1' }]
|
||
const bereit = ansichtsZustand({ data: { konten: konten({ auftraegeAktiv: true }), auftraege: liste, auftraegeFehler: '' }, error: '' })
|
||
assert.equal(bereit.auftraegeAktiv, true)
|
||
assert.equal(bereit.auftraegeStatus, 'bereit')
|
||
assert.deepEqual(bereit.auftraege, liste)
|
||
const kaputt = ansichtsZustand({
|
||
data: { konten: konten({ auftraegeAktiv: true }), auftraege: null, auftraegeFehler: 'Interner Fehler.' },
|
||
error: '',
|
||
})
|
||
assert.equal(kaputt.projekteStatus, 'bereit')
|
||
assert.equal(kaputt.auftraegeStatus, 'fehler')
|
||
assert.equal(kaputt.auftraegeFehler, 'Interner Fehler.')
|
||
assert.deepEqual(kaputt.auftraege, [])
|
||
})
|
||
|
||
test('ansichtsZustand: Neuladen scheitert – die alten Daten bleiben, die Meldung steht daneben', () => {
|
||
const data = { konten: konten({ auftraegeAktiv: true }), auftraege: [{ id: 'a1' }], auftraegeFehler: '' }
|
||
const z = ansichtsZustand({ data, error: 'Das Kundenportal ist gerade nicht erreichbar.' })
|
||
assert.equal(z.projekteStatus, 'bereit')
|
||
assert.equal(z.fehler, '')
|
||
assert.equal(z.nachladeFehler, 'Das Kundenportal ist gerade nicht erreichbar.')
|
||
assert.equal(z.konten.length, 1)
|
||
assert.equal(z.auftraegeStatus, 'bereit')
|
||
assert.equal(z.auftraege.length, 1)
|
||
})
|
||
|
||
test('ansichtsZustand: unvollständige Antworten brechen die Ansicht nicht', () => {
|
||
for (const data of [{}, { konten: null }, { konten: {} }, { konten: { konten: 'x', ohneProjekt: 5, kunde: 'k' } }]) {
|
||
const z = ansichtsZustand({ data, error: '' })
|
||
assert.equal(z.projekteStatus, 'bereit')
|
||
assert.deepEqual(z.konten, [])
|
||
assert.deepEqual(z.ohneProjekt, OHNE_PROJEKT_LEER)
|
||
assert.equal(z.stripeOk, true)
|
||
assert.equal(z.kunde, null)
|
||
assert.equal(z.auftraegeAktiv, false)
|
||
assert.equal(z.auftraegeStatus, 'aus')
|
||
}
|
||
assert.equal(ansichtsZustand({ data: { konten: konten({ stripeOk: false }) }, error: '' }).stripeOk, false)
|
||
})
|
||
|
||
test('kundeMitKundenart: ein gültiger Wert des Portals gewinnt gegen das veraltete Kundendokument', () => {
|
||
const doc = { $id: 'k1', name: 'Anelia Wolf', kundenart: '' }
|
||
assert.deepEqual(kundeMitKundenart(doc, { id: 'k1', kundenart: 'privat' }), { ...doc, kundenart: 'privat' })
|
||
assert.equal(doc.kundenart, '') // das Dokument der Seite wird nicht verändert
|
||
assert.equal(kundeMitKundenart({ ...doc, kundenart: 'unternehmen' }, { kundenart: 'privat' }).kundenart, 'privat')
|
||
})
|
||
|
||
test('kundeMitKundenart: ohne gültigen Wert vom Portal bleibt das Dokument (dieselbe Referenz)', () => {
|
||
const doc = { $id: 'k1', kundenart: 'unternehmen' }
|
||
for (const info of [null, undefined, {}, { kundenart: '' }, { kundenart: 'firma' }, { kundenart: 5 }, 'privat']) {
|
||
assert.equal(kundeMitKundenart(doc, info), doc)
|
||
}
|
||
assert.equal(kundeMitKundenart(null, { kundenart: 'privat' }), null)
|
||
})
|
||
|
||
test('erstelltMeldung: gesendet, Entwurf und die Meldung nach festgeschriebener, nicht gesendeter Rechnung', () => {
|
||
assert.deepEqual(
|
||
erstelltMeldung({ number: 'WEBKLAR-0009', customerEmail: 'a@b.de' }, { senden: true }),
|
||
{ tone: 'ok', text: 'Rechnung WEBKLAR-0009 wurde an a@b.de gesendet.' },
|
||
)
|
||
assert.deepEqual(erstelltMeldung({ id: 'in_1' }, { senden: false }), { tone: 'ok', text: 'Der Entwurf wurde gespeichert.' })
|
||
assert.deepEqual(erstelltMeldung(null, undefined), { tone: 'ok', text: 'Der Entwurf wurde gespeichert.' })
|
||
assert.deepEqual(erstelltMeldung(null, null), { tone: 'ok', text: 'Der Entwurf wurde gespeichert.' })
|
||
const text = 'Rechnung WEBKLAR-0010 wurde festgeschrieben, aber nicht versendet. Bitte in der Liste erneut senden.'
|
||
assert.deepEqual(erstelltMeldung(null, { senden: true, notice: text, tone: 'warn', finalizedFilter: 'offen' }), { tone: 'warn', text })
|
||
assert.deepEqual(erstelltMeldung(null, { senden: true, notice: text }), { tone: 'ok', text })
|
||
})
|
||
|
||
test('auftragMeldung: Entwurf, gesendet und gesendet ohne zugestellte Mail', () => {
|
||
assert.deepEqual(auftragMeldung({ status: 'entwurf', nummer: '' }), { tone: 'ok', text: 'Der Entwurf wurde gespeichert.' })
|
||
assert.deepEqual(
|
||
auftragMeldung({ status: 'versendet', nummer: 'AB-2026-0001', gesendetAn: 'k@x.de', mailStatus: 'gesendet' }),
|
||
{ tone: 'ok', text: 'Auftragsbestätigung AB-2026-0001 wurde an k@x.de gesendet.' },
|
||
)
|
||
assert.deepEqual(
|
||
auftragMeldung({ status: 'versendet', nummer: 'AB-2026-0001', gesendetAn: 'k@x.de', mailStatus: 'fehler' }),
|
||
{ tone: 'warn', text: 'Auftragsbestätigung AB-2026-0001 ist versendet, die Mail an den Kunden wurde aber nicht zugestellt. Bitte in der Liste erneut senden.' },
|
||
)
|
||
assert.deepEqual(auftragMeldung(null), { tone: 'ok', text: 'Die Auftragsbestätigung wurde gespeichert.' })
|
||
})
|