71735354made TvTextInputPresentation.automatic use native platform input for single-line Apple TV fields, and829d3745migrated 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.
132 lines
4.5 KiB
Dart
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;
|
|
}
|