import { describe, it, expect, vi, beforeEach } from 'vitest'; vi.mock('../../prisma.js', () => ({ prisma: { app: { findMany: vi.fn() }, board: { findMany: vi.fn() }, group: { findMany: vi.fn() }, systemSettings: { upsert: vi.fn() } } })); import { prisma } from '../../prisma.js'; import { exportAllData } from '../exportService.js'; const mockApp = prisma.app as unknown as { findMany: ReturnType }; const mockBoard = prisma.board as unknown as { findMany: ReturnType }; const mockGroup = prisma.group as unknown as { findMany: ReturnType }; const mockSettings = prisma.systemSettings as unknown as { upsert: ReturnType; }; describe('exportService', () => { beforeEach(() => { vi.clearAllMocks(); }); describe('exportAllData', () => { it('returns export data with version and timestamp', async () => { mockApp.findMany.mockResolvedValue([]); mockBoard.findMany.mockResolvedValue([]); mockGroup.findMany.mockResolvedValue([]); mockSettings.upsert.mockResolvedValue({ authMode: 'local', registrationEnabled: true, defaultTheme: 'dark', defaultPrimaryColor: '#6366f1', healthcheckDefaults: '{}' }); const result = await exportAllData(); expect(result.version).toBe('1.0'); expect(result.exportedAt).toBeTruthy(); expect(result.apps).toEqual([]); expect(result.boards).toEqual([]); expect(result.groups).toEqual([]); expect(result.settings).toEqual({ authMode: 'local', registrationEnabled: true, defaultTheme: 'dark', defaultPrimaryColor: '#6366f1', healthcheckDefaults: '{}' }); }); it('maps apps to export format stripping internal fields', async () => { mockApp.findMany.mockResolvedValue([ { id: 'a1', name: 'Gitea', url: 'https://git.local', icon: 'gitea', iconType: 'simple', description: 'Self-hosted Git', category: 'dev', tags: 'git,code', healthcheckEnabled: true, healthcheckInterval: 300, healthcheckMethod: 'GET', healthcheckExpectedStatus: 200, healthcheckTimeout: 5000, createdById: 'u1', createdAt: new Date(), updatedAt: new Date() } ]); mockBoard.findMany.mockResolvedValue([]); mockGroup.findMany.mockResolvedValue([]); mockSettings.upsert.mockResolvedValue({ authMode: 'local', registrationEnabled: true, defaultTheme: 'dark', defaultPrimaryColor: '#6366f1', healthcheckDefaults: '{}' }); const result = await exportAllData(); expect(result.apps).toHaveLength(1); expect(result.apps[0]).toEqual({ name: 'Gitea', url: 'https://git.local', icon: 'gitea', iconType: 'simple', description: 'Self-hosted Git', category: 'dev', tags: 'git,code', healthcheckEnabled: true, healthcheckInterval: 300, healthcheckMethod: 'GET', healthcheckExpectedStatus: 200, healthcheckTimeout: 5000 }); // Internal fields should not be present expect((result.apps[0] as unknown as Record).id).toBeUndefined(); expect((result.apps[0] as unknown as Record).createdById).toBeUndefined(); }); it('maps boards with nested sections and widgets', async () => { mockApp.findMany.mockResolvedValue([]); mockBoard.findMany.mockResolvedValue([ { name: 'Dashboard', icon: null, description: 'Main board', isDefault: true, isGuestAccessible: false, backgroundConfig: null, sections: [ { title: 'Apps', icon: null, order: 0, isExpandedByDefault: true, widgets: [ { type: 'app', order: 0, config: '{}', app: { name: 'Gitea' } } ] } ] } ]); mockGroup.findMany.mockResolvedValue([]); mockSettings.upsert.mockResolvedValue({ authMode: 'local', registrationEnabled: true, defaultTheme: 'dark', defaultPrimaryColor: '#6366f1', healthcheckDefaults: '{}' }); const result = await exportAllData(); expect(result.boards).toHaveLength(1); expect(result.boards[0].name).toBe('Dashboard'); expect(result.boards[0].sections).toHaveLength(1); expect(result.boards[0].sections[0].widgets).toHaveLength(1); expect(result.boards[0].sections[0].widgets[0].appName).toBe('Gitea'); }); it('maps groups stripping internal fields', async () => { mockApp.findMany.mockResolvedValue([]); mockBoard.findMany.mockResolvedValue([]); mockGroup.findMany.mockResolvedValue([ { id: 'g1', name: 'Admins', description: 'Admin users', isDefault: false, createdAt: new Date(), updatedAt: new Date() } ]); mockSettings.upsert.mockResolvedValue({ authMode: 'local', registrationEnabled: true, defaultTheme: 'dark', defaultPrimaryColor: '#6366f1', healthcheckDefaults: '{}' }); const result = await exportAllData(); expect(result.groups).toHaveLength(1); expect(result.groups[0]).toEqual({ name: 'Admins', description: 'Admin users', isDefault: false }); }); }); });