@dxos/app-graph 0.4.6 → 0.4.7-main.0a4f1cd
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/index.mjs +289 -229
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +282 -239
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/types/src/graph-builder.d.ts +8 -16
- package/dist/types/src/graph-builder.d.ts.map +1 -1
- package/dist/types/src/graph.d.ts +71 -14
- package/dist/types/src/graph.d.ts.map +1 -1
- package/dist/types/src/helpers.d.ts +14 -0
- package/dist/types/src/helpers.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/node.d.ts +57 -47
- package/dist/types/src/node.d.ts.map +1 -1
- package/dist/types/src/stories/EchoGraph.stories.d.ts.map +1 -1
- package/package.json +10 -29
- package/src/graph-builder.ts +18 -206
- package/src/graph.test.ts +242 -146
- package/src/graph.ts +241 -48
- package/src/helpers.ts +27 -0
- package/src/index.ts +1 -1
- package/src/node.ts +78 -66
- package/src/stories/EchoGraph.stories.tsx +59 -27
- package/dist/lib/browser/testing.mjs +0 -98
- package/dist/lib/browser/testing.mjs.map +0 -7
- package/dist/lib/node/testing.cjs +0 -122
- package/dist/lib/node/testing.cjs.map +0 -7
- package/dist/types/src/action.d.ts +0 -68
- package/dist/types/src/action.d.ts.map +0 -1
- package/dist/types/src/testing.d.ts +0 -52
- package/dist/types/src/testing.d.ts.map +0 -1
- package/src/action.ts +0 -92
- package/src/testing.ts +0 -152
package/src/graph.test.ts
CHANGED
|
@@ -2,219 +2,315 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { effect } from '@preact/signals-core';
|
|
5
6
|
import { expect } from 'chai';
|
|
6
7
|
|
|
7
8
|
import { describe, test } from '@dxos/test';
|
|
8
9
|
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
10
|
+
import { Graph } from './graph';
|
|
11
|
+
import { type Node, type NodeFilter } from './node';
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
test('returns root node', () => {
|
|
14
|
-
const graph = new GraphBuilder().build();
|
|
15
|
-
expect(graph.root).to.not.be.undefined;
|
|
16
|
-
expect(graph.root.id).to.equal('root');
|
|
17
|
-
});
|
|
13
|
+
const longestPaths = new Map<string, string[]>();
|
|
18
14
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
});
|
|
15
|
+
const filterLongestPath: NodeFilter = (node, connectedNode): node is Node => {
|
|
16
|
+
const longestPath = longestPaths.get(node.id);
|
|
17
|
+
if (!longestPath) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
25
20
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const id = 'test';
|
|
30
|
-
builder.addNodeBuilder(id, (parent) => {
|
|
31
|
-
if (parent.id === 'root') {
|
|
32
|
-
parent.addNode(id, testNode);
|
|
33
|
-
}
|
|
34
|
-
});
|
|
21
|
+
if (longestPath[longestPath.length - 2] !== connectedNode.id) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
35
24
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
25
|
+
return true;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// TODO(wittjosiah): Add tests for granularity of reactivity.
|
|
29
|
+
describe('Graph', () => {
|
|
30
|
+
test('add nodes', () => {
|
|
31
|
+
const graph = new Graph();
|
|
40
32
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
builder.addNodeBuilder('test', (parent) => {
|
|
45
|
-
if (parent.id === 'root') {
|
|
46
|
-
parent.addAction(testAction);
|
|
47
|
-
}
|
|
33
|
+
const [root] = graph.addNodes({
|
|
34
|
+
id: 'root',
|
|
35
|
+
nodes: [{ id: 'test1' }, { id: 'test2' }],
|
|
48
36
|
});
|
|
49
37
|
|
|
50
|
-
|
|
51
|
-
expect(
|
|
38
|
+
expect(root.id).to.equal('root');
|
|
39
|
+
expect(root.nodes()).to.have.length(2);
|
|
40
|
+
expect(graph.findNode('test1')?.id).to.equal('test1');
|
|
41
|
+
expect(graph.findNode('test2')?.id).to.equal('test2');
|
|
42
|
+
expect(graph.findNode('test1')?.nodes()).to.be.empty;
|
|
43
|
+
expect(graph.findNode('test2')?.nodes()).to.be.empty;
|
|
44
|
+
expect(graph.findNode('test1')?.nodes({ direction: 'inbound' })).to.have.length(1);
|
|
45
|
+
expect(graph.findNode('test2')?.nodes({ direction: 'inbound' })).to.have.length(1);
|
|
52
46
|
});
|
|
53
47
|
|
|
54
|
-
test('
|
|
55
|
-
const
|
|
56
|
-
builder.addNodeBuilder('test1', createTestNodeBuilder('test1').nodeBuilder);
|
|
57
|
-
builder.addNodeBuilder('test2', createTestNodeBuilder('test2').nodeBuilder);
|
|
48
|
+
test('add nodes updates existing nodes', () => {
|
|
49
|
+
const graph = new Graph();
|
|
58
50
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
51
|
+
graph.addNodes({
|
|
52
|
+
id: 'root',
|
|
53
|
+
nodes: [{ id: 'test1' }, { id: 'test2' }],
|
|
54
|
+
});
|
|
55
|
+
graph.addNodes({
|
|
56
|
+
id: 'root',
|
|
57
|
+
nodes: [{ id: 'test1' }, { id: 'test2' }],
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
expect(Object.keys(graph._nodes)).to.have.length(3);
|
|
61
|
+
expect(Object.keys(graph._edges)).to.have.length(3);
|
|
62
|
+
expect(graph.root.nodes()).to.have.length(2);
|
|
64
63
|
});
|
|
65
64
|
|
|
66
|
-
test('
|
|
67
|
-
const
|
|
68
|
-
builder.addNodeBuilder('test1', createTestNodeBuilder('test1').nodeBuilder);
|
|
69
|
-
builder.addNodeBuilder('test2', createTestNodeBuilder('test2').nodeBuilder);
|
|
65
|
+
test('remove node', () => {
|
|
66
|
+
const graph = new Graph();
|
|
70
67
|
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
68
|
+
const [root] = graph.addNodes({
|
|
69
|
+
id: 'root',
|
|
70
|
+
nodes: [{ id: 'test1' }, { id: 'test2' }],
|
|
71
|
+
});
|
|
74
72
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
expect(root.id).to.equal('root');
|
|
74
|
+
expect(root.nodes()).to.have.length(2);
|
|
75
|
+
expect(graph.findNode('test1')?.id).to.equal('test1');
|
|
76
|
+
expect(graph.findNode('test2')?.id).to.equal('test2');
|
|
79
77
|
|
|
80
|
-
|
|
81
|
-
expect(
|
|
82
|
-
expect(
|
|
83
|
-
for (const node of graph.root.childrenMap['root-test2'].children) {
|
|
84
|
-
expect(graph.root.childrenMap['root-test2'].id).to.equal(node.parent!.id);
|
|
85
|
-
}
|
|
78
|
+
graph.removeNode('test1');
|
|
79
|
+
expect(graph.findNode('test1')).to.be.undefined;
|
|
80
|
+
expect(root.nodes()).to.have.length(1);
|
|
86
81
|
});
|
|
87
82
|
|
|
88
|
-
test('
|
|
89
|
-
const
|
|
90
|
-
builder.addNodeBuilder('test1', createTestNodeBuilder('test1', 2).nodeBuilder);
|
|
91
|
-
builder.addNodeBuilder('test2', createTestNodeBuilder('test2').nodeBuilder);
|
|
83
|
+
test('add edge', () => {
|
|
84
|
+
const graph = new Graph();
|
|
92
85
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
86
|
+
graph.addNodes({
|
|
87
|
+
id: 'root',
|
|
88
|
+
nodes: [{ id: 'test1' }, { id: 'test2' }],
|
|
89
|
+
});
|
|
90
|
+
graph.addEdge({ source: 'test1', target: 'test2' });
|
|
91
|
+
|
|
92
|
+
expect(graph.findNode('test1')?.nodes()).to.have.length(1);
|
|
93
|
+
expect(graph.findNode('test2')?.nodes({ direction: 'inbound' })).to.have.length(2);
|
|
96
94
|
});
|
|
97
95
|
|
|
98
|
-
test('
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
96
|
+
test('add edges is idempontent', () => {
|
|
97
|
+
const graph = new Graph();
|
|
98
|
+
|
|
99
|
+
graph.addNodes({
|
|
100
|
+
id: 'root',
|
|
101
|
+
nodes: [{ id: 'test1' }, { id: 'test2' }],
|
|
103
102
|
});
|
|
103
|
+
graph.addEdge({ source: 'test1', target: 'test2' });
|
|
104
|
+
graph.addEdge({ source: 'test1', target: 'test2' });
|
|
104
105
|
|
|
105
|
-
|
|
106
|
-
expect(
|
|
106
|
+
expect(graph.findNode('test1')?.nodes()).to.have.length(1);
|
|
107
|
+
expect(graph.findNode('test2')?.nodes({ direction: 'inbound' })).to.have.length(2);
|
|
107
108
|
});
|
|
108
109
|
|
|
109
|
-
test('
|
|
110
|
-
const
|
|
110
|
+
test('sort edges', () => {
|
|
111
|
+
const graph = new Graph();
|
|
111
112
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
const [root] = graph.addNodes({
|
|
114
|
+
id: 'root',
|
|
115
|
+
nodes: [{ id: 'test1' }, { id: 'test3' }, { id: 'test2' }, { id: 'test4' }],
|
|
116
|
+
});
|
|
116
117
|
|
|
117
|
-
|
|
118
|
-
expect(graph.root.children).to.have.length(1);
|
|
119
|
-
addNode('root', { id: 'root-test2', label: 'root-test2' });
|
|
120
|
-
expect(graph.root.children).to.have.length(2);
|
|
121
|
-
expect(graph.root.childrenMap['root-test2'].children).to.have.length(0);
|
|
118
|
+
expect(root.nodes().map((node) => node.id)).to.deep.equal(['test1', 'test3', 'test2', 'test4']);
|
|
122
119
|
|
|
123
|
-
|
|
124
|
-
addNode('root-test1', { id: 'root-test1-test2', label: 'root-test1-test2' });
|
|
125
|
-
expect(graph.root.childrenMap['root-test1'].children).to.have.length(1);
|
|
126
|
-
expect(graph.root.childrenMap['root-test1'].childrenMap['root-test1-test2'].children).to.have.length(0);
|
|
120
|
+
graph.sortEdges('root', 'outbound', ['test4', 'test3']);
|
|
127
121
|
|
|
128
|
-
expect(
|
|
129
|
-
|
|
130
|
-
expect(graph.root.actions).to.have.length(2);
|
|
122
|
+
expect(root.nodes().map((node) => node.id)).to.deep.equal(['test4', 'test3', 'test1', 'test2']);
|
|
123
|
+
});
|
|
131
124
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
expect(graph.root.childrenMap['root-test1'].properties.test).to.equal('test');
|
|
125
|
+
test('remove edge', () => {
|
|
126
|
+
const graph = new Graph();
|
|
135
127
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
128
|
+
graph.addNodes({
|
|
129
|
+
id: 'root',
|
|
130
|
+
nodes: [{ id: 'test1' }, { id: 'test2' }],
|
|
131
|
+
});
|
|
132
|
+
graph.removeEdge({ source: 'root', target: 'test1' });
|
|
139
133
|
|
|
140
|
-
expect(graph.root.
|
|
141
|
-
|
|
142
|
-
|
|
134
|
+
expect(graph.root.nodes()).to.have.length(1);
|
|
135
|
+
expect(graph.findNode('test1')?.nodes({ direction: 'inbound' })).to.be.empty;
|
|
136
|
+
});
|
|
143
137
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
expect(graph.root.actions).to.have.length(1);
|
|
138
|
+
test('toJSON', () => {
|
|
139
|
+
const graph = new Graph();
|
|
147
140
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
141
|
+
graph.addNodes({
|
|
142
|
+
id: 'root',
|
|
143
|
+
nodes: [{ id: 'test1' }, { id: 'test2' }],
|
|
144
|
+
});
|
|
145
|
+
graph.addEdge({ source: 'test1', target: 'test2' });
|
|
152
146
|
|
|
153
|
-
|
|
154
|
-
|
|
147
|
+
const json = graph.toJSON();
|
|
148
|
+
expect(json).to.deep.equal({
|
|
149
|
+
id: 'root',
|
|
150
|
+
nodes: [{ id: 'test1', nodes: [{ id: 'test2' }] }, { id: 'test2' }],
|
|
151
|
+
});
|
|
155
152
|
});
|
|
156
153
|
|
|
157
|
-
test('can
|
|
158
|
-
const
|
|
159
|
-
builder.addNodeBuilder('test1', createTestNodeBuilder('test1', 2).nodeBuilder);
|
|
160
|
-
builder.addNodeBuilder('test2', createTestNodeBuilder('test2').nodeBuilder);
|
|
154
|
+
test('can be traversed', () => {
|
|
155
|
+
const graph = new Graph();
|
|
161
156
|
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
157
|
+
const [root] = graph.addNodes({
|
|
158
|
+
id: 'root',
|
|
159
|
+
nodes: [{ id: 'test1' }, { id: 'test2' }],
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const nodes: string[] = [];
|
|
163
|
+
graph.traverse({ node: root, visitor: (node) => nodes.push(node.id) });
|
|
164
|
+
expect(nodes).to.deep.equal(['root', 'test1', 'test2']);
|
|
165
165
|
});
|
|
166
166
|
|
|
167
|
-
test('
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
167
|
+
test('traversal breaks cycles', () => {
|
|
168
|
+
const graph = new Graph();
|
|
169
|
+
|
|
170
|
+
const [root] = graph.addNodes({
|
|
171
|
+
id: 'root',
|
|
172
|
+
nodes: [{ id: 'test1' }, { id: 'test2' }],
|
|
173
|
+
});
|
|
174
|
+
graph.addEdge({ source: 'test1', target: 'root' });
|
|
171
175
|
|
|
172
|
-
const graph = builder.build();
|
|
173
176
|
const nodes: string[] = [];
|
|
174
|
-
graph.traverse({ visitor: (node) => nodes.push(node.id) });
|
|
175
|
-
expect(nodes).to.deep.equal(['root', '
|
|
177
|
+
graph.traverse({ node: root, visitor: (node) => nodes.push(node.id) });
|
|
178
|
+
expect(nodes).to.deep.equal(['root', 'test1', 'test2']);
|
|
176
179
|
});
|
|
177
180
|
|
|
178
181
|
test('traversal can be limited by predicate', () => {
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
+
const graph = new Graph();
|
|
183
|
+
|
|
184
|
+
const [root] = graph.addNodes({
|
|
185
|
+
id: 'root',
|
|
186
|
+
nodes: [{ id: 'test1' }, { id: 'test2' }, { id: 'test3' }, { id: 'test4' }],
|
|
187
|
+
});
|
|
182
188
|
|
|
183
|
-
const graph = builder.build();
|
|
184
189
|
const nodes: string[] = [];
|
|
185
190
|
graph.traverse({
|
|
186
|
-
|
|
191
|
+
node: root,
|
|
187
192
|
visitor: (node) => nodes.push(node.id),
|
|
193
|
+
filter: (node) => {
|
|
194
|
+
try {
|
|
195
|
+
const id = parseInt(node.id.replace('test', ''), 10);
|
|
196
|
+
return id % 2 === 0;
|
|
197
|
+
} catch (e) {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
},
|
|
188
201
|
});
|
|
189
|
-
expect(nodes).to.deep.equal(['
|
|
202
|
+
expect(nodes).to.deep.equal(['test2', 'test4']);
|
|
190
203
|
});
|
|
191
204
|
|
|
192
205
|
test('traversal can be started from any node', () => {
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
206
|
+
const graph = new Graph();
|
|
207
|
+
|
|
208
|
+
graph.addNodes({
|
|
209
|
+
id: 'root',
|
|
210
|
+
nodes: [{ id: 'test1', nodes: [{ id: 'test2', nodes: [{ id: 'test3' }] }] }],
|
|
211
|
+
});
|
|
196
212
|
|
|
197
|
-
const graph = builder.build();
|
|
198
213
|
const nodes: string[] = [];
|
|
199
214
|
graph.traverse({
|
|
200
|
-
node: graph.
|
|
215
|
+
node: graph.findNode('test2')!,
|
|
201
216
|
visitor: (node) => nodes.push(node.id),
|
|
202
217
|
});
|
|
203
|
-
expect(nodes).to.deep.equal(['
|
|
218
|
+
expect(nodes).to.deep.equal(['test2', 'test3']);
|
|
204
219
|
});
|
|
205
220
|
|
|
206
|
-
test('can
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
|
|
221
|
+
test('traversal can follow inbound edges', () => {
|
|
222
|
+
const graph = new Graph();
|
|
223
|
+
|
|
224
|
+
graph.addNodes({
|
|
225
|
+
id: 'root',
|
|
226
|
+
nodes: [{ id: 'test1', nodes: [{ id: 'test2', nodes: [{ id: 'test3' }] }] }],
|
|
227
|
+
});
|
|
210
228
|
|
|
211
|
-
const graph = builder.build();
|
|
212
229
|
const nodes: string[] = [];
|
|
213
230
|
graph.traverse({
|
|
214
|
-
|
|
215
|
-
|
|
231
|
+
node: graph.findNode('test2')!,
|
|
232
|
+
direction: 'inbound',
|
|
216
233
|
visitor: (node) => nodes.push(node.id),
|
|
217
234
|
});
|
|
218
|
-
expect(nodes).to.deep.equal(['
|
|
235
|
+
expect(nodes).to.deep.equal(['test2', 'test1', 'root']);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
test('can filter to longest pathes', () => {
|
|
239
|
+
const graph = new Graph();
|
|
240
|
+
|
|
241
|
+
graph.addNodes({
|
|
242
|
+
id: 'root',
|
|
243
|
+
nodes: [{ id: 'test1' }, { id: 'test2' }],
|
|
244
|
+
});
|
|
245
|
+
graph.addEdge({ source: 'test1', target: 'test2' });
|
|
246
|
+
|
|
247
|
+
graph.traverse({
|
|
248
|
+
visitor: (node, path) => {
|
|
249
|
+
if (!longestPaths.has(node.id) || longestPaths.get(node.id)!.length < path.length) {
|
|
250
|
+
longestPaths.set(node.id, path);
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
expect(longestPaths.get('root')).to.deep.equal(['root']);
|
|
256
|
+
expect(longestPaths.get('test1')).to.deep.equal(['root', 'test1']);
|
|
257
|
+
expect(longestPaths.get('test2')).to.deep.equal(['root', 'test1', 'test2']);
|
|
258
|
+
expect(graph.root.nodes({ filter: filterLongestPath })).to.have.length(1);
|
|
259
|
+
expect(graph.findNode('test1')?.nodes({ filter: filterLongestPath })).to.have.length(1);
|
|
260
|
+
expect(graph.findNode('test2')?.nodes({ filter: filterLongestPath })).to.be.empty;
|
|
261
|
+
|
|
262
|
+
longestPaths.clear();
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
test('traversing the graph subscribes to changes', () => {
|
|
266
|
+
const graph = new Graph();
|
|
267
|
+
|
|
268
|
+
graph.addNodes({
|
|
269
|
+
id: 'root',
|
|
270
|
+
nodes: [{ id: 'test1' }, { id: 'test2' }],
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
const dispose = effect(() => {
|
|
274
|
+
graph.traverse({
|
|
275
|
+
visitor: (node, path) => {
|
|
276
|
+
if (!longestPaths.has(node.id) || longestPaths.get(node.id)!.length < path.length) {
|
|
277
|
+
longestPaths.set(node.id, path);
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
expect(longestPaths.get('root')).to.deep.equal(['root']);
|
|
284
|
+
expect(longestPaths.get('test1')).to.deep.equal(['root', 'test1']);
|
|
285
|
+
expect(longestPaths.get('test2')).to.deep.equal(['root', 'test2']);
|
|
286
|
+
expect(graph.root.nodes({ filter: filterLongestPath })).to.have.length(2);
|
|
287
|
+
expect(graph.findNode('test1')?.nodes({ filter: filterLongestPath })).to.be.empty;
|
|
288
|
+
expect(graph.findNode('test2')?.nodes({ filter: filterLongestPath })).to.be.empty;
|
|
289
|
+
|
|
290
|
+
graph.addEdge({ source: 'test1', target: 'test2' });
|
|
291
|
+
|
|
292
|
+
expect(longestPaths.get('root')).to.deep.equal(['root']);
|
|
293
|
+
expect(longestPaths.get('test1')).to.deep.equal(['root', 'test1']);
|
|
294
|
+
expect(longestPaths.get('test2')).to.deep.equal(['root', 'test1', 'test2']);
|
|
295
|
+
expect(graph.root.nodes({ filter: filterLongestPath })).to.have.length(1);
|
|
296
|
+
expect(graph.findNode('test1')?.nodes({ filter: filterLongestPath })).to.have.length(1);
|
|
297
|
+
expect(graph.findNode('test2')?.nodes({ filter: filterLongestPath })).to.be.empty;
|
|
298
|
+
|
|
299
|
+
dispose();
|
|
300
|
+
longestPaths.clear();
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
test('get path', () => {
|
|
304
|
+
const graph = new Graph();
|
|
305
|
+
|
|
306
|
+
graph.addNodes({
|
|
307
|
+
id: 'root',
|
|
308
|
+
nodes: [{ id: 'test1' }, { id: 'test2' }],
|
|
309
|
+
});
|
|
310
|
+
graph.addEdge({ source: 'test1', target: 'test2' });
|
|
311
|
+
|
|
312
|
+
expect(graph.getPath({ target: 'test2' })).to.deep.equal(['root', 'test1', 'test2']);
|
|
313
|
+
expect(graph.getPath({ source: 'test1', target: 'test2' })).to.deep.equal(['test1', 'test2']);
|
|
314
|
+
expect(graph.getPath({ source: 'test2', target: 'test1' })).to.be.undefined;
|
|
219
315
|
});
|
|
220
316
|
});
|