| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- import 'package:cardash_launcher/data/models/jellyfin_library.dart';
- import 'package:cardash_launcher/data/models/jellyfin_models.dart';
- import 'package:cardash_launcher/data/services/jellyfin_library_service.dart';
- import 'package:cardash_launcher/features/jellyfin/jellyfin_dashboard_controller.dart';
- import 'package:cardash_launcher/features/settings/jellyfin_controller.dart';
- import 'package:flutter_test/flutter_test.dart';
- import 'jellyfin_fakes.dart';
- class _Fixture {
- _Fixture({
- required this.jellyfin,
- required this.gateway,
- required this.library,
- required this.dashboard,
- });
- final JellyfinController jellyfin;
- final FakeJellyfinLibraryGateway gateway;
- final JellyfinLibraryService library;
- final JellyfinDashboardController dashboard;
- }
- Future<_Fixture> _fixture({List<String> genres = const []}) async {
- final jellyfin = await configuredJellyfinController();
- await jellyfin.setGenreSelections([
- for (final id in genres) JellyfinGenreSelection(id: id, label: id),
- ]);
- final gateway = FakeJellyfinLibraryGateway()
- ..played = [
- track(
- 'a2',
- albumId: 'album-a',
- albumName: 'Album A',
- lastPlayed: DateTime.utc(2026, 10, 31, 12),
- ),
- track('a1', albumId: 'album-a', albumName: 'Album A'),
- track('b1', albumId: 'album-b', albumName: 'Album B'),
- track('c1', albumId: 'album-c', albumName: 'Album C'),
- track('d1', albumId: 'album-d', albumName: 'Album D'),
- track('e1', albumId: 'album-e', albumName: 'Album E'),
- track('f1', albumId: 'album-f', albumName: 'Album F'),
- ]
- ..added = [
- album('new-1'),
- album('new-2'),
- album('new-3'),
- album('new-4'),
- album('new-5'),
- ]
- ..random = [album('r1'), album('r2'), album('r3'), album('r4'), album('r5')]
- ..genres = const ['Metal', 'Melodic Metal', 'Метъл', 'Jazz', 'Рок'];
- final library = testLibraryService(jellyfin, gateway);
- final dashboard = JellyfinDashboardController(
- library: library,
- jellyfin: jellyfin,
- );
- return _Fixture(
- jellyfin: jellyfin,
- gateway: gateway,
- library: library,
- dashboard: dashboard,
- );
- }
- void main() {
- test('loads three rows and expands only the selected genres', () async {
- final fixture = await _fixture(genres: ['metal', 'jazz']);
- addTearDown(fixture.dashboard.dispose);
- addTearDown(fixture.jellyfin.dispose);
- await fixture.dashboard.load();
- expect(fixture.dashboard.hasLoaded, isTrue);
- expect(fixture.dashboard.loading, isFalse);
- expect(fixture.dashboard.error, isNull);
- expect(fixture.dashboard.latestPlayed.length, 6);
- expect(fixture.dashboard.latestPlayed.first.id, 'album-a');
- expect(fixture.dashboard.latestAdded.length, 5);
- expect(fixture.dashboard.random.length, 5);
- expect(
- fixture.gateway.lastRandomGenres,
- containsAll(['Metal', 'Melodic Metal', 'Метъл', 'Jazz']),
- );
- expect(fixture.gateway.lastRandomGenres, isNot(contains('Рок')));
- });
- test('no selected genres means no random query', () async {
- final fixture = await _fixture();
- addTearDown(fixture.dashboard.dispose);
- addTearDown(fixture.jellyfin.dispose);
- await fixture.dashboard.load();
- expect(fixture.dashboard.hasGenres, isFalse);
- expect(fixture.dashboard.random, isEmpty);
- expect(fixture.gateway.randomCalls, 0);
- });
- test('shuffle replaces the random row', () async {
- final fixture = await _fixture(genres: ['metal']);
- addTearDown(fixture.dashboard.dispose);
- addTearDown(fixture.jellyfin.dispose);
- await fixture.dashboard.load();
- expect(fixture.dashboard.random.first.id, 'r1');
- fixture.gateway.random = [album('r9'), album('r10')];
- await fixture.dashboard.shuffle();
- expect(fixture.dashboard.random.map((entry) => entry.id), ['r9', 'r10']);
- expect(fixture.gateway.randomCalls, 2);
- expect(fixture.dashboard.randomLoading, isFalse);
- });
- test('markPlayed moves an album to the front and trims to five', () async {
- final fixture = await _fixture();
- addTearDown(fixture.dashboard.dispose);
- addTearDown(fixture.jellyfin.dispose);
- await fixture.dashboard.load();
- fixture.dashboard.markPlayed(album('album-a'));
- expect(fixture.dashboard.latestPlayed.first.id, 'album-a');
- expect(fixture.dashboard.latestPlayed.length, 6);
- });
- test('a server error is surfaced with retry state', () async {
- final fixture = await _fixture();
- addTearDown(fixture.dashboard.dispose);
- addTearDown(fixture.jellyfin.dispose);
- fixture.gateway.error = JellyfinUnreachable('offline');
- await fixture.dashboard.load();
- expect(fixture.dashboard.hasLoaded, isTrue);
- expect(fixture.dashboard.loading, isFalse);
- expect(fixture.dashboard.error, contains('unreachable'));
- });
- test('a random-only failure keeps the latest rows', () async {
- final fixture = await _fixture(genres: ['metal']);
- addTearDown(fixture.dashboard.dispose);
- addTearDown(fixture.jellyfin.dispose);
- fixture.gateway.randomError = JellyfinUnreachable('offline');
- await fixture.dashboard.load();
- expect(fixture.dashboard.error, isNull);
- expect(fixture.dashboard.randomError, contains('unreachable'));
- expect(fixture.dashboard.latestPlayed, isNotEmpty);
- expect(fixture.dashboard.latestAdded, isNotEmpty);
- expect(fixture.dashboard.random, isEmpty);
- });
- test('no connection reports a pairing error', () async {
- final fixture = await _fixture();
- addTearDown(fixture.dashboard.dispose);
- addTearDown(fixture.jellyfin.dispose);
- final unconfigured = JellyfinLibraryService(
- connectionProvider: () => null,
- gateway: fixture.gateway,
- );
- final dashboard = JellyfinDashboardController(
- library: unconfigured,
- jellyfin: fixture.jellyfin,
- );
- addTearDown(dashboard.dispose);
- await dashboard.load();
- expect(dashboard.hasLoaded, isTrue);
- expect(dashboard.error, contains('Pair Jellyfin'));
- });
- }
|