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); }); }); }