mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
Merge pull request #857 from LucasXu0/test/internal_key_event_handlers
implement white_space_handler & update_text_style_by_command_X test
This commit is contained in:
@ -41,6 +41,30 @@ extension TextNodeExtension on TextNode {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool allNotSatisfyInSelection(String styleKey, Selection selection) {
|
||||||
|
final ops = delta.whereType<TextInsert>();
|
||||||
|
final startOffset =
|
||||||
|
selection.isBackward ? selection.start.offset : selection.end.offset;
|
||||||
|
final endOffset =
|
||||||
|
selection.isBackward ? selection.end.offset : selection.start.offset;
|
||||||
|
var start = 0;
|
||||||
|
for (final op in ops) {
|
||||||
|
if (start >= endOffset) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
final length = op.length;
|
||||||
|
if (start < endOffset && start + length > startOffset) {
|
||||||
|
if (op.attributes != null &&
|
||||||
|
op.attributes!.containsKey(styleKey) &&
|
||||||
|
op.attributes![styleKey] == true) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
start += length;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TextNodesExtension on List<TextNode> {
|
extension TextNodesExtension on List<TextNode> {
|
||||||
|
@ -72,8 +72,8 @@ class _CheckboxNodeWidgetState extends State<CheckboxNodeWidget>
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
|
key: iconKey,
|
||||||
child: FlowySvg(
|
child: FlowySvg(
|
||||||
key: iconKey,
|
|
||||||
size: Size.square(_iconSize),
|
size: Size.square(_iconSize),
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
top: topPadding, right: _iconRightPadding),
|
top: topPadding, right: _iconRightPadding),
|
||||||
@ -149,7 +149,11 @@ class _CheckboxNodeWidgetState extends State<CheckboxNodeWidget>
|
|||||||
style: widget.textNode.attributes.check
|
style: widget.textNode.attributes.check
|
||||||
? span.style?.copyWith(
|
? span.style?.copyWith(
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
decoration: TextDecoration.lineThrough,
|
decoration: TextDecoration.combine([
|
||||||
|
TextDecoration.lineThrough,
|
||||||
|
if (span.style?.decoration != null)
|
||||||
|
span.style!.decoration!
|
||||||
|
]),
|
||||||
)
|
)
|
||||||
: span.style,
|
: span.style,
|
||||||
recognizer: span.recognizer,
|
recognizer: span.recognizer,
|
||||||
|
@ -9,6 +9,13 @@ import 'package:flowy_editor/src/operation/transaction_builder.dart';
|
|||||||
import 'package:flowy_editor/src/render/rich_text/rich_text_style.dart';
|
import 'package:flowy_editor/src/render/rich_text/rich_text_style.dart';
|
||||||
import 'package:flowy_editor/src/service/keyboard_service.dart';
|
import 'package:flowy_editor/src/service/keyboard_service.dart';
|
||||||
|
|
||||||
|
@visibleForTesting
|
||||||
|
List<String> get checkboxListSymbols => _checkboxListSymbols;
|
||||||
|
@visibleForTesting
|
||||||
|
List<String> get unCheckboxListSymbols => _unCheckboxListSymbols;
|
||||||
|
@visibleForTesting
|
||||||
|
List<String> get bulletedListSymbols => _bulletedListSymbols;
|
||||||
|
|
||||||
const _bulletedListSymbols = ['*', '-'];
|
const _bulletedListSymbols = ['*', '-'];
|
||||||
const _checkboxListSymbols = ['[x]', '-[x]'];
|
const _checkboxListSymbols = ['[x]', '-[x]'];
|
||||||
const _unCheckboxListSymbols = ['[]', '-[]'];
|
const _unCheckboxListSymbols = ['[]', '-[]'];
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
import 'package:flowy_editor/src/service/keyboard_service.dart';
|
import 'package:flowy_editor/flowy_editor.dart';
|
||||||
import 'package:flowy_editor/src/service/render_plugin_service.dart';
|
|
||||||
import 'package:flowy_editor/src/service/scroll_service.dart';
|
|
||||||
import 'package:flowy_editor/src/service/selection_service.dart';
|
|
||||||
import 'package:flowy_editor/src/service/toolbar_service.dart';
|
import 'package:flowy_editor/src/service/toolbar_service.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
@ -26,6 +23,13 @@ class FlowyService {
|
|||||||
|
|
||||||
// input service
|
// input service
|
||||||
final inputServiceKey = GlobalKey(debugLabel: 'flowy_input_service');
|
final inputServiceKey = GlobalKey(debugLabel: 'flowy_input_service');
|
||||||
|
FlowyInputService? get inputService {
|
||||||
|
if (inputServiceKey.currentState != null &&
|
||||||
|
inputServiceKey.currentState is FlowyInputService) {
|
||||||
|
return inputServiceKey.currentState! as FlowyInputService;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// render plugin service
|
// render plugin service
|
||||||
late FlowyRenderPlugin renderPluginService;
|
late FlowyRenderPlugin renderPluginService;
|
||||||
|
@ -47,13 +47,11 @@ class EditorWidgetTester {
|
|||||||
insert(TextNode.empty());
|
insert(TextNode.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
void insertTextNode(String? text, {Attributes? attributes}) {
|
void insertTextNode(String? text, {Attributes? attributes, Delta? delta}) {
|
||||||
insert(
|
insert(
|
||||||
TextNode(
|
TextNode(
|
||||||
type: 'text',
|
type: 'text',
|
||||||
delta: Delta(
|
delta: delta ?? Delta([TextInsert(text ?? 'Test')]),
|
||||||
[TextInsert(text ?? 'Test')],
|
|
||||||
),
|
|
||||||
attributes: attributes,
|
attributes: attributes,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -70,6 +68,31 @@ class EditorWidgetTester {
|
|||||||
_editorState.service.selectionService.updateSelection(selection);
|
_editorState.service.selectionService.updateSelection(selection);
|
||||||
}
|
}
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(_editorState.service.selectionService.currentSelection.value,
|
||||||
|
selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> insertText(TextNode textNode, String text, int offset,
|
||||||
|
{Selection? selection}) async {
|
||||||
|
await apply([
|
||||||
|
TextEditingDeltaInsertion(
|
||||||
|
oldText: textNode.toRawString(),
|
||||||
|
textInserted: text,
|
||||||
|
insertionOffset: offset,
|
||||||
|
selection: selection != null
|
||||||
|
? TextSelection(
|
||||||
|
baseOffset: selection.start.offset,
|
||||||
|
extentOffset: selection.end.offset)
|
||||||
|
: TextSelection.collapsed(offset: offset),
|
||||||
|
composing: TextRange.empty,
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> apply(List<TextEditingDelta> deltas) async {
|
||||||
|
_editorState.service.inputService?.apply(deltas);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> pressLogicKey(
|
Future<void> pressLogicKey(
|
||||||
|
@ -79,6 +79,9 @@ extension on LogicalKeyboardKey {
|
|||||||
if (this == LogicalKeyboardKey.enter) {
|
if (this == LogicalKeyboardKey.enter) {
|
||||||
return PhysicalKeyboardKey.enter;
|
return PhysicalKeyboardKey.enter;
|
||||||
}
|
}
|
||||||
|
if (this == LogicalKeyboardKey.space) {
|
||||||
|
return PhysicalKeyboardKey.space;
|
||||||
|
}
|
||||||
if (this == LogicalKeyboardKey.backspace) {
|
if (this == LogicalKeyboardKey.backspace) {
|
||||||
return PhysicalKeyboardKey.backspace;
|
return PhysicalKeyboardKey.backspace;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
import 'package:flowy_editor/flowy_editor.dart';
|
||||||
|
import 'package:flowy_editor/src/render/rich_text/default_selectable.dart';
|
||||||
|
import 'package:flowy_editor/src/render/rich_text/rich_text_style.dart';
|
||||||
|
import 'package:flowy_editor/src/extensions/text_node_extensions.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import '../../infra/test_editor.dart';
|
||||||
|
|
||||||
|
void main() async {
|
||||||
|
setUpAll(() {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
});
|
||||||
|
|
||||||
|
group('delete_text_handler.dart', () {
|
||||||
|
testWidgets('Presses backspace key in empty document', (tester) async {
|
||||||
|
// Before
|
||||||
|
//
|
||||||
|
// [BIUS]Welcome to Appflowy 😁[BIUS]
|
||||||
|
//
|
||||||
|
// After
|
||||||
|
//
|
||||||
|
// [checkbox]Welcome to Appflowy 😁
|
||||||
|
//
|
||||||
|
const text = 'Welcome to Appflowy 😁';
|
||||||
|
final editor = tester.editor
|
||||||
|
..insertTextNode(
|
||||||
|
'',
|
||||||
|
attributes: {
|
||||||
|
StyleKey.subtype: StyleKey.checkbox,
|
||||||
|
StyleKey.checkbox: false,
|
||||||
|
},
|
||||||
|
delta: Delta([
|
||||||
|
TextInsert(text, {
|
||||||
|
StyleKey.bold: true,
|
||||||
|
StyleKey.italic: true,
|
||||||
|
StyleKey.underline: true,
|
||||||
|
StyleKey.strikethrough: true,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
await editor.startTesting();
|
||||||
|
await editor.updateSelection(
|
||||||
|
Selection.single(path: [0], startOffset: 0),
|
||||||
|
);
|
||||||
|
|
||||||
|
final selection =
|
||||||
|
Selection.single(path: [0], startOffset: 0, endOffset: text.length);
|
||||||
|
var node = editor.nodeAtPath([0]) as TextNode;
|
||||||
|
var state = node.key?.currentState as DefaultSelectable;
|
||||||
|
var checkboxWidget = find.byKey(state.iconKey!);
|
||||||
|
await tester.tap(checkboxWidget);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(node.attributes.check, true);
|
||||||
|
|
||||||
|
expect(node.allSatisfyBoldInSelection(selection), true);
|
||||||
|
expect(node.allSatisfyItalicInSelection(selection), true);
|
||||||
|
expect(node.allSatisfyUnderlineInSelection(selection), true);
|
||||||
|
expect(node.allSatisfyStrikethroughInSelection(selection), true);
|
||||||
|
|
||||||
|
node = editor.nodeAtPath([0]) as TextNode;
|
||||||
|
state = node.key?.currentState as DefaultSelectable;
|
||||||
|
await tester.ensureVisible(find.byKey(state.iconKey!));
|
||||||
|
await tester.tap(find.byKey(state.iconKey!));
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(node.attributes.check, false);
|
||||||
|
expect(node.allSatisfyBoldInSelection(selection), true);
|
||||||
|
expect(node.allSatisfyItalicInSelection(selection), true);
|
||||||
|
expect(node.allSatisfyUnderlineInSelection(selection), true);
|
||||||
|
expect(node.allSatisfyStrikethroughInSelection(selection), true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@ -18,7 +18,6 @@ void main() async {
|
|||||||
LogicalKeyboardKey.keyB,
|
LogicalKeyboardKey.keyB,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Presses Command + I to update text style', (tester) async {
|
testWidgets('Presses Command + I to update text style', (tester) async {
|
||||||
await _testUpdateTextStyleByCommandX(
|
await _testUpdateTextStyleByCommandX(
|
||||||
tester,
|
tester,
|
||||||
@ -26,7 +25,6 @@ void main() async {
|
|||||||
LogicalKeyboardKey.keyI,
|
LogicalKeyboardKey.keyI,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Presses Command + U to update text style', (tester) async {
|
testWidgets('Presses Command + U to update text style', (tester) async {
|
||||||
await _testUpdateTextStyleByCommandX(
|
await _testUpdateTextStyleByCommandX(
|
||||||
tester,
|
tester,
|
||||||
@ -34,7 +32,6 @@ void main() async {
|
|||||||
LogicalKeyboardKey.keyU,
|
LogicalKeyboardKey.keyU,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Presses Command + S to update text style', (tester) async {
|
testWidgets('Presses Command + S to update text style', (tester) async {
|
||||||
await _testUpdateTextStyleByCommandX(
|
await _testUpdateTextStyleByCommandX(
|
||||||
tester,
|
tester,
|
||||||
@ -83,5 +80,49 @@ Future<void> _testUpdateTextStyleByCommandX(
|
|||||||
isMetaPressed: true,
|
isMetaPressed: true,
|
||||||
);
|
);
|
||||||
textNode = editor.nodeAtPath([1]) as TextNode;
|
textNode = editor.nodeAtPath([1]) as TextNode;
|
||||||
expect(textNode.allSatisfyInSelection(matchStyle, selection), false);
|
expect(textNode.allNotSatisfyInSelection(matchStyle, selection), true);
|
||||||
|
|
||||||
|
selection = Selection(
|
||||||
|
start: Position(path: [0], offset: 0),
|
||||||
|
end: Position(path: [2], offset: text.length),
|
||||||
|
);
|
||||||
|
await editor.updateSelection(selection);
|
||||||
|
await editor.pressLogicKey(
|
||||||
|
key,
|
||||||
|
isShiftPressed: key == LogicalKeyboardKey.keyS,
|
||||||
|
isMetaPressed: true,
|
||||||
|
);
|
||||||
|
var nodes = editor.editorState.service.selectionService.currentSelectedNodes
|
||||||
|
.whereType<TextNode>();
|
||||||
|
expect(nodes.length, 3);
|
||||||
|
for (final node in nodes) {
|
||||||
|
expect(
|
||||||
|
node.allSatisfyInSelection(
|
||||||
|
matchStyle,
|
||||||
|
Selection.single(
|
||||||
|
path: node.path, startOffset: 0, endOffset: text.length),
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await editor.updateSelection(selection);
|
||||||
|
await editor.pressLogicKey(
|
||||||
|
key,
|
||||||
|
isShiftPressed: key == LogicalKeyboardKey.keyS,
|
||||||
|
isMetaPressed: true,
|
||||||
|
);
|
||||||
|
nodes = editor.editorState.service.selectionService.currentSelectedNodes
|
||||||
|
.whereType<TextNode>();
|
||||||
|
expect(nodes.length, 3);
|
||||||
|
for (final node in nodes) {
|
||||||
|
expect(
|
||||||
|
node.allNotSatisfyInSelection(
|
||||||
|
matchStyle,
|
||||||
|
Selection.single(
|
||||||
|
path: node.path, startOffset: 0, endOffset: text.length),
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,178 @@
|
|||||||
|
import 'package:flowy_editor/flowy_editor.dart';
|
||||||
|
import 'package:flowy_editor/src/render/rich_text/rich_text_style.dart';
|
||||||
|
import 'package:flowy_editor/src/service/internal_key_event_handlers/whitespace_handler.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('white_space_handler.dart', () {
|
||||||
|
// Before
|
||||||
|
//
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
//
|
||||||
|
// After
|
||||||
|
// [h1]Welcome to Appflowy 😁
|
||||||
|
// [h2]Welcome to Appflowy 😁
|
||||||
|
// [h3]Welcome to Appflowy 😁
|
||||||
|
// [h4]Welcome to Appflowy 😁
|
||||||
|
// [h5]Welcome to Appflowy 😁
|
||||||
|
// [h6]Welcome to Appflowy 😁
|
||||||
|
//
|
||||||
|
testWidgets('Presses whitespace key after #*', (tester) async {
|
||||||
|
const maxSignCount = 6;
|
||||||
|
const text = 'Welcome to Appflowy 😁';
|
||||||
|
final editor = tester.editor;
|
||||||
|
for (var i = 1; i <= maxSignCount; i++) {
|
||||||
|
editor.insertTextNode('${'#' * i}$text');
|
||||||
|
}
|
||||||
|
await editor.startTesting();
|
||||||
|
|
||||||
|
for (var i = 1; i <= maxSignCount; i++) {
|
||||||
|
await editor.updateSelection(
|
||||||
|
Selection.single(path: [i - 1], startOffset: i),
|
||||||
|
);
|
||||||
|
await editor.pressLogicKey(LogicalKeyboardKey.space);
|
||||||
|
|
||||||
|
final textNode = (editor.nodeAtPath([i - 1]) as TextNode);
|
||||||
|
|
||||||
|
expect(textNode.subtype, StyleKey.heading);
|
||||||
|
// StyleKey.h1 ~ StyleKey.h6
|
||||||
|
expect(textNode.attributes.heading, 'h$i');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Before
|
||||||
|
//
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
//
|
||||||
|
// After
|
||||||
|
// [h1]##Welcome to Appflowy 😁
|
||||||
|
// [h2]##Welcome to Appflowy 😁
|
||||||
|
// [h3]##Welcome to Appflowy 😁
|
||||||
|
// [h4]##Welcome to Appflowy 😁
|
||||||
|
// [h5]##Welcome to Appflowy 😁
|
||||||
|
// [h6]##Welcome to Appflowy 😁
|
||||||
|
//
|
||||||
|
testWidgets('Presses whitespace key inside #*', (tester) async {
|
||||||
|
const maxSignCount = 6;
|
||||||
|
const text = 'Welcome to Appflowy 😁';
|
||||||
|
final editor = tester.editor;
|
||||||
|
for (var i = 1; i <= maxSignCount; i++) {
|
||||||
|
editor.insertTextNode('${'###' * i}$text');
|
||||||
|
}
|
||||||
|
await editor.startTesting();
|
||||||
|
|
||||||
|
for (var i = 1; i <= maxSignCount; i++) {
|
||||||
|
await editor.updateSelection(
|
||||||
|
Selection.single(path: [i - 1], startOffset: i),
|
||||||
|
);
|
||||||
|
await editor.pressLogicKey(LogicalKeyboardKey.space);
|
||||||
|
|
||||||
|
final textNode = (editor.nodeAtPath([i - 1]) as TextNode);
|
||||||
|
|
||||||
|
expect(textNode.subtype, StyleKey.heading);
|
||||||
|
// StyleKey.h1 ~ StyleKey.h6
|
||||||
|
expect(textNode.attributes.heading, 'h$i');
|
||||||
|
expect(textNode.toRawString().startsWith('##'), true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Before
|
||||||
|
//
|
||||||
|
// Welcome to Appflowy 😁
|
||||||
|
//
|
||||||
|
// After
|
||||||
|
// [h1 ~ h6]##Welcome to Appflowy 😁
|
||||||
|
//
|
||||||
|
testWidgets('Presses whitespace key in heading styled text',
|
||||||
|
(tester) async {
|
||||||
|
const text = 'Welcome to Appflowy 😁';
|
||||||
|
final editor = tester.editor..insertTextNode(text);
|
||||||
|
|
||||||
|
await editor.startTesting();
|
||||||
|
|
||||||
|
const maxSignCount = 6;
|
||||||
|
for (var i = 1; i <= maxSignCount; i++) {
|
||||||
|
await editor.updateSelection(
|
||||||
|
Selection.single(path: [0], startOffset: 0),
|
||||||
|
);
|
||||||
|
|
||||||
|
final textNode = (editor.nodeAtPath([0]) as TextNode);
|
||||||
|
|
||||||
|
await editor.insertText(textNode, '#' * i, 0);
|
||||||
|
await editor.pressLogicKey(LogicalKeyboardKey.space);
|
||||||
|
|
||||||
|
expect(textNode.subtype, StyleKey.heading);
|
||||||
|
// StyleKey.h2 ~ StyleKey.h6
|
||||||
|
expect(textNode.attributes.heading, 'h$i');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Presses whitespace key after (un)checkbox symbols',
|
||||||
|
(tester) async {
|
||||||
|
const text = 'Welcome to Appflowy 😁';
|
||||||
|
final editor = tester.editor..insertTextNode(text);
|
||||||
|
await editor.startTesting();
|
||||||
|
|
||||||
|
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||||
|
for (final symbol in unCheckboxListSymbols) {
|
||||||
|
await editor.updateSelection(
|
||||||
|
Selection.single(path: [0], startOffset: 0),
|
||||||
|
);
|
||||||
|
await editor.insertText(textNode, symbol, 0);
|
||||||
|
await editor.pressLogicKey(LogicalKeyboardKey.space);
|
||||||
|
expect(textNode.subtype, StyleKey.checkbox);
|
||||||
|
expect(textNode.attributes.check, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Presses whitespace key after checkbox symbols',
|
||||||
|
(tester) async {
|
||||||
|
const text = 'Welcome to Appflowy 😁';
|
||||||
|
final editor = tester.editor..insertTextNode(text);
|
||||||
|
await editor.startTesting();
|
||||||
|
|
||||||
|
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||||
|
for (final symbol in checkboxListSymbols) {
|
||||||
|
await editor.updateSelection(
|
||||||
|
Selection.single(path: [0], startOffset: 0),
|
||||||
|
);
|
||||||
|
await editor.insertText(textNode, symbol, 0);
|
||||||
|
await editor.pressLogicKey(LogicalKeyboardKey.space);
|
||||||
|
expect(textNode.subtype, StyleKey.checkbox);
|
||||||
|
expect(textNode.attributes.check, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Presses whitespace key after bulleted list', (tester) async {
|
||||||
|
const text = 'Welcome to Appflowy 😁';
|
||||||
|
final editor = tester.editor..insertTextNode(text);
|
||||||
|
await editor.startTesting();
|
||||||
|
|
||||||
|
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||||
|
for (final symbol in bulletedListSymbols) {
|
||||||
|
await editor.updateSelection(
|
||||||
|
Selection.single(path: [0], startOffset: 0),
|
||||||
|
);
|
||||||
|
await editor.insertText(textNode, symbol, 0);
|
||||||
|
await editor.pressLogicKey(LogicalKeyboardKey.space);
|
||||||
|
expect(textNode.subtype, StyleKey.bulletedList);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Reference in New Issue
Block a user