Aufträge und Rechnungen: Laden und Ladezustand des Reiters als reine Funktionen (mit Tests)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e7bd146641
commit
312705efc4
2 files changed
+213
No files matched your search
@@ -0,0 +1,144 @@
|
||||
import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { loadModule } from './load.mjs'
|
||||
|
||||
const { KONTEN_FEHLER, AUFTRAEGE_FEHLER, ladeAuftraegeAnsicht, ansichtsZustand } = 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)
|
||||
})
|
||||
Reference in new issue
Block a user