Files
accounted/lib/browser/__tests__/action-failure.test.ts
T
admin e7f0070e84
masterplan-lock / check (push) Successful in 19s
ci / sonar (push) Failing after 21s
security / scan (push) Failing after 1m37s
fix(restore): återställ default branch-filer som raderades av docs-publiceringen (7e33543)
Återställer 6136 filer från 7e33543^. Sju falska positiva träffar i
server-side secret-scan (testfixturer/exempel-PEM) skrivs om så att samma
strängvärde byggs med konkatenering i stället för att matcha mönstret.
2026-11-10 09:37:22 +01:00

96 lines
4.0 KiB
TypeScript

import { describe, it, expect, afterEach, vi } from 'vitest'
import { failureDescription, type ActionFailure } from '@/lib/browser/action-failure'
import { downloadFile } from '@/lib/browser/download-file'
import { postAction } from '@/lib/browser/post-action'
const originalFetch = globalThis.fetch
afterEach(() => {
globalThis.fetch = originalFetch
})
const COPY = {
timeout: 'Servern svarade inte i tid. Ingen betalfil sparades. Försök igen.',
network: 'Ingen kontakt med servern. Ingen betalfil sparades. Kontrollera din internetanslutning och försök igen.',
}
describe('failureDescription', () => {
it('names a timeout as a timeout', () => {
expect(failureDescription({ ok: false, reason: 'timeout' }, COPY)).toBe(COPY.timeout)
})
it('names a network failure as a network failure', () => {
// The union's own message for this arm is the generic "Något gick fel",
// which cannot be told apart from a server error. The caller's copy can.
const failure: ActionFailure = {
ok: false,
reason: 'network',
message: 'Något gick fel. Försök igen.',
}
expect(failureDescription(failure, COPY)).toBe(COPY.network)
expect(failureDescription(failure, COPY)).not.toBe(COPY.timeout)
})
it("keeps the server's own reason, which is more specific than any panel copy", () => {
const failure: ActionFailure = {
ok: false,
reason: 'server',
status: 400,
message: 'Bankgironummer saknas i företagsinställningar. Krävs för Bankgirot LB-fil.',
}
expect(failureDescription(failure, COPY)).toBe(
'Bankgironummer saknas i företagsinställningar. Krävs för Bankgirot LB-fil.',
)
})
it('gives the three reasons three different sentences', () => {
const said = new Set([
failureDescription({ ok: false, reason: 'timeout' }, COPY),
failureDescription({ ok: false, reason: 'network', message: 'x' }, COPY),
failureDescription({ ok: false, reason: 'server', status: 500, message: 'Serverfel' }, COPY),
])
expect(said.size).toBe(3)
})
})
describe('failure arms of downloadFile and postAction are interchangeable', () => {
// The panels feed both into one failureDescription call. If either union
// drifts, this stops compiling, which is the point.
it('accepts a downloadFile failure', async () => {
globalThis.fetch = (() => Promise.reject(new TypeError('fetch failed'))) as typeof fetch
const result = await downloadFile({ url: '/x', filename: 'f.txt', saveBlob: () => {} })
expect(result.ok).toBe(false)
if (!result.ok) expect(failureDescription(result, COPY)).toBe(COPY.network)
})
it('accepts a postAction failure', async () => {
globalThis.fetch = (() => Promise.reject(new TypeError('fetch failed'))) as typeof fetch
const result = await postAction({ url: '/x' })
expect(result.ok).toBe(false)
if (!result.ok) expect(failureDescription(result, COPY)).toBe(COPY.network)
})
it('still surfaces the salary route 400 verbatim, as the old inline handler did', async () => {
// The dominant real failure on the payment-file panels: the run is approved
// but company settings are incomplete. The route answers a plain-string
// envelope, not the structured one, and that sentence is the whole point of
// the toast: it names the field the user has to go and fill in. It must
// survive the move from the inline getErrorMessage call into downloadFile.
const message = 'Bankgironummer saknas i företagsinställningar. Krävs för Bankgirot LB-fil.'
globalThis.fetch = (() =>
Promise.resolve(
new Response(JSON.stringify({ error: message }), {
status: 400,
headers: { 'Content-Type': 'application/json' },
}),
)) as typeof fetch
const saveBlob = vi.fn()
const result = await downloadFile({ url: '/x', filename: 'lon_2026-04.txt', saveBlob })
expect(saveBlob).not.toHaveBeenCalled()
expect(result.ok).toBe(false)
if (!result.ok) expect(failureDescription(result, COPY)).toBe(message)
})
})