Files
plezy/test/utils/dialogs_test.dart
T
edde746 01d7d523aa test(tv): follow the native text input contract on Apple TV
71735354 made TvTextInputPresentation.automatic use native platform
input for single-line Apple TV fields, and 829d3745 migrated the search
and Add Jellyfin suites to it. These five cases still expected the
Flutter on-screen keyboard widget and failed looking for a panel that no
longer exists.

Drives the native path instead: each case asserts input is live
(readOnly false), raises the keyboard, then keeps its original
regression intent — the first Back deactivates input and is consumed so
it cannot also pop, and only the second Back pops or cancels.
2026-07-26 23:05:53 +02:00

132 lines
4.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:plezy/utils/dialogs.dart';
import 'package:plezy/utils/platform_detector.dart';
void main() {
tearDown(() {
TvDetectionService.debugSetAppleTVOverride(null);
TvDetectionService.setForceTVSync(false);
});
testWidgets('text input dialog returns submitted text', (tester) async {
final hostContext = await _pumpHost(tester);
final result = showTextInputDialog(hostContext, title: 'Name', labelText: 'Name');
await tester.pumpAndSettle();
await tester.enterText(find.byType(TextField), 'New name');
await tester.tap(find.text('Save'));
await tester.pumpAndSettle();
await expectLater(result, completion('New name'));
expect(find.byType(AlertDialog), findsNothing);
});
testWidgets('text input dialog returns null when cancelled', (tester) async {
final hostContext = await _pumpHost(tester);
final result = showTextInputDialog(hostContext, title: 'Name', labelText: 'Name');
await tester.pumpAndSettle();
await tester.tap(find.text('Cancel'));
await tester.pumpAndSettle();
await expectLater(result, completion(isNull));
});
testWidgets('text input dialog shows validation errors and stays open', (tester) async {
final hostContext = await _pumpHost(tester);
final result = showTextInputDialog(
hostContext,
title: 'Name',
labelText: 'Name',
validator: (value) => value.length < 3 ? 'Too short' : null,
);
await tester.pumpAndSettle();
await tester.enterText(find.byType(TextField), 'ab');
await tester.tap(find.text('Save'));
await tester.pump();
expect(find.text('Too short'), findsOneWidget);
expect(find.byType(AlertDialog), findsOneWidget);
await tester.enterText(find.byType(TextField), 'valid');
await tester.tap(find.text('Save'));
await tester.pumpAndSettle();
await expectLater(result, completion('valid'));
});
testWidgets('text input dialog seeds multiline initial value', (tester) async {
final hostContext = await _pumpHost(tester);
final result = showTextInputDialog(
hostContext,
title: 'Summary',
labelText: 'Summary',
initialValue: 'Line one\nLine two',
allowEmpty: true,
multiline: true,
);
await tester.pumpAndSettle();
final field = tester.widget<TextField>(find.byType(TextField));
expect(field.controller?.text, 'Line one\nLine two');
expect(field.keyboardType, TextInputType.multiline);
expect(field.maxLines, 8);
await tester.tap(find.text('Save'));
await tester.pumpAndSettle();
await expectLater(result, completion('Line one\nLine two'));
});
testWidgets('TV back closes keyboard, restores field focus, then cancels dialog', (tester) async {
TvDetectionService.debugSetAppleTVOverride(true);
await tester.binding.setSurfaceSize(const Size(1280, 720));
addTearDown(() => tester.binding.setSurfaceSize(null));
final hostContext = await _pumpHost(tester);
final result = showTextInputDialog(hostContext, title: 'Name', labelText: 'Name', initialValue: 'TV value');
await tester.pumpAndSettle();
final fieldFinder = find.byType(TextField, skipOffstage: false);
final field = tester.widget<TextField>(fieldFinder);
expect(find.byKey(const Key('tv_virtual_keyboard_dialog')), findsNothing);
expect(field.readOnly, isFalse);
await tester.showKeyboard(fieldFinder);
await tester.sendKeyDownEvent(LogicalKeyboardKey.escape);
await tester.pump();
expect(find.byType(AlertDialog), findsOneWidget);
expect(tester.widget<TextField>(fieldFinder).readOnly, isTrue);
await tester.sendKeyUpEvent(LogicalKeyboardKey.escape);
await tester.pumpAndSettle();
expect(find.byKey(const Key('tv_virtual_keyboard_dialog')), findsNothing);
expect(find.byType(AlertDialog), findsOneWidget);
expect(field.focusNode?.hasPrimaryFocus, isTrue);
expect(tester.widget<TextField>(fieldFinder).readOnly, isTrue);
await tester.sendKeyEvent(LogicalKeyboardKey.escape);
await tester.pumpAndSettle();
await expectLater(result, completion(isNull));
expect(find.byType(AlertDialog), findsNothing);
});
}
Future<BuildContext> _pumpHost(WidgetTester tester) async {
late BuildContext hostContext;
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Builder(
builder: (context) {
hostContext = context;
return const SizedBox.shrink();
},
),
),
),
);
return hostContext;
}