Files
accounted/lib/reports/__tests__/full-archive-export.test.ts
T
Jakob Wennberg 091d043c85 feat: UI polish, lint fixes, onboarding redesign, help page expansion, and test improvements
Broad update across dashboard pages, components, extensions, and lib code. Includes ESLint config additions, onboarding flow redesign, settings page refactor, help page content expansion, dead code removal, and test mock fixes. Adds dev docs and public assets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 23:05:49 +01:00

238 lines
6.8 KiB
TypeScript

/* eslint-disable @typescript-eslint/no-explicit-any */
import { describe, it, expect, vi, beforeEach } from 'vitest'
import JSZip from 'jszip'
import { generateFullArchive } from '../full-archive-export'
import { createQueuedMockSupabase } from '@/tests/helpers'
vi.mock('../sie-export', () => ({
generateSIEExport: vi.fn().mockResolvedValue('#FLAGGA 0\n#PROGRAM "ERPBase"'),
}))
vi.mock('../trial-balance', () => ({
generateTrialBalance: vi.fn().mockResolvedValue({
rows: [], totalDebit: 0, totalCredit: 0, isBalanced: true,
}),
}))
vi.mock('../income-statement', () => ({
generateIncomeStatement: vi.fn().mockResolvedValue({
sections: [], netResult: 0, period: { start: '2024-01-01', end: '2024-12-31' },
}),
}))
vi.mock('../balance-sheet', () => ({
generateBalanceSheet: vi.fn().mockResolvedValue({
asset_sections: [], equity_liability_sections: [],
total_assets: 0, total_equity_liabilities: 0,
period: { start: '2024-01-01', end: '2024-12-31' },
}),
}))
vi.mock('../general-ledger', () => ({
generateGeneralLedger: vi.fn().mockResolvedValue({
accounts: [], period: { start: '2024-01-01', end: '2024-12-31' },
}),
}))
vi.mock('../journal-register', () => ({
generateJournalRegister: vi.fn().mockResolvedValue({
entries: [], total_entries: 0, total_debit: 0, total_credit: 0,
period: { start: '2024-01-01', end: '2024-12-31' },
}),
}))
vi.mock('../vat-declaration', () => ({
calculateVatDeclaration: vi.fn().mockResolvedValue({
period: { type: 'yearly', year: 2024, period: 1, start: '2024-01-01', end: '2024-12-31' },
rutor: {
ruta05: 0, ruta06: 0, ruta07: 0,
ruta10: 0, ruta11: 0, ruta12: 0,
ruta39: 0, ruta40: 0, ruta48: 0, ruta49: 0,
},
invoiceCount: 0, transactionCount: 0,
breakdown: {
invoices: { ruta05: 0, ruta06: 0, ruta07: 0, ruta10: 0, ruta11: 0, ruta12: 0, ruta39: 0, ruta40: 0, base25: 0, base12: 0, base6: 0 },
transactions: { ruta48: 0 },
receipts: { ruta48: 0 },
},
}),
}))
vi.mock('@/lib/core/audit/audit-service', () => ({
getAuditLog: vi.fn().mockResolvedValue({ data: [], count: 0 }),
}))
describe('generateFullArchive', () => {
let supabase: ReturnType<typeof createQueuedMockSupabase>['supabase']
let enqueueMany: ReturnType<typeof createQueuedMockSupabase>['enqueueMany']
beforeEach(() => {
vi.clearAllMocks()
const mock = createQueuedMockSupabase()
supabase = mock.supabase
enqueueMany = mock.enqueueMany
})
function enqueueStandardResponses(opts?: { includeDocuments?: boolean }) {
// 1. fiscal_periods query
enqueueMany([
{
data: {
id: 'period-1',
period_start: '2024-01-01',
period_end: '2024-12-31',
user_id: 'user-1',
},
},
// 2. company_settings query
{
data: {
company_name: 'Test AB',
org_number: '5566778899',
moms_period: 'quarterly',
},
},
])
if (opts?.includeDocuments !== false) {
enqueueMany([
// 3. document_attachments query
{ data: [] },
])
}
}
it('generates a ZIP with expected file structure', async () => {
enqueueStandardResponses()
const buffer = await generateFullArchive(supabase as any, 'user-1', {
period_id: 'period-1',
})
const zip = await JSZip.loadAsync(buffer)
expect(zip.file('bokforing.se')).not.toBeNull()
expect(zip.file('rapporter/saldobalans.json')).not.toBeNull()
expect(zip.file('rapporter/resultatrakning.json')).not.toBeNull()
expect(zip.file('rapporter/balansrakning.json')).not.toBeNull()
expect(zip.file('rapporter/huvudbok.json')).not.toBeNull()
expect(zip.file('rapporter/grundbok.json')).not.toBeNull()
expect(zip.file('rapporter/momsdeklaration.json')).not.toBeNull()
expect(zip.file('dokument/manifest.json')).not.toBeNull()
expect(zip.file('revision/behandlingshistorik.json')).not.toBeNull()
})
it('handles missing documents gracefully', async () => {
const mock = createQueuedMockSupabase()
supabase = mock.supabase
enqueueMany = mock.enqueueMany
enqueueMany([
// fiscal_periods
{
data: {
id: 'period-1',
period_start: '2024-01-01',
period_end: '2024-12-31',
user_id: 'user-1',
},
},
// company_settings
{
data: {
company_name: 'Test AB',
org_number: '5566778899',
moms_period: 'quarterly',
},
},
// document_attachments — one document
{
data: [
{
id: 'doc-1',
file_name: 'receipt.pdf',
storage_path: 'documents/user-1/receipt.pdf',
journal_entry_id: 'entry-1',
},
],
},
// journal_entries in period
{
data: [{ id: 'entry-1' }],
},
])
// Mock storage download to fail
supabase.storage.from = vi.fn().mockReturnValue({
download: vi.fn().mockResolvedValue({
data: null,
error: { message: 'File not found' },
}),
})
const buffer = await generateFullArchive(supabase as any, 'user-1', {
period_id: 'period-1',
})
const zip = await JSZip.loadAsync(buffer)
const manifestFile = zip.file('dokument/manifest.json')
expect(manifestFile).not.toBeNull()
const manifest = JSON.parse(await manifestFile!.async('text'))
expect(manifest).toHaveLength(1)
expect(manifest[0].status).toBe('error')
expect(manifest[0].error).toBe('File not found')
})
it('skips documents when include_documents is false', async () => {
const mock = createQueuedMockSupabase()
supabase = mock.supabase
enqueueMany = mock.enqueueMany
enqueueMany([
// fiscal_periods
{
data: {
id: 'period-1',
period_start: '2024-01-01',
period_end: '2024-12-31',
user_id: 'user-1',
},
},
// company_settings
{
data: {
company_name: 'Test AB',
org_number: '5566778899',
moms_period: 'quarterly',
},
},
])
const buffer = await generateFullArchive(supabase as any, 'user-1', {
period_id: 'period-1',
include_documents: false,
})
const zip = await JSZip.loadAsync(buffer)
// Should not have dokument folder
expect(zip.file('dokument/manifest.json')).toBeNull()
// Should still have other files
expect(zip.file('bokforing.se')).not.toBeNull()
expect(zip.file('revision/behandlingshistorik.json')).not.toBeNull()
})
it('throws when fiscal period not found', async () => {
const mock = createQueuedMockSupabase()
supabase = mock.supabase
enqueueMany = mock.enqueueMany
enqueueMany([{ data: null }])
await expect(
generateFullArchive(supabase as any, 'user-1', { period_id: 'nonexistent' })
).rejects.toThrow('Fiscal period not found')
})
})