test(apps): 添加 UI Schema 单元测试
This commit is contained in:
@@ -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');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user