dartlangeditorflutterflutter-appsflutter-examplesflutter-packageflutter-widgetquillquill-deltaquilljsreactquillrich-textrich-text-editorwysiwygwysiwyg-editor
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
220 lines
6.3 KiB
220 lines
6.3 KiB
import 'dart:convert' show jsonDecode; |
|
|
|
import 'package:flutter/material.dart'; |
|
import 'package:flutter/services.dart'; |
|
import 'package:flutter_quill/flutter_quill.dart'; |
|
import 'package:flutter_quill/translations.dart'; |
|
import 'package:flutter_quill_test/flutter_quill_test.dart'; |
|
import 'package:flutter_test/flutter_test.dart'; |
|
|
|
void main() { |
|
late QuillController controller; |
|
var didCopy = false; |
|
|
|
setUp(() { |
|
controller = QuillController.basic(); |
|
}); |
|
|
|
tearDown(() { |
|
controller.dispose(); |
|
}); |
|
|
|
group('QuillEditor', () { |
|
testWidgets('Keyboard entered text is stored in document', (tester) async { |
|
await tester.pumpWidget( |
|
MaterialApp( |
|
home: QuillEditor.basic( |
|
controller: controller, |
|
// ignore: avoid_redundant_argument_values |
|
configurations: const QuillEditorConfigurations( |
|
// ignore: avoid_redundant_argument_values |
|
), |
|
), |
|
), |
|
); |
|
await tester.quillEnterText(find.byType(QuillEditor), 'test\n'); |
|
|
|
expect(controller.document.toPlainText(), 'test\n'); |
|
}); |
|
|
|
testWidgets('insertContent is handled correctly', (tester) async { |
|
String? latestUri; |
|
await tester.pumpWidget( |
|
MaterialApp( |
|
home: QuillEditor( |
|
focusNode: FocusNode(), |
|
scrollController: ScrollController(), |
|
controller: controller, |
|
configurations: QuillEditorConfigurations( |
|
// ignore: avoid_redundant_argument_values |
|
autoFocus: true, |
|
expands: true, |
|
contentInsertionConfiguration: ContentInsertionConfiguration( |
|
onContentInserted: (content) { |
|
latestUri = content.uri; |
|
}, |
|
allowedMimeTypes: <String>['image/gif'], |
|
), |
|
), |
|
), |
|
), |
|
); |
|
await tester.tap(find.byType(QuillEditor)); |
|
await tester.quillEnterText(find.byType(QuillEditor), 'test\n'); |
|
await tester.idle(); |
|
|
|
const uri = |
|
'content://com.google.android.inputmethod.latin.fileprovider/test.gif'; |
|
final messageBytes = |
|
const JSONMessageCodec().encodeMessage(<String, dynamic>{ |
|
'args': <dynamic>[ |
|
-1, |
|
'TextInputAction.commitContent', |
|
jsonDecode( |
|
'{"mimeType": "image/gif", "data": [0,1,0,1,0,1,0,0,0], "uri": "$uri"}'), |
|
], |
|
'method': 'TextInputClient.performAction', |
|
}); |
|
|
|
Object? error; |
|
try { |
|
await tester.binding.defaultBinaryMessenger |
|
.handlePlatformMessage('flutter/textinput', messageBytes, (_) {}); |
|
} catch (e) { |
|
error = e; |
|
} |
|
expect(error, isNull); |
|
expect(latestUri, equals(uri)); |
|
}); |
|
|
|
Widget customBuilder(BuildContext context, QuillRawEditorState state) { |
|
return AdaptiveTextSelectionToolbar( |
|
anchors: state.contextMenuAnchors, |
|
children: [ |
|
Container( |
|
height: 50, |
|
color: Colors.white, |
|
child: Row( |
|
mainAxisAlignment: MainAxisAlignment.spaceAround, |
|
children: [ |
|
IconButton( |
|
onPressed: () { |
|
didCopy = true; |
|
}, |
|
icon: const Icon(Icons.copy), |
|
), |
|
], |
|
), |
|
), |
|
], |
|
); |
|
} |
|
|
|
testWidgets('custom context menu builder', (tester) async { |
|
await tester.pumpWidget( |
|
MaterialApp( |
|
home: QuillEditor( |
|
focusNode: FocusNode(), |
|
scrollController: ScrollController(), |
|
controller: controller, |
|
// ignore: avoid_redundant_argument_values |
|
configurations: QuillEditorConfigurations( |
|
// ignore: avoid_redundant_argument_values |
|
autoFocus: true, |
|
expands: true, |
|
contextMenuBuilder: customBuilder, |
|
), |
|
), |
|
), |
|
); |
|
|
|
// Long press to show menu |
|
await tester.longPress(find.byType(QuillEditor)); |
|
await tester.pumpAndSettle(); |
|
|
|
// Verify custom widget shows |
|
expect(find.byIcon(Icons.copy), findsOneWidget); |
|
|
|
await tester.tap(find.byIcon(Icons.copy)); |
|
expect(didCopy, isTrue); |
|
}); |
|
|
|
testWidgets( |
|
'make sure QuillEditorOpenSearchAction does not throw an exception', |
|
(tester) async { |
|
final editorFocusNode = FocusNode(); |
|
await tester.pumpWidget( |
|
MaterialApp( |
|
home: QuillEditor.basic( |
|
controller: controller, |
|
configurations: const QuillEditorConfigurations(), |
|
focusNode: editorFocusNode, |
|
), |
|
), |
|
); |
|
// Required, otherwise the action shortcuts won't be invoked. |
|
editorFocusNode.requestFocus(); |
|
|
|
await tester.sendKeyDownEvent(LogicalKeyboardKey.control); |
|
await tester.sendKeyEvent(LogicalKeyboardKey.keyF); |
|
await tester.sendKeyUpEvent(LogicalKeyboardKey.control); |
|
|
|
await tester.pump(); |
|
|
|
final exception = tester.takeException(); |
|
expect( |
|
exception, |
|
isNot( |
|
isInstanceOf<MissingFlutterQuillLocalizationException>(), |
|
), |
|
); |
|
|
|
expect(exception, isNull); |
|
}, |
|
); |
|
|
|
testWidgets( |
|
'should throw MissingFlutterQuillLocalizationException if the delegate not provided', |
|
(tester) async { |
|
await tester.pumpWidget( |
|
MaterialApp( |
|
home: Builder( |
|
builder: (context) => Text(context.loc.font), |
|
), |
|
), |
|
); |
|
|
|
final exception = tester.takeException(); |
|
|
|
expect(exception, isNotNull); |
|
expect( |
|
exception, |
|
isA<MissingFlutterQuillLocalizationException>(), |
|
); |
|
}, |
|
); |
|
|
|
testWidgets( |
|
'should not throw MissingFlutterQuillLocalizationException if the delegate is provided', |
|
(tester) async { |
|
await tester.pumpWidget( |
|
MaterialApp( |
|
home: FlutterQuillLocalizationsWidget( |
|
child: Builder( |
|
builder: (context) => Text(context.loc.font), |
|
), |
|
), |
|
), |
|
); |
|
|
|
final exception = tester.takeException(); |
|
|
|
expect(exception, isNull); |
|
expect( |
|
exception, |
|
isNot(isA<MissingFlutterQuillLocalizationException>()), |
|
); |
|
}, |
|
); |
|
}); |
|
}
|
|
|