Files
sync_replay_project/apps/desktop/test/home_test.dart
T
foxyzandClaude Opus 5.5 aeff087c7d Desktop: video freeze recovery, session fixes, Home redesign
- Player + VideoController per session; Reload video (Ctrl+R) and a
  frozen-picture watchdog that reloads automatically.
- Shortcuts no longer fire while typing; empty swap disabled;
  hwdec setting/env actually applied.
- Idle unready measured from real inactivity; cancellable reconnects
  and setup; ready restored from server state; kicked/failed host
  stops its server; graceful leave on window close; no URLs with
  keys in display names.
- Welcome + connect screens replaced by one Home screen with Join and
  Host cards, recent servers, Settings, Integrations and About.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 00:41:02 +03:00

127 lines
5.2 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:watch_together/src/screens/home/home_screen.dart';
import 'package:watch_together/src/state/session_state.dart';
import 'package:watch_together/src/state/settings.dart';
import 'package:watch_together/src/update/update_controller.dart';
RecentServer join(String host, String port, [String secret = '']) =>
RecentServer(hosted: false, host: host, port: port, secret: secret);
void main() {
group('recent servers', () {
test('newest first, deduped by server, capped', () {
var list = <RecentServer>[];
for (var i = 0; i < 8; i++) {
list = pushRecent(list, join('10.0.0.$i', '8080'));
}
expect(list.length, maxRecentServers);
expect(list.first.host, '10.0.0.7');
list = pushRecent(list, join('10.0.0.4', '8080', 'pw'));
expect(list.length, maxRecentServers);
expect(list.first.secret, 'pw');
expect(list.where((r) => r.host == '10.0.0.4').length, 1);
});
test('hosted entries are one per port, separate from joins', () {
var list = <RecentServer>[];
list = pushRecent(list, const RecentServer(hosted: true, host: '', port: '8080'));
list = pushRecent(list, join('127.0.0.1', '8080'));
list = pushRecent(list, const RecentServer(hosted: true, host: '', port: '8080', secret: 'x'));
expect(list.length, 2);
expect(list.first.secret, 'x');
});
test('round-trips and tolerates junk', () {
final list = [join('a.example', '9000', 's'), const RecentServer(hosted: true, host: '', port: '8080')];
final back = decodeRecents(encodeRecents(list));
expect(back.map((r) => r.key), list.map((r) => r.key));
expect(back.first.secret, 's');
expect(back.last.hosted, isTrue);
expect(decodeRecents('not json'), isEmpty);
expect(decodeRecents(42), isEmpty);
expect(decodeRecents('[{"host":1},{"host":"h","port":"1"}]').single.host, 'h');
});
test('old single form migrates to one recent unless it was localhost', () {
expect(migrateRecents(hadForm: true, host: 'friend.example', port: '8080', secret: 'pw').single.secret, 'pw');
expect(migrateRecents(hadForm: true, host: '127.0.0.1', port: '8080', secret: ''), isEmpty);
expect(migrateRecents(hadForm: false, host: 'friend.example', port: '8080', secret: ''), isEmpty);
});
});
test('hwdec value follows mode', () {
final s = AppSettings();
expect(s.hwdec.value, 'auto');
s.setHwdecMode(HwdecMode.off);
expect(s.hwdec.value, 'no');
s.setHwdecMode(HwdecMode.custom);
expect(s.hwdec.value, 'auto');
s.setHwdecCustom(' vaapi ');
expect(s.hwdec.value, 'vaapi');
});
Future<void> pumpShell(WidgetTester tester, Size size) async {
tester.view.physicalSize = size;
tester.view.devicePixelRatio = 1;
addTearDown(tester.view.reset);
await tester.pumpWidget(MaterialApp(
theme: ThemeData.dark(),
home: Scaffold(
body: HomeShell(updates: UpdateController(currentVersion: '0.0.0-dev'), autoUpdateCheck: false),
),
));
await tester.pump();
}
testWidgets('home shows both cards side by side on a wide window', (tester) async {
await pumpShell(tester, const Size(1280, 720));
final join = tester.getRect(find.byKey(const ValueKey('join-card')));
final host = tester.getRect(find.byKey(const ValueKey('host-card')));
expect(join.top, host.top);
expect(join.height, host.height);
expect(join.right, lessThan(host.left));
expect(find.text('No password — anyone can join'), findsOneWidget);
expect(tester.takeException(), isNull);
});
testWidgets('cards stack on a narrow window', (tester) async {
await pumpShell(tester, const Size(560, 900));
final join = tester.getRect(find.byKey(const ValueKey('join-card')));
final host = tester.getRect(find.byKey(const ValueKey('host-card')));
expect(join.bottom, lessThan(host.top));
expect(tester.takeException(), isNull);
});
testWidgets('join without a name errors inline in the join card', (tester) async {
SessionState.instance.lastForm.name = '';
await pumpShell(tester, const Size(1280, 720));
await tester.tap(find.widgetWithText(FilledButton, 'Join'));
await tester.pump();
await tester.pump();
expect(
find.descendant(
of: find.byKey(const ValueKey('join-card')),
matching: find.textContaining('display name', findRichText: true),
),
findsOneWidget,
);
});
testWidgets('rail switches to settings, integrations and about', (tester) async {
await pumpShell(tester, const Size(1280, 900));
await tester.tap(find.byIcon(Icons.settings_outlined));
await tester.pumpAndSettle();
expect(find.text('Hardware decoding'), findsOneWidget);
expect(find.text('Check automatically on start'), findsOneWidget);
expect(find.text('Toggle ready'), findsOneWidget);
await tester.tap(find.byIcon(Icons.extension_outlined));
await tester.pumpAndSettle();
expect(find.text('Jellyfin'), findsOneWidget);
await tester.tap(find.byIcon(Icons.info_outline));
await tester.pumpAndSettle();
expect(find.text('Dev build — update checks are off'), findsOneWidget);
expect(tester.takeException(), isNull);
});
}