Zusatzspeicher: Vorschau im flexiblen Abrechnungsmodus, Aufgaben nach Zeitpunkt, keine stillen Abbrüche
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
188db4b3c1
commit
bc20ce0673
9 files changed
+922
-228
No files matched your search
@@ -38,8 +38,24 @@ export async function startFakeStripe() {
|
||||
let seq = 0
|
||||
let nextSubscriptionUpdate = null
|
||||
let invoicePreview = null
|
||||
// Eingeplanter Fehler (failNext, F41d): der naechste passende Aufruf scheitert einmalig
|
||||
let pendingFailure = null
|
||||
const nextId = (prefix) => `${prefix}_test_${(seq += 1)}`
|
||||
|
||||
const matchesPath = (path, pathname) => (path instanceof RegExp ? path.test(pathname) : path === pathname)
|
||||
const plannedFailure = (method, pathname) => {
|
||||
if (!pendingFailure) return null
|
||||
if (pendingFailure.method && pendingFailure.method !== method) return null
|
||||
if (pendingFailure.path && !matchesPath(pendingFailure.path, pathname)) return null
|
||||
if (pendingFailure.after > 0) {
|
||||
pendingFailure.after -= 1
|
||||
return null
|
||||
}
|
||||
const { status, message } = pendingFailure
|
||||
pendingFailure = null
|
||||
return [status, { error: { type: status >= 500 ? 'api_error' : 'invalid_request_error', message: message || `Nachbau: eingeplanter Fehler ${status}` } }]
|
||||
}
|
||||
|
||||
const flat = (params) => Object.fromEntries(params.entries())
|
||||
const noSuch = (what, id) => [404, { error: { type: 'invalid_request_error', code: 'resource_missing', message: `No such ${what}: '${id}'` } }]
|
||||
const invalid = (param, message) => [400, { error: { type: 'invalid_request_error', param, message } }]
|
||||
@@ -337,7 +353,7 @@ export async function startFakeStripe() {
|
||||
const url = new URL(req.url, 'http://127.0.0.1')
|
||||
const body = await readBody(req)
|
||||
calls.push({ method: req.method, path: url.pathname, query: flat(url.searchParams), body: flat(body) })
|
||||
const [status, payload] = route(req.method, url.pathname, url.searchParams, body)
|
||||
const [status, payload] = plannedFailure(req.method, url.pathname) || route(req.method, url.pathname, url.searchParams, body)
|
||||
res.writeHead(status, { 'Content-Type': 'application/json', 'Request-Id': `req_test_${calls.length}` })
|
||||
res.end(JSON.stringify(payload))
|
||||
})
|
||||
@@ -380,6 +396,14 @@ export async function startFakeStripe() {
|
||||
set invoicePreview(value) {
|
||||
invoicePreview = value
|
||||
},
|
||||
/**
|
||||
* Naechster passender Aufruf (method, path als String oder RegExp) scheitert einmalig mit status; after
|
||||
* passende Aufrufe gehen vorher durch. Der Aufruf steht trotzdem in calls. 4xx wiederholt stripe-node
|
||||
* nicht, 5xx schon (maxNetworkRetries) - fuer "Stripe lehnt ab" also 4xx einplanen.
|
||||
*/
|
||||
failNext: ({ method = null, path = null, status = 500, message = '', after = 0 }) => {
|
||||
pendingFailure = { method, path, status, message, after }
|
||||
},
|
||||
close: () => new Promise((resolve) => server.close(resolve)),
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user