test: improve test coverage (#23)
This commit is contained in:
parent
6ea90facd1
commit
226d39cc78
18 changed files with 472 additions and 21 deletions
|
|
@ -12,6 +12,7 @@ class Position {
|
||||||
factory Position.fromJson(Map<String, dynamic> json) {
|
factory Position.fromJson(Map<String, dynamic> json) {
|
||||||
final path = Path.from(json['path'] as List);
|
final path = Path.from(json['path'] as List);
|
||||||
final offset = json['offset'];
|
final offset = json['offset'];
|
||||||
|
|
||||||
return Position(
|
return Position(
|
||||||
path: path,
|
path: path,
|
||||||
offset: offset ?? 0,
|
offset: offset ?? 0,
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,14 @@ import 'package:flutter_svg/svg.dart';
|
||||||
|
|
||||||
class FlowySvg extends StatelessWidget {
|
class FlowySvg extends StatelessWidget {
|
||||||
const FlowySvg({
|
const FlowySvg({
|
||||||
Key? key,
|
super.key,
|
||||||
this.name,
|
this.name,
|
||||||
this.width,
|
this.width,
|
||||||
this.height,
|
this.height,
|
||||||
this.color,
|
this.color,
|
||||||
this.number,
|
this.number,
|
||||||
this.padding,
|
this.padding,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
final String? name;
|
final String? name;
|
||||||
final double? width;
|
final double? width;
|
||||||
|
|
|
||||||
|
|
@ -46,14 +46,12 @@ class ActionMenuItem {
|
||||||
Widget Function(Widget item)? itemWrapper,
|
Widget Function(Widget item)? itemWrapper,
|
||||||
}) {
|
}) {
|
||||||
return ActionMenuItem(
|
return ActionMenuItem(
|
||||||
iconBuilder: ({size, color}) {
|
iconBuilder: ({color, size}) => FlowySvg(
|
||||||
return FlowySvg(
|
name: name,
|
||||||
name: name,
|
color: color,
|
||||||
color: color,
|
width: size,
|
||||||
width: size,
|
height: size,
|
||||||
height: size,
|
),
|
||||||
);
|
|
||||||
},
|
|
||||||
onPressed: onPressed,
|
onPressed: onPressed,
|
||||||
selected: selected,
|
selected: selected,
|
||||||
itemWrapper: itemWrapper,
|
itemWrapper: itemWrapper,
|
||||||
|
|
@ -62,13 +60,11 @@ class ActionMenuItem {
|
||||||
|
|
||||||
factory ActionMenuItem.separator() {
|
factory ActionMenuItem.separator() {
|
||||||
return ActionMenuItem(
|
return ActionMenuItem(
|
||||||
iconBuilder: ({size, color}) {
|
iconBuilder: ({color, size}) => FlowySvg(
|
||||||
return FlowySvg(
|
name: 'image_toolbar/divider',
|
||||||
name: 'image_toolbar/divider',
|
color: color,
|
||||||
color: color,
|
height: size,
|
||||||
height: size,
|
),
|
||||||
);
|
|
||||||
},
|
|
||||||
onPressed: null,
|
onPressed: null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -130,9 +130,7 @@ class _LinkMenuState extends State<LinkMenu> {
|
||||||
width: 24,
|
width: 24,
|
||||||
height: 24,
|
height: 24,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: _textEditingController.clear,
|
||||||
_textEditingController.clear();
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
border: const OutlineInputBorder(
|
border: const OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(12.0)),
|
borderRadius: BorderRadius.all(Radius.circular(12.0)),
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
|
@ -22,5 +24,17 @@ void main() async {
|
||||||
'offset': 4,
|
'offset': 4,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Position.fromJson', (tester) async {
|
||||||
|
final positionJson = jsonDecode("""{
|
||||||
|
"path": [4],
|
||||||
|
"offset": 5
|
||||||
|
}""");
|
||||||
|
|
||||||
|
final position = Position.fromJson(positionJson);
|
||||||
|
|
||||||
|
expect(position.path.first, 4);
|
||||||
|
expect(position.offset, 5);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
|
@ -73,5 +75,26 @@ void main() async {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Selection.fromJson', (tester) async {
|
||||||
|
final selectionJson = jsonDecode("""{
|
||||||
|
"start": {
|
||||||
|
"path": [0],
|
||||||
|
"offset": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"path": [2],
|
||||||
|
"offset": 25
|
||||||
|
}
|
||||||
|
}""");
|
||||||
|
|
||||||
|
final position = Selection.fromJson(selectionJson);
|
||||||
|
|
||||||
|
expect(position.start.path.first, 0);
|
||||||
|
expect(position.start.offset, 0);
|
||||||
|
|
||||||
|
expect(position.end.path.first, 2);
|
||||||
|
expect(position.end.offset, 25);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,5 +75,9 @@ void main() async {
|
||||||
expect(op.invert().invert(), op);
|
expect(op.invert().invert(), op);
|
||||||
expect(op.copyWith(), op);
|
expect(op.copyWith(), op);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Operation.fromJson throws', () {
|
||||||
|
expect(() => Operation.fromJson(), throwsA(isA<UnimplementedError>()));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,48 @@ void main() {
|
||||||
expect(result, false);
|
expect(result, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('inSelection w/ Reverse selection', () {
|
||||||
|
final linkedList = LinkedList<Node>()
|
||||||
|
..addAll([
|
||||||
|
Node(
|
||||||
|
type: 'type',
|
||||||
|
attributes: {},
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
final node = Node(
|
||||||
|
type: 'type',
|
||||||
|
children: linkedList,
|
||||||
|
attributes: {},
|
||||||
|
);
|
||||||
|
|
||||||
|
final reverseSelection = Selection(
|
||||||
|
start: Position(path: [1]),
|
||||||
|
end: Position(path: [0]),
|
||||||
|
);
|
||||||
|
|
||||||
|
final result = node.inSelection(reverseSelection);
|
||||||
|
expect(result, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('isSelected', (tester) async {
|
||||||
|
final editor = tester.editor
|
||||||
|
..insertTextNode('Hello')
|
||||||
|
..insertTextNode('World');
|
||||||
|
await editor.startTesting();
|
||||||
|
|
||||||
|
final selection = Selection(
|
||||||
|
start: Position(path: [0]),
|
||||||
|
end: Position(path: [0], offset: 1),
|
||||||
|
);
|
||||||
|
|
||||||
|
await editor.updateSelection(selection);
|
||||||
|
|
||||||
|
final node = editor.editorState.getTextNode(path: [0]);
|
||||||
|
|
||||||
|
expect(node.isSelected(editor.editorState), true);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('insert a new checkbox after an exsiting checkbox',
|
testWidgets('insert a new checkbox after an exsiting checkbox',
|
||||||
(tester) async {
|
(tester) async {
|
||||||
const text = 'Welcome to Appflowy 😁';
|
const text = 'Welcome to Appflowy 😁';
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import 'package:appflowy_editor/src/extensions/url_launcher_extension.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('safeLaunchUrl without scheme', () async {
|
test('safeLaunchUrl without href and scheme', () async {
|
||||||
const href = null;
|
const href = null;
|
||||||
final result = await safeLaunchUrl(href);
|
final result = await safeLaunchUrl(href);
|
||||||
expect(result, false);
|
expect(result, false);
|
||||||
|
|
|
||||||
88
test/infra/clipboard_test.dart
Normal file
88
test/infra/clipboard_test.dart
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
import 'package:appflowy_editor/src/infra/clipboard.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
class MockClipboard {
|
||||||
|
final String? text;
|
||||||
|
final String? html;
|
||||||
|
|
||||||
|
const MockClipboard({required this.text, required this.html});
|
||||||
|
|
||||||
|
MockClipboard copyWith({
|
||||||
|
String? text,
|
||||||
|
String? html,
|
||||||
|
}) =>
|
||||||
|
MockClipboard(
|
||||||
|
text: text,
|
||||||
|
html: html,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, String?> get getData => {"html": html, "text": text};
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
late MockClipboard mockClipboard;
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
mockClipboard = const MockClipboard(html: null, text: null);
|
||||||
|
|
||||||
|
SystemChannels.platform
|
||||||
|
.setMockMethodCallHandler((MethodCall methodCall) async {
|
||||||
|
switch (methodCall.method) {
|
||||||
|
case "Clipboard.getData":
|
||||||
|
return mockClipboard.getData;
|
||||||
|
case "Clipboard.setData":
|
||||||
|
final args = methodCall.arguments as Map<String, dynamic>;
|
||||||
|
mockClipboard = mockClipboard.copyWith(
|
||||||
|
text: args['text'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Clipboard tests', () {
|
||||||
|
test('AppFlowyClipboardData constructor', () {
|
||||||
|
const data = AppFlowyClipboardData(text: null, html: null);
|
||||||
|
|
||||||
|
expect(data.text, null);
|
||||||
|
expect(data.html, null);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('AppFlowyClipboard setData and getData', (tester) async {
|
||||||
|
const rawText = "Hello World";
|
||||||
|
|
||||||
|
AppFlowyClipboardData? clipboardData;
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
theme: ThemeData(platform: TargetPlatform.windows),
|
||||||
|
home: Column(
|
||||||
|
children: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () async =>
|
||||||
|
await AppFlowyClipboard.setData(text: rawText),
|
||||||
|
child: const Text('setData'),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () async =>
|
||||||
|
clipboardData = await AppFlowyClipboard.getData(),
|
||||||
|
child: const Text('getData'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
await tester.tap(find.text('setData'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
await tester.tap(find.text('getData'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(clipboardData?.text, rawText);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
43
test/infra/flowy_svg_test.dart
Normal file
43
test/infra/flowy_svg_test.dart
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
import 'package:appflowy_editor/src/infra/flowy_svg.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import '../test_helper.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('FlowySvg tests', () {
|
||||||
|
testWidgets('FlowySvg w/ Name', (tester) async {
|
||||||
|
await tester.buildAndPump(
|
||||||
|
const FlowySvg(name: 'checkmark', color: Colors.blue),
|
||||||
|
);
|
||||||
|
|
||||||
|
final svgFinder = find.byType(SvgPicture);
|
||||||
|
expect(svgFinder, findsOneWidget);
|
||||||
|
|
||||||
|
final svgPicture = tester.widget<SvgPicture>(svgFinder);
|
||||||
|
expect(svgPicture.fit, BoxFit.fill);
|
||||||
|
expect(
|
||||||
|
svgPicture.colorFilter,
|
||||||
|
const ColorFilter.mode(Colors.blue, BlendMode.srcIn),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('FlowySvg w/ Number', (tester) async {
|
||||||
|
await tester.buildAndPump(
|
||||||
|
const FlowySvg(number: 1),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(find.byType(SvgPicture), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('FlowySvg null', (tester) async {
|
||||||
|
await tester.buildAndPump(
|
||||||
|
const FlowySvg(),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(find.byType(Container), findsOneWidget);
|
||||||
|
expect(find.byType(SvgPicture), findsNothing);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
53
test/infra/html_converter_test.dart
Normal file
53
test/infra/html_converter_test.dart
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
import 'package:appflowy_editor/src/infra/html_converter.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('HTMLConverter tests', () {
|
||||||
|
test('HTMLToNodesConverter', () {
|
||||||
|
final converter = HTMLToNodesConverter(rawHTML);
|
||||||
|
final nodes = converter.toNodes();
|
||||||
|
|
||||||
|
expect(nodes.isNotEmpty, true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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>
|
||||||
|
|
||||||
|
<span style="font-weight: bold;">Span element</span>
|
||||||
|
|
||||||
|
<span style="font-weight: medium;">Span element two</span>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>[x] Customizable</li>
|
||||||
|
<li>[x] Test-covered</li>
|
||||||
|
<li>[ ] more to come!</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>First item</li>
|
||||||
|
<li>Second item</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<li>List element</li>
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<p>This is a quote!</p>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<code>
|
||||||
|
Code block
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<b>Bold tag</b>
|
||||||
|
<img src="http://appflowy.io" alt="AppFlowy">
|
||||||
|
<p>You can also use <strong><em>AppFlowy Editor</em></strong> as a component to build your own app.</p>
|
||||||
|
<h3>Awesome features</h3>
|
||||||
|
<p>If you have questions or feedback, please submit an issue on Github or join the community along with 1000+ builders!</p>
|
||||||
|
<hr>""";
|
||||||
|
|
@ -52,6 +52,17 @@ void main() async {
|
||||||
assert(transaction.operations[2] is UpdateOperation);
|
assert(transaction.operations[2] is UpdateOperation);
|
||||||
assert(isInsertAndPathEqual(transaction.operations[3], [0], '0'));
|
assert(isInsertAndPathEqual(transaction.operations[3], [0], '0'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("HistoryItem sealed", () {
|
||||||
|
final historyItem = HistoryItem();
|
||||||
|
|
||||||
|
historyItem.add(
|
||||||
|
DeleteOperation([0], [TextNode(delta: Delta()..insert('0'))]),
|
||||||
|
);
|
||||||
|
|
||||||
|
historyItem.seal();
|
||||||
|
expect(historyItem.sealed, true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isInsertAndPathEqual(Operation operation, Path path, [String? content]) {
|
bool isInsertAndPathEqual(Operation operation, Path path, [String? content]) {
|
||||||
|
|
|
||||||
60
test/plugins/markdown/document_markdown_test.dart
Normal file
60
test/plugins/markdown/document_markdown_test.dart
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('document_markdown.dart tests', () {
|
||||||
|
test('markdownToDocument()', () {
|
||||||
|
final document = markdownToDocument(markdownDocument);
|
||||||
|
final data = Map<String, Object>.from(json.decode(testDocument));
|
||||||
|
|
||||||
|
expect(document.toJson(), data);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('documentToMarkdown()', () {
|
||||||
|
final document = markdownToDocument(markdownDocument);
|
||||||
|
final markdown = documentToMarkdown(document);
|
||||||
|
|
||||||
|
expect(markdown, markdownDocumentEncoded);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const testDocument = '''{
|
||||||
|
"document": {
|
||||||
|
"type": "editor",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"attributes": {"subtype": "heading", "heading": "h1"},
|
||||||
|
"delta": [{"insert": "Heading 1"}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"attributes": {"subtype": "heading", "heading": "h2"},
|
||||||
|
"delta": [{"insert": "Heading 2"}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"attributes": {"subtype": "heading", "heading": "h3"},
|
||||||
|
"delta": [{"insert": "Heading 3"}]
|
||||||
|
},
|
||||||
|
{"type": "text", "delta": []},
|
||||||
|
{"type": "divider"},
|
||||||
|
{"type": "text", "delta": [{"insert": ""}]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}''';
|
||||||
|
|
||||||
|
const markdownDocument = """# Heading 1
|
||||||
|
## Heading 2
|
||||||
|
### Heading 3
|
||||||
|
|
||||||
|
---""";
|
||||||
|
|
||||||
|
const markdownDocumentEncoded = """# Heading 1
|
||||||
|
## Heading 2
|
||||||
|
### Heading 3
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
@ -10,8 +10,14 @@ void main() async {
|
||||||
'image_src': 'https://appflowy.io',
|
'image_src': 'https://appflowy.io',
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
final result = const ImageNodeParser().transform(node);
|
final result = const ImageNodeParser().transform(node);
|
||||||
expect(result, '');
|
expect(result, '');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('ImageNodeParser id getter', () {
|
||||||
|
const imageNodeParser = ImageNodeParser();
|
||||||
|
expect(imageNodeParser.id, 'image');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,34 @@ void main() async {
|
||||||
BuiltInAttributeKey.heading: BuiltInAttributeKey.h3,
|
BuiltInAttributeKey.heading: BuiltInAttributeKey.h3,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
final h4 = TextNode(
|
||||||
|
delta: Delta(operations: [TextInsert(text)]),
|
||||||
|
attributes: {
|
||||||
|
BuiltInAttributeKey.subtype: BuiltInAttributeKey.heading,
|
||||||
|
BuiltInAttributeKey.heading: BuiltInAttributeKey.h4,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
final h5 = TextNode(
|
||||||
|
delta: Delta(operations: [TextInsert(text)]),
|
||||||
|
attributes: {
|
||||||
|
BuiltInAttributeKey.subtype: BuiltInAttributeKey.heading,
|
||||||
|
BuiltInAttributeKey.heading: BuiltInAttributeKey.h5,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
final h6 = TextNode(
|
||||||
|
delta: Delta(operations: [TextInsert(text)]),
|
||||||
|
attributes: {
|
||||||
|
BuiltInAttributeKey.subtype: BuiltInAttributeKey.heading,
|
||||||
|
BuiltInAttributeKey.heading: BuiltInAttributeKey.h6,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
expect(const TextNodeParser().transform(h1), '# $text');
|
expect(const TextNodeParser().transform(h1), '# $text');
|
||||||
expect(const TextNodeParser().transform(h2), '## $text');
|
expect(const TextNodeParser().transform(h2), '## $text');
|
||||||
expect(const TextNodeParser().transform(h3), '### $text');
|
expect(const TextNodeParser().transform(h3), '### $text');
|
||||||
|
expect(const TextNodeParser().transform(h4), '#### $text');
|
||||||
|
expect(const TextNodeParser().transform(h5), '##### $text');
|
||||||
|
expect(const TextNodeParser().transform(h6), '###### $text');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('bulleted list style', () {
|
test('bulleted list style', () {
|
||||||
|
|
@ -91,5 +116,19 @@ void main() async {
|
||||||
);
|
);
|
||||||
expect(const TextNodeParser().transform(node), '```\n$text\n```');
|
expect(const TextNodeParser().transform(node), '```\n$text\n```');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('fallback', () {
|
||||||
|
final node = TextNode(
|
||||||
|
delta: Delta(operations: [TextInsert(text)]),
|
||||||
|
attributes: {
|
||||||
|
BuiltInAttributeKey.bold: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
expect(const TextNodeParser().transform(node), text);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('TextNodeParser.id', () {
|
||||||
|
expect(const TextNodeParser().id, 'text');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
48
test/render/action_menu/action_menu_item_test.dart
Normal file
48
test/render/action_menu/action_menu_item_test.dart
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
|
import 'package:appflowy_editor/src/infra/flowy_svg.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import '../../test_helper.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('ActionMenuItem tests', () {
|
||||||
|
testWidgets('ActionMenuItem.icon()', (tester) async {
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
final item = ActionMenuItem.icon(
|
||||||
|
iconData: Icons.abc,
|
||||||
|
onPressed: () => count++,
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.buildAndPump(item.iconBuilder());
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
item.onPressed!.call();
|
||||||
|
expect(count, 1);
|
||||||
|
|
||||||
|
expect(find.byType(Icon), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('ActionMenuItem.svg()', (tester) async {
|
||||||
|
final item = ActionMenuItem.svg(name: 'check', onPressed: () {});
|
||||||
|
|
||||||
|
await tester.buildAndPump(item.iconBuilder());
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.byType(FlowySvg), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('ActionMenuItem.separator()', (tester) async {
|
||||||
|
final item = ActionMenuItem.separator();
|
||||||
|
|
||||||
|
await tester.buildAndPump(item.iconBuilder());
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.byType(FlowySvg), findsOneWidget);
|
||||||
|
|
||||||
|
final svg = tester.widget<FlowySvg>(find.byType(FlowySvg));
|
||||||
|
expect(svg.name, 'image_toolbar/divider');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
25
test/test_helper.dart
Normal file
25
test/test_helper.dart
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
extension BuildAndPump on WidgetTester {
|
||||||
|
Future<void> buildAndPump(Widget child) async {
|
||||||
|
await pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
localizationsDelegates: const [
|
||||||
|
GlobalMaterialLocalizations.delegate,
|
||||||
|
GlobalCupertinoLocalizations.delegate,
|
||||||
|
GlobalWidgetsLocalizations.delegate,
|
||||||
|
AppFlowyEditorLocalizations.delegate,
|
||||||
|
],
|
||||||
|
supportedLocales: AppFlowyEditorLocalizations.delegate.supportedLocales,
|
||||||
|
locale: const Locale('en'),
|
||||||
|
home: Scaffold(
|
||||||
|
body: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await pump();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue