Files
Melo/test/navidrome_parse_test.dart
Hermes (Server)andClaude Opus 4.8 3d39e8b922 Fix: Server-Bibliothek lädt nicht + Tab '🌐 Server' abgeschnitten
Bug 2 (Laden schlägt fehl trotz 'ping ok'): Der Code ignorierte das Subsonic-
status-Feld. Navidrome liefert bei falschem Passwort HTTP 200 mit
status:"failed" — ping() meldete dadurch fälschlich Erfolg, getAlben/getArtists
behandelten die Fehlerantwort still als leer ("Erneut versuchen").
- parseSubsonic() wirft NavidromeException bei status:"failed" (mit Servermsg).
- ping() prüft jetzt den Body statt nur HTTP 200.
- getAlben/getArtists reichen den Fehler durch (rethrow) statt [] zu liefern.
- getAlben nutzt getAlbumList2 (ID3, wie getArtists) statt getAlbumList (Folder).
- Server-Tab zeigt die echte Fehlermeldung statt "Keine Alben geladen".

Bug 1 (Tab abgeschnitten -> nur "Serve"): TabBar labelPadding verkleinert
(engere Abstände), Schriftgröße unverändert.

Neue Tests: test/navidrome_parse_test.dart (5). 84/84 grün, analyze sauber.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tr2UwurtxyJUpWpBSeVmBm
2026-08-20 02:24:37 +02:00

59 lines
2.3 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:melo/services/navidrome_service.dart';
/// Tests für die Subsonic-Antwort-Auswertung. Kern des Bugfixes:
/// Navidrome liefert bei Fehlern (z. B. falsches Passwort) HTTP 200 mit
/// {"subsonic-response":{"status":"failed","error":{...}}}. Diese Antworten
/// dürfen NICHT stillschweigend als „leer" behandelt werden.
void main() {
group('NavidromeService.parseSubsonic', () {
test('status:failed wirft NavidromeException mit Server-Meldung', () {
const body =
'{"subsonic-response":{"status":"failed","version":"1.16.1",'
'"error":{"code":40,"message":"Wrong username or password"}}}';
expect(
() => NavidromeService.parseSubsonic(body),
throwsA(isA<NavidromeException>()
.having((e) => e.message, 'message', 'Wrong username or password')
.having((e) => e.code, 'code', 40)),
);
});
test('status:ok liefert den subsonic-response-Block zurück', () {
const body =
'{"subsonic-response":{"status":"ok","version":"1.16.1",'
'"albumList2":{"album":[]}}}';
final resp = NavidromeService.parseSubsonic(body);
expect(resp['status'], 'ok');
expect(resp['albumList2'], isNotNull);
});
test('fehlender subsonic-response wirft NavidromeException', () {
expect(() => NavidromeService.parseSubsonic('{"foo":1}'),
throwsA(isA<NavidromeException>()));
});
});
group('NavidromeService.parseAlben (ID3 / getAlbumList2)', () {
test('liest albumList2.album korrekt', () {
const body = '{"subsonic-response":{"status":"ok","albumList2":{"album":['
'{"id":"a1","name":"Erstes Album","coverArt":"c1","songCount":9},'
'{"id":"a2","title":"Zweites","songCount":3}'
']}}}';
final resp = NavidromeService.parseSubsonic(body);
final alben = NavidromeService.parseAlben(resp);
expect(alben.length, 2);
expect(alben[0].id, 'a1');
expect(alben[0].name, 'Erstes Album');
expect(alben[0].songCount, 9);
expect(alben[1].name, 'Zweites');
});
test('leere albumList2 liefert leere Liste (kein Fehler)', () {
final resp = NavidromeService.parseSubsonic(
'{"subsonic-response":{"status":"ok","albumList2":{}}}');
expect(NavidromeService.parseAlben(resp), isEmpty);
});
});
}