Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions __tests__/db/couchdb-note-repository.error.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -516,4 +516,81 @@ describe('CouchDbNoteRepository Error Scenarios', () => {
expect(result).toEqual([]);
});
});

describe('Additional Coverage', () => {
test('init should log when updating existing design document with missing views', async () => {
const existingDoc = {
_id: '_design/notes',
_rev: '1-abc',
views: {
all: { map: 'function(doc) { emit(doc._id, null); }' }
}
};

const mockDb = {
get: jest.fn().mockResolvedValue(existingDoc),
insert: jest.fn().mockResolvedValue({ ok: true })
};
const mockClient = {
db: {
list: jest.fn().mockResolvedValue(['test_notes_error_db'])
},
use: jest.fn().mockReturnValue(mockDb)
};

repository.client = mockClient;

const consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
await repository.init();

expect(consoleSpy).toHaveBeenCalledWith('Updated design document with all views');
consoleSpy.mockRestore();
});

test('moveToRecycleBin should return false when insert throws 404', async () => {
const mockDb = {
get: jest.fn().mockResolvedValue({ _id: 'note1', _rev: '1-rev' }),
insert: jest.fn().mockRejectedValue({ statusCode: 404 })
};
repository.db = mockDb;

const result = await repository.moveToRecycleBin('note1');
expect(result).toBe(false);
});

test('restore should return false when insert throws 404', async () => {
const mockDb = {
get: jest.fn().mockResolvedValue({ _id: 'note1', _rev: '1-rev' }),
insert: jest.fn().mockRejectedValue({ statusCode: 404 })
};
repository.db = mockDb;

const result = await repository.restore('note1');
expect(result).toBe(false);
});

test('permanentDelete should return false when destroy throws 404', async () => {
const mockDb = {
get: jest.fn().mockResolvedValue({ _id: 'note1', _rev: '1-rev' }),
destroy: jest.fn().mockRejectedValue({ statusCode: 404 })
};
repository.db = mockDb;

const result = await repository.permanentDelete('note1');
expect(result).toBe(false);
});

test('restoreAll should handle errors', async () => {
repository.findDeleted = jest.fn().mockRejectedValue(new Error('findDeleted failed'));
await expect(repository.restoreAll()).rejects.toThrow('findDeleted failed');
});

test('countDeleted should handle errors', async () => {
const mockDb = {
view: jest.fn().mockRejectedValue(new Error('view failed'))
};
repository.db = mockDb;
await expect(repository.countDeleted()).rejects.toThrow('view failed');
});
});
});
46 changes: 46 additions & 0 deletions __tests__/db/extra-coverage.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { jest } from '@jest/globals';
import { NoteRepository } from '../../src/db/note-repository.js';
import * as apiServer from '../../src/notes-api-server.js';

describe('Extra Coverage Tests', () => {
describe('NoteRepository Base Class', () => {
const repo = new NoteRepository();
const methods = [
'findAll', 'findDeleted', 'findAllIncludingDeleted', 'findById',
'create', 'update', 'moveToRecycleBin', 'restore', 'permanentDelete',
'emptyRecycleBin', 'restoreAll', 'countDeleted'
];

test.each(methods)('%s should throw Method not implemented', async (method) => {
await expect(repo[method]()).rejects.toThrow('Method not implemented');
});
});

describe('API Server Backward Compatibility Exports', () => {
test('should export app', () => {
expect(apiServer.app).toBeDefined();
});

test('should export createNoteRepository', () => {
expect(typeof apiServer.createNoteRepository).toBe('function');
});

test('should export gracefulShutdown', () => {
expect(typeof apiServer.gracefulShutdown).toBe('function');
});

test('should export initializeApp', async () => {
expect(typeof apiServer.initializeApp).toBe('function');
// Mock repository to avoid real DB connection
const mockRepo = {
init: jest.fn().mockResolvedValue()
};
const result = await apiServer.initializeApp(mockRepo);
expect(result.repository).toBe(mockRepo);
});

test('should export startServer', () => {
expect(typeof apiServer.startServer).toBe('function');
});
});
});
33 changes: 32 additions & 1 deletion __tests__/db/mongodb-note-repository.error.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -417,5 +417,36 @@ describe('MongoDbNoteRepository Error Handling Tests', () => {
await expect(repository.countDeleted()).rejects.toThrow('No connection to database');
expect(console.error).toHaveBeenCalledWith('Failed to count deleted notes:', expect.any(Error));
});

test('should handle restoreAll database errors', async () => {
repository.NoteModel.updateMany = jest.fn().mockRejectedValue(new Error('Update failed'));
await expect(repository.restoreAll()).rejects.toThrow('Update failed');
expect(console.error).toHaveBeenCalledWith('Failed to restore all notes from recycle bin:', expect.any(Error));
});

test('should handle emptyRecycleBin database errors', async () => {
repository.NoteModel.deleteMany = jest.fn().mockRejectedValue(new Error('Delete failed'));
await expect(repository.emptyRecycleBin()).rejects.toThrow('Delete failed');
expect(console.error).toHaveBeenCalledWith('Failed to empty recycle bin:', expect.any(Error));
});

test('init should not re-create model if it exists', async () => {
mongoose.connect = jest.fn().mockResolvedValue();
repository.NoteModel = { some: 'model' };
await repository.init();
expect(repository.NoteModel).toEqual({ some: 'model' });
});

test('restoreAll should return 0 if no notes modified', async () => {
repository.NoteModel.updateMany = jest.fn().mockResolvedValue({ modifiedCount: 0 });
const result = await repository.restoreAll();
expect(result).toBe(0);
});

test('emptyRecycleBin should return 0 if no notes deleted', async () => {
repository.NoteModel.deleteMany = jest.fn().mockResolvedValue({ deletedCount: 0 });
const result = await repository.emptyRecycleBin();
expect(result).toBe(0);
});
});
});
});