Skip to content

Commit c2bb057

Browse files
committed
change to object representation
1 parent 2cec420 commit c2bb057

File tree

3 files changed

+177
-41
lines changed

3 files changed

+177
-41
lines changed

src/material/tree/testing/shared.spec.ts

Lines changed: 95 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -100,32 +100,107 @@ export function runHarnessTests(
100100
it ('should correctly get tree structure', async () => {
101101
const trees = await loader.getAllHarnesses(treeHarness);
102102
const flatTree = trees[0];
103-
expect(await flatTree.getStructureText()).toEqual(
104-
`Flat Group 1
105-
Flat Group 2`);
103+
104+
expect(await flatTree.getTreeStructure()).toEqual({
105+
children: [
106+
{text: 'Flat Group 1'},
107+
{text: 'Flat Group 2'}
108+
]
109+
});
110+
111+
const firstGroup = (await flatTree.getNodes({text: /Flat Group 1/}))[0];
112+
await firstGroup.expand();
113+
114+
expect(await flatTree.getTreeStructure()).toEqual({
115+
children: [
116+
{
117+
text: 'Flat Group 1',
118+
children: [
119+
{text: 'Flat Leaf 1.1'},
120+
{text: 'Flat Leaf 1.2'},
121+
{text: 'Flat Leaf 1.3'}]
122+
},
123+
{text: 'Flat Group 2'}
124+
]
125+
});
126+
127+
const secondGroup = (await flatTree.getNodes({text: /Flat Group 2/}))[0];
128+
await secondGroup.expand();
129+
130+
expect(await flatTree.getTreeStructure()).toEqual({
131+
children: [
132+
{
133+
text: 'Flat Group 1',
134+
children: [
135+
{text: 'Flat Leaf 1.1'},
136+
{text: 'Flat Leaf 1.2'},
137+
{text: 'Flat Leaf 1.3'}]
138+
},
139+
{
140+
text: 'Flat Group 2',
141+
children: [
142+
{text: 'Flat Group 2.1'},
143+
]
144+
}
145+
]
146+
});
106147
});
107148

108149
it('should correctly get tree structure', async () => {
109150
const trees = await loader.getAllHarnesses(treeHarness);
110151
const nestedTree = trees[1];
111-
expect(await nestedTree.getStructureText()).toEqual(
112-
`Nested Group 1
113-
\tNested Leaf 1.1
114-
\tNested Leaf 1.2
115-
\tNested Leaf 1.3
116-
Nested Group 2
117-
\tNested Group 2.1
118-
\t\tNested Leaf 2.1.1
119-
\t\tNested Leaf 2.1.2`);
152+
expect(await nestedTree.getTreeStructure()).toEqual({
153+
children: [
154+
{text: 'Nested Group 1'},
155+
{text: 'Nested Group 2'}
156+
]
157+
});
158+
159+
const firstGroup = (await nestedTree.getNodes({text: /Nested Group 1/}))[0];
160+
await firstGroup.expand();
161+
expect(await nestedTree.getTreeStructure()).toEqual(
162+
{
163+
children: [
164+
{
165+
text: 'Nested Group 1',
166+
children: [
167+
{text: 'Nested Leaf 1.1'},
168+
{text: 'Nested Leaf 1.2'},
169+
{text: 'Nested Leaf 1.3'}]
170+
},
171+
{text: 'Nested Group 2'}
172+
]
173+
});
174+
175+
const secondGroup = (await nestedTree.getNodes({text: /Nested Group 2/}))[0];
176+
await secondGroup.expand();
177+
expect(await nestedTree.getTreeStructure()).toEqual(
178+
{
179+
children: [
180+
{
181+
text: 'Nested Group 1',
182+
children: [
183+
{text: 'Nested Leaf 1.1'},
184+
{text: 'Nested Leaf 1.2'},
185+
{text: 'Nested Leaf 1.3'}]
186+
},
187+
{
188+
text: 'Nested Group 2',
189+
children: [
190+
{text: 'Nested Group 2.1'},
191+
]
192+
}
193+
]
194+
});
120195
});
121196
}
122197

123-
interface FoodNode {
198+
interface Node {
124199
name: string;
125-
children?: FoodNode[];
200+
children?: Node[];
126201
}
127202

128-
const FLAT_TREE_DATA: FoodNode[] = [
203+
const FLAT_TREE_DATA: Node[] = [
129204
{
130205
name: 'Flat Group 1',
131206
children: [
@@ -148,7 +223,7 @@ const FLAT_TREE_DATA: FoodNode[] = [
148223
},
149224
];
150225

151-
const NESTED_TREE_DATA: FoodNode[] = [
226+
const NESTED_TREE_DATA: Node[] = [
152227
{
153228
name: 'Nested Group 1',
154229
children: [
@@ -210,7 +285,7 @@ interface ExampleFlatNode {
210285
`
211286
})
212287
class TreeHarnessTest {
213-
private _transformer = (node: FoodNode, level: number) => {
288+
private _transformer = (node: Node, level: number) => {
214289
return {
215290
expandable: !!node.children && node.children.length > 0,
216291
name: node.name,
@@ -223,8 +298,8 @@ class TreeHarnessTest {
223298
flatTreeControl = new FlatTreeControl<ExampleFlatNode>(
224299
node => node.level, node => node.expandable);
225300
flatTreeDataSource = new MatTreeFlatDataSource(this.flatTreeControl, this.treeFlattener);
226-
nestedTreeControl = new NestedTreeControl<FoodNode>(node => node.children);
227-
nestedTreeDataSource = new MatTreeNestedDataSource<FoodNode>();
301+
nestedTreeControl = new NestedTreeControl<Node>(node => node.children);
302+
nestedTreeDataSource = new MatTreeNestedDataSource<Node>();
228303

229304
constructor() {
230305
this.flatTreeDataSource.data = FLAT_TREE_DATA;
@@ -233,5 +308,5 @@ class TreeHarnessTest {
233308

234309
flatTreeHasChild = (_: number, node: ExampleFlatNode) => node.expandable;
235310

236-
nestedTreeHasChild = (_: number, node: FoodNode) => !!node.children && node.children.length > 0;
311+
nestedTreeHasChild = (_: number, node: Node) => !!node.children && node.children.length > 0;
237312
}

src/material/tree/testing/tree-harness.ts

Lines changed: 81 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,15 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {ComponentHarness, HarnessPredicate} from '@angular/cdk/testing';
9+
import {ComponentHarness, HarnessPredicate, parallel} from '@angular/cdk/testing';
1010
import {MatTreeNodeHarness} from './node-harness';
1111
import {TreeHarnessFilters, TreeNodeHarnessFilters} from './tree-harness-filters';
1212

13+
type TreeNode = {
14+
text?: string;
15+
children?: TreeNode[];
16+
};
17+
1318
/** Harness for interacting with a standard mat-tree in tests. */
1419
export class MatTreeHarness extends ComponentHarness {
1520
/** The selector for the host element of a `MatTableHarness` instance. */
@@ -30,9 +35,10 @@ export class MatTreeHarness extends ComponentHarness {
3035
}
3136

3237
/**
33-
* String representation of the tree structure.
38+
* Object representation of the visible tree structure.
39+
* If a node is under an unexpanded node it will not be shown here.
3440
* Eg.
35-
* Tree:
41+
* Tree (all nodes expanded):
3642
* `
3743
* <mat-tree>
3844
* <mat-tree-node>Node 1<mat-tree-node>
@@ -50,25 +56,80 @@ export class MatTreeHarness extends ComponentHarness {
5056
* <mat-nested-tree-node>
5157
* </mat-tree>`
5258
*
53-
* Structured text:
54-
* Node 1
55-
* Node 2
56-
* Node 2.1
57-
* Node 2.1.1
58-
* Node 2.2
59+
* Tree structure:
60+
* {
61+
* children: [
62+
* {
63+
* text: 'Node 1',
64+
* children: [
65+
* {
66+
* text: 'Node 2',
67+
* children: [
68+
* {
69+
* text: 'Node 2.1',
70+
* children: [{text: 'Node 2.1.1'}]
71+
* },
72+
* {text: 'Node 2.2'}
73+
* ]
74+
* }
75+
* ]
76+
* }
77+
* ]
78+
* };
5979
*/
60-
async getStructureText(): Promise<string> {
61-
let treeString = '';
80+
async getTreeStructure(): Promise<TreeNode> {
6281
const nodes = await this.getNodes();
63-
const levelsAndText = await Promise.all(nodes.map(node => {
64-
return Promise.all([node.getLevel(), node.getText()]);
65-
}));
66-
for (let i = 0; i < nodes.length; i++) {
67-
const [level, text] = levelsAndText[i];
68-
treeString += i === 0 ? '' : '\n';
69-
treeString += '\t'.repeat(level - 1);
70-
treeString += text;
82+
const nodeInformation = await parallel(() => nodes.map(node => {
83+
return Promise.all([node.getLevel(), node.getText(), node.isExpanded()]);
84+
}));
85+
return this._getTreeStructureRecursion(nodeInformation, 1, true);
86+
}
87+
88+
private _getTreeStructureRecursion(tree: [number, string, boolean][],
89+
level: number,
90+
parentExpanded: boolean): TreeNode {
91+
// param level is the level of nodes that are being accounted for during this iteration
92+
let result: TreeNode = {};
93+
for (let i = 0; i < tree.length; i++) {
94+
const [nodeLevel, text, expanded] = tree[i];
95+
const nextNodeLevel = tree[i + 1]?.[0] ?? -1;
96+
97+
if (nodeLevel < level) {
98+
// reached a node in an outer level/end of node list so stop and return the accumulated
99+
// children nodes
100+
return result;
101+
}
102+
if (nodeLevel > level) {
103+
// reached a node in an inner level so skip this as it will be added in an upcoming
104+
// iteration
105+
continue;
106+
}
107+
108+
if (parentExpanded) {
109+
// only add to representation if it is visible (parent is expanded)
110+
if (nextNodeLevel === level) {
111+
// next node in list is at the same level so add to the children list
112+
this._addChildToNode(result, {text});
113+
} else if (nextNodeLevel > level) {
114+
// next node in list is a child of the current node, recurse on and collect nodes on
115+
// the child node's level to add as children of current node
116+
let children = this._getTreeStructureRecursion(tree.slice(i + 1),
117+
nextNodeLevel,
118+
expanded)?.children;
119+
let child = children ? {text, children} : {text};
120+
this._addChildToNode(result, child);
121+
} else { // nextNodeLevel < level
122+
// next node in list is on an outer level, this means this is the last child of the
123+
// current node's parent
124+
this._addChildToNode(result, {text});
125+
return result;
126+
}
127+
}
71128
}
72-
return treeString;
129+
return result;
130+
}
131+
132+
private _addChildToNode(result: TreeNode, child: TreeNode) {
133+
result.children ? result.children.push(child) : result.children = [child];
73134
}
74135
}

tools/public_api_guard/material/tree/testing.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export declare class MatTreeHarness extends ComponentHarness {
22
getNodes(filter?: TreeNodeHarnessFilters): Promise<MatTreeNodeHarness[]>;
3-
getTreeStructure(): Promise<string>;
3+
getTreeStructure(): Promise<TreeNode>;
44
static hostSelector: string;
55
static with(options?: TreeHarnessFilters): HarnessPredicate<MatTreeHarness>;
66
}

0 commit comments

Comments
 (0)