Files
accounted/lib/mileage/__tests__/csv-export.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

83 lines
2.6 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { mileageTripsToCsv } from '@/lib/mileage/csv-export'
import type { MileageTrip } from '@/types'
function trip(overrides: Partial<MileageTrip>): MileageTrip {
return {
id: 'trip-1',
company_id: 'company-1',
user_id: 'user-1',
employee_id: null,
trip_date: '2026-05-10',
vehicle_type: 'own_car',
vehicle_registration: 'ABC123',
odometer_start: 1000,
odometer_end: 1032,
distance_km: 32.3,
from_location: 'Kontoret',
to_location: 'Kunden',
purpose: 'Kundbesök',
visited: null,
is_round_trip: false,
status: 'draft',
journal_entry_id: null,
salary_run_id: null,
notes: null,
created_via: 'manual',
created_at: '2026-05-10T00:00:00Z',
updated_at: '2026-05-10T00:00:00Z',
...overrides,
}
}
describe('mileageTripsToCsv', () => {
it('starts with a UTF-8 BOM and the Swedish header row', () => {
const csv = mileageTripsToCsv([])
expect(csv.charCodeAt(0)).toBe(0xfeff)
expect(csv).toContain('Datum;Förare;Fordon;Registreringsnummer')
})
it('renders decimal comma, odometer readings and status labels', () => {
const csv = mileageTripsToCsv([trip({})])
const row = csv.split('\r\n')[1]
expect(row).toContain('2026-05-10;;Egen bil;ABC123;1000;1032;32,3;Kontoret;Kunden')
expect(row).toContain('Utkast')
})
it('names the driver for employee-attributed trips', () => {
const csv = mileageTripsToCsv(
[trip({ employee_id: 'emp-1' })],
new Map(),
new Map([['emp-1', 'Anna Andersson']])
)
expect(csv.split('\r\n')[1]).toContain('2026-05-10;Anna Andersson;Egen bil')
})
it('neutralizes formula-injection triggers in user text', () => {
const csv = mileageTripsToCsv([
trip({ purpose: '=HYPERLINK("http://evil","x")', from_location: '+SUM(A1)', visited: '@cmd' }),
])
const row = csv.split('\r\n')[1]
expect(row).toContain(`'=HYPERLINK`)
expect(row).toContain(`'+SUM(A1)`)
expect(row).toContain(`'@cmd`)
})
it('quotes fields containing separators and escapes quotes', () => {
const csv = mileageTripsToCsv([
trip({ purpose: 'Möte; leverans', visited: 'Firma "AB"' }),
])
expect(csv).toContain('"Möte; leverans"')
expect(csv).toContain('"Firma ""AB"""')
})
it('maps journal entry ids to voucher labels for booked trips', () => {
const csv = mileageTripsToCsv(
[trip({ status: 'booked', journal_entry_id: 'je-1' })],
new Map([['je-1', 'A42']])
)
const row = csv.split('\r\n')[1]
expect(row).toContain('Bokförd;A42')
})
})