forked from eatvio/eatvio_app
Co-authored-by: misha <mikhail_zakharov_15482356@mail.ru> Co-authored-by: misha <misha@noreply.localhost> Reviewed-on: eatvio/eatvio_app#985
855 lines
25 KiB
Dart
855 lines
25 KiB
Dart
import 'package:eatvio_app/common/widgets/markdown_editor.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_test/flutter_test.dart';
|
||
|
||
void main() {
|
||
group('MarkdownEditor', () {
|
||
testWidgets('отображается как виджет', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(),
|
||
),
|
||
),
|
||
);
|
||
|
||
expect(find.byType(MarkdownEditor), findsOneWidget);
|
||
});
|
||
|
||
testWidgets('инициализируется с initialText', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(initialText: 'Initial text'),
|
||
),
|
||
),
|
||
);
|
||
|
||
expect(find.byType(MarkdownEditor), findsOneWidget);
|
||
});
|
||
|
||
testWidgets('отображает hintText', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(hintText: 'Enter text here'),
|
||
),
|
||
),
|
||
);
|
||
|
||
expect(find.byType(MarkdownEditor), findsOneWidget);
|
||
});
|
||
|
||
testWidgets('вызывает onChanged при изменении текста', (WidgetTester tester) async {
|
||
String? changedValue;
|
||
await tester.pumpWidget(
|
||
MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
onChanged: (value) => changedValue = value,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
final textField = find.byType(TextField);
|
||
expect(textField, findsOneWidget);
|
||
|
||
await tester.enterText(textField, 'Test');
|
||
await tester.pump();
|
||
|
||
// onChanged должен быть вызван
|
||
expect(changedValue, isNotNull);
|
||
});
|
||
|
||
testWidgets('отображает toolbar когда showInlineToolbar = true', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(showInlineToolbar: true),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
// Toolbar должен быть виден
|
||
expect(find.byIcon(Icons.format_bold), findsOneWidget);
|
||
});
|
||
|
||
testWidgets('скрывает toolbar когда showInlineToolbar = false', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(showInlineToolbar: false),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
// Toolbar не должен быть виден
|
||
expect(find.byIcon(Icons.format_bold), findsNothing);
|
||
});
|
||
|
||
testWidgets('применяет форматирование жирным', (WidgetTester tester) async {
|
||
String? changedValue;
|
||
await tester.pumpWidget(
|
||
MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
onChanged: (value) => changedValue = value,
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
final textField = find.byType(TextField);
|
||
await tester.enterText(textField, 'Test');
|
||
await tester.pump();
|
||
|
||
// Нажимаем кнопку жирного
|
||
await tester.tap(find.byIcon(Icons.format_bold));
|
||
await tester.pump();
|
||
|
||
expect(changedValue, isNotNull);
|
||
});
|
||
|
||
testWidgets('применяет форматирование курсивом', (WidgetTester tester) async {
|
||
String? changedValue;
|
||
await tester.pumpWidget(
|
||
MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
onChanged: (value) => changedValue = value,
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
final textField = find.byType(TextField);
|
||
await tester.enterText(textField, 'Test');
|
||
await tester.pump();
|
||
|
||
await tester.tap(find.byIcon(Icons.format_italic));
|
||
await tester.pump();
|
||
|
||
expect(changedValue, isNotNull);
|
||
});
|
||
|
||
testWidgets('применяет заголовок', (WidgetTester tester) async {
|
||
String? changedValue;
|
||
await tester.pumpWidget(
|
||
MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
onChanged: (value) => changedValue = value,
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
final textField = find.byType(TextField);
|
||
await tester.enterText(textField, 'Test');
|
||
await tester.pump();
|
||
|
||
// Находим кнопку заголовка (текст 'H')
|
||
final headingButton = find.text('H');
|
||
await tester.tap(headingButton);
|
||
await tester.pump();
|
||
|
||
expect(changedValue, isNotNull);
|
||
});
|
||
|
||
testWidgets('применяет нумерованный список', (WidgetTester tester) async {
|
||
String? changedValue;
|
||
await tester.pumpWidget(
|
||
MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
onChanged: (value) => changedValue = value,
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
final textField = find.byType(TextField);
|
||
await tester.enterText(textField, 'Test');
|
||
await tester.pump();
|
||
|
||
await tester.tap(find.byIcon(Icons.format_list_numbered));
|
||
await tester.pump();
|
||
|
||
expect(changedValue, isNotNull);
|
||
});
|
||
|
||
testWidgets('применяет маркированный список', (WidgetTester tester) async {
|
||
String? changedValue;
|
||
await tester.pumpWidget(
|
||
MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
onChanged: (value) => changedValue = value,
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
final textField = find.byType(TextField);
|
||
await tester.enterText(textField, 'Test');
|
||
await tester.pump();
|
||
|
||
await tester.tap(find.byIcon(Icons.format_list_bulleted));
|
||
await tester.pump();
|
||
|
||
expect(changedValue, isNotNull);
|
||
});
|
||
|
||
testWidgets('применяет ссылку', (WidgetTester tester) async {
|
||
String? changedValue;
|
||
await tester.pumpWidget(
|
||
MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
onChanged: (value) => changedValue = value,
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
final textField = find.byType(TextField);
|
||
await tester.enterText(textField, 'Test');
|
||
await tester.pump();
|
||
|
||
await tester.tap(find.byIcon(Icons.link));
|
||
await tester.pump();
|
||
|
||
expect(changedValue, isNotNull);
|
||
});
|
||
|
||
testWidgets('применяет горизонтальную линию', (WidgetTester tester) async {
|
||
String? changedValue;
|
||
await tester.pumpWidget(
|
||
MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
onChanged: (value) => changedValue = value,
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
final textField = find.byType(TextField);
|
||
await tester.enterText(textField, 'Test');
|
||
await tester.pump();
|
||
|
||
await tester.tap(textField);
|
||
await tester.pump();
|
||
|
||
await tester.tap(find.byIcon(Icons.horizontal_rule));
|
||
await tester.pump();
|
||
|
||
expect(changedValue, contains('---'));
|
||
});
|
||
|
||
testWidgets('переключает режим preview', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: '# Test',
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
|
||
// Изначально должен быть режим редактирования
|
||
expect(find.byType(TextField), findsOneWidget);
|
||
|
||
// Нажимаем кнопку preview
|
||
await tester.tap(find.byIcon(Icons.visibility));
|
||
await tester.pumpAndSettle();
|
||
|
||
// Должен быть режим preview
|
||
expect(find.byType(TextField), findsNothing);
|
||
|
||
// Нажимаем кнопку редактирования
|
||
await tester.tap(find.byIcon(Icons.edit));
|
||
await tester.pumpAndSettle();
|
||
|
||
// Должен вернуться режим редактирования
|
||
expect(find.byType(TextField), findsOneWidget);
|
||
});
|
||
|
||
testWidgets('вызывает onToolbarVisibilityChanged при изменении видимости', (WidgetTester tester) async {
|
||
bool? toolbarVisible;
|
||
await tester.pumpWidget(
|
||
MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
showInlineToolbar: true,
|
||
onToolbarVisibilityChanged: (visible) => toolbarVisible = visible,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pumpAndSettle();
|
||
expect(toolbarVisible, isNotNull);
|
||
});
|
||
|
||
testWidgets('удаляет форматирование жирным если уже применено', (WidgetTester tester) async {
|
||
String? changedValue;
|
||
await tester.pumpWidget(
|
||
MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: '**Test**',
|
||
onChanged: (value) => changedValue = value,
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
final textField = find.byType(TextField);
|
||
await tester.tap(textField);
|
||
await tester.pump();
|
||
|
||
await tester.tap(find.byIcon(Icons.format_bold));
|
||
await tester.pump();
|
||
|
||
expect(changedValue, isNotNull);
|
||
});
|
||
|
||
testWidgets('обрабатывает ссылку в формате markdown', (WidgetTester tester) async {
|
||
String? changedValue;
|
||
await tester.pumpWidget(
|
||
MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: '[Link](url)',
|
||
onChanged: (value) => changedValue = value,
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
final textField = find.byType(TextField);
|
||
await tester.tap(textField);
|
||
await tester.pump();
|
||
|
||
await tester.tap(find.byIcon(Icons.link));
|
||
await tester.pump();
|
||
|
||
expect(changedValue, isNotNull);
|
||
});
|
||
|
||
testWidgets('отображает preview с заголовком', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: '# Heading',
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
await tester.tap(find.byIcon(Icons.visibility));
|
||
await tester.pumpAndSettle();
|
||
|
||
// Заголовок рендерится через Text виджет
|
||
expect(find.textContaining('Heading'), findsWidgets);
|
||
});
|
||
|
||
testWidgets('отображает preview с маркированным списком', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: '- Item 1\n- Item 2',
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
await tester.tap(find.byIcon(Icons.visibility));
|
||
await tester.pumpAndSettle();
|
||
|
||
// Проверяем, что preview отображается (RichText виджеты должны быть)
|
||
expect(find.byType(RichText), findsWidgets);
|
||
// Проверяем наличие текста через RichText
|
||
final richTexts = find.byType(RichText);
|
||
expect(richTexts, findsWidgets);
|
||
});
|
||
|
||
testWidgets('отображает preview с нумерованным списком', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: '1. First\n2. Second',
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
await tester.tap(find.byIcon(Icons.visibility));
|
||
await tester.pumpAndSettle();
|
||
|
||
// Проверяем, что preview отображается (RichText виджеты должны быть)
|
||
expect(find.byType(RichText), findsWidgets);
|
||
});
|
||
|
||
testWidgets('отображает preview с горизонтальной линией', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: '---',
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
await tester.tap(find.byIcon(Icons.visibility));
|
||
await tester.pumpAndSettle();
|
||
|
||
expect(find.byType(Divider), findsOneWidget);
|
||
});
|
||
|
||
testWidgets('обрабатывает hasError параметр', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
hasError: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
expect(find.byType(MarkdownEditor), findsOneWidget);
|
||
});
|
||
|
||
testWidgets('обрабатывает minLines и maxLines', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
minLines: 2,
|
||
maxLines: 5,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
expect(find.byType(MarkdownEditor), findsOneWidget);
|
||
});
|
||
|
||
testWidgets('обрабатывает heightPreview', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
heightPreview: 200,
|
||
initialText: 'Test',
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
await tester.tap(find.byIcon(Icons.visibility));
|
||
await tester.pumpAndSettle();
|
||
|
||
expect(find.byType(MarkdownEditor), findsOneWidget);
|
||
});
|
||
|
||
testWidgets('обрабатывает пустой текст в preview', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
hintText: 'Enter text',
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
await tester.tap(find.byIcon(Icons.visibility));
|
||
await tester.pumpAndSettle();
|
||
|
||
expect(find.text('Enter text'), findsOneWidget);
|
||
});
|
||
|
||
testWidgets('обрабатывает многострочный текст с форматированием', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: '# Title\n\n**Bold** text\n\n- List item',
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
await tester.tap(find.byIcon(Icons.visibility));
|
||
await tester.pumpAndSettle();
|
||
|
||
// Проверяем, что preview отображается (должны быть Text и RichText виджеты)
|
||
expect(find.byType(Text), findsWidgets);
|
||
expect(find.byType(RichText), findsWidgets);
|
||
});
|
||
|
||
testWidgets('обрабатывает встроенное форматирование в тексте', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: 'This is **bold** and this is *italic*',
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
await tester.tap(find.byIcon(Icons.visibility));
|
||
await tester.pumpAndSettle();
|
||
|
||
// Проверяем, что preview отображается (RichText должен быть)
|
||
expect(find.byType(RichText), findsWidgets);
|
||
});
|
||
|
||
testWidgets('обрабатывает ссылки в тексте', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: 'Check [this link](https://example.com)',
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
await tester.tap(find.byIcon(Icons.visibility));
|
||
await tester.pumpAndSettle();
|
||
|
||
// Проверяем, что preview отображается (RichText должен быть)
|
||
expect(find.byType(RichText), findsWidgets);
|
||
});
|
||
|
||
testWidgets('обрабатывает заголовки разных уровней', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: '# H1\n## H2\n### H3',
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
await tester.tap(find.byIcon(Icons.visibility));
|
||
await tester.pumpAndSettle();
|
||
|
||
expect(find.text('H1'), findsOneWidget);
|
||
expect(find.text('H2'), findsOneWidget);
|
||
expect(find.text('H3'), findsOneWidget);
|
||
});
|
||
|
||
testWidgets('обрабатывает пустые строки в preview', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: 'Line 1\n\nLine 2',
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
await tester.tap(find.byIcon(Icons.visibility));
|
||
await tester.pumpAndSettle();
|
||
|
||
// Проверяем, что preview отображается (RichText должен быть)
|
||
expect(find.byType(RichText), findsWidgets);
|
||
});
|
||
|
||
testWidgets('preview: маркер списка со звёздочкой', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: '* Asterisk item',
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
await tester.tap(find.byIcon(Icons.visibility));
|
||
await tester.pumpAndSettle();
|
||
|
||
// Тело пункта в RichText/TextSpan — find.textContaining не всегда его видит
|
||
expect(find.byType(RichText), findsWidgets);
|
||
expect(find.textContaining('•'), findsWidgets);
|
||
});
|
||
|
||
testWidgets('preview: нумерация из двух цифр', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: '10. Tenth row',
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
await tester.tap(find.byIcon(Icons.visibility));
|
||
await tester.pumpAndSettle();
|
||
|
||
expect(find.byType(RichText), findsWidgets);
|
||
expect(find.textContaining('10.'), findsWidgets);
|
||
});
|
||
|
||
testWidgets(' после выхода из preview выполняется отложенный requestFocus', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: 'focus',
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
await tester.tap(find.byIcon(Icons.visibility));
|
||
await tester.pumpAndSettle();
|
||
await tester.tap(find.byIcon(Icons.edit));
|
||
await tester.pump();
|
||
await tester.pump(const Duration(milliseconds: 150));
|
||
|
||
expect(find.byType(TextField), findsOneWidget);
|
||
});
|
||
|
||
testWidgets(' снимает разметку ссылки когда выделен markdown-link', (WidgetTester tester) async {
|
||
String? changed;
|
||
await tester.pumpWidget(
|
||
MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: '[Label](https://example.com)',
|
||
showInlineToolbar: true,
|
||
onChanged: (v) => changed = v,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
|
||
final field = tester.widget<TextField>(find.byType(TextField));
|
||
final controller = field.controller!;
|
||
controller.selection = TextSelection(baseOffset: 0, extentOffset: controller.text.length);
|
||
|
||
await tester.tap(find.byIcon(Icons.link));
|
||
await tester.pump();
|
||
|
||
expect(changed, contains('Label'));
|
||
expect(changed, isNot(contains('[Label](https://example.com)')));
|
||
});
|
||
|
||
testWidgets('preview: H2 heading renders larger heading style', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: '## Subtitle',
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
await tester.tap(find.byIcon(Icons.visibility));
|
||
await tester.pumpAndSettle();
|
||
|
||
expect(find.text('Subtitle'), findsOneWidget);
|
||
});
|
||
|
||
testWidgets('preview: H3 heading renders heading text', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: '### Detail',
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
await tester.tap(find.byIcon(Icons.visibility));
|
||
await tester.pumpAndSettle();
|
||
|
||
expect(find.text('Detail'), findsOneWidget);
|
||
});
|
||
|
||
testWidgets('preview: horizontal rule renders Divider', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: 'Above\n---\nBelow',
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
await tester.tap(find.byIcon(Icons.visibility));
|
||
await tester.pumpAndSettle();
|
||
|
||
expect(find.byType(Divider), findsOneWidget);
|
||
});
|
||
|
||
testWidgets('preview: italic span renders inside RichText', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: 'A *cursive* word',
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
await tester.tap(find.byIcon(Icons.visibility));
|
||
await tester.pumpAndSettle();
|
||
|
||
expect(find.byType(RichText), findsWidgets);
|
||
});
|
||
|
||
testWidgets('preview: link span renders inside RichText', (WidgetTester tester) async {
|
||
await tester.pumpWidget(
|
||
const MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: 'Visit [the docs](https://example.com)',
|
||
showInlineToolbar: true,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
await tester.pump();
|
||
await tester.tap(find.byIcon(Icons.visibility));
|
||
await tester.pumpAndSettle();
|
||
|
||
expect(find.byType(RichText), findsWidgets);
|
||
});
|
||
|
||
testWidgets('toolbar buttons mutate text via onChanged when cursor is set', (WidgetTester tester) async {
|
||
String? changed;
|
||
|
||
await tester.pumpWidget(
|
||
MaterialApp(
|
||
home: Scaffold(
|
||
body: MarkdownEditor(
|
||
initialText: 'plain',
|
||
showInlineToolbar: true,
|
||
onChanged: (v) => changed = v,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
await tester.pump();
|
||
|
||
final field = tester.widget<TextField>(find.byType(TextField));
|
||
final controller = field.controller!;
|
||
controller.selection = const TextSelection.collapsed(offset: 0);
|
||
|
||
await tester.tap(find.byIcon(Icons.format_bold));
|
||
await tester.pump();
|
||
expect(changed, contains('**'));
|
||
|
||
controller.text = 'plain';
|
||
controller.selection = const TextSelection.collapsed(offset: 0);
|
||
await tester.tap(find.byIcon(Icons.format_italic));
|
||
await tester.pump();
|
||
expect(changed, contains('*'));
|
||
|
||
controller.text = 'plain';
|
||
controller.selection = const TextSelection.collapsed(offset: 0);
|
||
await tester.tap(find.byIcon(Icons.horizontal_rule));
|
||
await tester.pump();
|
||
expect(changed, contains('---'));
|
||
|
||
controller.text = 'plain';
|
||
controller.selection = const TextSelection.collapsed(offset: 0);
|
||
await tester.tap(find.byIcon(Icons.link));
|
||
await tester.pump();
|
||
expect(changed, contains('](url)'));
|
||
});
|
||
});
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|