mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
test: implement delete key test for styled text
This commit is contained in:
parent
c008f3369c
commit
c66e1e4df8
@ -80,11 +80,13 @@ KeyEventResult _handleBackspace(EditorState editorState, RawKeyEvent event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
KeyEventResult _handleDelete(EditorState editorState, RawKeyEvent event) {
|
KeyEventResult _handleDelete(EditorState editorState, RawKeyEvent event) {
|
||||||
final selection = editorState.service.selectionService.currentSelection.value;
|
var selection = editorState.service.selectionService.currentSelection.value;
|
||||||
if (selection == null) {
|
if (selection == null) {
|
||||||
return KeyEventResult.ignored;
|
return KeyEventResult.ignored;
|
||||||
}
|
}
|
||||||
final nodes = editorState.service.selectionService.currentSelectedNodes;
|
var nodes = editorState.service.selectionService.currentSelectedNodes;
|
||||||
|
nodes = selection.isBackward ? nodes : nodes.reversed.toList(growable: false);
|
||||||
|
selection = selection.isBackward ? selection : selection.reversed;
|
||||||
// make sure all nodes is [TextNode].
|
// make sure all nodes is [TextNode].
|
||||||
final textNodes = nodes.whereType<TextNode>().toList();
|
final textNodes = nodes.whereType<TextNode>().toList();
|
||||||
if (textNodes.length != nodes.length) {
|
if (textNodes.length != nodes.length) {
|
||||||
|
@ -95,6 +95,15 @@ class EditorWidgetTester {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension TestString on String {
|
||||||
|
String safeSubString([int start = 0, int? end]) {
|
||||||
|
end ??= length - 1;
|
||||||
|
end = end.clamp(start, length - 1);
|
||||||
|
final sRunes = runes;
|
||||||
|
return String.fromCharCodes(sRunes, start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension TestEditorExtension on WidgetTester {
|
extension TestEditorExtension on WidgetTester {
|
||||||
EditorWidgetTester get editor =>
|
EditorWidgetTester get editor =>
|
||||||
EditorWidgetTester(tester: this)..initialize();
|
EditorWidgetTester(tester: this)..initialize();
|
||||||
|
@ -58,6 +58,9 @@ extension on LogicalKeyboardKey {
|
|||||||
if (this == LogicalKeyboardKey.backspace) {
|
if (this == LogicalKeyboardKey.backspace) {
|
||||||
return PhysicalKeyboardKey.backspace;
|
return PhysicalKeyboardKey.backspace;
|
||||||
}
|
}
|
||||||
|
if (this == LogicalKeyboardKey.delete) {
|
||||||
|
return PhysicalKeyboardKey.delete;
|
||||||
|
}
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,87 @@ void main() async {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Before
|
||||||
|
//
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
//
|
||||||
|
// After
|
||||||
|
//
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
// Welcome t Appflowy 😁
|
||||||
|
// Welcome Appflowy 😁
|
||||||
|
//
|
||||||
|
// Then
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
//
|
||||||
|
testWidgets(
|
||||||
|
'Presses backspace key in non-empty document and selection is backward',
|
||||||
|
(tester) async {
|
||||||
|
await _deleteTextByBackspace(tester, true);
|
||||||
|
});
|
||||||
|
testWidgets(
|
||||||
|
'Presses backspace key in non-empty document and selection is forward',
|
||||||
|
(tester) async {
|
||||||
|
await _deleteTextByBackspace(tester, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Before
|
||||||
|
//
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
//
|
||||||
|
// After
|
||||||
|
//
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
// Welcome t Appflowy 😁
|
||||||
|
// Welcome Appflowy 😁
|
||||||
|
//
|
||||||
|
// Then
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
//
|
||||||
|
testWidgets(
|
||||||
|
'Presses delete key in non-empty document and selection is backward',
|
||||||
|
(tester) async {
|
||||||
|
await _deleteTextByDelete(tester, true);
|
||||||
|
});
|
||||||
|
testWidgets(
|
||||||
|
'Presses delete key in non-empty document and selection is forward',
|
||||||
|
(tester) async {
|
||||||
|
await _deleteTextByDelete(tester, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Before
|
||||||
|
//
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
//
|
||||||
|
// After
|
||||||
|
//
|
||||||
|
// Welcome to Appflowy 😁Welcome Appflowy 😁
|
||||||
|
testWidgets(
|
||||||
|
'Presses delete key in non-empty document and selection is at the end of the text',
|
||||||
|
(tester) async {
|
||||||
|
const text = 'Welcome to Appflowy 😁';
|
||||||
|
final editor = tester.editor
|
||||||
|
..insertTextNode(text)
|
||||||
|
..insertTextNode(text);
|
||||||
|
await editor.startTesting();
|
||||||
|
|
||||||
|
// delete 'o'
|
||||||
|
await editor.updateSelection(
|
||||||
|
Selection.single(path: [0], startOffset: text.length),
|
||||||
|
);
|
||||||
|
await editor.pressLogicKey(LogicalKeyboardKey.delete);
|
||||||
|
|
||||||
|
expect(editor.documentLength, 1);
|
||||||
|
expect(editor.documentSelection,
|
||||||
|
Selection.single(path: [0], startOffset: text.length));
|
||||||
|
expect((editor.nodeAtPath([0]) as TextNode).toRawString(), text * 2);
|
||||||
|
});
|
||||||
|
|
||||||
// Before
|
// Before
|
||||||
//
|
//
|
||||||
// Welcome to Appflowy 😁
|
// Welcome to Appflowy 😁
|
||||||
@ -47,12 +128,49 @@ void main() async {
|
|||||||
// Welcome to Appflowy 😁
|
// Welcome to Appflowy 😁
|
||||||
// [Style] Welcome to Appflowy 😁Welcome to Appflowy 😁
|
// [Style] Welcome to Appflowy 😁Welcome to Appflowy 😁
|
||||||
//
|
//
|
||||||
testWidgets('Presses backspace key in styled text', (tester) async {
|
testWidgets('Presses backspace key in styled text (checkbox)',
|
||||||
await _deleteStyledText(tester, StyleKey.checkbox);
|
(tester) async {
|
||||||
|
await _deleteStyledTextByBackspace(tester, StyleKey.checkbox);
|
||||||
|
});
|
||||||
|
testWidgets('Presses backspace key in styled text (bulletedList)',
|
||||||
|
(tester) async {
|
||||||
|
await _deleteStyledTextByBackspace(tester, StyleKey.bulletedList);
|
||||||
|
});
|
||||||
|
testWidgets('Presses backspace key in styled text (heading)', (tester) async {
|
||||||
|
await _deleteStyledTextByBackspace(tester, StyleKey.heading);
|
||||||
|
});
|
||||||
|
testWidgets('Presses backspace key in styled text (quote)', (tester) async {
|
||||||
|
await _deleteStyledTextByBackspace(tester, StyleKey.quote);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Before
|
||||||
|
//
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
// [Style] Welcome to Appflowy 😁
|
||||||
|
// [Style] Welcome to Appflowy 😁
|
||||||
|
//
|
||||||
|
// After
|
||||||
|
//
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
// [Style] Welcome to Appflowy 😁
|
||||||
|
//
|
||||||
|
testWidgets('Presses delete key in styled text (checkbox)', (tester) async {
|
||||||
|
await _deleteStyledTextByDelete(tester, StyleKey.checkbox);
|
||||||
|
});
|
||||||
|
testWidgets('Presses delete key in styled text (bulletedList)',
|
||||||
|
(tester) async {
|
||||||
|
await _deleteStyledTextByDelete(tester, StyleKey.bulletedList);
|
||||||
|
});
|
||||||
|
testWidgets('Presses delete key in styled text (heading)', (tester) async {
|
||||||
|
await _deleteStyledTextByDelete(tester, StyleKey.heading);
|
||||||
|
});
|
||||||
|
testWidgets('Presses delete key in styled text (quote)', (tester) async {
|
||||||
|
await _deleteStyledTextByDelete(tester, StyleKey.quote);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _deleteStyledText(WidgetTester tester, String style) async {
|
Future<void> _deleteStyledTextByBackspace(
|
||||||
|
WidgetTester tester, String style) async {
|
||||||
const text = 'Welcome to Appflowy 😁';
|
const text = 'Welcome to Appflowy 😁';
|
||||||
Attributes attributes = {
|
Attributes attributes = {
|
||||||
StyleKey.subtype: style,
|
StyleKey.subtype: style,
|
||||||
@ -61,6 +179,8 @@ Future<void> _deleteStyledText(WidgetTester tester, String style) async {
|
|||||||
attributes[StyleKey.checkbox] = true;
|
attributes[StyleKey.checkbox] = true;
|
||||||
} else if (style == StyleKey.numberList) {
|
} else if (style == StyleKey.numberList) {
|
||||||
attributes[StyleKey.number] = 1;
|
attributes[StyleKey.number] = 1;
|
||||||
|
} else if (style == StyleKey.heading) {
|
||||||
|
attributes[StyleKey.heading] = StyleKey.h1;
|
||||||
}
|
}
|
||||||
final editor = tester.editor
|
final editor = tester.editor
|
||||||
..insertTextNode(text)
|
..insertTextNode(text)
|
||||||
@ -95,3 +215,137 @@ Future<void> _deleteStyledText(WidgetTester tester, String style) async {
|
|||||||
expect(editor.documentSelection, Selection.single(path: [1], startOffset: 0));
|
expect(editor.documentSelection, Selection.single(path: [1], startOffset: 0));
|
||||||
expect(editor.nodeAtPath([1])?.subtype, null);
|
expect(editor.nodeAtPath([1])?.subtype, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _deleteStyledTextByDelete(
|
||||||
|
WidgetTester tester, String style) async {
|
||||||
|
const text = 'Welcome to Appflowy 😁';
|
||||||
|
Attributes attributes = {
|
||||||
|
StyleKey.subtype: style,
|
||||||
|
};
|
||||||
|
if (style == StyleKey.checkbox) {
|
||||||
|
attributes[StyleKey.checkbox] = true;
|
||||||
|
} else if (style == StyleKey.numberList) {
|
||||||
|
attributes[StyleKey.number] = 1;
|
||||||
|
} else if (style == StyleKey.heading) {
|
||||||
|
attributes[StyleKey.heading] = StyleKey.h1;
|
||||||
|
}
|
||||||
|
final editor = tester.editor
|
||||||
|
..insertTextNode(text)
|
||||||
|
..insertTextNode(text, attributes: attributes)
|
||||||
|
..insertTextNode(text, attributes: attributes);
|
||||||
|
|
||||||
|
await editor.startTesting();
|
||||||
|
await editor.updateSelection(
|
||||||
|
Selection.single(path: [1], startOffset: 0),
|
||||||
|
);
|
||||||
|
for (var i = 1; i < text.length; i++) {
|
||||||
|
await editor.pressLogicKey(
|
||||||
|
LogicalKeyboardKey.delete,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
editor.documentSelection, Selection.single(path: [1], startOffset: 0));
|
||||||
|
expect(editor.nodeAtPath([1])?.subtype, style);
|
||||||
|
expect((editor.nodeAtPath([1]) as TextNode).toRawString(),
|
||||||
|
text.safeSubString(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
await editor.pressLogicKey(
|
||||||
|
LogicalKeyboardKey.delete,
|
||||||
|
);
|
||||||
|
expect(editor.documentLength, 2);
|
||||||
|
expect(editor.documentSelection, Selection.single(path: [1], startOffset: 0));
|
||||||
|
expect(editor.nodeAtPath([1])?.subtype, style);
|
||||||
|
expect((editor.nodeAtPath([1]) as TextNode).toRawString(), text);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _deleteTextByBackspace(
|
||||||
|
WidgetTester tester, bool isBackwardSelection) async {
|
||||||
|
const text = 'Welcome to Appflowy 😁';
|
||||||
|
final editor = tester.editor
|
||||||
|
..insertTextNode(text)
|
||||||
|
..insertTextNode(text)
|
||||||
|
..insertTextNode(text);
|
||||||
|
await editor.startTesting();
|
||||||
|
|
||||||
|
// delete 'o'
|
||||||
|
await editor.updateSelection(
|
||||||
|
Selection.single(path: [1], startOffset: 10),
|
||||||
|
);
|
||||||
|
await editor.pressLogicKey(LogicalKeyboardKey.backspace);
|
||||||
|
|
||||||
|
expect(editor.documentLength, 3);
|
||||||
|
expect(editor.documentSelection, Selection.single(path: [1], startOffset: 9));
|
||||||
|
expect((editor.nodeAtPath([1]) as TextNode).toRawString(),
|
||||||
|
'Welcome t Appflowy 😁');
|
||||||
|
|
||||||
|
// delete 'to '
|
||||||
|
await editor.updateSelection(
|
||||||
|
Selection.single(path: [2], startOffset: 8, endOffset: 11),
|
||||||
|
);
|
||||||
|
await editor.pressLogicKey(LogicalKeyboardKey.backspace);
|
||||||
|
expect(editor.documentLength, 3);
|
||||||
|
expect(editor.documentSelection, Selection.single(path: [2], startOffset: 8));
|
||||||
|
expect((editor.nodeAtPath([2]) as TextNode).toRawString(),
|
||||||
|
'Welcome Appflowy 😁');
|
||||||
|
|
||||||
|
// delete 'Appflowy 😁
|
||||||
|
// Welcome t Appflowy 😁
|
||||||
|
// Welcome '
|
||||||
|
final start = Position(path: [0], offset: 11);
|
||||||
|
final end = Position(path: [2], offset: 8);
|
||||||
|
await editor.updateSelection(Selection(
|
||||||
|
start: isBackwardSelection ? start : end,
|
||||||
|
end: isBackwardSelection ? end : start));
|
||||||
|
await editor.pressLogicKey(LogicalKeyboardKey.backspace);
|
||||||
|
expect(editor.documentLength, 1);
|
||||||
|
expect(
|
||||||
|
editor.documentSelection, Selection.single(path: [0], startOffset: 11));
|
||||||
|
expect((editor.nodeAtPath([0]) as TextNode).toRawString(),
|
||||||
|
'Welcome to Appflowy 😁');
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _deleteTextByDelete(
|
||||||
|
WidgetTester tester, bool isBackwardSelection) async {
|
||||||
|
const text = 'Welcome to Appflowy 😁';
|
||||||
|
final editor = tester.editor
|
||||||
|
..insertTextNode(text)
|
||||||
|
..insertTextNode(text)
|
||||||
|
..insertTextNode(text);
|
||||||
|
await editor.startTesting();
|
||||||
|
|
||||||
|
// delete 'o'
|
||||||
|
await editor.updateSelection(
|
||||||
|
Selection.single(path: [1], startOffset: 9),
|
||||||
|
);
|
||||||
|
await editor.pressLogicKey(LogicalKeyboardKey.delete);
|
||||||
|
|
||||||
|
expect(editor.documentLength, 3);
|
||||||
|
expect(editor.documentSelection, Selection.single(path: [1], startOffset: 9));
|
||||||
|
expect((editor.nodeAtPath([1]) as TextNode).toRawString(),
|
||||||
|
'Welcome t Appflowy 😁');
|
||||||
|
|
||||||
|
// delete 'to '
|
||||||
|
await editor.updateSelection(
|
||||||
|
Selection.single(path: [2], startOffset: 8, endOffset: 11),
|
||||||
|
);
|
||||||
|
await editor.pressLogicKey(LogicalKeyboardKey.delete);
|
||||||
|
expect(editor.documentLength, 3);
|
||||||
|
expect(editor.documentSelection, Selection.single(path: [2], startOffset: 8));
|
||||||
|
expect((editor.nodeAtPath([2]) as TextNode).toRawString(),
|
||||||
|
'Welcome Appflowy 😁');
|
||||||
|
|
||||||
|
// delete 'Appflowy 😁
|
||||||
|
// Welcome t Appflowy 😁
|
||||||
|
// Welcome '
|
||||||
|
final start = Position(path: [0], offset: 11);
|
||||||
|
final end = Position(path: [2], offset: 8);
|
||||||
|
await editor.updateSelection(Selection(
|
||||||
|
start: isBackwardSelection ? start : end,
|
||||||
|
end: isBackwardSelection ? end : start));
|
||||||
|
await editor.pressLogicKey(LogicalKeyboardKey.delete);
|
||||||
|
expect(editor.documentLength, 1);
|
||||||
|
expect(
|
||||||
|
editor.documentSelection, Selection.single(path: [0], startOffset: 11));
|
||||||
|
expect((editor.nodeAtPath([0]) as TextNode).toRawString(),
|
||||||
|
'Welcome to Appflowy 😁');
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user