import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:go_router/go_router.dart'; import 'package:social_app/features/chat/ui/widgets/ui_schema_renderer.dart'; void main() { group('UiSchemaRenderer', () { testWidgets('renders stack title and badge', (tester) async { final schema = { 'version': '2.0', 'locale': 'zh-CN', 'status': 'success', 'theme': 'default', 'root': { 'type': 'stack', 'direction': 'vertical', 'appearance': 'card', 'children': [ {'type': 'text', 'role': 'title', 'content': '日程已创建'}, {'type': 'badge', 'label': 'SUCCESS', 'status': 'success'}, ], }, }; await tester.pumpWidget( MaterialApp( home: Scaffold(body: UiSchemaRenderer.renderSchema(schema)), ), ); expect(find.text('日程已创建'), findsOneWidget); expect(find.text('SUCCESS'), findsOneWidget); }); testWidgets('renders kv node values', (tester) async { final schema = { 'version': '2.0', 'root': { 'type': 'stack', 'direction': 'vertical', 'appearance': 'card', 'children': [ { 'type': 'kv', 'items': [ {'key': 'title', 'label': '标题', 'value': '评审会'}, ], }, ], }, }; await tester.pumpWidget( MaterialApp( home: Scaffold(body: UiSchemaRenderer.renderSchema(schema)), ), ); expect(find.text('标题'), findsOneWidget); expect(find.text('评审会'), findsOneWidget); }); testWidgets('renders batch result list items in one card', (tester) async { final schema = { 'version': '2.0', 'root': { 'type': 'stack', 'direction': 'vertical', 'appearance': 'card', 'status': 'warning', 'children': [ {'type': 'text', 'role': 'title', 'content': '日历操作完成'}, { 'type': 'stack', 'direction': 'vertical', 'gap': 8, 'children': [ { 'type': 'stack', 'direction': 'vertical', 'appearance': 'card', 'children': [ {'type': 'text', 'role': 'body', 'content': '#1 create'}, {'type': 'text', 'role': 'caption', 'content': '成功'}, {'type': 'text', 'role': 'caption', 'content': '日程「晨会」已创建'}, ], }, { 'type': 'stack', 'direction': 'vertical', 'appearance': 'card', 'children': [ {'type': 'text', 'role': 'body', 'content': '#2 delete'}, {'type': 'text', 'role': 'caption', 'content': '失败'}, { 'type': 'text', 'role': 'caption', 'content': 'Schedule item not found', }, ], }, ], }, ], }, }; await tester.pumpWidget( MaterialApp( home: Scaffold(body: UiSchemaRenderer.renderSchema(schema)), ), ); expect(find.text('日历操作完成'), findsOneWidget); expect(find.text('#1 create'), findsOneWidget); expect(find.text('#2 delete'), findsOneWidget); expect(find.text('成功'), findsOneWidget); expect(find.text('失败'), findsOneWidget); }); testWidgets('renders fallback for invalid schema', (tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( body: UiSchemaRenderer.renderSchema({'version': '2.0'}), ), ), ); expect(find.textContaining('无效 UI Schema'), findsOneWidget); }); testWidgets('handles navigation action by pushing target page', ( tester, ) async { final schema = { 'version': '2.0', 'root': { 'type': 'stack', 'direction': 'vertical', 'appearance': 'plain', 'children': [ { 'type': 'button', 'label': '查看待办', 'style': 'primary', 'action': { 'type': 'navigation', 'path': '/todo/123', 'params': {'from': 'assistant'}, }, }, ], }, }; final router = GoRouter( initialLocation: '/', routes: [ GoRoute( path: '/', builder: (context, state) => Scaffold(body: UiSchemaRenderer.renderSchema(schema)), ), GoRoute( path: '/todo/:id', builder: (context, state) => Text( 'todo detail ${state.pathParameters['id']} from ${state.uri.queryParameters['from']}', ), ), ], ); await tester.pumpWidget(MaterialApp.router(routerConfig: router)); await tester.tap(find.text('查看待办')); await tester.pumpAndSettle(); expect(find.text('todo detail 123 from assistant'), findsOneWidget); expect(router.canPop(), isTrue); router.pop(); await tester.pumpAndSettle(); expect(find.text('查看待办'), findsOneWidget); }); testWidgets('uses replace navigation when replace is true', (tester) async { final schema = { 'version': '2.0', 'root': { 'type': 'stack', 'direction': 'vertical', 'appearance': 'plain', 'children': [ { 'type': 'button', 'label': '替换跳转', 'style': 'primary', 'action': { 'type': 'navigation', 'path': '/todo/456', 'replace': true, }, }, ], }, }; final router = GoRouter( initialLocation: '/', routes: [ GoRoute( path: '/', builder: (context, state) => Scaffold(body: UiSchemaRenderer.renderSchema(schema)), ), GoRoute( path: '/todo/:id', builder: (context, state) => Text('todo detail ${state.pathParameters['id']}'), ), ], ); await tester.pumpWidget(MaterialApp.router(routerConfig: router)); await tester.tap(find.text('替换跳转')); await tester.pumpAndSettle(); expect(find.text('todo detail 456'), findsOneWidget); expect(router.canPop(), isFalse); expect(find.text('todo detail 456'), findsOneWidget); }); testWidgets('does not navigate for placeholder path', (tester) async { final schema = { 'version': '2.0', 'root': { 'type': 'stack', 'direction': 'vertical', 'appearance': 'plain', 'children': [ { 'type': 'button', 'label': '坏路径', 'style': 'primary', 'action': {'type': 'navigation', 'path': '/todo/:id'}, }, ], }, }; final router = GoRouter( initialLocation: '/', routes: [ GoRoute( path: '/', builder: (context, state) => Scaffold(body: UiSchemaRenderer.renderSchema(schema)), ), GoRoute( path: '/todo/:id', builder: (context, state) => const Text('detail'), ), ], ); await tester.pumpWidget(MaterialApp.router(routerConfig: router)); await tester.tap(find.text('坏路径')); await tester.pumpAndSettle(); await tester.pump(const Duration(seconds: 3)); expect(find.text('坏路径'), findsOneWidget); expect(find.text('detail'), findsNothing); }); }); }