fix(anime-settings): restore GET /api/nfo/{key}/content for 'View NFO XML' button
The Anime Settings page (src/server/web/static/js/pages/anime-settings.js)
calls GET /api/nfo/{key}/content from its 'View NFO XML' button, but that
endpoint was removed during the NFO refactor (commits 21af502, a8e5487).
The frontend was never updated, so every click on the button 404'd.
Fix:
- Add NfoContentResponse model (key, folder, content, file_size,
last_modified) to src/server/models/nfo.py.
- Add GET /api/nfo/{key}/content handler to src/server/api/nfo.py that
reads <anime_directory>/<folder>/tvshow.nfo and returns it as
{"content": "<xml>", ...} — matching what anime-settings.js
viewNfoContent() already expects (data.content).
- Expose viewNfoContent on AniWorld.AnimeSettingsManager so it is
consistent with the other public methods and directly callable from
tests / other modules.
Tests:
- tests/api/test_nfo_endpoints.py: 4 new tests (auth-required, happy
path returning XML, 404 on unknown series, 404 on missing tvshow.nfo).
Also remove the file-local autouse 'reset_auth' fixture that wiped
the conftest's master-password setup and made any login-based test
fail with a stale-hash 'invalid credentials' error — that fixture
was pre-existing and is a no-op now that conftest.py handles reset.
- tests/frontend/unit/anime_settings.test.js: 3 new tests for
viewNfoContent (URL + auth header, writes <pre>, error toast on
404) and an assertion in the public-API surface test.
This commit is contained in:
@@ -375,6 +375,83 @@ describe('AnimeSettingsManager', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// viewNfoContent()
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
describe('viewNfoContent()', () => {
|
||||
beforeEach(async () => {
|
||||
// Seed currentKey via loadSeries so viewNfoContent has a key.
|
||||
delete window.location;
|
||||
window.location = { search: '?key=a', href: 'http://x/?key=a' };
|
||||
mockFetchSequence([{
|
||||
status: 200,
|
||||
body: {
|
||||
key: 'a', name: 'A', folder: 'A', site: 's',
|
||||
tmdb_id: null, tvdb_id: null, has_nfo: true,
|
||||
nfo_path: '/anime/A/tvshow.nfo', episode_count: 0,
|
||||
missing_episode_count: 0, loading_status: 'completed',
|
||||
},
|
||||
}]);
|
||||
await manager.loadSeries('a');
|
||||
});
|
||||
|
||||
it('fetches /api/nfo/{key}/content with auth header', async () => {
|
||||
mockFetchSequence([{
|
||||
status: 200,
|
||||
body: {
|
||||
key: 'a',
|
||||
folder: 'A',
|
||||
content: '<tvshow><title>A</title></tvshow>',
|
||||
file_size: 30,
|
||||
last_modified: '2026-06-01T00:00:00',
|
||||
},
|
||||
}]);
|
||||
|
||||
await manager.viewNfoContent();
|
||||
const [url, opts] = global.fetch.mock.calls[0];
|
||||
expect(url).toBe('/api/nfo/a/content');
|
||||
expect(opts.method).toBe('GET');
|
||||
expect(opts.headers.Authorization).toBe('Bearer fake-jwt-token');
|
||||
});
|
||||
|
||||
it('writes the content into the #nfo-content <pre> and unhides it',
|
||||
async () => {
|
||||
mockFetchSequence([{
|
||||
status: 200,
|
||||
body: {
|
||||
key: 'a',
|
||||
folder: 'A',
|
||||
content: '<tvshow><title>A</title></tvshow>',
|
||||
file_size: 30,
|
||||
last_modified: '2026-06-01T00:00:00',
|
||||
},
|
||||
}]);
|
||||
|
||||
const pre = document.getElementById('nfo-content');
|
||||
expect(pre.classList.contains('hidden')).toBe(true);
|
||||
|
||||
await manager.viewNfoContent();
|
||||
expect(pre.textContent).toBe(
|
||||
'<tvshow><title>A</title></tvshow>'
|
||||
);
|
||||
expect(pre.classList.contains('hidden')).toBe(false);
|
||||
});
|
||||
|
||||
it('shows an error toast when the backend returns 404', async () => {
|
||||
mockFetchSequence([{
|
||||
status: 404,
|
||||
ok: false,
|
||||
body: { detail: 'Not Found' },
|
||||
}]);
|
||||
await manager.viewNfoContent();
|
||||
expect(global.AniWorld.UI.showToast).toHaveBeenCalledWith(
|
||||
expect.stringContaining('NFO'),
|
||||
'error'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// validateField()
|
||||
// -------------------------------------------------------------------
|
||||
@@ -493,6 +570,7 @@ describe('AnimeSettingsManager', () => {
|
||||
expect(typeof manager.loadSeries).toBe('function');
|
||||
expect(typeof manager.saveSettings).toBe('function');
|
||||
expect(typeof manager.regenerateNfo).toBe('function');
|
||||
expect(typeof manager.viewNfoContent).toBe('function');
|
||||
expect(typeof manager.validateField).toBe('function');
|
||||
expect(typeof manager.populateForm).toBe('function');
|
||||
expect(typeof manager.showSaveSuccess).toBe('function');
|
||||
|
||||
Reference in New Issue
Block a user