test: implement simple redo/undo test for no-styled text

This commit is contained in:
Lucas.Xu 2022-08-15 16:35:22 +08:00
parent f5cc886b6e
commit e926c89548
5 changed files with 127 additions and 28 deletions

View File

@ -28,10 +28,12 @@ List<String> defaultListToolbarEventNames = [
'H1',
'H2',
'H3',
// 'B-List',
// 'N-List',
];
mixin ToolBarMixin<T extends StatefulWidget> on State<T> {
void hide();
}
class ToolbarWidget extends StatefulWidget {
const ToolbarWidget({
Key? key,
@ -50,7 +52,7 @@ class ToolbarWidget extends StatefulWidget {
State<ToolbarWidget> createState() => _ToolbarWidgetState();
}
class _ToolbarWidgetState extends State<ToolbarWidget> {
class _ToolbarWidgetState extends State<ToolbarWidget> with ToolBarMixin {
final GlobalKey _listToolbarKey = GlobalKey();
final toolbarHeight = 32.0;
@ -63,21 +65,6 @@ class _ToolbarWidgetState extends State<ToolbarWidget> {
OverlayEntry? _listToolbarOverlay;
@override
void initState() {
super.initState();
widget.editorState.service.selectionService.currentSelection
.addListener(_onSelectionChange);
}
@override
void dispose() {
widget.editorState.service.selectionService.currentSelection
.removeListener(_onSelectionChange);
super.dispose();
}
@override
Widget build(BuildContext context) {
return Positioned(
@ -92,6 +79,12 @@ class _ToolbarWidgetState extends State<ToolbarWidget> {
);
}
@override
void hide() {
_listToolbarOverlay?.remove();
_listToolbarOverlay = null;
}
Widget _buildToolbar(BuildContext context) {
return Material(
borderRadius: BorderRadius.circular(cornerRadius),
@ -212,9 +205,4 @@ class _ToolbarWidgetState extends State<ToolbarWidget> {
}
assert(false, 'Could not find the event handler for $eventName');
}
void _onSelectionChange() {
_listToolbarOverlay?.remove();
_listToolbarOverlay = null;
}
}

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flowy_editor/flowy_editor.dart';
import 'package:flowy_editor/src/render/selection/toolbar_widget.dart';
import 'package:flowy_editor/src/extensions/object_extensions.dart';
abstract class FlowyToolbarService {
/// Show the toolbar widget beside the offset.
@ -28,12 +29,15 @@ class FlowyToolbar extends StatefulWidget {
class _FlowyToolbarState extends State<FlowyToolbar>
implements FlowyToolbarService {
OverlayEntry? _toolbarOverlay;
final _toolbarWidgetKey = GlobalKey(debugLabel: '_toolbar_widget');
@override
void showInOffset(Offset offset, LayerLink layerLink) {
_toolbarOverlay?.remove();
hide();
_toolbarOverlay = OverlayEntry(
builder: (context) => ToolbarWidget(
key: _toolbarWidgetKey,
editorState: widget.editorState,
layerLink: layerLink,
offset: offset.translate(0, -37.0),
@ -45,6 +49,7 @@ class _FlowyToolbarState extends State<FlowyToolbar>
@override
void hide() {
_toolbarWidgetKey.currentState?.unwrapOrNull<ToolBarMixin>()?.hide();
_toolbarOverlay?.remove();
_toolbarOverlay = null;
}
@ -55,4 +60,11 @@ class _FlowyToolbarState extends State<FlowyToolbar>
child: widget.child,
);
}
@override
void dispose() {
hide();
super.dispose();
}
}

View File

@ -72,8 +72,20 @@ class EditorWidgetTester {
await tester.pumpAndSettle();
}
Future<void> pressLogicKey(LogicalKeyboardKey key) async {
final testRawKeyEventData = TestRawKeyEventData(logicalKey: key).toKeyEvent;
Future<void> pressLogicKey(
LogicalKeyboardKey key, {
bool isControlPressed = false,
bool isShiftPressed = false,
bool isAltPressed = false,
bool isMetaPressed = false,
}) async {
final testRawKeyEventData = TestRawKeyEventData(
logicalKey: key,
isControlPressed: isControlPressed,
isShiftPressed: isShiftPressed,
isAltPressed: isAltPressed,
isMetaPressed: isMetaPressed,
).toKeyEvent;
_editorState.service.keyboardService!.onKey(testRawKeyEventData);
await tester.pumpAndSettle();
}

View File

@ -1,7 +1,25 @@
import 'package:flutter/services.dart';
class TestRawKeyEvent extends RawKeyDownEvent {
const TestRawKeyEvent({required super.data});
const TestRawKeyEvent({
required super.data,
this.isControlPressed = false,
this.isShiftPressed = false,
this.isAltPressed = false,
this.isMetaPressed = false,
});
@override
final bool isControlPressed;
@override
final bool isShiftPressed;
@override
final bool isAltPressed;
@override
final bool isMetaPressed;
}
class TestRawKeyEventData extends RawKeyEventData {
@ -46,7 +64,13 @@ class TestRawKeyEventData extends RawKeyEventData {
String get keyLabel => throw UnimplementedError();
RawKeyEvent get toKeyEvent {
return TestRawKeyEvent(data: this);
return TestRawKeyEvent(
data: this,
isAltPressed: isAltPressed,
isControlPressed: isControlPressed,
isMetaPressed: isMetaPressed,
isShiftPressed: isShiftPressed,
);
}
}
@ -67,6 +91,9 @@ extension on LogicalKeyboardKey {
if (this == LogicalKeyboardKey.pageUp) {
return PhysicalKeyboardKey.pageUp;
}
if (this == LogicalKeyboardKey.keyZ) {
return PhysicalKeyboardKey.keyZ;
}
throw UnimplementedError();
}
}

View File

@ -0,0 +1,60 @@
import 'package:flowy_editor/flowy_editor.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import '../../infra/test_editor.dart';
void main() async {
setUpAll(() {
TestWidgetsFlutterBinding.ensureInitialized();
});
group('redo_undo_handler_test.dart', () {
// TODO: need to test more cases.
testWidgets('Redo, Undo for backspace key, and selection is downward',
(tester) async {
await _testBackspaceUndoRedo(tester, true);
});
testWidgets('Redo, Undo for backspace key, and selection is forward',
(tester) async {
await _testBackspaceUndoRedo(tester, false);
});
});
}
Future<void> _testBackspaceUndoRedo(
WidgetTester tester, bool isDownwardSelection) async {
const text = 'Welcome to Appflowy 😁';
final editor = tester.editor
..insertTextNode(text)
..insertTextNode(text)
..insertTextNode(text);
await editor.startTesting();
final start = Position(path: [0], offset: text.length);
final end = Position(path: [1], offset: text.length);
final selection = Selection(
start: isDownwardSelection ? start : end,
end: isDownwardSelection ? end : start,
);
await editor.updateSelection(selection);
await editor.pressLogicKey(LogicalKeyboardKey.backspace);
expect(editor.documentLength, 2);
await editor.pressLogicKey(
LogicalKeyboardKey.keyZ,
isMetaPressed: true,
);
expect(editor.documentLength, 3);
expect((editor.nodeAtPath([1]) as TextNode).toRawString(), text);
expect(editor.documentSelection, selection);
await editor.pressLogicKey(
LogicalKeyboardKey.keyZ,
isMetaPressed: true,
isShiftPressed: true,
);
expect(editor.documentLength, 2);
}