Skip to content

Commit

Permalink
test: improve coverage (AppFlowy-IO#61)
Browse files Browse the repository at this point in the history
Relates: #16
  • Loading branch information
Xazin authored Apr 12, 2023
1 parent 8602a36 commit fd13ad4
Show file tree
Hide file tree
Showing 10 changed files with 349 additions and 67 deletions.
8 changes: 3 additions & 5 deletions lib/src/editor_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -213,13 +213,11 @@ class EditorState {
return;
}

final tr = transaction;

// Rules
_insureLastNodeEditable(tr);
_insureLastNodeEditable(transaction);

if (tr.operations.isNotEmpty) {
apply(tr, ruleCount: ruleCount + 1, withUpdateCursor: false);
if (transaction.operations.isNotEmpty) {
apply(transaction, ruleCount: ruleCount + 1, withUpdateCursor: false);
}
}

Expand Down
14 changes: 6 additions & 8 deletions lib/src/infra/html_converter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,8 @@ class HTMLToNodesConverter {
} else {
final delta = Delta();
delta.insert(element.text);
if (delta.isNotEmpty) {
return [TextNode(delta: delta)];
}
return [TextNode(delta: delta)];
}

return [];
}

Node _handleParagraph(html.Element element,
Expand Down Expand Up @@ -240,12 +236,14 @@ class HTMLToNodesConverter {
} else if (element.localName == HTMLTag.strong ||
element.localName == HTMLTag.bold) {
delta.insert(element.text, attributes: {BuiltInAttributeKey.bold: true});
} else if ([HTMLTag.em, HTMLTag.italic].contains(element.localName)) {
delta.insert(
element.text,
attributes: {BuiltInAttributeKey.italic: true},
);
} else if (element.localName == HTMLTag.underline) {
delta.insert(element.text,
attributes: {BuiltInAttributeKey.underline: true});
} else if ([HTMLTag.italic, HTMLTag.em].contains(element.localName)) {
delta
.insert(element.text, attributes: {BuiltInAttributeKey.italic: true});
} else if (element.localName == HTMLTag.del) {
delta.insert(element.text,
attributes: {BuiltInAttributeKey.strikethrough: true});
Expand Down
28 changes: 9 additions & 19 deletions lib/src/render/image/image_upload_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,19 @@ void showImageUploadMenu(
menuService.dismiss();

_imageUploadMenu?.remove();
_imageUploadMenu = OverlayEntry(builder: (context) {
return Positioned(
_imageUploadMenu = OverlayEntry(
builder: (context) => Positioned(
top: menuService.topLeft.dy,
left: menuService.topLeft.dx,
child: Material(
child: ImageUploadMenu(
editorState: editorState,
onSubmitted: (text) {
// _dismissImageUploadMenu();
editorState.insertImageNode(text);
},
onUpload: (text) {
// _dismissImageUploadMenu();
editorState.insertImageNode(text);
},
onSubmitted: editorState.insertImageNode,
onUpload: editorState.insertImageNode,
),
),
);
});
),
);

Overlay.of(context).insert(_imageUploadMenu!);

Expand Down Expand Up @@ -144,9 +138,7 @@ class _ImageUploadMenuState extends State<ImageUploadMenu> {
width: 24,
height: 24,
),
onPressed: () {
_textEditingController.clear();
},
onPressed: _textEditingController.clear,
),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12.0)),
Expand All @@ -169,9 +161,7 @@ class _ImageUploadMenuState extends State<ImageUploadMenu> {
),
),
),
onPressed: () {
widget.onUpload(_textEditingController.text);
},
onPressed: () => widget.onUpload(_textEditingController.text),
child: const Text(
'Upload',
style: TextStyle(color: Colors.white, fontSize: 14.0),
Expand All @@ -181,7 +171,7 @@ class _ImageUploadMenuState extends State<ImageUploadMenu> {
}
}

extension on EditorState {
extension InsertImage on EditorState {
void insertImageNode(String src) {
final selection = service.selectionService.currentSelection.value;
if (selection == null) {
Expand Down
1 change: 1 addition & 0 deletions lib/src/render/style/plugin_styles.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Iterable<ThemeExtension<dynamic>> get lightPluginStyleExtension => [
CheckboxPluginStyle.light,
NumberListPluginStyle.light,
QuotedTextPluginStyle.light,
BulletedListPluginStyle.light,
];

Iterable<ThemeExtension<dynamic>> get darkPluginStyleExtension => [
Expand Down
47 changes: 36 additions & 11 deletions test/infra/html_converter_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,27 @@ import 'package:appflowy_editor/src/infra/html_converter.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
group('HTMLTag tests', () {
test('isTopLevel', () {
const topLevelTag = HTMLTag.h1;
const nTopLevelTag = HTMLTag.strong;

expect(HTMLTag.isTopLevel(topLevelTag), true);
expect(HTMLTag.isTopLevel(nTopLevelTag), false);
});
});

group('HTMLConverter tests', () {
test('HTMLToNodesConverter', () {
final converter = HTMLToNodesConverter(rawHTML);
final nodes = converter.toNodes();
test('HTMLToNodesConverter and NodesToHTMLConverter', () {
final fromHTMLConverter = HTMLToNodesConverter(rawHTML);
final nodes = fromHTMLConverter.toNodes();

expect(nodes.isNotEmpty, true);

final toHTMLConverter = NodesToHTMLConverter(nodes: nodes);
final html = toHTMLConverter.toHTMLString();

expect(html.isNotEmpty, true);
});
});
}
Expand All @@ -16,11 +31,21 @@ const rawHTML = """<h1>AppFlowyEditor</h1>
<h2>👋 <strong>Welcome to</strong> <strong><em><a href="appflowy.io">AppFlowy Editor</a></em></strong></h2>
<p>AppFlowy Editor is a <strong>highly customizable</strong> <em>rich-text editor</em></p>
<p>Here is an example you can give a try</p>
<hr />
<span style="font-weight: bold;">Span element</span>
<p><u>Here</u> is an example <del>your</del> you can give a try</p>
<span style="font-weight: medium;">Span element two</span>
<span style="font-weight: bold;background-color: #cccccc;font-style: italic;">Span element</span>
<span style="font-weight: medium;text-decoration: underline;">Span element two</span>
<span style="font-weight: 900;text-decoration: line-through;">Span element three</span>
<a href="https://appflowy.io">This is an anchor tag!</a>
<img src="https://images.squarespace-cdn.com/content/v1/617f6f16b877c06711e87373/c3f23723-37f4-44d7-9c5d-6e2a53064ae7/Asset+10.png?format=1500w" />
<h3>Features!</h3>
<ul>
<li>[x] Customizable</li>
Expand All @@ -39,11 +64,11 @@ const rawHTML = """<h1>AppFlowyEditor</h1>
<p>This is a quote!</p>
</blockquote>
<pre>
<code>
Code block
</code>
</pre>
<code>
Code block
</code>
<em>Italic one</em> <i>Italic two</i>
<b>Bold tag</b>
<img src="http://appflowy.io" alt="AppFlowy">
Expand Down
33 changes: 17 additions & 16 deletions test/infra/test_editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,26 @@ class EditorWidgetTester {
bool autoFocus = false,
bool editable = true,
}) async {
final app = MaterialApp(
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
AppFlowyEditorLocalizations.delegate,
],
supportedLocales: AppFlowyEditorLocalizations.delegate.supportedLocales,
locale: locale,
home: Scaffold(
body: AppFlowyEditor(
editorState: _editorState,
shrinkWrap: shrinkWrap,
autoFocus: autoFocus,
editable: editable,
await tester.pumpWidget(
MaterialApp(
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
AppFlowyEditorLocalizations.delegate,
],
supportedLocales: AppFlowyEditorLocalizations.delegate.supportedLocales,
locale: locale,
home: Scaffold(
body: AppFlowyEditor(
editorState: _editorState,
shrinkWrap: shrinkWrap,
autoFocus: autoFocus,
editable: editable,
),
),
),
);
await tester.pumpWidget(app);
await tester.pump();
return this;
}
Expand Down
43 changes: 43 additions & 0 deletions test/render/image/image_upload_widget_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/render/image/image_upload_widget.dart';
import 'package:flutter_test/flutter_test.dart';

import '../../infra/test_editor.dart';

void main() {
group('ImageUploadMenu tests', () {
testWidgets('showImageUploadMenu', (tester) async {
final editor = tester.editor..insertTextNode('Welcome to AppFlowy');
await editor.startTesting();

await editor.updateSelection(
Selection.single(path: [0], startOffset: 19),
);

await editor.pressLogicKey(character: '/');
await tester.pumpAndSettle();

expect(find.byType(SelectionMenuWidget), findsOneWidget);

final imageMenuItemFinder = find.text('Image');
expect(imageMenuItemFinder, findsOneWidget);

await tester.tap(imageMenuItemFinder);
await tester.pumpAndSettle();
});

testWidgets('insertImageNode extension', (tester) async {
final editor = tester.editor..insertTextNode('Welcome to AppFlowy');
await editor.startTesting();

await editor.updateSelection(
Selection.single(path: [0], startOffset: 19),
);

editor.editorState.insertImageNode('no_src');
await tester.pumpAndSettle();

expect(editor.documentLength, 2);
});
});
}
24 changes: 16 additions & 8 deletions test/render/selection_menu/selection_menu_widget_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -218,13 +218,19 @@ Future<EditorWidgetTester> _prepare(WidgetTester tester) async {
}

Future<void> _testDefaultSelectionMenuItems(
int index, EditorWidgetTester editor) async {
int index,
EditorWidgetTester editor,
) async {
expect(editor.documentLength, 4);
expect(editor.documentSelection, Selection.single(path: [2], startOffset: 0));
expect((editor.nodeAtPath([0]) as TextNode).toPlainText(),
'Welcome to Appflowy 😁');
expect((editor.nodeAtPath([1]) as TextNode).toPlainText(),
'Welcome to Appflowy 😁');
expect(
(editor.nodeAtPath([0]) as TextNode).toPlainText(),
'Welcome to Appflowy 😁',
);
expect(
(editor.nodeAtPath([1]) as TextNode).toPlainText(),
'Welcome to Appflowy 😁',
);
final node = editor.nodeAtPath([2]);
final item = defaultSelectionMenuItems[index];
if (item.name == 'Text') {
Expand Down Expand Up @@ -252,8 +258,10 @@ Future<void> _testDefaultSelectionMenuItems(

SelectionMenuItemWidget getSelectedMenuItem(WidgetTester tester) {
return tester
.state(find.byWidgetPredicate(
(widget) => widget is SelectionMenuItemWidget && widget.isSelected,
))
.state(
find.byWidgetPredicate(
(widget) => widget is SelectionMenuItemWidget && widget.isSelected,
),
)
.widget as SelectionMenuItemWidget;
}
64 changes: 64 additions & 0 deletions test/render/style/editor_style_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
group('EditorStyle tests', () {
test('extensions', () {
final lightExtensions = lightEditorStyleExtension;
expect(lightExtensions.length, 1);
expect(lightExtensions.contains(EditorStyle.light), true);

final darkExtensions = darkEditorStyleExtension;
expect(darkExtensions.length, 1);
expect(darkExtensions.contains(EditorStyle.dark), true);
});

test('EditorStyle members', () {
EditorStyle style = EditorStyle.light;
expect(style.padding, isNot(EdgeInsets.zero));

style = style.copyWith(padding: EdgeInsets.zero);
expect(style.padding, EdgeInsets.zero);
});

testWidgets('EditorStyle.of not found', (tester) async {
late BuildContext context;

await tester.pumpWidget(
Builder(builder: (ctx) {
context = ctx;
return const SizedBox.shrink();
}),
);

expect(EditorStyle.of(context), null);
});

testWidgets('EditorStyle.of found', (tester) async {
late BuildContext context;

await tester.pumpWidget(
MaterialApp(
theme: ThemeData.light().copyWith(
extensions: [...lightEditorStyleExtension],
),
home: Builder(builder: (ctx) {
context = ctx;
return const SizedBox.shrink();
}),
),
);

final editorStyle = EditorStyle.of(context);
expect(editorStyle, isNotNull);
expect(editorStyle!.backgroundColor, EditorStyle.light.backgroundColor);
});

test('EditorStyle.lerp', () {
final editorStyle =
EditorStyle.light.lerp(EditorStyle.dark, 1.0) as EditorStyle;
expect(editorStyle.backgroundColor, EditorStyle.dark.backgroundColor);
});
});
}
Loading

0 comments on commit fd13ad4

Please sign in to comment.