Files
clide/test/draw/graph_template_test.dart
T
jpmschweitzerandClaude Opus 4.8 c167a37ea7 feat(draw): graph card template — circular node/edge layout (T-321)
graphTemplateHandler lowers a {nodes,edges} payload to SVG: a deterministic
circular layout of labelled <circle> nodes with <line> edges, self-contained
(own light backdrop + content colors, like a d2 card) and painted by the
shared renderer. Display-only (D-78); decoupled from the interactive graph
pane (T-323) since a static card only needs a layout->SVG. Honest error on
a duplicate id or an edge to an unknown node.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 00:00:44 +02:00

82 lines
2.1 KiB
Dart

import 'package:clide/src/draw/draw_dispatch.dart';
import 'package:clide/src/draw/draw_doc.dart';
import 'package:clide/src/draw/graph_template.dart';
import 'package:test/test.dart';
void main() {
final handler = graphTemplateHandler();
DrawingCardDoc doc(Map<String, Object?> fields) => DrawingCardDoc(template: 'graph', fields: {'template': 'graph', ...fields});
test('lays out nodes as labelled circles and edges as lines', () async {
final r = await handler(
doc({
'nodes': [
{'id': 'a', 'label': 'Alpha'},
{'id': 'b', 'label': 'Beta'},
],
'edges': [
{'from': 'a', 'to': 'b'},
],
}),
);
final svg = (r as DrawOk).svg;
expect('<circle'.allMatches(svg).length, 2);
expect('<line'.allMatches(svg).length, 1);
expect(svg, contains('>Alpha<'));
expect(svg, contains('>Beta<'));
});
test('a node label defaults to its id', () async {
final r = await handler(
doc({
'nodes': [
{'id': 'solo'},
],
}),
);
expect((r as DrawOk).svg, contains('>solo<'));
});
test('empty or missing nodes is an honest error', () async {
expect(await handler(doc({'nodes': const []})), isA<DrawErr>());
expect(await handler(doc(const {})), isA<DrawErr>());
});
test('a duplicate node id is an error', () async {
final r = await handler(
doc({
'nodes': [
{'id': 'x'},
{'id': 'x'},
],
}),
);
expect((r as DrawErr).message, contains('duplicate'));
});
test('an edge to an unknown node is an error', () async {
final r = await handler(
doc({
'nodes': [
{'id': 'a'},
],
'edges': [
{'from': 'a', 'to': 'ghost'},
],
}),
);
expect((r as DrawErr).message, contains('ghost'));
});
test('escapes label text', () async {
final r = await handler(
doc({
'nodes': [
{'id': 'a', 'label': '<b>&'},
],
}),
);
expect((r as DrawOk).svg, contains('&lt;b&gt;&amp;'));
});
}