test: migrate the markdown_syntax_to_styled_text

This commit is contained in:
Lucas.Xu 2023-05-02 19:59:22 +08:00
commit 4a32d0a460
7 changed files with 279 additions and 256 deletions

View file

@ -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,
),
);

View file

@ -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]. // If we have more in the future, we should add them in this enum and update the [style] variable in [handleDoubleCharactersFormat].
enum DoubleCharacterFormatStyle { enum DoubleCharacterFormatStyle {
bold, bold,
strikethrough,
} }
bool handleFormatByWrappingWithDoubleCharacter({ bool handleFormatByWrappingWithDoubleCharacter({
@ -79,6 +80,9 @@ bool handleFormatByWrappingWithDoubleCharacter({
case DoubleCharacterFormatStyle.bold: case DoubleCharacterFormatStyle.bold:
style = 'bold'; style = 'bold';
break; break;
case DoubleCharacterFormatStyle.strikethrough:
style = 'strikethrough';
break;
default: default:
style = ''; style = '';
assert(false, 'Invalid format style'); assert(false, 'Invalid format style');

View file

@ -1,5 +1,6 @@
import 'package:appflowy_editor/appflowy_editor.dart'; 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_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_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_italic.dart';
import 'package:appflowy_editor/src/editor/editor_component/service/shortcuts/character_shortcut_events/format_by_wrapping_with_single_character/format_strikethrough.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~ // 4. tilde to strikethrough -> ~abc~
final List<CharacterShortcutEvent> markdownSyntaxShortcutEvents = [ final List<CharacterShortcutEvent> markdownSyntaxShortcutEvents = [
// format code, 'code' // format code, `code`
formatBackquoteToCode, formatBackquoteToCode,
// format italic, _italic_ or *italic* // format italic,
// _italic_
// *italic*
formatUnderscoreToItalic, formatUnderscoreToItalic,
formatAsteriskToItalic, formatAsteriskToItalic,
//format strikethrough, ~strikethrough~ // format strikethrough,
// ~strikethrough~
// ~~strikethrough~~
formatTildeToStrikethrough, formatTildeToStrikethrough,
formatDoubleTilesToStrikethrough,
//format bold, **bold** or __bold__ // format bold, **bold** or __bold__
formatDoubleAsterisksToBold, formatDoubleAsterisksToBold,
formatDoubleUnderscoresToBold, formatDoubleUnderscoresToBold,
]; ];

View file

@ -56,7 +56,8 @@ class _FlowyRichTextState extends State<FlowyRichText> with SelectableMixin {
_textKey.currentContext?.findRenderObject() as RenderParagraph; _textKey.currentContext?.findRenderObject() as RenderParagraph;
RenderParagraph? get _placeholderRenderParagraph => RenderParagraph? get _placeholderRenderParagraph =>
_placeholderTextKey.currentContext?.findRenderObject() as RenderParagraph; _placeholderTextKey.currentContext?.findRenderObject()
as RenderParagraph?;
@override @override
void didUpdateWidget(covariant FlowyRichText oldWidget) { void didUpdateWidget(covariant FlowyRichText oldWidget) {

View file

@ -184,6 +184,10 @@ class TestableEditor {
final keyToCharacterMap = { final keyToCharacterMap = {
LogicalKeyboardKey.space: ' ', LogicalKeyboardKey.space: ' ',
LogicalKeyboardKey.enter: '\n', LogicalKeyboardKey.enter: '\n',
LogicalKeyboardKey.backquote: '`',
LogicalKeyboardKey.tilde: '~',
LogicalKeyboardKey.asterisk: '*',
LogicalKeyboardKey.underscore: '_',
}; };
Future<void> pressLogicKey({ Future<void> pressLogicKey({
String? character, String? character,

View file

@ -22,6 +22,7 @@ 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,
@ -30,6 +31,7 @@ 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,
@ -38,6 +40,7 @@ void main() async {
LogicalKeyboardKey.keyU, LogicalKeyboardKey.keyU,
); );
}); });
testWidgets('Presses Command + Shift + S to update text style', testWidgets('Presses Command + Shift + S to update text style',
(tester) async { (tester) async {
await _testUpdateTextStyleByCommandX( await _testUpdateTextStyleByCommandX(

View file

@ -1,509 +1,492 @@
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import '../../infra/test_editor.dart';
import '../../new/infra/testable_editor.dart';
void main() async { 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(() { setUpAll(() {
TestWidgetsFlutterBinding.ensureInitialized(); TestWidgetsFlutterBinding.ensureInitialized();
}); });
group('markdown_syntax_to_styled_text.dart', () { group('markdown_syntax_to_styled_text.dart', () {
group('convert single backquote to code', () { Future<void> insertBackquote(
Future<void> insertBackquote( TestableEditor editor, {
EditorWidgetTester editor, { int repeat = 1,
int repeat = 1, }) async {
}) async { for (var i = 0; i < repeat; i++) {
for (var i = 0; i < repeat; i++) { await editor.pressLogicKey(
await editor.pressLogicKey( key: LogicalKeyboardKey.backquote,
key: LogicalKeyboardKey.backquote, );
);
}
} }
}
group('convert single backquote to code', () {
testWidgets('`AppFlowy` to code AppFlowy', (tester) async { testWidgets('`AppFlowy` to code AppFlowy', (tester) async {
const text = '`AppFlowy'; const text = '`AppFlowy';
final editor = tester.editor..insertTextNode(''); final editor = tester.editor..addEmptyParagraph();
await editor.startTesting(); await editor.startTesting();
await editor.updateSelection( await editor.updateSelection(
Selection.single(path: [0], startOffset: 0), Selection.single(path: [0], startOffset: 0),
); );
final textNode = editor.nodeAtPath([0]) as TextNode;
for (var i = 0; i < text.length; i++) { await editor.editorState.insertTextAtCurrentSelection(text);
await editor.insertText(textNode, text[i], i);
}
await insertBackquote(editor); await insertBackquote(editor);
final allCode = textNode.allSatisfyCodeInSelection( final node = editor.nodeAtPath([0]);
final allCode = allCodeInSelection(
node,
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 0, startOffset: 0,
endOffset: textNode.toPlainText().length, endOffset: text.length - 1,
), ),
); );
expect(allCode, true); expect(allCode, true);
expect(textNode.toPlainText(), 'AppFlowy'); expect(node?.delta?.toPlainText(), 'AppFlowy');
await editor.dispose();
}); });
testWidgets('App`Flowy` to code AppFlowy', (tester) async { testWidgets('App`Flowy` to code AppFlowy', (tester) async {
const text = 'App`Flowy'; const text = 'App`Flowy';
final editor = tester.editor..insertTextNode(''); final editor = tester.editor..addEmptyParagraph();
await editor.startTesting(); await editor.startTesting();
await editor.updateSelection( await editor.updateSelection(
Selection.single(path: [0], startOffset: 0), Selection.single(path: [0], startOffset: 0),
); );
final textNode = editor.nodeAtPath([0]) as TextNode;
for (var i = 0; i < text.length; i++) { await editor.editorState.insertTextAtCurrentSelection(text);
await editor.insertText(textNode, text[i], i);
}
await insertBackquote(editor); await insertBackquote(editor);
final allCode = textNode.allSatisfyCodeInSelection( final node = editor.nodeAtPath([0]);
final allCode = allCodeInSelection(
node,
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 3, startOffset: 3,
endOffset: textNode.toPlainText().length, endOffset: text.length - 1,
), ),
); );
expect(allCode, true); expect(allCode, true);
expect(textNode.toPlainText(), 'AppFlowy'); expect(node?.delta?.toPlainText(), 'AppFlowy');
await editor.dispose();
}); });
testWidgets('`` nothing changes', (tester) async { testWidgets('`` nothing changes', (tester) async {
const text = '`'; const text = '`';
final editor = tester.editor..insertTextNode(''); final editor = tester.editor..addEmptyParagraph();
await editor.startTesting(); await editor.startTesting();
await editor.updateSelection( await editor.updateSelection(
Selection.single(path: [0], startOffset: 0), Selection.single(path: [0], startOffset: 0),
); );
final textNode = editor.nodeAtPath([0]) as TextNode; await editor.editorState.insertTextAtCurrentSelection(text);
for (var i = 0; i < text.length; i++) {
await editor.insertText(textNode, text[i], i);
}
await insertBackquote(editor); await insertBackquote(editor);
final allCode = textNode.allSatisfyCodeInSelection( final node = editor.nodeAtPath([0]);
final allCode = allCodeInSelection(
node,
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 0, startOffset: 0,
endOffset: textNode.toPlainText().length, endOffset: node!.delta!.toPlainText().length,
), ),
); );
expect(allCode, false); expect(allCode, false);
expect(textNode.toPlainText(), text); expect(node.delta?.toPlainText(), '``');
await editor.dispose();
}); });
}); });
group('convert double backquote to code', () { 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 { testWidgets('```` nothing changes', (tester) async {
const text = '```'; const text = '```';
final editor = tester.editor..insertTextNode(''); final editor = tester.editor..addEmptyParagraph();
await editor.startTesting(); await editor.startTesting();
await editor.updateSelection( await editor.updateSelection(
Selection.single(path: [0], startOffset: 0), Selection.single(path: [0], startOffset: 0),
); );
final textNode = editor.nodeAtPath([0]) as TextNode; await editor.editorState.insertTextAtCurrentSelection(text);
for (var i = 0; i < text.length; i++) {
await editor.insertText(textNode, text[i], i);
}
await insertBackquote(editor); await insertBackquote(editor);
final allCode = textNode.allSatisfyCodeInSelection( final node = editor.nodeAtPath([0]);
final allCode = allCodeInSelection(
node,
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 0, startOffset: 0,
endOffset: textNode.toPlainText().length, endOffset: node!.delta!.toPlainText().length,
), ),
); );
expect(allCode, false); expect(allCode, false);
expect(textNode.toPlainText(), text); expect(node.delta?.toPlainText(), '````');
await editor.dispose();
}); });
}); });
group('convert double tilde to strikethrough', () { group('convert double tilde to strikethrough', () {
Future<void> insertTilde( Future<void> insertTilde(
EditorWidgetTester editor, { TestableEditor editor, {
int repeat = 1, int repeat = 1,
}) async { }) async {
for (var i = 0; i < repeat; i++) { for (var i = 0; i < repeat; i++) {
await editor.pressLogicKey(character: '~'); await editor.pressLogicKey(key: LogicalKeyboardKey.tilde);
} }
} }
testWidgets('~~AppFlowy~~ to strikethrough AppFlowy', (tester) async { testWidgets('~~AppFlowy~~ to strikethrough AppFlowy', (tester) async {
const text = '~~AppFlowy~'; const text = '~~AppFlowy~';
final editor = tester.editor..insertTextNode(''); final editor = tester.editor..addEmptyParagraph();
await editor.startTesting(); await editor.startTesting();
await editor.updateSelection( await editor.updateSelection(
Selection.single(path: [0], startOffset: 0), Selection.single(path: [0], startOffset: 0),
); );
final textNode = editor.nodeAtPath([0]) as TextNode; await editor.editorState.insertTextAtCurrentSelection(text);
for (var i = 0; i < text.length; i++) {
await editor.insertText(textNode, text[i], i);
}
await insertTilde(editor); await insertTilde(editor);
final allStrikethrough = textNode.allSatisfyStrikethroughInSelection( final node = editor.nodeAtPath([0]);
final result = allStrikethroughInSelection(
node,
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 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 { testWidgets('App~~Flowy~~ to strikethrough AppFlowy', (tester) async {
const text = 'App~~Flowy~'; const text = 'App~~Flowy~';
final editor = tester.editor..insertTextNode(''); final editor = tester.editor..addEmptyParagraph();
await editor.startTesting(); await editor.startTesting();
await editor.updateSelection( await editor.updateSelection(
Selection.single(path: [0], startOffset: 0), Selection.single(path: [0], startOffset: 0),
); );
final textNode = editor.nodeAtPath([0]) as TextNode; await editor.editorState.insertTextAtCurrentSelection(text);
for (var i = 0; i < text.length; i++) {
await editor.insertText(textNode, text[i], i);
}
await insertTilde(editor); await insertTilde(editor);
final allStrikethrough = textNode.allSatisfyStrikethroughInSelection( final node = editor.nodeAtPath([0]);
final result = allStrikethroughInSelection(
node,
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 3, 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 { expect(result, true);
const text = '~~~AppFlowy~'; expect(node.delta?.toPlainText(), 'AppFlowy');
final editor = tester.editor..insertTextNode(''); await editor.dispose();
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');
}); });
testWidgets('~~~~ nothing changes', (tester) async { testWidgets('~~~~ nothing changes', (tester) async {
const text = '~~~'; const text = '~~~';
final editor = tester.editor..insertTextNode(''); final editor = tester.editor..addEmptyParagraph();
await editor.startTesting(); await editor.startTesting();
await editor.updateSelection( await editor.updateSelection(
Selection.single(path: [0], startOffset: 0), Selection.single(path: [0], startOffset: 0),
); );
final textNode = editor.nodeAtPath([0]) as TextNode; await editor.editorState.insertTextAtCurrentSelection(text);
for (var i = 0; i < text.length; i++) {
await editor.insertText(textNode, text[i], i);
}
await insertTilde(editor); await insertTilde(editor);
final allStrikethrough = textNode.allSatisfyStrikethroughInSelection( final node = editor.nodeAtPath([0]);
final result = allStrikethroughInSelection(
node,
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 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', () { group('convert double asterisk to bold', () {
Future<void> insertAsterisk( Future<void> insertAsterisk(
EditorWidgetTester editor, { TestableEditor editor, {
int repeat = 1, int repeat = 1,
}) async { }) async {
for (var i = 0; i < repeat; i++) { for (var i = 0; i < repeat; i++) {
await editor.pressLogicKey(character: '*'); await editor.pressLogicKey(key: LogicalKeyboardKey.asterisk);
} }
} }
testWidgets( testWidgets(
'**AppFlowy** to bold AppFlowy', '**AppFlowy** to bold AppFlowy',
((widgetTester) async { (tester) async {
const text = '**AppFlowy*'; const text = '**AppFlowy*';
final editor = widgetTester.editor..insertTextNode(''); final editor = tester.editor..addEmptyParagraph();
await editor.startTesting(); await editor.startTesting();
await editor await editor.updateSelection(
.updateSelection(Selection.single(path: [0], startOffset: 0)); Selection.single(path: [0], startOffset: 0),
final textNode = editor.nodeAtPath([0]) as TextNode; );
for (var i = 0; i < text.length; i++) { await editor.editorState.insertTextAtCurrentSelection(text);
await editor.insertText(textNode, text[i], i);
}
await insertAsterisk(editor); await insertAsterisk(editor);
final node = editor.nodeAtPath([0]);
final allBold = textNode.allSatisfyBoldInSelection( final result = allBoldInSelection(
node,
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 0, startOffset: 0,
endOffset: textNode.toPlainText().length, endOffset: node!.delta!.toPlainText().length,
), ),
); );
expect(allBold, true); expect(result, true);
expect(textNode.toPlainText(), 'AppFlowy'); expect(node.delta?.toPlainText(), 'AppFlowy');
}), await editor.dispose();
},
); );
testWidgets( testWidgets(
'App**Flowy** to bold AppFlowy', 'App**Flowy** to bold AppFlowy',
((widgetTester) async { ((tester) async {
const text = 'App**Flowy*'; const text = 'App**Flowy*';
final editor = widgetTester.editor..insertTextNode(''); final editor = tester.editor..addEmptyParagraph();
await editor.startTesting(); await editor.startTesting();
await editor await editor.updateSelection(
.updateSelection(Selection.single(path: [0], startOffset: 0)); Selection.single(path: [0], startOffset: 0),
final textNode = editor.nodeAtPath([0]) as TextNode; );
for (var i = 0; i < text.length; i++) { await editor.editorState.insertTextAtCurrentSelection(text);
await editor.insertText(textNode, text[i], i);
}
await insertAsterisk(editor); await insertAsterisk(editor);
final node = editor.nodeAtPath([0]);
final allBold = textNode.allSatisfyBoldInSelection( final result = allBoldInSelection(
node,
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 3, startOffset: 3,
endOffset: textNode.toPlainText().length, endOffset: node!.delta!.toPlainText().length,
), ),
); );
expect(allBold, true); expect(result, true);
expect(textNode.toPlainText(), 'AppFlowy'); expect(node.delta?.toPlainText(), 'AppFlowy');
await editor.dispose();
}), }),
); );
testWidgets( testWidgets(
'***AppFlowy** to bold *AppFlowy', '***AppFlowy** to bold *AppFlowy',
((widgetTester) async { ((tester) async {
const text = '***AppFlowy*'; const text = '***AppFlowy*';
final editor = widgetTester.editor..insertTextNode(''); final editor = tester.editor..addEmptyParagraph();
await editor.startTesting(); await editor.startTesting();
await editor await editor.updateSelection(
.updateSelection(Selection.single(path: [0], startOffset: 0)); Selection.single(path: [0], startOffset: 0),
final textNode = editor.nodeAtPath([0]) as TextNode; );
for (var i = 0; i < text.length; i++) { await editor.editorState.insertTextAtCurrentSelection(text);
await editor.insertText(textNode, text[i], i);
}
await insertAsterisk(editor); await insertAsterisk(editor);
final node = editor.nodeAtPath([0]);
final allBold = textNode.allSatisfyBoldInSelection( final result = allBoldInSelection(
node,
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 1, startOffset: 1,
endOffset: textNode.toPlainText().length, endOffset: node!.delta!.toPlainText().length,
), ),
); );
expect(allBold, true); expect(result, true);
expect(textNode.toPlainText(), '*AppFlowy'); expect(node.delta?.toPlainText(), '*AppFlowy');
await editor.dispose();
}), }),
); );
testWidgets( testWidgets(
'**** nothing changes', '**** nothing changes',
((widgetTester) async { ((tester) async {
const text = '***'; const text = '***';
final editor = widgetTester.editor..insertTextNode(''); final editor = tester.editor..addEmptyParagraph();
await editor.startTesting(); await editor.startTesting();
await editor await editor.updateSelection(
.updateSelection(Selection.single(path: [0], startOffset: 0)); Selection.single(path: [0], startOffset: 0),
final textNode = editor.nodeAtPath([0]) as TextNode; );
for (var i = 0; i < text.length; i++) { await editor.editorState.insertTextAtCurrentSelection(text);
await editor.insertText(textNode, text[i], i);
}
await insertAsterisk(editor); await insertAsterisk(editor);
final node = editor.nodeAtPath([0]);
final allBold = textNode.allSatisfyBoldInSelection( final result = allBoldInSelection(
node,
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 0, startOffset: 1,
endOffset: textNode.toPlainText().length, endOffset: node!.delta!.toPlainText().length,
), ),
); );
expect(allBold, false); expect(result, false);
expect(textNode.toPlainText(), text); expect(node.delta?.toPlainText(), '****');
await editor.dispose();
}), }),
); );
}); });
group('convert double underscore to bold', () { group('convert double underscore to bold', () {
Future<void> insertUnderscore( Future<void> insertUnderscore(
EditorWidgetTester editor, { TestableEditor editor, {
int repeat = 1, int repeat = 1,
}) async { }) async {
for (var i = 0; i < repeat; i++) { for (var i = 0; i < repeat; i++) {
await editor.pressLogicKey(character: '_'); await editor.pressLogicKey(key: LogicalKeyboardKey.underscore);
} }
} }
testWidgets( testWidgets(
'__AppFlowy__ to bold AppFlowy', '__AppFlowy__ to bold AppFlowy',
((widgetTester) async { ((tester) async {
const text = '__AppFlowy_'; const text = '__AppFlowy_';
final editor = widgetTester.editor..insertTextNode(''); final editor = tester.editor..addEmptyParagraph();
await editor.startTesting(); await editor.startTesting();
await editor await editor.updateSelection(
.updateSelection(Selection.single(path: [0], startOffset: 0)); Selection.single(path: [0], startOffset: 0),
final textNode = editor.nodeAtPath([0]) as TextNode; );
for (var i = 0; i < text.length; i++) { await editor.editorState.insertTextAtCurrentSelection(text);
await editor.insertText(textNode, text[i], i);
}
await insertUnderscore(editor); await insertUnderscore(editor);
final node = editor.nodeAtPath([0]);
final allBold = textNode.allSatisfyBoldInSelection( final result = allItalicInSelection(
node,
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 0, startOffset: 0,
endOffset: textNode.toPlainText().length, endOffset: node!.delta!.toPlainText().length,
), ),
); );
expect(allBold, true); expect(result, true);
expect(textNode.toPlainText(), 'AppFlowy'); expect(node.delta!.toPlainText(), 'AppFlowy');
await editor.dispose();
}), }),
); );
testWidgets( testWidgets(
'App__Flowy__ to bold AppFlowy', 'App__Flowy__ to bold AppFlowy',
((widgetTester) async { ((tester) async {
const text = 'App__Flowy_'; const text = 'App__Flowy_';
final editor = widgetTester.editor..insertTextNode(''); final editor = tester.editor..addEmptyParagraph();
await editor.startTesting(); await editor.startTesting();
await editor await editor.updateSelection(
.updateSelection(Selection.single(path: [0], startOffset: 0)); Selection.single(path: [0], startOffset: 0),
final textNode = editor.nodeAtPath([0]) as TextNode; );
for (var i = 0; i < text.length; i++) { await editor.editorState.insertTextAtCurrentSelection(text);
await editor.insertText(textNode, text[i], i);
}
await insertUnderscore(editor); await insertUnderscore(editor);
final node = editor.nodeAtPath([0]);
final allBold = textNode.allSatisfyBoldInSelection( final result = allItalicInSelection(
node,
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 3, startOffset: 3,
endOffset: textNode.toPlainText().length, endOffset: node!.delta!.toPlainText().length,
), ),
); );
expect(allBold, true); expect(result, true);
expect(textNode.toPlainText(), 'AppFlowy'); expect(node.delta!.toPlainText(), 'AppFlowy');
await editor.dispose();
}), }),
); );
testWidgets( testWidgets(
'__*AppFlowy__ to bold *AppFlowy', '__*AppFlowy__ to bold *AppFlowy',
((widgetTester) async { ((tester) async {
const text = '__*AppFlowy_'; const text = '__*AppFlowy_';
final editor = widgetTester.editor..insertTextNode(''); final editor = tester.editor..addEmptyParagraph();
await editor.startTesting(); await editor.startTesting();
await editor await editor.updateSelection(
.updateSelection(Selection.single(path: [0], startOffset: 0)); Selection.single(path: [0], startOffset: 0),
final textNode = editor.nodeAtPath([0]) as TextNode; );
for (var i = 0; i < text.length; i++) { await editor.editorState.insertTextAtCurrentSelection(text);
await editor.insertText(textNode, text[i], i);
}
await insertUnderscore(editor); await insertUnderscore(editor);
final node = editor.nodeAtPath([0]);
final allBold = textNode.allSatisfyBoldInSelection( final result = allItalicInSelection(
node,
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 1, startOffset: 1,
endOffset: textNode.toPlainText().length, endOffset: node!.delta!.toPlainText().length,
), ),
); );
expect(allBold, true); expect(result, true);
expect(textNode.toPlainText(), '*AppFlowy'); expect(node.delta!.toPlainText(), '*AppFlowy');
await editor.dispose();
}), }),
); );
testWidgets( testWidgets(
'____ nothing changes', '____ nothing changes',
((widgetTester) async { ((tester) async {
const text = '___'; const text = '___';
final editor = widgetTester.editor..insertTextNode(''); final editor = tester.editor..addEmptyParagraph();
await editor.startTesting(); await editor.startTesting();
await editor await editor.updateSelection(
.updateSelection(Selection.single(path: [0], startOffset: 0)); Selection.single(path: [0], startOffset: 0),
final textNode = editor.nodeAtPath([0]) as TextNode; );
for (var i = 0; i < text.length; i++) { await editor.editorState.insertTextAtCurrentSelection(text);
await editor.insertText(textNode, text[i], i);
}
await insertUnderscore(editor); await insertUnderscore(editor);
final node = editor.nodeAtPath([0]);
final allBold = textNode.allSatisfyBoldInSelection( final result = allItalicInSelection(
node,
Selection.single( Selection.single(
path: [0], path: [0],
startOffset: 0, startOffset: 1,
endOffset: textNode.toPlainText().length, endOffset: node!.delta!.toPlainText().length,
), ),
); );
expect(allBold, false); expect(result, false);
expect(textNode.toPlainText(), text); expect(node.delta!.toPlainText(), '____');
await editor.dispose();
}), }),
); );
}); });