test: 更新 AgentScope 相关单元测试与集成测试
- 重命名 test_react_runner.py 为 test_runner.py - 新增 test_utils.py 测试工具函数 - 更新现有测试用例适配新架构
This commit is contained in:
@@ -2,375 +2,90 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:social_app/features/chat/data/models/ag_ui_event.dart';
|
||||
|
||||
void main() {
|
||||
group('agUiEventTypeFromWire', () {
|
||||
test('maps RUN_STARTED correctly', () {
|
||||
expect(agUiEventTypeFromWire('RUN_STARTED'), AgUiEventType.runStarted);
|
||||
});
|
||||
|
||||
test('maps RUN_FINISHED correctly', () {
|
||||
expect(agUiEventTypeFromWire('RUN_FINISHED'), AgUiEventType.runFinished);
|
||||
});
|
||||
|
||||
test('maps RUN_ERROR correctly', () {
|
||||
expect(agUiEventTypeFromWire('RUN_ERROR'), AgUiEventType.runError);
|
||||
});
|
||||
|
||||
test('maps TEXT_MESSAGE_START correctly', () {
|
||||
expect(
|
||||
agUiEventTypeFromWire('TEXT_MESSAGE_START'),
|
||||
AgUiEventType.textMessageStart,
|
||||
);
|
||||
});
|
||||
|
||||
test('maps TEXT_MESSAGE_CONTENT correctly', () {
|
||||
expect(
|
||||
agUiEventTypeFromWire('TEXT_MESSAGE_CONTENT'),
|
||||
AgUiEventType.textMessageContent,
|
||||
);
|
||||
});
|
||||
|
||||
test('maps TEXT_MESSAGE_END correctly', () {
|
||||
expect(
|
||||
agUiEventTypeFromWire('TEXT_MESSAGE_END'),
|
||||
AgUiEventType.textMessageEnd,
|
||||
);
|
||||
});
|
||||
|
||||
test('maps TOOL_CALL_START correctly', () {
|
||||
expect(
|
||||
agUiEventTypeFromWire('TOOL_CALL_START'),
|
||||
AgUiEventType.toolCallStart,
|
||||
);
|
||||
});
|
||||
|
||||
test('maps TOOL_CALL_ARGS correctly', () {
|
||||
expect(
|
||||
agUiEventTypeFromWire('TOOL_CALL_ARGS'),
|
||||
AgUiEventType.toolCallArgs,
|
||||
);
|
||||
});
|
||||
|
||||
test('maps TOOL_CALL_END correctly', () {
|
||||
expect(agUiEventTypeFromWire('TOOL_CALL_END'), AgUiEventType.toolCallEnd);
|
||||
});
|
||||
|
||||
test('maps TOOL_CALL_RESULT correctly', () {
|
||||
expect(
|
||||
agUiEventTypeFromWire('TOOL_CALL_RESULT'),
|
||||
AgUiEventType.toolCallResult,
|
||||
);
|
||||
});
|
||||
|
||||
test('maps TOOL_CALL_ERROR correctly', () {
|
||||
expect(
|
||||
agUiEventTypeFromWire('TOOL_CALL_ERROR'),
|
||||
AgUiEventType.toolCallError,
|
||||
);
|
||||
});
|
||||
|
||||
test('maps STATE_SNAPSHOT correctly', () {
|
||||
expect(
|
||||
agUiEventTypeFromWire('STATE_SNAPSHOT'),
|
||||
AgUiEventType.stateSnapshot,
|
||||
);
|
||||
});
|
||||
|
||||
test('returns unknown for unknown type', () {
|
||||
expect(agUiEventTypeFromWire('UNKNOWN_TYPE'), AgUiEventType.unknown);
|
||||
});
|
||||
|
||||
test('returns unknown for empty string', () {
|
||||
expect(agUiEventTypeFromWire(''), AgUiEventType.unknown);
|
||||
});
|
||||
});
|
||||
|
||||
group('agUiEventTypeToWire', () {
|
||||
test('maps runStarted to RUN_STARTED', () {
|
||||
expect(agUiEventTypeToWire(AgUiEventType.runStarted), 'RUN_STARTED');
|
||||
});
|
||||
|
||||
test('maps runFinished to RUN_FINISHED', () {
|
||||
expect(agUiEventTypeToWire(AgUiEventType.runFinished), 'RUN_FINISHED');
|
||||
});
|
||||
|
||||
test('maps textMessageStart to TEXT_MESSAGE_START', () {
|
||||
expect(
|
||||
agUiEventTypeToWire(AgUiEventType.textMessageStart),
|
||||
'TEXT_MESSAGE_START',
|
||||
);
|
||||
});
|
||||
|
||||
test('maps unknown to empty string', () {
|
||||
expect(agUiEventTypeToWire(AgUiEventType.unknown), '');
|
||||
});
|
||||
});
|
||||
|
||||
group('AgUiEvent.fromJson', () {
|
||||
test('parses RunStartedEvent', () {
|
||||
final json = {
|
||||
'type': 'RUN_STARTED',
|
||||
'threadId': 'thread_123',
|
||||
'runId': 'run_456',
|
||||
};
|
||||
|
||||
final event = AgUiEvent.fromJson(json);
|
||||
|
||||
expect(event, isA<RunStartedEvent>());
|
||||
final runStarted = event as RunStartedEvent;
|
||||
expect(runStarted.threadId, 'thread_123');
|
||||
expect(runStarted.runId, 'run_456');
|
||||
});
|
||||
|
||||
test('parses RunFinishedEvent', () {
|
||||
final json = {
|
||||
'type': 'RUN_FINISHED',
|
||||
'threadId': 'thread_123',
|
||||
'runId': 'run_456',
|
||||
};
|
||||
|
||||
final event = AgUiEvent.fromJson(json);
|
||||
|
||||
expect(event, isA<RunFinishedEvent>());
|
||||
final runFinished = event as RunFinishedEvent;
|
||||
expect(runFinished.threadId, 'thread_123');
|
||||
});
|
||||
|
||||
test('parses RunErrorEvent', () {
|
||||
final json = {
|
||||
'type': 'RUN_ERROR',
|
||||
'message': 'Something went wrong',
|
||||
'code': 'ERR_001',
|
||||
};
|
||||
|
||||
final event = AgUiEvent.fromJson(json);
|
||||
|
||||
expect(event, isA<RunErrorEvent>());
|
||||
final runError = event as RunErrorEvent;
|
||||
expect(runError.message, 'Something went wrong');
|
||||
expect(runError.code, 'ERR_001');
|
||||
});
|
||||
|
||||
test('parses TextMessageStartEvent', () {
|
||||
final json = {
|
||||
'type': 'TEXT_MESSAGE_START',
|
||||
'messageId': 'msg_123',
|
||||
group('AgUiEvent parsing', () {
|
||||
test('parses TEXT_MESSAGE_END with ui_schema payload', () {
|
||||
final event = AgUiEvent.fromJson({
|
||||
'type': 'TEXT_MESSAGE_END',
|
||||
'messageId': 'msg_1',
|
||||
'answer': '你好',
|
||||
'role': 'assistant',
|
||||
};
|
||||
|
||||
final event = AgUiEvent.fromJson(json);
|
||||
|
||||
expect(event, isA<TextMessageStartEvent>());
|
||||
final textStart = event as TextMessageStartEvent;
|
||||
expect(textStart.messageId, 'msg_123');
|
||||
expect(textStart.role, 'assistant');
|
||||
});
|
||||
|
||||
test('parses TextMessageContentEvent', () {
|
||||
final json = {
|
||||
'type': 'TEXT_MESSAGE_CONTENT',
|
||||
'messageId': 'msg_123',
|
||||
'delta': 'Hello',
|
||||
};
|
||||
|
||||
final event = AgUiEvent.fromJson(json);
|
||||
|
||||
expect(event, isA<TextMessageContentEvent>());
|
||||
final textContent = event as TextMessageContentEvent;
|
||||
expect(textContent.messageId, 'msg_123');
|
||||
expect(textContent.delta, 'Hello');
|
||||
});
|
||||
|
||||
test('parses TextMessageEndEvent', () {
|
||||
final json = {'type': 'TEXT_MESSAGE_END', 'messageId': 'msg_123'};
|
||||
|
||||
final event = AgUiEvent.fromJson(json);
|
||||
'status': 'success',
|
||||
'ui_schema': {
|
||||
'version': '2.0',
|
||||
'root': {
|
||||
'type': 'stack',
|
||||
'direction': 'vertical',
|
||||
'appearance': 'card',
|
||||
'children': [
|
||||
{'type': 'text', 'role': 'title', 'content': '创建成功'},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(event, isA<TextMessageEndEvent>());
|
||||
final textEnd = event as TextMessageEndEvent;
|
||||
expect(textEnd.messageId, 'msg_123');
|
||||
expect(textEnd.messageId, 'msg_1');
|
||||
expect(textEnd.answer, '你好');
|
||||
expect(textEnd.uiSchema?['version'], '2.0');
|
||||
});
|
||||
|
||||
test('parses ToolCallStartEvent', () {
|
||||
final json = {
|
||||
'type': 'TOOL_CALL_START',
|
||||
'toolCallId': 'tc_123',
|
||||
'toolCallName': 'back.mutate_calendar_event',
|
||||
'parentMessageId': 'msg_001',
|
||||
};
|
||||
|
||||
final event = AgUiEvent.fromJson(json);
|
||||
|
||||
expect(event, isA<ToolCallStartEvent>());
|
||||
final toolStart = event as ToolCallStartEvent;
|
||||
expect(toolStart.toolCallId, 'tc_123');
|
||||
expect(toolStart.toolCallName, 'back.mutate_calendar_event');
|
||||
expect(toolStart.parentMessageId, 'msg_001');
|
||||
});
|
||||
|
||||
test('parses ToolCallArgsEvent', () {
|
||||
final json = {
|
||||
'type': 'TOOL_CALL_ARGS',
|
||||
'toolCallId': 'tc_123',
|
||||
'delta': '{"title": "test"}',
|
||||
};
|
||||
|
||||
final event = AgUiEvent.fromJson(json);
|
||||
|
||||
expect(event, isA<ToolCallArgsEvent>());
|
||||
final toolArgs = event as ToolCallArgsEvent;
|
||||
expect(toolArgs.toolCallId, 'tc_123');
|
||||
expect(toolArgs.delta, '{"title": "test"}');
|
||||
});
|
||||
|
||||
test('parses ToolCallEndEvent', () {
|
||||
final json = {'type': 'TOOL_CALL_END', 'toolCallId': 'tc_123'};
|
||||
|
||||
final event = AgUiEvent.fromJson(json);
|
||||
|
||||
expect(event, isA<ToolCallEndEvent>());
|
||||
});
|
||||
|
||||
test('parses ToolCallResultEvent', () {
|
||||
final json = {
|
||||
test('parses TOOL_CALL_RESULT snake_case fields', () {
|
||||
final event = AgUiEvent.fromJson({
|
||||
'type': 'TOOL_CALL_RESULT',
|
||||
'messageId': 'msg_123',
|
||||
'toolCallId': 'tc_123',
|
||||
'content': '{"result":{"ok":true,"eventId":"evt_001"}}',
|
||||
};
|
||||
|
||||
final event = AgUiEvent.fromJson(json);
|
||||
'messageId': 'tool_1',
|
||||
'tool_call_id': 'call_1',
|
||||
'tool_name': 'calendar_read',
|
||||
'status': 'success',
|
||||
'result_summary': '找到 2 条结果',
|
||||
'ui_schema': {
|
||||
'version': '2.0',
|
||||
'root': {
|
||||
'type': 'stack',
|
||||
'direction': 'vertical',
|
||||
'appearance': 'card',
|
||||
'children': [],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(event, isA<ToolCallResultEvent>());
|
||||
final toolResult = event as ToolCallResultEvent;
|
||||
expect(toolResult.messageId, 'msg_123');
|
||||
expect(toolResult.toolCallId, 'tc_123');
|
||||
expect(toolResult.result['ok'], true);
|
||||
final result = event as ToolCallResultEvent;
|
||||
expect(result.toolCallId, 'call_1');
|
||||
expect(result.toolName, 'calendar_read');
|
||||
expect(result.resultSummary, '找到 2 条结果');
|
||||
expect(result.uiSchema, isNotNull);
|
||||
});
|
||||
|
||||
test('parses ToolCallResultEvent content payload', () {
|
||||
final json = {
|
||||
'type': 'TOOL_CALL_RESULT',
|
||||
'messageId': 'msg_123',
|
||||
'toolCallId': 'tc_123',
|
||||
'content': '{"result":{"ok":true,"eventId":"evt_001"}}',
|
||||
};
|
||||
test('parses history snapshot with ui_schema', () {
|
||||
final snapshot = HistorySnapshot.fromJson({
|
||||
'scope': 'history_day',
|
||||
'threadId': 'thread_1',
|
||||
'day': '2026-03-16',
|
||||
'hasMore': false,
|
||||
'messages': [
|
||||
{
|
||||
'id': 'm1',
|
||||
'seq': 1,
|
||||
'role': 'assistant',
|
||||
'content': '已处理',
|
||||
'ui_schema': {
|
||||
'version': '2.0',
|
||||
'root': {
|
||||
'type': 'stack',
|
||||
'direction': 'vertical',
|
||||
'appearance': 'card',
|
||||
'children': [],
|
||||
},
|
||||
},
|
||||
'timestamp': '2026-03-16T10:00:00Z',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
final event = AgUiEvent.fromJson(json);
|
||||
|
||||
expect(event, isA<ToolCallResultEvent>());
|
||||
final toolResult = event as ToolCallResultEvent;
|
||||
expect(toolResult.messageId, 'msg_123');
|
||||
expect(toolResult.toolCallId, 'tc_123');
|
||||
expect(toolResult.result['ok'], true);
|
||||
expect(toolResult.result['eventId'], 'evt_001');
|
||||
});
|
||||
|
||||
test('ToolCallResultEvent.ui parses from payload.ui', () {
|
||||
final json = {
|
||||
'type': 'TOOL_CALL_RESULT',
|
||||
'messageId': 'msg_123',
|
||||
'toolCallId': 'tc_123',
|
||||
'content':
|
||||
'{"ui":{"type":"calendar_card.v1","version":"v1","data":{"id":"evt_1","title":"会议","startAt":"2026-03-01T10:00:00Z"},"actions":[]}}',
|
||||
};
|
||||
|
||||
final event = AgUiEvent.fromJson(json) as ToolCallResultEvent;
|
||||
expect(event.ui, isNotNull);
|
||||
expect(event.ui!.cardType, 'calendar_card.v1');
|
||||
});
|
||||
|
||||
test(
|
||||
'ToolCallResultEvent.ui parses from payload.result when result is UiCard',
|
||||
() {
|
||||
final json = {
|
||||
'type': 'TOOL_CALL_RESULT',
|
||||
'messageId': 'msg_123',
|
||||
'toolCallId': 'tc_123',
|
||||
'content':
|
||||
'{"result":{"type":"calendar_operation.v1","version":"v1","data":{"operation":"delete","ok":true},"actions":[]}}',
|
||||
};
|
||||
|
||||
final event = AgUiEvent.fromJson(json) as ToolCallResultEvent;
|
||||
expect(event.ui, isNotNull);
|
||||
expect(event.ui!.cardType, 'calendar_operation.v1');
|
||||
},
|
||||
);
|
||||
|
||||
test('parses ToolCallErrorEvent', () {
|
||||
final json = {
|
||||
'type': 'TOOL_CALL_ERROR',
|
||||
'toolCallId': 'tc_123',
|
||||
'error': 'Execution failed',
|
||||
'code': 'EXEC_ERROR',
|
||||
};
|
||||
|
||||
final event = AgUiEvent.fromJson(json);
|
||||
|
||||
expect(event, isA<ToolCallErrorEvent>());
|
||||
final toolError = event as ToolCallErrorEvent;
|
||||
expect(toolError.toolCallId, 'tc_123');
|
||||
expect(toolError.error, 'Execution failed');
|
||||
expect(toolError.code, 'EXEC_ERROR');
|
||||
});
|
||||
|
||||
test('parses StateSnapshotEvent', () {
|
||||
final json = {
|
||||
'type': 'STATE_SNAPSHOT',
|
||||
'snapshot': {'scope': 'history_day', 'hasMore': false, 'messages': []},
|
||||
};
|
||||
|
||||
final event = AgUiEvent.fromJson(json);
|
||||
|
||||
expect(event, isA<StateSnapshotEvent>());
|
||||
final stateSnapshot = event as StateSnapshotEvent;
|
||||
expect(stateSnapshot.snapshot['scope'], 'history_day');
|
||||
});
|
||||
|
||||
test('returns UnknownAgUiEvent for unknown type', () {
|
||||
final json = {'type': 'UNKNOWN_TYPE', 'someField': 'someValue'};
|
||||
|
||||
final event = AgUiEvent.fromJson(json);
|
||||
|
||||
expect(event, isA<UnknownAgUiEvent>());
|
||||
final unknown = event as UnknownAgUiEvent;
|
||||
expect(unknown.rawJson['someField'], 'someValue');
|
||||
});
|
||||
|
||||
test('returns UnknownAgUiEvent for missing type', () {
|
||||
final json = {'someField': 'someValue'};
|
||||
|
||||
final event = AgUiEvent.fromJson(json);
|
||||
|
||||
expect(event, isA<UnknownAgUiEvent>());
|
||||
});
|
||||
});
|
||||
|
||||
group('toJson', () {
|
||||
test('RunStartedEvent serializes with correct fields', () {
|
||||
final event = RunStartedEvent(threadId: 't1', runId: 'r1');
|
||||
final json = event.toJson();
|
||||
|
||||
expect(json['threadId'], 't1');
|
||||
expect(json['runId'], 'r1');
|
||||
});
|
||||
|
||||
test('TextMessageContentEvent serializes with correct fields', () {
|
||||
final event = TextMessageContentEvent(messageId: 'm1', delta: 'hello');
|
||||
final json = event.toJson();
|
||||
|
||||
expect(json['messageId'], 'm1');
|
||||
expect(json['delta'], 'hello');
|
||||
});
|
||||
|
||||
test('ToolCallStartEvent serializes with correct fields', () {
|
||||
final event = ToolCallStartEvent(
|
||||
toolCallId: 'tc1',
|
||||
toolCallName: 'test_tool',
|
||||
);
|
||||
final json = event.toJson();
|
||||
|
||||
expect(json['toolCallId'], 'tc1');
|
||||
expect(json['toolCallName'], 'test_tool');
|
||||
expect(snapshot.scope, 'history_day');
|
||||
expect(snapshot.messages, hasLength(1));
|
||||
expect(snapshot.messages.first.uiSchema, isNotNull);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,226 +1,74 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:social_app/features/chat/data/models/tool_result.dart';
|
||||
import 'package:social_app/features/chat/ui/widgets/ui_schema_renderer.dart';
|
||||
|
||||
void main() {
|
||||
group('UiSchemaRenderer', () {
|
||||
testWidgets('calendar_card.v1 renders title', (tester) async {
|
||||
final card = UiCard(
|
||||
cardType: 'calendar_card.v1',
|
||||
data: CalendarCardData(
|
||||
id: 'evt_001',
|
||||
title: 'Team Meeting',
|
||||
startAt: '2026-03-01T10:00:00Z',
|
||||
).toJson(),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(home: Scaffold(body: UiSchemaRenderer.render(card))),
|
||||
);
|
||||
|
||||
expect(find.text('Team Meeting'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('calendar_card.v1 renders time', (tester) async {
|
||||
final card = UiCard(
|
||||
cardType: 'calendar_card.v1',
|
||||
data: CalendarCardData(
|
||||
id: 'evt_001',
|
||||
title: 'Meeting',
|
||||
startAt: '2026-03-01T10:00:00Z',
|
||||
endAt: '2026-03-01T11:30:00Z',
|
||||
).toJson(),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(home: Scaffold(body: UiSchemaRenderer.render(card))),
|
||||
);
|
||||
|
||||
expect(find.textContaining('3月1日'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('calendar_card.v1 renders location', (tester) async {
|
||||
final card = UiCard(
|
||||
cardType: 'calendar_card.v1',
|
||||
data: CalendarCardData(
|
||||
id: 'evt_001',
|
||||
title: 'Meeting',
|
||||
startAt: '2026-03-01T10:00:00Z',
|
||||
location: 'Room 101',
|
||||
).toJson(),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(home: Scaffold(body: UiSchemaRenderer.render(card))),
|
||||
);
|
||||
|
||||
expect(find.text('Room 101'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('calendar_card.v1 renders description', (tester) async {
|
||||
final card = UiCard(
|
||||
cardType: 'calendar_card.v1',
|
||||
data: CalendarCardData(
|
||||
id: 'evt_001',
|
||||
title: 'Meeting',
|
||||
startAt: '2026-03-01T10:00:00Z',
|
||||
description: 'Quarterly review',
|
||||
).toJson(),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(home: Scaffold(body: UiSchemaRenderer.render(card))),
|
||||
);
|
||||
|
||||
expect(find.text('Quarterly review'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('calendar_card.v1 renders AI generated tag', (tester) async {
|
||||
final card = UiCard(
|
||||
cardType: 'calendar_card.v1',
|
||||
data: CalendarCardData(
|
||||
id: 'evt_001',
|
||||
title: 'Meeting',
|
||||
startAt: '2026-03-01T10:00:00Z',
|
||||
sourceType: 'ai_generated',
|
||||
).toJson(),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(home: Scaffold(body: UiSchemaRenderer.render(card))),
|
||||
);
|
||||
|
||||
expect(find.text('AI生成'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('calendar_card.v1 renders agent generated tag', (tester) async {
|
||||
final card = UiCard(
|
||||
cardType: 'calendar_card.v1',
|
||||
data: CalendarCardData(
|
||||
id: 'evt_001',
|
||||
title: 'Meeting',
|
||||
startAt: '2026-03-01T10:00:00Z',
|
||||
sourceType: 'agent_generated',
|
||||
).toJson(),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(home: Scaffold(body: UiSchemaRenderer.render(card))),
|
||||
);
|
||||
|
||||
expect(find.text('AI生成'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('calendar_event_list.v1 renders list items', (tester) async {
|
||||
final card = UiCard(
|
||||
cardType: 'calendar_event_list.v1',
|
||||
data: {
|
||||
'items': [
|
||||
{'id': 'evt_1', 'title': '晨会'},
|
||||
{'id': 'evt_2', 'title': '评审'},
|
||||
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'},
|
||||
],
|
||||
'pagination': {'page': 1, 'total': 2},
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(home: Scaffold(body: UiSchemaRenderer.render(card))),
|
||||
MaterialApp(
|
||||
home: Scaffold(body: UiSchemaRenderer.renderSchema(schema)),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.text('日程列表'), findsOneWidget);
|
||||
expect(find.text('晨会'), findsOneWidget);
|
||||
expect(find.text('评审'), findsOneWidget);
|
||||
expect(find.text('日程已创建'), findsOneWidget);
|
||||
expect(find.text('SUCCESS'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('calendar_operation.v1 renders operation message', (
|
||||
tester,
|
||||
) async {
|
||||
final card = UiCard(
|
||||
cardType: 'calendar_operation.v1',
|
||||
data: {'operation': 'delete', 'ok': true, 'message': '日程已删除'},
|
||||
);
|
||||
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.render(card))),
|
||||
MaterialApp(
|
||||
home: Scaffold(body: UiSchemaRenderer.renderSchema(schema)),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.text('日程delete结果'), findsOneWidget);
|
||||
expect(find.text('日程已删除'), findsOneWidget);
|
||||
expect(find.text('标题'), findsOneWidget);
|
||||
expect(find.text('评审会'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('error_card.v1 renders error message', (tester) async {
|
||||
final card = UiCard(
|
||||
cardType: 'error_card.v1',
|
||||
data: {'message': 'Something went wrong'},
|
||||
);
|
||||
|
||||
testWidgets('renders fallback for invalid schema', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(home: Scaffold(body: UiSchemaRenderer.render(card))),
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: UiSchemaRenderer.renderSchema({'version': '2.0'}),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.text('Something went wrong'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('error_card.v1 renders default message when missing', (
|
||||
tester,
|
||||
) async {
|
||||
final card = UiCard(cardType: 'error_card.v1', data: {});
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(home: Scaffold(body: UiSchemaRenderer.render(card))),
|
||||
);
|
||||
|
||||
expect(find.text('发生错误'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('unknown card type renders fallback', (tester) async {
|
||||
final card = UiCard(cardType: 'unknown_type', data: {'foo': 'bar'});
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(home: Scaffold(body: UiSchemaRenderer.render(card))),
|
||||
);
|
||||
|
||||
expect(find.textContaining('未知卡片类型'), findsOneWidget);
|
||||
expect(find.textContaining('unknown_type'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('calendar_card.v1 renders actions', (tester) async {
|
||||
final card = UiCard(
|
||||
cardType: 'calendar_card.v1',
|
||||
data: CalendarCardData(
|
||||
id: 'evt_001',
|
||||
title: 'Meeting',
|
||||
startAt: '2026-03-01T10:00:00Z',
|
||||
).toJson(),
|
||||
actions: [
|
||||
CardAction(type: 'link', label: '查看详情', target: '/calendar/evt_001'),
|
||||
],
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(home: Scaffold(body: UiSchemaRenderer.render(card))),
|
||||
);
|
||||
|
||||
expect(find.text('查看详情'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('calendar_card.v1 renders custom color', (tester) async {
|
||||
final card = UiCard(
|
||||
cardType: 'calendar_card.v1',
|
||||
data: CalendarCardData(
|
||||
id: 'evt_001',
|
||||
title: 'Meeting',
|
||||
startAt: '2026-03-01T10:00:00Z',
|
||||
color: '#FF0000',
|
||||
).toJson(),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(home: Scaffold(body: UiSchemaRenderer.render(card))),
|
||||
);
|
||||
|
||||
expect(find.text('Meeting'), findsOneWidget);
|
||||
expect(find.textContaining('无效 UI Schema'), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user