Skip to content

Commit

Permalink
Add more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Amir-P committed Dec 6, 2023
1 parent f727706 commit 2a588c6
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 115 deletions.
85 changes: 3 additions & 82 deletions packages/fleather/lib/src/widgets/editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,8 @@ class _FleatherEditorState extends State<FleatherEditor>
@override
GlobalKey<EditorState> get editableTextKey => widget.editorKey ?? _editorKey!;

// TODO: Add support for forcePress on iOS.
@override
bool get forcePressEnabled => false;
bool get forcePressEnabled => true;

@override
bool get selectionEnabled => widget.enableInteractiveSelection;
Expand Down Expand Up @@ -430,102 +429,24 @@ class _FleatherEditorSelectionGestureDetectorBuilder
}
}

@override
void onForcePressEnd(ForcePressDetails details) {
// Not required.
}

@override
void onSingleLongTapMoveUpdate(LongPressMoveUpdateDetails details) {
if (delegate.selectionEnabled) {
switch (Theme.of(_state.context).platform) {
case TargetPlatform.iOS:
case TargetPlatform.macOS:
renderEditor.selectPositionAt(
from: details.globalPosition,
cause: SelectionChangedCause.longPress,
);
break;
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
renderEditor.selectWordsInRange(
from: details.globalPosition - details.offsetFromOrigin,
to: details.globalPosition,
cause: SelectionChangedCause.longPress,
);
break;
}
}
}

bool isShiftClick(PointerDeviceKind deviceKind) {
final pressed = RawKeyboard.instance.keysPressed;
return deviceKind == PointerDeviceKind.mouse &&
(pressed.contains(LogicalKeyboardKey.shiftLeft) ||
pressed.contains(LogicalKeyboardKey.shiftRight));
}

@override
void onSingleTapUp(TapDragUpDetails details) {
editor.hideToolbar();

if (delegate.selectionEnabled) {
switch (Theme.of(_state.context).platform) {
case TargetPlatform.iOS:
case TargetPlatform.macOS:
switch (details.kind) {
case PointerDeviceKind.mouse:
case PointerDeviceKind.stylus:
case PointerDeviceKind.invertedStylus:
// Precise devices should place the cursor at a precise position.
// If `Shift` key is pressed then extend current selection instead.
if (isShiftClick(details.kind)) {
renderEditor.extendSelection(details.globalPosition,
cause: SelectionChangedCause.tap);
} else {
renderEditor.selectPosition(cause: SelectionChangedCause.tap);
}
break;
case PointerDeviceKind.touch:
case PointerDeviceKind.trackpad:
case PointerDeviceKind.unknown:
// On macOS/iOS/iPadOS a touch tap places the cursor at the edge
// of the word.
renderEditor.selectWordEdge(cause: SelectionChangedCause.tap);
break;
}
break;
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
renderEditor.selectPosition(cause: SelectionChangedCause.tap);
break;
}
}
super.onSingleTapUp(details);
_state._requestKeyboard();
// if (_state.widget.onTap != null)
// _state.widget.onTap();
}

@override
void onSingleLongTapStart(LongPressStartDetails details) {
super.onSingleLongTapStart(details);
if (delegate.selectionEnabled) {
switch (Theme.of(_state.context).platform) {
case TargetPlatform.iOS:
case TargetPlatform.macOS:
renderEditor.selectPositionAt(
from: details.globalPosition,
cause: SelectionChangedCause.longPress,
);
break;
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
renderEditor.selectWord(cause: SelectionChangedCause.longPress);
Feedback.forLongPress(_state.context);
break;
}
Expand Down
1 change: 1 addition & 0 deletions packages/fleather/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ dev_dependencies:
flutter_lints: ^2.0.1
fake_async: ^1.3.1
mocktail: ^0.3.0
meta: ^1.10.0
6 changes: 1 addition & 5 deletions packages/fleather/test/testing.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ class EditorSandBox {
FocusNode? focusNode,
ParchmentDocument? document,
FleatherThemeData? fleatherTheme,
ThemeData? theme,
bool autofocus = false,
}) {
focusNode ??= FocusNode();
Expand All @@ -39,10 +38,7 @@ class EditorSandBox {
if (fleatherTheme != null) {
widget = FleatherTheme(data: fleatherTheme, child: widget);
}
widget = MaterialApp(
home: widget,
theme: theme,
);
widget = MaterialApp(home: widget);

return EditorSandBox._(tester, focusNode, document, controller, widget);
}
Expand Down
150 changes: 122 additions & 28 deletions packages/fleather/test/widgets/editor_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:meta/meta.dart';
import 'package:quill_delta/quill_delta.dart';

import '../testing.dart';
Expand Down Expand Up @@ -101,7 +102,7 @@ void main() {
// Fails if thrown
});

group('Context menu', () {
group('Text selection', () {
testWidgets('Hides toolbar and selection handles when text changed',
(tester) async {
const delta = TextEditingDeltaInsertion(
Expand Down Expand Up @@ -213,10 +214,116 @@ void main() {
await tester.pump();
expect(find.byType(AdaptiveTextSelectionToolbar), findsNothing);
}, TargetPlatform.windows);
});

group('Text selection', () {
testWidgets('Can select last separated character in paragraph on iOS',
testWidgetsWithPlatform(
'Shift tap selects from beginning when unfocused on mac',
(tester) async {
final document = ParchmentDocument.fromJson([
{'insert': 'Test\n'}
]);
final editor = EditorSandBox(
tester: tester,
document: document,
focusNode: FocusNode(canRequestFocus: false));
await editor.pump();
await editor.updateSelection(base: 1, extent: 1);
await tester.sendKeyDownEvent(LogicalKeyboardKey.shift);
await tester.tapAt(tester.getTopRight(find.byType(FleatherEditor)) +
const Offset(-1, 1));
await tester.pump();
expect(
editor.selection,
const TextSelection(
baseOffset: 0,
extentOffset: 4,
affinity: TextAffinity.upstream));
}, TargetPlatform.macOS);

testWidgetsWithPlatform(
'Shift tap selects from current selection when focused on mac',
(tester) async {
final document = ParchmentDocument.fromJson([
{'insert': 'Test\n'}
]);
final editor =
EditorSandBox(tester: tester, document: document, autofocus: true);
await editor.pump();
await editor.updateSelection(base: 1, extent: 1);
await tester.sendKeyDownEvent(LogicalKeyboardKey.shift);
await tester.tapAt(tester.getTopRight(find.byType(FleatherEditor)) +
const Offset(-1, 1));
await tester.pump();
expect(
editor.selection,
const TextSelection(
baseOffset: 1,
extentOffset: 4,
affinity: TextAffinity.upstream));
}, TargetPlatform.macOS);

testWidgetsWithPlatform('Mouse drag updates selection', (tester) async {
final document = ParchmentDocument.fromJson([
{'insert': 'Test\n'}
]);
final editor = EditorSandBox(tester: tester, document: document);
await editor.pump();
final gesture = await tester.startGesture(
tester.getTopLeft(find.byType(FleatherEditor)) + const Offset(10, 1),
pointer: tester.nextPointer,
kind: PointerDeviceKind.mouse,
);
await tester.pump();
expect(
editor.selection,
const TextSelection.collapsed(
offset: 1, affinity: TextAffinity.upstream));
await gesture.moveBy(const Offset(30, 0));
await tester.pump();
await gesture.up();
await tester.pumpAndSettle();
expect(
editor.selection,
const TextSelection(
baseOffset: 1,
extentOffset: 2,
affinity: TextAffinity.upstream));
}, TargetPlatform.macOS);

testWidgetsWithPlatform('Mouse drag with shift extends selection',
(tester) async {
final document = ParchmentDocument.fromJson([
{'insert': 'Test test\n'}
]);
final editor = EditorSandBox(tester: tester, document: document);
await editor.pump();
await editor.updateSelection(base: 1, extent: 2);
await tester.sendKeyDownEvent(LogicalKeyboardKey.shift);
final gesture = await tester.startGesture(
tester.getTopLeft(find.byType(FleatherEditor)) + const Offset(45, 1),
pointer: tester.nextPointer,
kind: PointerDeviceKind.mouse,
);
await tester.pump();
expect(
editor.selection,
const TextSelection(
baseOffset: 1,
extentOffset: 3,
affinity: TextAffinity.upstream));
await gesture.moveBy(const Offset(30, 0));
await tester.pump();
await gesture.up();
await tester.pumpAndSettle();
expect(
editor.selection,
const TextSelection(
baseOffset: 1,
extentOffset: 5,
affinity: TextAffinity.upstream));
}, TargetPlatform.macOS);

testWidgetsWithPlatform(
'Can select last separated character in paragraph on iOS',
(tester) async {
const text = 'Test.';
final document = ParchmentDocument.fromJson([
Expand All @@ -226,7 +333,6 @@ void main() {
tester: tester,
document: document,
autofocus: true,
theme: ThemeData(platform: TargetPlatform.iOS),
);
await editor.pump();
await tester.tapAt(tester.getBottomRight(find.byType(FleatherEditor)) -
Expand All @@ -236,16 +342,12 @@ void main() {
editor.selection,
const TextSelection.collapsed(
offset: text.length, affinity: TextAffinity.upstream));
});
}, TargetPlatform.iOS);

testWidgets(
testWidgetsWithPlatform(
'Tapping after the beginning of a word moves cursor after word on iOS',
(tester) async {
final editor = EditorSandBox(
tester: tester,
autofocus: true,
theme: ThemeData(platform: TargetPlatform.iOS),
);
final editor = EditorSandBox(tester: tester, autofocus: true);
await editor.pump();
await tester.tapAt(tester.getBottomLeft(find.byType(FleatherEditor)) +
const Offset(10, -1));
Expand All @@ -254,9 +356,9 @@ void main() {
editor.selection,
const TextSelection.collapsed(
offset: 4, affinity: TextAffinity.upstream));
});
}, TargetPlatform.iOS);

testWidgets(
testWidgetsWithPlatform(
'Tapping before the beginning of a word moves cursor at the end of previous word on iOS',
(tester) async {
final document = ParchmentDocument.fromJson([
Expand All @@ -266,7 +368,6 @@ void main() {
tester: tester,
document: document,
autofocus: true,
theme: ThemeData(platform: TargetPlatform.iOS),
);
await editor.pump();
await tester.tapAt(tester.getBottomLeft(find.byType(FleatherEditor)) +
Expand All @@ -276,7 +377,7 @@ void main() {
editor.selection,
const TextSelection.collapsed(
offset: 3, affinity: TextAffinity.upstream));
});
}, TargetPlatform.iOS);

testWidgets(
'Tapping moves the cursor right where user tapped on other platforms',
Expand Down Expand Up @@ -356,12 +457,8 @@ void main() {
{'insert': '$text\n'},
{'insert': 'Some other text in another paragraph\n'},
]);
final editor = EditorSandBox(
tester: tester,
document: document,
autofocus: true,
theme: ThemeData(platform: TargetPlatform.iOS),
);
final editor =
EditorSandBox(tester: tester, document: document, autofocus: true);
await editor.pump();
await tester.tapAt(tester.getTopLeft(find.byType(FleatherEditor)) +
const Offset(1, 1));
Expand All @@ -387,12 +484,8 @@ void main() {
{'insert': '$text\n'},
{'insert': 'Some other text in another paragraph\n'},
]);
final editor = EditorSandBox(
tester: tester,
document: document,
autofocus: true,
theme: ThemeData(platform: TargetPlatform.iOS),
);
final editor =
EditorSandBox(tester: tester, document: document, autofocus: true);
await editor.pump();
await tester.tapAt(tester.getTopLeft(find.byType(FleatherEditor)) +
const Offset(1, 1));
Expand Down Expand Up @@ -481,6 +574,7 @@ void prepareClipboard() {
});
}

@isTest
Future<void> testWidgetsWithPlatform(String description,
WidgetTesterCallback callback, TargetPlatform platform) async {
testWidgets(description, (tester) async {
Expand Down

0 comments on commit 2a588c6

Please sign in to comment.