mirror of
https://github.com/kikootwo/ReadMeABook.git
synced 2026-06-03 21:00:09 +00:00
94dbaf073b
Introduced a Vitest-based backend unit testing framework with supporting scripts, helpers, and GitHub Actions integration. Refactored the admin settings page to a modular architecture, splitting monolithic logic into feature-specific tabs and hooks for improved maintainability and testability. Updated documentation to reflect the new testing setup and settings architecture, and added new dependencies for testing utilities.
151 lines
4.2 KiB
TypeScript
151 lines
4.2 KiB
TypeScript
/**
|
|
* Component: Audiobookshelf Library Service Tests
|
|
* Documentation: documentation/features/audiobookshelf-integration.md
|
|
*/
|
|
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { AudiobookshelfLibraryService } from '@/lib/services/library/AudiobookshelfLibraryService';
|
|
|
|
const apiMock = vi.hoisted(() => ({
|
|
getABSServerInfo: vi.fn(),
|
|
getABSLibraries: vi.fn(),
|
|
getABSLibraryItems: vi.fn(),
|
|
getABSRecentItems: vi.fn(),
|
|
getABSItem: vi.fn(),
|
|
searchABSItems: vi.fn(),
|
|
triggerABSScan: vi.fn(),
|
|
}));
|
|
|
|
vi.mock('@/lib/services/audiobookshelf/api', () => apiMock);
|
|
|
|
describe('AudiobookshelfLibraryService', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it('tests connection and returns server info', async () => {
|
|
apiMock.getABSServerInfo.mockResolvedValue({ name: 'ABS', version: '2.0.0' });
|
|
|
|
const service = new AudiobookshelfLibraryService();
|
|
const result = await service.testConnection();
|
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.serverInfo).toEqual({
|
|
name: 'ABS',
|
|
version: '2.0.0',
|
|
identifier: 'ABS',
|
|
});
|
|
});
|
|
|
|
it('returns errors when server info fails', async () => {
|
|
apiMock.getABSServerInfo.mockRejectedValue(new Error('No connection'));
|
|
|
|
const service = new AudiobookshelfLibraryService();
|
|
const result = await service.testConnection();
|
|
|
|
expect(result.success).toBe(false);
|
|
expect(result.error).toBe('No connection');
|
|
});
|
|
|
|
it('filters audiobook libraries only', async () => {
|
|
apiMock.getABSLibraries.mockResolvedValue([
|
|
{ id: 'lib-1', name: 'Books', mediaType: 'book', stats: { totalItems: 10 } },
|
|
{ id: 'lib-2', name: 'Podcasts', mediaType: 'podcast', stats: { totalItems: 5 } },
|
|
]);
|
|
|
|
const service = new AudiobookshelfLibraryService();
|
|
const libs = await service.getLibraries();
|
|
|
|
expect(libs).toEqual([
|
|
{ id: 'lib-1', name: 'Books', type: 'book', itemCount: 10 },
|
|
]);
|
|
});
|
|
|
|
it('maps library items to generic fields', async () => {
|
|
apiMock.getABSLibraryItems.mockResolvedValue([
|
|
{
|
|
id: 'item-1',
|
|
addedAt: 1700000000000,
|
|
updatedAt: 1700000100000,
|
|
media: {
|
|
duration: 3600,
|
|
coverPath: '/covers/1.jpg',
|
|
metadata: {
|
|
title: 'Title',
|
|
authorName: 'Author',
|
|
narratorName: 'Narrator',
|
|
description: 'Desc',
|
|
asin: 'ASIN1',
|
|
isbn: 'ISBN1',
|
|
publishedYear: '2020',
|
|
},
|
|
},
|
|
},
|
|
]);
|
|
|
|
const service = new AudiobookshelfLibraryService();
|
|
const items = await service.getLibraryItems('lib-1');
|
|
|
|
expect(items[0]).toEqual({
|
|
id: 'item-1',
|
|
externalId: 'item-1',
|
|
title: 'Title',
|
|
author: 'Author',
|
|
narrator: 'Narrator',
|
|
description: 'Desc',
|
|
coverUrl: '/api/items/item-1/cover',
|
|
duration: 3600,
|
|
asin: 'ASIN1',
|
|
isbn: 'ISBN1',
|
|
year: 2020,
|
|
addedAt: new Date(1700000000000),
|
|
updatedAt: new Date(1700000100000),
|
|
});
|
|
});
|
|
|
|
it('returns null when item fetch fails', async () => {
|
|
apiMock.getABSItem.mockRejectedValue(new Error('missing'));
|
|
|
|
const service = new AudiobookshelfLibraryService();
|
|
const result = await service.getItem('item-1');
|
|
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('searches items and maps results', async () => {
|
|
apiMock.searchABSItems.mockResolvedValue([
|
|
{
|
|
libraryItem: {
|
|
id: 'item-2',
|
|
addedAt: 1700000000000,
|
|
updatedAt: 1700000000000,
|
|
media: {
|
|
duration: 200,
|
|
metadata: {
|
|
title: 'Search Title',
|
|
authorName: 'Search Author',
|
|
narratorName: '',
|
|
description: '',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
]);
|
|
|
|
const service = new AudiobookshelfLibraryService();
|
|
const items = await service.searchItems('lib-1', 'Search');
|
|
|
|
expect(items[0].title).toBe('Search Title');
|
|
expect(items[0].author).toBe('Search Author');
|
|
});
|
|
|
|
it('triggers library scans', async () => {
|
|
apiMock.triggerABSScan.mockResolvedValue(undefined);
|
|
|
|
const service = new AudiobookshelfLibraryService();
|
|
await service.triggerLibraryScan('lib-1');
|
|
|
|
expect(apiMock.triggerABSScan).toHaveBeenCalledWith('lib-1');
|
|
});
|
|
});
|