feat(library): book author-hint resolve + ambiguous candidate logging
This commit is contained in:
parent
548e4c8ce0
commit
49d7779bc1
8 changed files with 161 additions and 7 deletions
|
|
@ -325,6 +325,19 @@ describe('bookSpec.resolve', () => {
|
|||
const result = await bookSpec.resolve(ctxFor({ title: '1984' }, ''), deps);
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
test('ambiguous -> logs top candidates with olid + title', async () => {
|
||||
const deps = makeDeps({
|
||||
http: async () => ({
|
||||
docs: [
|
||||
{ key: '/works/OL1W', title: 'Foo' },
|
||||
{ key: '/works/OL2W', title: 'Bar' },
|
||||
],
|
||||
}),
|
||||
});
|
||||
const result = await bookSpec.resolve(ctxFor({ title: '1984' }, ''), deps);
|
||||
expect(result).toBeNull();
|
||||
expect(deps.logCalls.some(m => m.includes('ambiguous') && m.includes('olid=OL1W') && m.includes('Foo') && m.includes('olid=OL2W') && m.includes('Bar'))).toBe(true);
|
||||
});
|
||||
test('no results -> null', async () => {
|
||||
const deps = makeDeps({ http: async () => ({ docs: [] }) });
|
||||
const result = await bookSpec.resolve(ctxFor({ title: '1984' }, ''), deps);
|
||||
|
|
@ -341,3 +354,47 @@ describe('bookSpec.resolve', () => {
|
|||
expect(deps.logCalls.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('bookSpec.resolve — author hint (stock `author` / canonical `authors`)', () => {
|
||||
test('stock `author` field present -> query is "title author", exact-title match still resolves', async () => {
|
||||
let capturedUrl = '';
|
||||
const deps = makeDeps({
|
||||
http: async (url: string) => {
|
||||
capturedUrl = url;
|
||||
return olFixture;
|
||||
},
|
||||
});
|
||||
const result = await bookSpec.resolve(ctxFor({ title: '1984', author: 'George Orwell' }, ''), deps);
|
||||
const q = new URL(capturedUrl).searchParams.get('q');
|
||||
expect(q).toBe('1984 George Orwell');
|
||||
expect(result).toEqual({ olid: 'OL1168083W' });
|
||||
});
|
||||
|
||||
test('canonical `authors` bracketed list -> first author used in query', async () => {
|
||||
let capturedUrl = '';
|
||||
const deps = makeDeps({
|
||||
http: async (url: string) => {
|
||||
capturedUrl = url;
|
||||
return olFixture;
|
||||
},
|
||||
});
|
||||
const result = await bookSpec.resolve(ctxFor({ title: '1984', authors: '[George Orwell, Someone Else]' }, ''), deps);
|
||||
const q = new URL(capturedUrl).searchParams.get('q');
|
||||
expect(q).toBe('1984 George Orwell');
|
||||
expect(result).toEqual({ olid: 'OL1168083W' });
|
||||
});
|
||||
|
||||
test('no author anywhere in frontmatter -> query is title only (unchanged behavior)', async () => {
|
||||
let capturedUrl = '';
|
||||
const deps = makeDeps({
|
||||
http: async (url: string) => {
|
||||
capturedUrl = url;
|
||||
return olFixture;
|
||||
},
|
||||
});
|
||||
const result = await bookSpec.resolve(ctxFor({ title: '1984' }, ''), deps);
|
||||
const q = new URL(capturedUrl).searchParams.get('q');
|
||||
expect(q).toBe('1984');
|
||||
expect(result).toEqual({ olid: 'OL1168083W' });
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -290,6 +290,20 @@ describe('comicSpec.resolve', () => {
|
|||
const result = await comicSpec.resolve(ctxFor({ title: 'Absolute Batman' }), deps);
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
test('ambiguous -> logs top candidates with id + name', async () => {
|
||||
const deps = makeDeps({
|
||||
http: async () => ({
|
||||
results: [
|
||||
{ id: 1, name: 'Batman' },
|
||||
{ id: 2, name: 'Batman Beyond' },
|
||||
],
|
||||
}),
|
||||
getKey: () => 'cvkey',
|
||||
});
|
||||
const result = await comicSpec.resolve(ctxFor({ title: 'Absolute Batman' }), deps);
|
||||
expect(result).toBeNull();
|
||||
expect(deps.logCalls.some(m => m.includes('ambiguous') && m.includes('id=1') && m.includes('Batman') && m.includes('id=2') && m.includes('Batman Beyond'))).toBe(true);
|
||||
});
|
||||
|
||||
test('no results -> null', async () => {
|
||||
const deps = makeDeps({ http: async () => ({ results: [] }), getKey: () => 'cvkey' });
|
||||
|
|
|
|||
|
|
@ -329,6 +329,19 @@ describe('gameSpec.resolve', () => {
|
|||
expect(result).toBeNull();
|
||||
expect(deps.logCalls.some(m => m.includes('RAWG'))).toBe(true);
|
||||
});
|
||||
test('steam storesearch ambiguous -> logs top candidates with appid + name', async () => {
|
||||
const deps = makeDeps({
|
||||
http: async () => ({
|
||||
items: [
|
||||
{ id: 1, name: 'Foo' },
|
||||
{ id: 2, name: 'Bar' },
|
||||
],
|
||||
}),
|
||||
});
|
||||
const result = await gameSpec.resolve(ctxFor({ title: '7 Billion Humans' }), deps);
|
||||
expect(result).toBeNull();
|
||||
expect(deps.logCalls.some(m => m.includes('ambiguous') && m.includes('appid=1') && m.includes('Foo') && m.includes('appid=2') && m.includes('Bar'))).toBe(true);
|
||||
});
|
||||
|
||||
test('steam storesearch throws -> falls through to RAWG', async () => {
|
||||
const deps = makeDeps({
|
||||
|
|
|
|||
|
|
@ -587,6 +587,19 @@ describe('mangaSpec.resolve', () => {
|
|||
const result = await mangaSpec.resolve(ctxFor({ title: 'Chainsaw Man' }, ''), deps);
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
test('ambiguous -> logs top candidates with mal_id + title', async () => {
|
||||
const deps = makeDeps({
|
||||
http: async () => ({
|
||||
data: [
|
||||
{ mal_id: 1, title: 'Foo' },
|
||||
{ mal_id: 2, title: 'Bar' },
|
||||
],
|
||||
}),
|
||||
});
|
||||
const result = await mangaSpec.resolve(ctxFor({ title: 'Chainsaw Man' }, ''), deps);
|
||||
expect(result).toBeNull();
|
||||
expect(deps.logCalls.some(m => m.includes('ambiguous') && m.includes('mal_id=1') && m.includes('Foo') && m.includes('mal_id=2') && m.includes('Bar'))).toBe(true);
|
||||
});
|
||||
test('no results -> null', async () => {
|
||||
const deps = makeDeps({ http: async () => ({ data: [] }) });
|
||||
const result = await mangaSpec.resolve(ctxFor({ title: 'Chainsaw Man' }, ''), deps);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue