test(apps): 添加 UI Schema 单元测试

This commit is contained in:
zl-q
2026-03-19 00:52:23 +08:00
parent 7c70422ad1
commit 636b37ee5a
+105
View File
@@ -0,0 +1,105 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:social_app/core/schemas/ui_schema.dart';
void main() {
group('ui_schema protocol stability', () {
test('UiSchemaDocument.fromJson keeps enum fallback defaults', () {
final doc = UiSchemaDocument.fromJson({
'version': '1.0',
'schemaType': 'unknown_type',
'status': 'unknown_status',
'nodes': const [],
});
expect(doc.schemaType, SchemaType.toolResult);
expect(doc.status, UiStatus.info);
});
test('actionSpecFromJson covers known and unknown branches', () {
final navigation = actionSpecFromJson({
'type': 'navigation',
'path': '/calendar/dayweek',
'params': {'from': 'home'},
});
expect(navigation, isA<NavigateAction>());
final unknown = actionSpecFromJson({'type': 'not_supported'});
expect(unknown, isA<EventAction>());
expect((unknown as EventAction).event, 'unknown');
});
test('UiNode.fromJson returns text fallback for unknown node type', () {
final node = UiNode.fromJson({'type': 'mystery'});
expect(node, isA<UiTextNode>());
expect((node as UiTextNode).content, 'Unknown node type: mystery');
});
test(
'buildSuccessDocument and buildErrorDocument keep status semantics',
() {
final success = buildSuccessDocument(const [
UiTextNode(content: 'ok'),
], schemaType: SchemaType.agentResponse);
final error = buildErrorDocument(const [UiTextNode(content: 'bad')]);
expect(success.status, UiStatus.success);
expect(success.schemaType, SchemaType.agentResponse);
expect(success.locale, 'zh-CN');
expect(error.status, UiStatus.error);
expect(error.schemaType, SchemaType.toolResult);
expect(error.version, '1.0');
},
);
test('UiSchemaDocument round-trip keeps critical fields stable', () {
final original = UiSchemaDocument(
version: '1.0',
schemaType: SchemaType.toolResult,
docId: 'doc_1',
timestamp: '2026-03-19T10:00:00Z',
locale: 'zh-CN',
status: UiStatus.success,
renderer: const RendererConfig(theme: RendererTheme.light),
meta: const DocumentMeta(requestId: 'req_1', toolId: 'tool_1'),
nodes: const [
UiContainerNode(
direction: ContainerDirection.vertical,
children: [
UiTextNode(content: 'hello', format: TextFormat.markdown),
],
),
],
);
final encoded = original.toJson();
final decoded = UiSchemaDocument.fromJson(encoded);
expect(decoded.version, '1.0');
expect(decoded.schemaType, SchemaType.toolResult);
expect(decoded.docId, 'doc_1');
expect(decoded.status, UiStatus.success);
expect(decoded.renderer?.theme, RendererTheme.light);
expect(decoded.nodes, hasLength(1));
expect(decoded.nodes.first, isA<UiContainerNode>());
});
test('toJson omits nullable fields as before', () {
const action = UiAction(
id: 'a1',
label: 'open',
action: NavigateAction(path: '/settings'),
);
final json = action.toJson();
expect(json['id'], 'a1');
expect(json['label'], 'open');
expect(json.containsKey('icon'), false);
expect(json.containsKey('style'), false);
expect(json.containsKey('confirm'), false);
expect((json['action'] as Map<String, dynamic>)['path'], '/settings');
});
});
}