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/flutter_quill_test.dart'; import 'package:flutter_quill/src/widgets/raw_editor.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, readOnly: false), ), ); 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( controller: controller, focusNode: FocusNode(), scrollController: ScrollController(), scrollable: true, padding: const EdgeInsets.all(0), autoFocus: true, readOnly: false, expands: true, contentInsertionConfiguration: ContentInsertionConfiguration( onContentInserted: (content) { latestUri = content.uri; }, allowedMimeTypes: const ['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({ 'args': [ -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, RawEditorState 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( controller: controller, focusNode: FocusNode(), scrollController: ScrollController(), scrollable: true, padding: EdgeInsets.zero, autoFocus: true, readOnly: false, 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); }); }); }