test: migrate the markdown_syntax_to_styled_text
This commit is contained in:
parent
3020ce0c4c
commit
4a32d0a460
7 changed files with 279 additions and 256 deletions
|
|
@ -0,0 +1,22 @@
|
|||
import 'package:appflowy_editor/src/editor/editor_component/service/shortcuts/character_shortcut_event.dart';
|
||||
import 'package:appflowy_editor/src/editor/editor_component/service/shortcuts/character_shortcut_events/format_by_wrapping_with_double_character/handle_format_by_wrapping_with_double_character.dart';
|
||||
|
||||
const _tile = '~';
|
||||
|
||||
/// format the text surrounded by double asterisks to bold
|
||||
///
|
||||
/// - support
|
||||
/// - desktop
|
||||
/// - mobile
|
||||
/// - web
|
||||
///
|
||||
final CharacterShortcutEvent formatDoubleTilesToStrikethrough =
|
||||
CharacterShortcutEvent(
|
||||
key: 'format the text surrounded by double asterisks to bold',
|
||||
character: _tile,
|
||||
handler: (editorState) async => handleFormatByWrappingWithDoubleCharacter(
|
||||
editorState: editorState,
|
||||
character: _tile,
|
||||
formatStyle: DoubleCharacterFormatStyle.strikethrough,
|
||||
),
|
||||
);
|
||||
|
|
@ -5,6 +5,7 @@ import 'package:appflowy_editor/appflowy_editor.dart';
|
|||
// If we have more in the future, we should add them in this enum and update the [style] variable in [handleDoubleCharactersFormat].
|
||||
enum DoubleCharacterFormatStyle {
|
||||
bold,
|
||||
strikethrough,
|
||||
}
|
||||
|
||||
bool handleFormatByWrappingWithDoubleCharacter({
|
||||
|
|
@ -79,6 +80,9 @@ bool handleFormatByWrappingWithDoubleCharacter({
|
|||
case DoubleCharacterFormatStyle.bold:
|
||||
style = 'bold';
|
||||
break;
|
||||
case DoubleCharacterFormatStyle.strikethrough:
|
||||
style = 'strikethrough';
|
||||
break;
|
||||
default:
|
||||
style = '';
|
||||
assert(false, 'Invalid format style');
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_editor/src/editor/editor_component/service/shortcuts/character_shortcut_events/format_by_wrapping_with_double_character/format_bold.dart';
|
||||
import 'package:appflowy_editor/src/editor/editor_component/service/shortcuts/character_shortcut_events/format_by_wrapping_with_double_character/format_strikethrough.dart';
|
||||
import 'package:appflowy_editor/src/editor/editor_component/service/shortcuts/character_shortcut_events/format_by_wrapping_with_single_character/format_code.dart';
|
||||
import 'package:appflowy_editor/src/editor/editor_component/service/shortcuts/character_shortcut_events/format_by_wrapping_with_single_character/format_italic.dart';
|
||||
import 'package:appflowy_editor/src/editor/editor_component/service/shortcuts/character_shortcut_events/format_by_wrapping_with_single_character/format_strikethrough.dart';
|
||||
|
|
@ -15,17 +16,22 @@ import 'package:appflowy_editor/src/editor/editor_component/service/shortcuts/ch
|
|||
// 4. tilde to strikethrough -> ~abc~
|
||||
|
||||
final List<CharacterShortcutEvent> markdownSyntaxShortcutEvents = [
|
||||
// format code, 'code'
|
||||
// format code, `code`
|
||||
formatBackquoteToCode,
|
||||
|
||||
// format italic, _italic_ or *italic*
|
||||
// format italic,
|
||||
// _italic_
|
||||
// *italic*
|
||||
formatUnderscoreToItalic,
|
||||
formatAsteriskToItalic,
|
||||
|
||||
//format strikethrough, ~strikethrough~
|
||||
// format strikethrough,
|
||||
// ~strikethrough~
|
||||
// ~~strikethrough~~
|
||||
formatTildeToStrikethrough,
|
||||
formatDoubleTilesToStrikethrough,
|
||||
|
||||
//format bold, **bold** or __bold__
|
||||
// format bold, **bold** or __bold__
|
||||
formatDoubleAsterisksToBold,
|
||||
formatDoubleUnderscoresToBold,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -56,7 +56,8 @@ class _FlowyRichTextState extends State<FlowyRichText> with SelectableMixin {
|
|||
_textKey.currentContext?.findRenderObject() as RenderParagraph;
|
||||
|
||||
RenderParagraph? get _placeholderRenderParagraph =>
|
||||
_placeholderTextKey.currentContext?.findRenderObject() as RenderParagraph;
|
||||
_placeholderTextKey.currentContext?.findRenderObject()
|
||||
as RenderParagraph?;
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant FlowyRichText oldWidget) {
|
||||
|
|
|
|||
|
|
@ -184,6 +184,10 @@ class TestableEditor {
|
|||
final keyToCharacterMap = {
|
||||
LogicalKeyboardKey.space: ' ',
|
||||
LogicalKeyboardKey.enter: '\n',
|
||||
LogicalKeyboardKey.backquote: '`',
|
||||
LogicalKeyboardKey.tilde: '~',
|
||||
LogicalKeyboardKey.asterisk: '*',
|
||||
LogicalKeyboardKey.underscore: '_',
|
||||
};
|
||||
Future<void> pressLogicKey({
|
||||
String? character,
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ void main() async {
|
|||
LogicalKeyboardKey.keyB,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Presses Command + I to update text style', (tester) async {
|
||||
await _testUpdateTextStyleByCommandX(
|
||||
tester,
|
||||
|
|
@ -30,6 +31,7 @@ void main() async {
|
|||
LogicalKeyboardKey.keyI,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Presses Command + U to update text style', (tester) async {
|
||||
await _testUpdateTextStyleByCommandX(
|
||||
tester,
|
||||
|
|
@ -38,6 +40,7 @@ void main() async {
|
|||
LogicalKeyboardKey.keyU,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Presses Command + Shift + S to update text style',
|
||||
(tester) async {
|
||||
await _testUpdateTextStyleByCommandX(
|
||||
|
|
|
|||
|
|
@ -1,509 +1,492 @@
|
|||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import '../../infra/test_editor.dart';
|
||||
|
||||
import '../../new/infra/testable_editor.dart';
|
||||
|
||||
void main() async {
|
||||
bool allInSelection(
|
||||
Node? node,
|
||||
Selection selection,
|
||||
String key,
|
||||
) {
|
||||
return node?.allSatisfyInSelection(
|
||||
selection,
|
||||
(delta) => delta.whereType<TextInsert>().every(
|
||||
(element) => element.attributes?[key] == true,
|
||||
),
|
||||
) ??
|
||||
false;
|
||||
}
|
||||
|
||||
bool allCodeInSelection(Node? node, Selection selection) => allInSelection(
|
||||
node,
|
||||
selection,
|
||||
'code',
|
||||
);
|
||||
|
||||
bool allStrikethroughInSelection(Node? node, Selection selection) =>
|
||||
allInSelection(
|
||||
node,
|
||||
selection,
|
||||
'strikethrough',
|
||||
);
|
||||
|
||||
bool allBoldInSelection(Node? node, Selection selection) => allInSelection(
|
||||
node,
|
||||
selection,
|
||||
'bold',
|
||||
);
|
||||
|
||||
bool allItalicInSelection(Node? node, Selection selection) => allInSelection(
|
||||
node,
|
||||
selection,
|
||||
'bold',
|
||||
);
|
||||
|
||||
setUpAll(() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
});
|
||||
|
||||
group('markdown_syntax_to_styled_text.dart', () {
|
||||
group('convert single backquote to code', () {
|
||||
Future<void> insertBackquote(
|
||||
EditorWidgetTester editor, {
|
||||
int repeat = 1,
|
||||
}) async {
|
||||
for (var i = 0; i < repeat; i++) {
|
||||
await editor.pressLogicKey(
|
||||
key: LogicalKeyboardKey.backquote,
|
||||
);
|
||||
}
|
||||
Future<void> insertBackquote(
|
||||
TestableEditor editor, {
|
||||
int repeat = 1,
|
||||
}) async {
|
||||
for (var i = 0; i < repeat; i++) {
|
||||
await editor.pressLogicKey(
|
||||
key: LogicalKeyboardKey.backquote,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
group('convert single backquote to code', () {
|
||||
testWidgets('`AppFlowy` to code AppFlowy', (tester) async {
|
||||
const text = '`AppFlowy';
|
||||
final editor = tester.editor..insertTextNode('');
|
||||
final editor = tester.editor..addEmptyParagraph();
|
||||
await editor.startTesting();
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0),
|
||||
);
|
||||
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
await editor.insertText(textNode, text[i], i);
|
||||
}
|
||||
|
||||
await editor.editorState.insertTextAtCurrentSelection(text);
|
||||
await insertBackquote(editor);
|
||||
final allCode = textNode.allSatisfyCodeInSelection(
|
||||
final node = editor.nodeAtPath([0]);
|
||||
|
||||
final allCode = allCodeInSelection(
|
||||
node,
|
||||
Selection.single(
|
||||
path: [0],
|
||||
startOffset: 0,
|
||||
endOffset: textNode.toPlainText().length,
|
||||
endOffset: text.length - 1,
|
||||
),
|
||||
);
|
||||
|
||||
expect(allCode, true);
|
||||
expect(textNode.toPlainText(), 'AppFlowy');
|
||||
expect(node?.delta?.toPlainText(), 'AppFlowy');
|
||||
await editor.dispose();
|
||||
});
|
||||
|
||||
testWidgets('App`Flowy` to code AppFlowy', (tester) async {
|
||||
const text = 'App`Flowy';
|
||||
final editor = tester.editor..insertTextNode('');
|
||||
final editor = tester.editor..addEmptyParagraph();
|
||||
await editor.startTesting();
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0),
|
||||
);
|
||||
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
await editor.insertText(textNode, text[i], i);
|
||||
}
|
||||
|
||||
await editor.editorState.insertTextAtCurrentSelection(text);
|
||||
|
||||
await insertBackquote(editor);
|
||||
final allCode = textNode.allSatisfyCodeInSelection(
|
||||
final node = editor.nodeAtPath([0]);
|
||||
|
||||
final allCode = allCodeInSelection(
|
||||
node,
|
||||
Selection.single(
|
||||
path: [0],
|
||||
startOffset: 3,
|
||||
endOffset: textNode.toPlainText().length,
|
||||
endOffset: text.length - 1,
|
||||
),
|
||||
);
|
||||
|
||||
expect(allCode, true);
|
||||
expect(textNode.toPlainText(), 'AppFlowy');
|
||||
expect(node?.delta?.toPlainText(), 'AppFlowy');
|
||||
await editor.dispose();
|
||||
});
|
||||
|
||||
testWidgets('`` nothing changes', (tester) async {
|
||||
const text = '`';
|
||||
final editor = tester.editor..insertTextNode('');
|
||||
final editor = tester.editor..addEmptyParagraph();
|
||||
await editor.startTesting();
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0),
|
||||
);
|
||||
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
await editor.insertText(textNode, text[i], i);
|
||||
}
|
||||
await editor.editorState.insertTextAtCurrentSelection(text);
|
||||
await insertBackquote(editor);
|
||||
final allCode = textNode.allSatisfyCodeInSelection(
|
||||
final node = editor.nodeAtPath([0]);
|
||||
final allCode = allCodeInSelection(
|
||||
node,
|
||||
Selection.single(
|
||||
path: [0],
|
||||
startOffset: 0,
|
||||
endOffset: textNode.toPlainText().length,
|
||||
endOffset: node!.delta!.toPlainText().length,
|
||||
),
|
||||
);
|
||||
|
||||
expect(allCode, false);
|
||||
expect(textNode.toPlainText(), text);
|
||||
expect(node.delta?.toPlainText(), '``');
|
||||
await editor.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
group('convert double backquote to code', () {
|
||||
Future<void> insertBackquote(
|
||||
EditorWidgetTester editor, {
|
||||
int repeat = 1,
|
||||
}) async {
|
||||
for (var i = 0; i < repeat; i++) {
|
||||
await editor.pressLogicKey(
|
||||
key: LogicalKeyboardKey.backquote,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
testWidgets('```AppFlowy`` to code `AppFlowy', (tester) async {
|
||||
const text = '```AppFlowy`';
|
||||
final editor = tester.editor..insertTextNode('');
|
||||
await editor.startTesting();
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0),
|
||||
);
|
||||
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
await editor.insertText(textNode, text[i], i);
|
||||
}
|
||||
await insertBackquote(editor);
|
||||
final allCode = textNode.allSatisfyCodeInSelection(
|
||||
Selection.single(
|
||||
path: [0],
|
||||
startOffset: 1,
|
||||
endOffset: textNode.toPlainText().length,
|
||||
),
|
||||
);
|
||||
expect(allCode, true);
|
||||
expect(textNode.toPlainText(), '`AppFlowy');
|
||||
});
|
||||
|
||||
testWidgets('```` nothing changes', (tester) async {
|
||||
const text = '```';
|
||||
final editor = tester.editor..insertTextNode('');
|
||||
final editor = tester.editor..addEmptyParagraph();
|
||||
await editor.startTesting();
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0),
|
||||
);
|
||||
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
await editor.insertText(textNode, text[i], i);
|
||||
}
|
||||
await editor.editorState.insertTextAtCurrentSelection(text);
|
||||
await insertBackquote(editor);
|
||||
final allCode = textNode.allSatisfyCodeInSelection(
|
||||
final node = editor.nodeAtPath([0]);
|
||||
final allCode = allCodeInSelection(
|
||||
node,
|
||||
Selection.single(
|
||||
path: [0],
|
||||
startOffset: 0,
|
||||
endOffset: textNode.toPlainText().length,
|
||||
endOffset: node!.delta!.toPlainText().length,
|
||||
),
|
||||
);
|
||||
|
||||
expect(allCode, false);
|
||||
expect(textNode.toPlainText(), text);
|
||||
expect(node.delta?.toPlainText(), '````');
|
||||
await editor.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
group('convert double tilde to strikethrough', () {
|
||||
Future<void> insertTilde(
|
||||
EditorWidgetTester editor, {
|
||||
TestableEditor editor, {
|
||||
int repeat = 1,
|
||||
}) async {
|
||||
for (var i = 0; i < repeat; i++) {
|
||||
await editor.pressLogicKey(character: '~');
|
||||
await editor.pressLogicKey(key: LogicalKeyboardKey.tilde);
|
||||
}
|
||||
}
|
||||
|
||||
testWidgets('~~AppFlowy~~ to strikethrough AppFlowy', (tester) async {
|
||||
const text = '~~AppFlowy~';
|
||||
final editor = tester.editor..insertTextNode('');
|
||||
final editor = tester.editor..addEmptyParagraph();
|
||||
await editor.startTesting();
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0),
|
||||
);
|
||||
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
await editor.insertText(textNode, text[i], i);
|
||||
}
|
||||
await editor.editorState.insertTextAtCurrentSelection(text);
|
||||
await insertTilde(editor);
|
||||
final allStrikethrough = textNode.allSatisfyStrikethroughInSelection(
|
||||
final node = editor.nodeAtPath([0]);
|
||||
final result = allStrikethroughInSelection(
|
||||
node,
|
||||
Selection.single(
|
||||
path: [0],
|
||||
startOffset: 0,
|
||||
endOffset: textNode.toPlainText().length,
|
||||
endOffset: node!.delta!.toPlainText().length,
|
||||
),
|
||||
);
|
||||
expect(allStrikethrough, true);
|
||||
expect(textNode.toPlainText(), 'AppFlowy');
|
||||
|
||||
expect(result, true);
|
||||
expect(node.delta?.toPlainText(), 'AppFlowy');
|
||||
await editor.dispose();
|
||||
});
|
||||
|
||||
testWidgets('App~~Flowy~~ to strikethrough AppFlowy', (tester) async {
|
||||
const text = 'App~~Flowy~';
|
||||
final editor = tester.editor..insertTextNode('');
|
||||
final editor = tester.editor..addEmptyParagraph();
|
||||
await editor.startTesting();
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0),
|
||||
);
|
||||
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
await editor.insertText(textNode, text[i], i);
|
||||
}
|
||||
await editor.editorState.insertTextAtCurrentSelection(text);
|
||||
await insertTilde(editor);
|
||||
final allStrikethrough = textNode.allSatisfyStrikethroughInSelection(
|
||||
final node = editor.nodeAtPath([0]);
|
||||
final result = allStrikethroughInSelection(
|
||||
node,
|
||||
Selection.single(
|
||||
path: [0],
|
||||
startOffset: 3,
|
||||
endOffset: textNode.toPlainText().length,
|
||||
endOffset: node!.delta!.toPlainText().length,
|
||||
),
|
||||
);
|
||||
expect(allStrikethrough, true);
|
||||
expect(textNode.toPlainText(), 'AppFlowy');
|
||||
});
|
||||
|
||||
testWidgets('~~~AppFlowy~~ to bold ~AppFlowy', (tester) async {
|
||||
const text = '~~~AppFlowy~';
|
||||
final editor = tester.editor..insertTextNode('');
|
||||
await editor.startTesting();
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0),
|
||||
);
|
||||
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
await editor.insertText(textNode, text[i], i);
|
||||
}
|
||||
await insertTilde(editor);
|
||||
final allStrikethrough = textNode.allSatisfyStrikethroughInSelection(
|
||||
Selection.single(
|
||||
path: [0],
|
||||
startOffset: 1,
|
||||
endOffset: textNode.toPlainText().length,
|
||||
),
|
||||
);
|
||||
expect(allStrikethrough, true);
|
||||
expect(textNode.toPlainText(), '~AppFlowy');
|
||||
expect(result, true);
|
||||
expect(node.delta?.toPlainText(), 'AppFlowy');
|
||||
await editor.dispose();
|
||||
});
|
||||
|
||||
testWidgets('~~~~ nothing changes', (tester) async {
|
||||
const text = '~~~';
|
||||
final editor = tester.editor..insertTextNode('');
|
||||
final editor = tester.editor..addEmptyParagraph();
|
||||
await editor.startTesting();
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0),
|
||||
);
|
||||
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
await editor.insertText(textNode, text[i], i);
|
||||
}
|
||||
await editor.editorState.insertTextAtCurrentSelection(text);
|
||||
await insertTilde(editor);
|
||||
final allStrikethrough = textNode.allSatisfyStrikethroughInSelection(
|
||||
final node = editor.nodeAtPath([0]);
|
||||
final result = allStrikethroughInSelection(
|
||||
node,
|
||||
Selection.single(
|
||||
path: [0],
|
||||
startOffset: 0,
|
||||
endOffset: textNode.toPlainText().length,
|
||||
endOffset: node!.delta!.toPlainText().length,
|
||||
),
|
||||
);
|
||||
expect(allStrikethrough, false);
|
||||
expect(textNode.toPlainText(), text);
|
||||
|
||||
expect(result, false);
|
||||
expect(node.delta?.toPlainText(), '~~~~');
|
||||
await editor.dispose();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
group('convert double asterisk to bold', () {
|
||||
Future<void> insertAsterisk(
|
||||
EditorWidgetTester editor, {
|
||||
TestableEditor editor, {
|
||||
int repeat = 1,
|
||||
}) async {
|
||||
for (var i = 0; i < repeat; i++) {
|
||||
await editor.pressLogicKey(character: '*');
|
||||
await editor.pressLogicKey(key: LogicalKeyboardKey.asterisk);
|
||||
}
|
||||
}
|
||||
|
||||
testWidgets(
|
||||
'**AppFlowy** to bold AppFlowy',
|
||||
((widgetTester) async {
|
||||
(tester) async {
|
||||
const text = '**AppFlowy*';
|
||||
final editor = widgetTester.editor..insertTextNode('');
|
||||
|
||||
final editor = tester.editor..addEmptyParagraph();
|
||||
await editor.startTesting();
|
||||
await editor
|
||||
.updateSelection(Selection.single(path: [0], startOffset: 0));
|
||||
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
await editor.insertText(textNode, text[i], i);
|
||||
}
|
||||
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0),
|
||||
);
|
||||
await editor.editorState.insertTextAtCurrentSelection(text);
|
||||
await insertAsterisk(editor);
|
||||
|
||||
final allBold = textNode.allSatisfyBoldInSelection(
|
||||
final node = editor.nodeAtPath([0]);
|
||||
final result = allBoldInSelection(
|
||||
node,
|
||||
Selection.single(
|
||||
path: [0],
|
||||
startOffset: 0,
|
||||
endOffset: textNode.toPlainText().length,
|
||||
endOffset: node!.delta!.toPlainText().length,
|
||||
),
|
||||
);
|
||||
|
||||
expect(allBold, true);
|
||||
expect(textNode.toPlainText(), 'AppFlowy');
|
||||
}),
|
||||
expect(result, true);
|
||||
expect(node.delta?.toPlainText(), 'AppFlowy');
|
||||
await editor.dispose();
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'App**Flowy** to bold AppFlowy',
|
||||
((widgetTester) async {
|
||||
((tester) async {
|
||||
const text = 'App**Flowy*';
|
||||
final editor = widgetTester.editor..insertTextNode('');
|
||||
|
||||
final editor = tester.editor..addEmptyParagraph();
|
||||
await editor.startTesting();
|
||||
await editor
|
||||
.updateSelection(Selection.single(path: [0], startOffset: 0));
|
||||
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
await editor.insertText(textNode, text[i], i);
|
||||
}
|
||||
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0),
|
||||
);
|
||||
await editor.editorState.insertTextAtCurrentSelection(text);
|
||||
await insertAsterisk(editor);
|
||||
|
||||
final allBold = textNode.allSatisfyBoldInSelection(
|
||||
final node = editor.nodeAtPath([0]);
|
||||
final result = allBoldInSelection(
|
||||
node,
|
||||
Selection.single(
|
||||
path: [0],
|
||||
startOffset: 3,
|
||||
endOffset: textNode.toPlainText().length,
|
||||
endOffset: node!.delta!.toPlainText().length,
|
||||
),
|
||||
);
|
||||
|
||||
expect(allBold, true);
|
||||
expect(textNode.toPlainText(), 'AppFlowy');
|
||||
expect(result, true);
|
||||
expect(node.delta?.toPlainText(), 'AppFlowy');
|
||||
await editor.dispose();
|
||||
}),
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'***AppFlowy** to bold *AppFlowy',
|
||||
((widgetTester) async {
|
||||
((tester) async {
|
||||
const text = '***AppFlowy*';
|
||||
final editor = widgetTester.editor..insertTextNode('');
|
||||
|
||||
final editor = tester.editor..addEmptyParagraph();
|
||||
await editor.startTesting();
|
||||
await editor
|
||||
.updateSelection(Selection.single(path: [0], startOffset: 0));
|
||||
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
await editor.insertText(textNode, text[i], i);
|
||||
}
|
||||
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0),
|
||||
);
|
||||
await editor.editorState.insertTextAtCurrentSelection(text);
|
||||
await insertAsterisk(editor);
|
||||
|
||||
final allBold = textNode.allSatisfyBoldInSelection(
|
||||
final node = editor.nodeAtPath([0]);
|
||||
final result = allBoldInSelection(
|
||||
node,
|
||||
Selection.single(
|
||||
path: [0],
|
||||
startOffset: 1,
|
||||
endOffset: textNode.toPlainText().length,
|
||||
endOffset: node!.delta!.toPlainText().length,
|
||||
),
|
||||
);
|
||||
|
||||
expect(allBold, true);
|
||||
expect(textNode.toPlainText(), '*AppFlowy');
|
||||
expect(result, true);
|
||||
expect(node.delta?.toPlainText(), '*AppFlowy');
|
||||
await editor.dispose();
|
||||
}),
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'**** nothing changes',
|
||||
((widgetTester) async {
|
||||
((tester) async {
|
||||
const text = '***';
|
||||
final editor = widgetTester.editor..insertTextNode('');
|
||||
|
||||
final editor = tester.editor..addEmptyParagraph();
|
||||
await editor.startTesting();
|
||||
await editor
|
||||
.updateSelection(Selection.single(path: [0], startOffset: 0));
|
||||
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
await editor.insertText(textNode, text[i], i);
|
||||
}
|
||||
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0),
|
||||
);
|
||||
await editor.editorState.insertTextAtCurrentSelection(text);
|
||||
await insertAsterisk(editor);
|
||||
|
||||
final allBold = textNode.allSatisfyBoldInSelection(
|
||||
final node = editor.nodeAtPath([0]);
|
||||
final result = allBoldInSelection(
|
||||
node,
|
||||
Selection.single(
|
||||
path: [0],
|
||||
startOffset: 0,
|
||||
endOffset: textNode.toPlainText().length,
|
||||
startOffset: 1,
|
||||
endOffset: node!.delta!.toPlainText().length,
|
||||
),
|
||||
);
|
||||
|
||||
expect(allBold, false);
|
||||
expect(textNode.toPlainText(), text);
|
||||
expect(result, false);
|
||||
expect(node.delta?.toPlainText(), '****');
|
||||
await editor.dispose();
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
group('convert double underscore to bold', () {
|
||||
Future<void> insertUnderscore(
|
||||
EditorWidgetTester editor, {
|
||||
TestableEditor editor, {
|
||||
int repeat = 1,
|
||||
}) async {
|
||||
for (var i = 0; i < repeat; i++) {
|
||||
await editor.pressLogicKey(character: '_');
|
||||
await editor.pressLogicKey(key: LogicalKeyboardKey.underscore);
|
||||
}
|
||||
}
|
||||
|
||||
testWidgets(
|
||||
'__AppFlowy__ to bold AppFlowy',
|
||||
((widgetTester) async {
|
||||
((tester) async {
|
||||
const text = '__AppFlowy_';
|
||||
final editor = widgetTester.editor..insertTextNode('');
|
||||
|
||||
final editor = tester.editor..addEmptyParagraph();
|
||||
await editor.startTesting();
|
||||
await editor
|
||||
.updateSelection(Selection.single(path: [0], startOffset: 0));
|
||||
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
await editor.insertText(textNode, text[i], i);
|
||||
}
|
||||
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0),
|
||||
);
|
||||
await editor.editorState.insertTextAtCurrentSelection(text);
|
||||
await insertUnderscore(editor);
|
||||
final node = editor.nodeAtPath([0]);
|
||||
|
||||
final allBold = textNode.allSatisfyBoldInSelection(
|
||||
final result = allItalicInSelection(
|
||||
node,
|
||||
Selection.single(
|
||||
path: [0],
|
||||
startOffset: 0,
|
||||
endOffset: textNode.toPlainText().length,
|
||||
endOffset: node!.delta!.toPlainText().length,
|
||||
),
|
||||
);
|
||||
|
||||
expect(allBold, true);
|
||||
expect(textNode.toPlainText(), 'AppFlowy');
|
||||
expect(result, true);
|
||||
expect(node.delta!.toPlainText(), 'AppFlowy');
|
||||
await editor.dispose();
|
||||
}),
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'App__Flowy__ to bold AppFlowy',
|
||||
((widgetTester) async {
|
||||
((tester) async {
|
||||
const text = 'App__Flowy_';
|
||||
final editor = widgetTester.editor..insertTextNode('');
|
||||
|
||||
final editor = tester.editor..addEmptyParagraph();
|
||||
await editor.startTesting();
|
||||
await editor
|
||||
.updateSelection(Selection.single(path: [0], startOffset: 0));
|
||||
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
await editor.insertText(textNode, text[i], i);
|
||||
}
|
||||
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0),
|
||||
);
|
||||
await editor.editorState.insertTextAtCurrentSelection(text);
|
||||
await insertUnderscore(editor);
|
||||
final node = editor.nodeAtPath([0]);
|
||||
|
||||
final allBold = textNode.allSatisfyBoldInSelection(
|
||||
final result = allItalicInSelection(
|
||||
node,
|
||||
Selection.single(
|
||||
path: [0],
|
||||
startOffset: 3,
|
||||
endOffset: textNode.toPlainText().length,
|
||||
endOffset: node!.delta!.toPlainText().length,
|
||||
),
|
||||
);
|
||||
|
||||
expect(allBold, true);
|
||||
expect(textNode.toPlainText(), 'AppFlowy');
|
||||
expect(result, true);
|
||||
expect(node.delta!.toPlainText(), 'AppFlowy');
|
||||
await editor.dispose();
|
||||
}),
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'__*AppFlowy__ to bold *AppFlowy',
|
||||
((widgetTester) async {
|
||||
((tester) async {
|
||||
const text = '__*AppFlowy_';
|
||||
final editor = widgetTester.editor..insertTextNode('');
|
||||
|
||||
final editor = tester.editor..addEmptyParagraph();
|
||||
await editor.startTesting();
|
||||
await editor
|
||||
.updateSelection(Selection.single(path: [0], startOffset: 0));
|
||||
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
await editor.insertText(textNode, text[i], i);
|
||||
}
|
||||
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0),
|
||||
);
|
||||
await editor.editorState.insertTextAtCurrentSelection(text);
|
||||
await insertUnderscore(editor);
|
||||
final node = editor.nodeAtPath([0]);
|
||||
|
||||
final allBold = textNode.allSatisfyBoldInSelection(
|
||||
final result = allItalicInSelection(
|
||||
node,
|
||||
Selection.single(
|
||||
path: [0],
|
||||
startOffset: 1,
|
||||
endOffset: textNode.toPlainText().length,
|
||||
endOffset: node!.delta!.toPlainText().length,
|
||||
),
|
||||
);
|
||||
|
||||
expect(allBold, true);
|
||||
expect(textNode.toPlainText(), '*AppFlowy');
|
||||
expect(result, true);
|
||||
expect(node.delta!.toPlainText(), '*AppFlowy');
|
||||
await editor.dispose();
|
||||
}),
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'____ nothing changes',
|
||||
((widgetTester) async {
|
||||
((tester) async {
|
||||
const text = '___';
|
||||
final editor = widgetTester.editor..insertTextNode('');
|
||||
|
||||
final editor = tester.editor..addEmptyParagraph();
|
||||
await editor.startTesting();
|
||||
await editor
|
||||
.updateSelection(Selection.single(path: [0], startOffset: 0));
|
||||
final textNode = editor.nodeAtPath([0]) as TextNode;
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
await editor.insertText(textNode, text[i], i);
|
||||
}
|
||||
|
||||
await editor.updateSelection(
|
||||
Selection.single(path: [0], startOffset: 0),
|
||||
);
|
||||
await editor.editorState.insertTextAtCurrentSelection(text);
|
||||
await insertUnderscore(editor);
|
||||
final node = editor.nodeAtPath([0]);
|
||||
|
||||
final allBold = textNode.allSatisfyBoldInSelection(
|
||||
final result = allItalicInSelection(
|
||||
node,
|
||||
Selection.single(
|
||||
path: [0],
|
||||
startOffset: 0,
|
||||
endOffset: textNode.toPlainText().length,
|
||||
startOffset: 1,
|
||||
endOffset: node!.delta!.toPlainText().length,
|
||||
),
|
||||
);
|
||||
|
||||
expect(allBold, false);
|
||||
expect(textNode.toPlainText(), text);
|
||||
expect(result, false);
|
||||
expect(node.delta!.toPlainText(), '____');
|
||||
await editor.dispose();
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue