fix(library): surface comic vine api errors + sync summary transparency

This commit is contained in:
afiqzudinhadi 2026-08-05 13:13:49 +08:00
parent f146de1b76
commit d76ed2631b
5 changed files with 98 additions and 6 deletions

View file

@ -1,4 +1,6 @@
{
"error": "OK",
"status_code": 1,
"results": {
"id": 195824,
"name": "Absolute Batman",

View file

@ -329,6 +329,16 @@ describe('comicSpec.resolve', () => {
const result = await comicSpec.resolve(ctx, deps);
expect(result).toBeNull();
});
test('Comic Vine error envelope (invalid key) -> null, logged', async () => {
const deps = makeDeps({
http: async () => ({ error: 'Invalid API Key', status_code: 100, results: [] }),
getKey: () => 'bad-key',
});
const result = await comicSpec.resolve(ctxFor({ title: 'Absolute Batman' }), deps);
expect(result).toBeNull();
expect(deps.logCalls.some(m => m.includes('Invalid API Key'))).toBe(true);
});
});
describe('comicSpec.sync — no id / no key', () => {
@ -385,6 +395,17 @@ describe('comicSpec.sync — comicvine enrich', () => {
expect(deps.notifyCalls).toEqual([]);
});
test('Comic Vine error envelope (invalid key) -> null, notify + log', async () => {
const deps = makeDeps({
http: async () => ({ error: 'Invalid API Key', status_code: 100, results: [] }),
getKey: () => 'bad-key',
});
const result = await comicSpec.sync(ctxFor({ comicvine_id: '195824' }), deps);
expect(result).toBeNull();
expect(deps.notifyCalls.some(m => m.includes('Invalid API Key'))).toBe(true);
expect(deps.logCalls.some(m => m.includes('Invalid API Key'))).toBe(true);
});
test('fetches from GET /volume/4050-{id}/ with api_key + format=json', async () => {
let calledUrl = '';
const deps = makeDeps({

View file

@ -1,4 +1,5 @@
import { describe, expect, test } from 'bun:test';
import type { MediaTypeSpec } from 'packages/obsidian/src/library/types';
import { bookSpec } from 'packages/obsidian/src/library/book';
import { gameSpec } from 'packages/obsidian/src/library/game';
import { LibraryController } from 'packages/obsidian/src/library/LibraryController';
@ -421,3 +422,42 @@ describe('dry-run notify suppression (minor)', () => {
expect(logs.some(m => m.includes('«Test Manga» ch. 5 out'))).toBe(true);
});
});
describe('sync summary transparency', () => {
test('scanned + no-data counts surface in summary notice, not hidden behind a silent-looking 0/0', async () => {
const c = new LibraryController(fakePlugin());
const notices: string[] = [];
(c as any).notify = (msg: string) => notices.push(msg);
(c as any).makeDeps = () => ({
listNotes: async () => [{ path: 'Mangas/Test.md' }],
readNote: async () => 'content',
writeNote: async () => {},
sleep: async () => {},
log: () => {},
specDeps: fakeSpecDeps(),
});
// simulates e.g. a Comic Vine error-envelope: fetch "succeeds" (no throw) but spec.sync
// has no usable data -> counted as skippedNoData rather than a written/errors change
const noDataSpec: MediaTypeSpec = {
typeName: 'manga',
itemType: 'manga_item',
folderSettingKey: 'libraryMangaFolder',
enabledSettingKey: 'libraryMangaEnabled',
throttleMs: 0,
hasId: () => true,
isActive: () => true,
resolve: async () => null,
sync: async () => null,
};
const report = await c.syncType(noDataSpec, false);
expect(report.scanned).toBe(1);
expect(report.skippedNoData).toBe(1);
expect(notices.length).toBe(1);
expect(notices[0]).toContain('1 scanned');
expect(notices[0]).toContain('0 ok');
expect(notices[0]).toContain('1 no-data (see console)');
});
});