UNPKG

20.8 kBJavaScriptView Raw
1import { expect } from '../test';
2import { TreeQuery } from '.';
3const create = TreeQuery.create;
4describe('TreeQuery', () => {
5 describe('create', () => {
6 it('with root (default node type)', () => {
7 const root = { id: 'root' };
8 const query = create(root);
9 expect(query.root).to.equal(root);
10 expect(query.namespace).to.eql('');
11 });
12 it('with root (specific node type)', () => {
13 const root = { id: 'root', count: 0 };
14 const query = create(root);
15 expect(query.root).to.equal(root);
16 expect(query.namespace).to.eql('');
17 });
18 it('with namespace', () => {
19 const test = (namespace, expected) => {
20 const root = { id: 'root' };
21 const query = create({ root, namespace });
22 expect(query.namespace).to.eql(expected);
23 };
24 test('', '');
25 test(' ', '');
26 test('foo', 'foo');
27 test(' foo ', 'foo');
28 });
29 });
30 describe('children (static)', () => {
31 it('no arguments', () => {
32 let count = 0;
33 const res = TreeQuery.children(undefined, () => count++);
34 expect(res).to.eql([]);
35 expect(count).to.eql(1);
36 });
37 it('no childen => empty array (and assigns by default)', () => {
38 const node = { id: 'root' };
39 expect(node.children).to.eql(undefined);
40 const res = TreeQuery.children(node);
41 expect(res).to.eql([]);
42 expect(node.children).to.equal(res);
43 });
44 it('no childen => empty array (and does not assign)', () => {
45 const node = { id: 'root' };
46 expect(node.children).to.eql(undefined);
47 const res1 = TreeQuery.children(node, { assign: false });
48 expect(res1).to.eql([]);
49 expect(node.children).to.equal(undefined);
50 const res2 = TreeQuery.children(node, undefined, { assign: false });
51 expect(res2).to.eql([]);
52 expect(node.children).to.equal(undefined);
53 });
54 it('returns child array (instance)', () => {
55 const node = { id: 'root', children: [{ id: 'child' }] };
56 expect(TreeQuery.children(node)).to.eql([{ id: 'child' }]);
57 });
58 it('runs visitor function', () => {
59 const node = { id: 'root', children: [{ id: 'child-1' }, { id: 'child-2' }] };
60 const visits = [];
61 TreeQuery.children(node, (children) => children.forEach((child) => visits.push(child)));
62 expect(visits.map((c) => c.id)).to.eql(['child-1', 'child-2']);
63 });
64 });
65 describe('hasChild (static)', () => {
66 const root = { id: 'A', children: [{ id: 'B' }, { id: 'C' }] };
67 it('does have child', () => {
68 expect(TreeQuery.hasChild(root, 'B')).to.eql(true);
69 expect(TreeQuery.hasChild(root, 'C')).to.eql(true);
70 expect(TreeQuery.hasChild(root, { id: 'C' })).to.eql(true);
71 });
72 it('does not have child', () => {
73 expect(TreeQuery.hasChild(root, 'A')).to.eql(false);
74 expect(TreeQuery.hasChild(root, 'NO_MATCH')).to.eql(false);
75 expect(TreeQuery.hasChild(root, undefined)).to.eql(false);
76 expect(TreeQuery.hasChild(undefined, undefined)).to.eql(false);
77 });
78 });
79 describe('walkDown', () => {
80 it('walkDown from root', () => {
81 const tree = {
82 id: 'root',
83 children: [{ id: 'child-1' }, { id: 'child-2' }],
84 };
85 const query = create(tree);
86 const items = [];
87 query.walkDown((e) => items.push(e));
88 expect(items.length).to.eql(3);
89 expect(items[0].node).to.equal(tree);
90 expect(items[1].node).to.equal(tree.children && tree.children[0]);
91 expect(items[2].node).to.equal(tree.children && tree.children[1]);
92 expect(items.every((m) => m.namespace === '')).to.eql(true);
93 });
94 it('walkDown from root (with namespace)', () => {
95 const tree = {
96 id: 'ns:root',
97 children: [{ id: 'ns:child-1' }, { id: 'ns:child-2' }],
98 };
99 const query = create(tree);
100 const items = [];
101 query.walkDown((e) => items.push(e));
102 expect(items.length).to.eql(3);
103 expect(items.every((m) => m.namespace === 'ns')).to.eql(true);
104 expect(items[0].key).to.equal('root');
105 expect(items[0].id).to.equal('ns:root');
106 expect(items[0].node.id).to.equal('ns:root');
107 expect(items[1].key).to.equal('child-1');
108 expect(items[1].id).to.equal('ns:child-1');
109 expect(items[1].node.id).to.equal('ns:child-1');
110 expect(items[2].key).to.equal('child-2');
111 expect(items[2].id).to.equal('ns:child-2');
112 expect(items[2].node.id).to.equal('ns:child-2');
113 });
114 it('walkDown: skip (children)', () => {
115 const tree = {
116 id: 'root',
117 children: [
118 { id: 'child-1', children: [{ id: 'child-1.1' }, { id: 'child-1.1' }] },
119 { id: 'child-2' },
120 ],
121 };
122 const query = create(tree);
123 const nodes = [];
124 query.walkDown((e) => {
125 nodes.push(e.node);
126 if (e.node.id === 'child-1') {
127 e.skip();
128 }
129 });
130 expect(nodes.length).to.eql(3);
131 expect(nodes[0].id).to.eql('root');
132 expect(nodes[1].id).to.eql('child-1');
133 expect(nodes[2].id).to.eql('child-2');
134 });
135 it('walkDown: stop mid-way', () => {
136 const root = {
137 id: 'root',
138 children: [{ id: 'child-1' }, { id: 'child-2', children: [{ id: 'child-2.1' }] }],
139 };
140 const state = create(root);
141 const walked = [];
142 state.walkDown((e) => {
143 walked.push(e);
144 if (e.id === 'child-1') {
145 e.stop();
146 }
147 });
148 expect(walked.length).to.eql(2);
149 expect(walked[0].id).to.eql('root');
150 expect(walked[1].id).to.eql('child-1');
151 });
152 it('walkDown: passes level/parent to visitor', () => {
153 const grandchild = { id: 'grandchild' };
154 const child = { id: 'child', children: [grandchild] };
155 const root = { id: 'root', children: [child] };
156 const query = create(root);
157 const items = [];
158 query.walkDown((e) => items.push(e));
159 expect(items.length).to.eql(3);
160 expect(items[0].level).to.eql(0);
161 expect(items[1].level).to.eql(1);
162 expect(items[2].level).to.eql(2);
163 expect(items[0].parent).to.eql(undefined);
164 expect(items[1].parent).to.eql(root);
165 expect(items[2].parent).to.eql(child);
166 });
167 it('walkDown: passes index to visitor (sibling position)', () => {
168 const root = {
169 id: 'root',
170 children: [{ id: 'child-1' }, { id: 'child-2' }],
171 };
172 const query = create(root);
173 const items = [];
174 query.walkDown((e) => items.push(e));
175 expect(items[0].index).to.eql(-1);
176 expect(items[1].index).to.eql(0);
177 expect(items[2].index).to.eql(1);
178 });
179 it('walkDown: does not walk down into child namespace', () => {
180 var _a;
181 const root = {
182 id: 'ns1:root',
183 children: [{ id: 'ns1:child-1' }, { id: 'ns1:child-2', children: [{ id: 'ns2:foo' }] }],
184 };
185 const query = create({ root, namespace: 'ns1' });
186 expect(query.namespace).to.eql('ns1');
187 expect((_a = create(root).findById('ns2:foo')) === null || _a === void 0 ? void 0 : _a.id).to.eql('ns2:foo');
188 const walked = [];
189 query.walkDown((e) => walked.push(e));
190 const ids = walked.map((e) => e.id);
191 expect(ids.length).to.eql(3);
192 expect(ids.includes('ns2:foo')).to.eql(false);
193 });
194 });
195 describe('walkUp', () => {
196 it('walkUp: to root', () => {
197 const tree = {
198 id: 'root',
199 children: [{ id: 'child-1' }, { id: 'child-2', children: [{ id: 'grandchild-1' }] }],
200 };
201 const query = create(tree);
202 const start = query.findById('grandchild-1');
203 const items = [];
204 query.walkUp(start, (e) => items.push(e));
205 expect(items.length).to.eql(3);
206 expect(items.map((e) => e.node.id)).to.eql(['grandchild-1', 'child-2', 'root']);
207 expect(items.every((m) => m.namespace === '')).to.eql(true);
208 expect(items[0].parent && items[0].parent.id).to.eql('child-2');
209 expect(items[1].parent && items[1].parent.id).to.eql('root');
210 expect(items[2].parent && items[2].parent.id).to.eql(undefined);
211 expect(items[0].index).to.eql(0);
212 expect(items[1].index).to.eql(1);
213 expect(items[2].index).to.eql(-1);
214 });
215 it('walkUp: to root (with namespace)', () => {
216 const tree = {
217 id: 'ns:root',
218 children: [
219 { id: 'ns:child-1' },
220 { id: 'ns:child-2', children: [{ id: 'ns:grandchild-1' }] },
221 ],
222 };
223 const query = create(tree);
224 const start = query.findById('ns:grandchild-1');
225 const items = [];
226 query.walkUp(start, (e) => items.push(e));
227 expect(items.length).to.eql(3);
228 expect(items.every((m) => m.namespace === 'ns')).to.eql(true);
229 expect(items.map((e) => e.key)).to.eql(['grandchild-1', 'child-2', 'root']);
230 expect(items.map((e) => e.node.id)).to.eql(['ns:grandchild-1', 'ns:child-2', 'ns:root']);
231 });
232 it('walkUp: stop mid-way', () => {
233 const tree = {
234 id: 'root',
235 children: [{ id: 'child-1' }, { id: 'child-2', children: [{ id: 'grandchild-1' }] }],
236 };
237 const query = create(tree);
238 const start = query.findById('grandchild-1');
239 const list = [];
240 query.walkUp(start, (e) => {
241 list.push(e);
242 if (e.node.id === 'child-2') {
243 e.stop();
244 }
245 });
246 expect(list.length).to.eql(2);
247 expect(list.map((e) => e.id)).to.eql(['grandchild-1', 'child-2']);
248 });
249 it('walkUp: startAt not found', () => {
250 const tree = {
251 id: 'root',
252 children: [{ id: 'child-1' }, { id: 'child-2', children: [{ id: 'grandchild-1' }] }],
253 };
254 const query = create(tree);
255 const test = (startAt) => {
256 const walked = [];
257 query.walkUp(startAt, (e) => walked.push(e));
258 expect(walked).to.eql([]);
259 };
260 test();
261 test('404');
262 test({ id: '404' });
263 });
264 it('walkUp: passes level (from start of ascent)', () => {
265 const tree = {
266 id: 'root',
267 children: [{ id: 'child-1' }, { id: 'child-2', children: [{ id: 'grandchild-1' }] }],
268 };
269 const query = create(tree);
270 const walked = [];
271 query.walkUp('grandchild-1', (e) => walked.push(e));
272 expect(walked.map((e) => e.level)).to.eql([0, 1, 2]);
273 });
274 it('walkUp: does not walk up into parent namespace', () => {
275 const tree = {
276 id: 'ns1:root',
277 children: [
278 { id: 'ns1:child-1' },
279 { id: 'ns2:child-2', children: [{ id: 'ns2:child-2.1' }] },
280 ],
281 };
282 const root = create(tree).findById('ns2:child-2');
283 const child = create(tree).findById('ns2:child-2.1');
284 expect(child).to.exist;
285 const query = create({ root, namespace: 'ns2' });
286 const test = (startAt) => {
287 const walked = [];
288 query.walkUp(startAt, (e) => walked.push(e));
289 expect(walked.map((e) => e.key)).to.eql(['child-2.1', 'child-2']);
290 };
291 test(child);
292 test(child === null || child === void 0 ? void 0 : child.id);
293 test('child-2.1');
294 });
295 });
296 describe('find', () => {
297 it('no namespace', () => {
298 const tree = {
299 id: 'root',
300 children: [{ id: 'child-1' }, { id: 'child-2', children: [{ id: 'child-3' }] }],
301 };
302 const query = create(tree);
303 const res1 = query.find((e) => e.node.id === 'child-3');
304 const res2 = query.find((e) => e.node.id === 'NO_EXIT');
305 expect(res1).to.eql({ id: 'child-3' });
306 expect(res2).to.eql(undefined);
307 });
308 it('with namespace', () => {
309 const tree = {
310 id: 'ns:root',
311 children: [{ id: 'child-1' }, { id: 'ns:child-2', children: [{ id: 'ns:child-3' }] }],
312 };
313 const query = create(tree);
314 const res1a = query.find((e) => e.namespace === 'ns' && e.key === 'child-3');
315 const res1b = query.find((e) => e.id === 'ns:child-3');
316 const res2 = query.find((e) => e.namespace === 'foo' && e.key === 'child-3');
317 expect(res1a).to.eql({ id: 'ns:child-3' });
318 expect(res1b).to.eql({ id: 'ns:child-3' });
319 expect(res2).to.eql(undefined);
320 });
321 it('root with namespace', () => {
322 const tree = {
323 id: 'root',
324 children: [
325 { id: 'child-1' },
326 { id: 'ns:child-2', children: [{ id: 'ns:child-2.1' }, { id: 'ns:child-2.1' }] },
327 ],
328 };
329 const query = create(tree);
330 const res = query.find((e) => e.namespace === 'ns');
331 expect(res === null || res === void 0 ? void 0 : res.id).to.eql('ns:child-2');
332 });
333 });
334 describe('findById', () => {
335 it('no namespace', () => {
336 const tree = {
337 id: 'root',
338 children: [{ id: 'child-1' }, { id: 'child-2', children: [{ id: 'child-3' }] }],
339 };
340 const query = create(tree);
341 const res1 = query.findById('child-3');
342 const res2 = query.findById('NO_EXIST');
343 const res3 = query.findById(undefined);
344 const res4 = query.findById({ id: 'child-2' });
345 expect(res1).to.eql({ id: 'child-3' });
346 expect(res2).to.eql(undefined);
347 expect(res3).to.eql(undefined);
348 expect(res4).to.eql({ id: 'child-2', children: [{ id: 'child-3' }] });
349 });
350 it('within namespace', () => {
351 var _a, _b, _c, _d, _e, _f, _g, _h, _j;
352 const root = {
353 id: 'ns1:root',
354 children: [{ id: 'ns1:child-1' }, { id: 'ns2:child-2' }, { id: 'foo' }],
355 };
356 const query = create({ root });
357 const ns1 = create({ root, namespace: 'ns1' });
358 expect((_a = query.findById('root')) === null || _a === void 0 ? void 0 : _a.id).to.eql('ns1:root');
359 expect(query.findById('foo:root')).to.eql(undefined);
360 expect((_b = query.findById('ns1:root')) === null || _b === void 0 ? void 0 : _b.id).to.eql('ns1:root');
361 expect((_c = query.findById('ns1:child-1')) === null || _c === void 0 ? void 0 : _c.id).to.eql('ns1:child-1');
362 expect((_d = query.findById('ns2:child-2')) === null || _d === void 0 ? void 0 : _d.id).to.eql('ns2:child-2');
363 expect((_e = query.findById('foo')) === null || _e === void 0 ? void 0 : _e.id).to.eql('foo');
364 expect((_f = ns1.findById('root')) === null || _f === void 0 ? void 0 : _f.id).to.eql('ns1:root');
365 expect((_g = ns1.findById('ns1:root')) === null || _g === void 0 ? void 0 : _g.id).to.eql('ns1:root');
366 expect(ns1.findById('foo:root')).to.eql(undefined);
367 expect(ns1.findById('404')).to.eql(undefined);
368 expect(ns1.findById('ns1:404')).to.eql(undefined);
369 expect((_h = ns1.findById('child-1')) === null || _h === void 0 ? void 0 : _h.id).to.eql('ns1:child-1');
370 expect((_j = ns1.findById('ns1:child-1')) === null || _j === void 0 ? void 0 : _j.id).to.eql('ns1:child-1');
371 expect(ns1.findById('child-2')).to.eql(undefined);
372 expect(ns1.findById('ns2:child-2')).to.eql(undefined);
373 expect(ns1.findById('foo')).to.eql(undefined);
374 });
375 });
376 describe('parent', () => {
377 it('has a parent', () => {
378 const grandchild = { id: 'grandchild' };
379 const child = { id: 'child', children: [grandchild] };
380 const root = { id: 'root', children: [child] };
381 const query = create(root);
382 expect(query.parent(child)).to.equal(root);
383 expect(query.parent(grandchild)).to.equal(child);
384 });
385 it('has no parent', () => {
386 const grandchild = { id: 'grandchild' };
387 const child = { id: 'child', children: [grandchild] };
388 const root = { id: 'root', children: [] };
389 const query = create(root);
390 expect(query.parent(child)).to.equal(undefined);
391 expect(query.parent(grandchild)).to.equal(undefined);
392 });
393 });
394 describe('ancestor', () => {
395 const tree = {
396 id: 'root',
397 children: [{ id: 'child-1' }, { id: 'child-2', children: [{ id: 'child-3' }] }],
398 };
399 it('matches self (first)', () => {
400 const query = create(tree);
401 const node = query.findById('child-3');
402 const res = query.ancestor(node, (e) => e.node.id === 'child-3');
403 expect(res && res.id).to.eql('child-3');
404 });
405 it('finds matching ancestor', () => {
406 const query = create(tree);
407 const node = query.findById('child-3');
408 const res1 = query.ancestor(node, (e) => e.node.id === 'child-2');
409 const res2 = query.ancestor(node, (e) => e.node.id === 'root');
410 expect(res1 && res1.id).to.eql('child-2');
411 expect(res2 && res2.id).to.eql('root');
412 });
413 it('no match', () => {
414 const query = create(tree);
415 const node = query.findById('root');
416 const res = query.ancestor(node, (e) => e.node.id === 'child-1');
417 expect(res).to.eql(undefined);
418 });
419 });
420 describe('depth', () => {
421 const root = {
422 id: 'A',
423 children: [{ id: 'B' }, { id: 'C', children: [{ id: 'D' }] }],
424 };
425 it('retrieves depth', () => {
426 const query = create(root);
427 expect(query.depth('A')).to.eql(0);
428 expect(query.depth({ id: 'A' })).to.eql(0);
429 expect(query.depth('B')).to.eql(1);
430 expect(query.depth('C')).to.eql(1);
431 expect(query.depth('D')).to.eql(2);
432 expect(query.depth({ id: 'D' })).to.eql(2);
433 });
434 it('-1', () => {
435 const query = create({ id: 'root' });
436 expect(query.depth('C')).to.eql(-1);
437 expect(query.depth(undefined)).to.eql(-1);
438 expect(query.depth('NO_EXIST')).to.eql(-1);
439 expect(query.depth({ id: 'NO_EXIST' })).to.eql(-1);
440 });
441 });
442 describe('exists', () => {
443 const tree = {
444 id: 'root',
445 children: [{ id: 'child-1' }, { id: 'child-2', children: [{ id: 'child-3' }] }],
446 };
447 it('exists', () => {
448 const query = create(tree);
449 expect(query.exists('root')).to.eql(true);
450 expect(query.exists('child-3')).to.eql(true);
451 expect(query.exists({ id: 'root' })).to.eql(true);
452 expect(query.exists({ id: 'child-3' })).to.eql(true);
453 expect(query.exists((e) => e.id === 'child-3')).to.eql(true);
454 });
455 it('does not exist', () => {
456 const query = create(tree);
457 expect(query.exists('404')).to.eql(false);
458 expect(query.exists({ id: '404' })).to.eql(false);
459 expect(query.exists((e) => e.id === '404')).to.eql(false);
460 });
461 });
462});