UNPKG

@gv-sh/specgen-server

Version:

SpecGen Server - API for Speculative Fiction Generator

364 lines (286 loc) 12.9 kB
/* global describe, test, expect, beforeEach, beforeAll, jest */ const { request, cleanDatabase, initDatabase } = require('./setup'); const fs = require('fs').promises; const path = require('path'); const databaseService = require('../services/databaseService'); const sqliteService = require('../services/sqliteService'); // Correct way to mock the entire module jest.mock('../services/databaseService', () => ({ getData: jest.fn(), saveData: jest.fn() })); // Mock the SQLite service jest.mock('../services/sqliteService', () => ({ getAllGenerationsForBackup: jest.fn(), restoreGenerationsFromBackup: jest.fn(), resetGeneratedContent: jest.fn() })); describe('Database API Tests', () => { // Sample test data const sampleData = { categories: [ { id: 1, name: 'Test Category' } ], parameters: [ { id: 1, name: 'Test Parameter' } ] }; // Sample generations data const sampleGenerationsData = { generations: [ { id: 'gen-1', title: 'Test Generation', type: 'fiction', content: 'This is test content.', parameterValues: { key: 'value' }, metadata: { model: 'test-model' }, createdAt: '2024-01-01T00:00:00.000Z', updatedAt: '2024-01-01T00:00:00.000Z' } ] }; // Setup before all tests beforeAll(async () => { await initDatabase(); await cleanDatabase(); }); // Reset mocks before each test beforeEach(() => { // Clear all mocks to ensure clean state jest.clearAllMocks(); }); test('GET /api/database/download - Should successfully download database data', async () => { // Properly mock the getData method to return sample data databaseService.getData.mockResolvedValue(sampleData); const response = await request.get('/api/database/download'); expect(response.status).toBe(200); expect(response.body).toEqual(sampleData); // Ensure getData was called expect(databaseService.getData).toHaveBeenCalledTimes(1); }); test('GET /api/database/download - Should handle errors when data retrieval fails', async () => { // Properly mock getData to throw an error databaseService.getData.mockRejectedValue(new Error('Retrieval failed')); const response = await request.get('/api/database/download'); expect(response.status).toBe(500); expect(response.body).toHaveProperty('success', false); expect(response.body).toHaveProperty('error', 'Failed to download database'); }); test('POST /api/database/restore - Should successfully restore database from a valid file', async () => { // Prepare a temporary file with test data const tempFilePath = path.join(path.resolve('.'), 'tests/test-restore.json'); await fs.writeFile(tempFilePath, JSON.stringify(sampleData)); // Mock saveData method to resolve successfully databaseService.saveData.mockResolvedValue(); const response = await request .post('/api/database/restore') .attach('file', tempFilePath); // Clean up temporary file await fs.unlink(tempFilePath); expect(response.status).toBe(200); expect(response.body).toEqual({ success: true, message: 'Database restored successfully' }); // Ensure saveData was called with correct data expect(databaseService.saveData).toHaveBeenCalledWith(sampleData); }); test('POST /api/database/restore - Should reject restore with no file', async () => { const response = await request.post('/api/database/restore'); expect(response.status).toBe(400); expect(response.body).toEqual({ success: false, error: 'No file uploaded' }); }); test('POST /api/database/restore - Should reject restore with invalid JSON', async () => { // Prepare a temporary file with invalid JSON const tempFilePath = path.join(path.resolve('.'), 'tests/invalid-test.json'); await fs.writeFile(tempFilePath, 'Invalid JSON'); const response = await request .post('/api/database/restore') .attach('file', tempFilePath); // Clean up temporary file await fs.unlink(tempFilePath); expect(response.status).toBe(400); expect(response.body).toEqual({ success: false, error: 'Invalid JSON file' }); }); test('POST /api/database/restore - Should reject restore with invalid database structure', async () => { // Prepare a temporary file with invalid database structure // Prepare the file path const tempFilePath = path.join(path.resolve('.'), 'tests/invalid-structure.json'); await fs.writeFile(tempFilePath, JSON.stringify({ invalid: 'structure' })); const response = await request .post('/api/database/restore') .attach('file', tempFilePath); // Clean up temporary file await fs.unlink(tempFilePath); expect(response.status).toBe(400); expect(response.body).toEqual({ success: false, error: 'Invalid database structure. File must contain categories and parameters arrays.' }); }); test('POST /api/database/reset - Should successfully reset the database', async () => { // Mock saveData method to resolve successfully databaseService.saveData.mockResolvedValue(); const response = await request.post('/api/database/reset'); expect(response.status).toBe(200); expect(response.body).toEqual({ success: true, message: 'Database reset successfully' }); // Ensure saveData was called with empty database expect(databaseService.saveData).toHaveBeenCalledWith({ categories: [], parameters: [] }); }); test('POST /api/database/reset - Should handle errors during database reset', async () => { // Mock saveData to reject with an error databaseService.saveData.mockRejectedValue(new Error('Reset failed')); const response = await request.post('/api/database/reset'); expect(response.status).toBe(500); expect(response.body).toHaveProperty('success', false); expect(response.body).toHaveProperty('error', 'Failed to reset database'); }); /* Tests for Generations Database Functionality */ test('GET /api/database/generations/download - Should successfully download generations data', async () => { // Mock the getAllGenerationsForBackup method to return sample generations const sampleGenerations = sampleGenerationsData.generations; sqliteService.getAllGenerationsForBackup.mockResolvedValue(sampleGenerations); const response = await request.get('/api/database/generations/download'); expect(response.status).toBe(200); expect(response.body).toEqual({ generations: sampleGenerations }); // Ensure the service method was called expect(sqliteService.getAllGenerationsForBackup).toHaveBeenCalledTimes(1); }); test('GET /api/database/generations/download - Should handle empty generations', async () => { // Mock the service to return empty array sqliteService.getAllGenerationsForBackup.mockResolvedValue([]); const response = await request.get('/api/database/generations/download'); expect(response.status).toBe(404); expect(response.body).toEqual({ success: false, error: 'No generations data found' }); }); test('GET /api/database/generations/download - Should handle errors during retrieval', async () => { // Mock service to throw an error sqliteService.getAllGenerationsForBackup.mockRejectedValue(new Error('Retrieval failed')); const response = await request.get('/api/database/generations/download'); expect(response.status).toBe(500); expect(response.body).toHaveProperty('success', false); expect(response.body).toHaveProperty('error', 'Failed to download generations database'); }); test('POST /api/database/generations/restore - Should successfully restore generations from a valid file', async () => { // Prepare a temporary file with test data const tempFilePath = path.join(path.resolve('.'), 'tests/test-generations-restore.json'); await fs.writeFile(tempFilePath, JSON.stringify(sampleGenerationsData)); // Mock restoreGenerationsFromBackup method to resolve successfully sqliteService.restoreGenerationsFromBackup.mockResolvedValue(); const response = await request .post('/api/database/generations/restore') .attach('file', tempFilePath); // Clean up temporary file await fs.unlink(tempFilePath); expect(response.status).toBe(200); expect(response.body).toEqual({ success: true, message: 'Generations database restored successfully' }); // Ensure the service method was called with correct data expect(sqliteService.restoreGenerationsFromBackup).toHaveBeenCalledWith(sampleGenerationsData.generations); }); test('POST /api/database/generations/restore - Should reject restore with no file', async () => { const response = await request.post('/api/database/generations/restore'); expect(response.status).toBe(400); expect(response.body).toEqual({ success: false, error: 'No file uploaded' }); }); test('POST /api/database/generations/restore - Should reject restore with invalid JSON', async () => { // Prepare a temporary file with invalid JSON const tempFilePath = path.join(path.resolve('.'), 'tests/invalid-generations.json'); await fs.writeFile(tempFilePath, 'Invalid JSON'); const response = await request .post('/api/database/generations/restore') .attach('file', tempFilePath); // Clean up temporary file await fs.unlink(tempFilePath); expect(response.status).toBe(400); expect(response.body).toEqual({ success: false, error: 'Invalid JSON file' }); }); test('POST /api/database/generations/restore - Should reject restore with invalid database structure', async () => { // Prepare a temporary file with invalid database structure const tempFilePath = path.join(path.resolve('.'), 'tests/invalid-generations-structure.json'); await fs.writeFile(tempFilePath, JSON.stringify({ invalid: 'structure' })); const response = await request .post('/api/database/generations/restore') .attach('file', tempFilePath); // Clean up temporary file await fs.unlink(tempFilePath); expect(response.status).toBe(400); expect(response.body).toEqual({ success: false, error: 'Invalid database structure. File must contain a generations array.' }); }); test('POST /api/database/generations/reset - Should successfully reset the generations database', async () => { // Mock resetGeneratedContent method to resolve successfully sqliteService.resetGeneratedContent.mockResolvedValue(); const response = await request.post('/api/database/generations/reset'); expect(response.status).toBe(200); expect(response.body).toEqual({ success: true, message: 'Generations database reset successfully' }); // Ensure the service method was called expect(sqliteService.resetGeneratedContent).toHaveBeenCalledTimes(1); }); test('POST /api/database/generations/reset - Should handle errors during reset', async () => { // Mock resetGeneratedContent to reject with an error sqliteService.resetGeneratedContent.mockRejectedValue(new Error('Reset failed')); const response = await request.post('/api/database/generations/reset'); expect(response.status).toBe(500); expect(response.body).toHaveProperty('success', false); expect(response.body).toHaveProperty('error', 'Failed to reset generations database'); }); test('POST /api/database/reset-all - Should successfully reset all databases', async () => { // Mock both service methods to resolve successfully databaseService.saveData.mockResolvedValue(); sqliteService.resetGeneratedContent.mockResolvedValue(); const response = await request.post('/api/database/reset-all'); expect(response.status).toBe(200); expect(response.body).toEqual({ success: true, message: 'All databases reset successfully' }); // Ensure both service methods were called expect(databaseService.saveData).toHaveBeenCalledWith({ categories: [], parameters: [] }); expect(sqliteService.resetGeneratedContent).toHaveBeenCalledTimes(1); }); test('POST /api/database/reset-all - Should handle errors during reset', async () => { // Mock one or both services to reject with an error databaseService.saveData.mockRejectedValue(new Error('Reset all failed')); const response = await request.post('/api/database/reset-all'); expect(response.status).toBe(500); expect(response.body).toHaveProperty('success', false); expect(response.body).toHaveProperty('error', 'Failed to reset all databases'); }); });