forked from eatvio/eatvio_app
627 lines
18 KiB
Dart
627 lines
18 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);
|
||
});
|
||
});
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|