jqtree 1.6.3 → 1.7.1

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.
Files changed (97) hide show
  1. package/.github/workflows/ci.yml +15 -21
  2. package/.github/workflows/codeql-analysis.yml +2 -2
  3. package/README.md +1 -1
  4. package/bower.json +10 -3
  5. package/config/production +2 -2
  6. package/config/{rollup.config.js → rollup.config.mjs} +3 -8
  7. package/docs/Gemfile.lock +34 -37
  8. package/docs/_config.yml +1 -1
  9. package/docs/_entries/10_changelog.md +13 -0
  10. package/docs/_entries/93_getnextnode.md +4 -1
  11. package/docs/_entries/{95_getpreviousnode.md → 95_getnextvisiblenode.md} +1 -1
  12. package/docs/_entries/96_getpreviousnode.md +0 -0
  13. package/docs/_entries/98_getpreviousvisiblenode.md +14 -0
  14. package/docs/package.json +7 -7
  15. package/docs/pnpm-lock.yaml +413 -265
  16. package/docs/static/bower.json +2 -2
  17. package/docs/static/bower_components/fontawesome/css/all.min.css +6 -2
  18. package/docs/static/bower_components/fontawesome/webfonts/fa-brands-400.ttf +0 -0
  19. package/docs/static/bower_components/fontawesome/webfonts/fa-brands-400.woff2 +0 -0
  20. package/docs/static/bower_components/fontawesome/webfonts/fa-regular-400.ttf +0 -0
  21. package/docs/static/bower_components/fontawesome/webfonts/fa-regular-400.woff2 +0 -0
  22. package/docs/static/bower_components/fontawesome/webfonts/fa-solid-900.ttf +0 -0
  23. package/docs/static/bower_components/fontawesome/webfonts/fa-solid-900.woff2 +0 -0
  24. package/docs/static/bower_components/fontawesome/webfonts/fa-v4compatibility.ttf +0 -0
  25. package/docs/static/bower_components/fontawesome/webfonts/fa-v4compatibility.woff2 +0 -0
  26. package/docs/static/bower_components/jquery/dist/jquery.js +944 -1121
  27. package/docs/static/bower_components/jquery/dist/jquery.min.js +2 -2
  28. package/docs/static/documentation.css +181 -159
  29. package/docs/static/example.css +0 -1
  30. package/docs/tree.jquery.js +3 -3
  31. package/lib/dataLoader.js +5 -31
  32. package/lib/dragAndDropHandler.js +40 -142
  33. package/lib/elementsRenderer.js +52 -72
  34. package/lib/keyHandler.js +8 -32
  35. package/lib/mouse.widget.js +24 -74
  36. package/lib/node.js +72 -134
  37. package/lib/nodeElement.js +24 -84
  38. package/lib/playwright/coverage.js +58 -97
  39. package/lib/playwright/playwright.test.js +148 -210
  40. package/lib/playwright/testUtils.js +116 -182
  41. package/lib/saveStateHandler.js +13 -62
  42. package/lib/scrollHandler.js +24 -77
  43. package/lib/selectNodeHandler.js +6 -25
  44. package/lib/simple.widget.js +20 -53
  45. package/lib/test/jqTree/accessibility.test.js +37 -0
  46. package/lib/test/jqTree/create.test.js +0 -4
  47. package/lib/test/jqTree/events.test.js +73 -84
  48. package/lib/test/jqTree/keyboard.test.js +0 -6
  49. package/lib/test/jqTree/loadOnDemand.test.js +84 -121
  50. package/lib/test/jqTree/methods.test.js +107 -150
  51. package/lib/test/jqTree/options.test.js +32 -54
  52. package/lib/test/node.test.js +134 -76
  53. package/lib/test/nodeUtil.test.js +0 -1
  54. package/lib/test/support/jqTreeMatchers.js +4 -9
  55. package/lib/test/support/setupTests.js +0 -4
  56. package/lib/test/support/testUtil.js +2 -11
  57. package/lib/test/support/treeStructure.js +0 -6
  58. package/lib/test/util.test.js +0 -1
  59. package/lib/tree.jquery.js +28 -239
  60. package/lib/util.js +0 -6
  61. package/lib/version.js +1 -1
  62. package/package.json +44 -47
  63. package/src/dragAndDropHandler.ts +24 -10
  64. package/src/elementsRenderer.ts +49 -42
  65. package/src/jqtreeOptions.ts +3 -3
  66. package/src/keyHandler.ts +3 -3
  67. package/src/mouse.widget.ts +12 -0
  68. package/src/node.ts +52 -16
  69. package/src/nodeElement.ts +27 -21
  70. package/src/saveStateHandler.ts +1 -1
  71. package/src/scrollHandler.ts +6 -2
  72. package/src/selectNodeHandler.ts +1 -1
  73. package/src/simple.widget.ts +2 -0
  74. package/src/test/.eslintrc +3 -1
  75. package/src/test/jqTree/accessibility.test.ts +25 -0
  76. package/src/test/jqTree/events.test.ts +79 -93
  77. package/src/test/jqTree/methods.test.ts +1 -1
  78. package/src/test/node.test.ts +152 -58
  79. package/src/test/nodeUtil.test.ts +1 -1
  80. package/src/tree.jquery.ts +7 -6
  81. package/src/version.ts +1 -1
  82. package/tree.jquery.debug.js +297 -904
  83. package/tree.jquery.debug.js.map +1 -1
  84. package/tree.jquery.js +3 -3
  85. package/tree.jquery.js.map +1 -1
  86. package/tsconfig.json +1 -0
  87. package/docs/static/bower_components/fontawesome/webfonts/fa-brands-400.eot +0 -0
  88. package/docs/static/bower_components/fontawesome/webfonts/fa-brands-400.svg +0 -3717
  89. package/docs/static/bower_components/fontawesome/webfonts/fa-brands-400.woff +0 -0
  90. package/docs/static/bower_components/fontawesome/webfonts/fa-regular-400.eot +0 -0
  91. package/docs/static/bower_components/fontawesome/webfonts/fa-regular-400.svg +0 -801
  92. package/docs/static/bower_components/fontawesome/webfonts/fa-regular-400.woff +0 -0
  93. package/docs/static/bower_components/fontawesome/webfonts/fa-solid-900.eot +0 -0
  94. package/docs/static/bower_components/fontawesome/webfonts/fa-solid-900.svg +0 -5028
  95. package/docs/static/bower_components/fontawesome/webfonts/fa-solid-900.woff +0 -0
  96. /package/docs/_entries/{96_getprevioussibling.md → 97_getprevioussibling.md} +0 -0
  97. /package/docs/_entries/{97_parent.md → 99_parent.md} +0 -0
@@ -34,7 +34,7 @@ export class NodeElement {
34
34
  if (this.mustShowBorderDropHint(position)) {
35
35
  return new BorderDropHint(
36
36
  this.$element,
37
- this.treeWidget._getScrollLeft()
37
+ this.treeWidget._getScrollLeft(),
38
38
  );
39
39
  } else {
40
40
  return new GhostDropHint(this.node, this.$element, position);
@@ -45,10 +45,10 @@ export class NodeElement {
45
45
  const $li = this.getLi();
46
46
 
47
47
  $li.addClass("jqtree-selected");
48
- $li.attr("aria-selected", "true");
49
48
 
50
49
  const $span = this.getSpan();
51
50
  $span.attr("tabindex", this.treeWidget.options.tabIndex ?? null);
51
+ $span.attr("aria-selected", "true");
52
52
 
53
53
  if (mustSetFocus) {
54
54
  $span.trigger("focus");
@@ -59,12 +59,12 @@ export class NodeElement {
59
59
  const $li = this.getLi();
60
60
 
61
61
  $li.removeClass("jqtree-selected");
62
- $li.attr("aria-selected", "false");
63
62
 
64
63
  const $span = this.getSpan();
65
64
  $span.removeAttr("tabindex");
65
+ $span.attr("aria-selected", "false");
66
66
 
67
- $span.blur();
67
+ $span.trigger("blur");
68
68
  }
69
69
 
70
70
  protected getUl(): JQuery<HTMLElement> {
@@ -81,7 +81,7 @@ export class NodeElement {
81
81
  return this.$element;
82
82
  }
83
83
 
84
- protected mustShowBorderDropHint(position: number): boolean {
84
+ protected mustShowBorderDropHint(position: Position): boolean {
85
85
  return position === Position.Inside;
86
86
  }
87
87
  }
@@ -90,7 +90,7 @@ export class FolderElement extends NodeElement {
90
90
  public open(
91
91
  onFinished: OnFinishOpenNode | null,
92
92
  slide = true,
93
- animationSpeed: JQuery.Duration | string = "fast"
93
+ animationSpeed: JQuery.Duration = "fast",
94
94
  ): void {
95
95
  if (this.node.is_open) {
96
96
  return;
@@ -105,18 +105,21 @@ export class FolderElement extends NodeElement {
105
105
  const buttonEl = $button.get(0);
106
106
 
107
107
  if (buttonEl) {
108
- const icon =
109
- this.treeWidget.renderer.openedIconElement.cloneNode(true);
108
+ const openedIconElement =
109
+ this.treeWidget.renderer.openedIconElement;
110
110
 
111
- buttonEl.appendChild(icon);
111
+ if (openedIconElement) {
112
+ const icon = openedIconElement.cloneNode(true);
113
+ buttonEl.appendChild(icon);
114
+ }
112
115
  }
113
116
 
114
117
  const doOpen = (): void => {
115
118
  const $li = this.getLi();
116
119
  $li.removeClass("jqtree-closed");
117
120
 
118
- const $span = this.getSpan();
119
- $span.attr("aria-expanded", "true");
121
+ const $titleSpan = this.getSpan();
122
+ $titleSpan.attr("aria-expanded", "true");
120
123
 
121
124
  if (onFinished) {
122
125
  onFinished(this.node);
@@ -137,7 +140,7 @@ export class FolderElement extends NodeElement {
137
140
 
138
141
  public close(
139
142
  slide = true,
140
- animationSpeed: JQuery.Duration | string = "fast"
143
+ animationSpeed: JQuery.Duration | undefined = "fast",
141
144
  ): void {
142
145
  if (!this.node.is_open) {
143
146
  return;
@@ -152,18 +155,21 @@ export class FolderElement extends NodeElement {
152
155
  const buttonEl = $button.get(0);
153
156
 
154
157
  if (buttonEl) {
155
- const icon =
156
- this.treeWidget.renderer.closedIconElement.cloneNode(true);
158
+ const closedIconElement =
159
+ this.treeWidget.renderer.closedIconElement;
157
160
 
158
- buttonEl.appendChild(icon);
161
+ if (closedIconElement) {
162
+ const icon = closedIconElement.cloneNode(true);
163
+ buttonEl.appendChild(icon);
164
+ }
159
165
  }
160
166
 
161
167
  const doClose = (): void => {
162
168
  const $li = this.getLi();
163
169
  $li.addClass("jqtree-closed");
164
170
 
165
- const $span = this.getSpan();
166
- $span.attr("aria-expanded", "false");
171
+ const $titleSpan = this.getSpan();
172
+ $titleSpan.attr("aria-expanded", "false");
167
173
 
168
174
  this.treeWidget._triggerEvent("tree.close", {
169
175
  node: this.node,
@@ -178,7 +184,7 @@ export class FolderElement extends NodeElement {
178
184
  }
179
185
  }
180
186
 
181
- protected mustShowBorderDropHint(position: number): boolean {
187
+ protected mustShowBorderDropHint(position: Position): boolean {
182
188
  return !this.node.is_open && position === Position.Inside;
183
189
  }
184
190
 
@@ -217,13 +223,13 @@ class GhostDropHint implements DropHint {
217
223
  private node: Node;
218
224
  private $ghost: JQuery;
219
225
 
220
- constructor(node: Node, $element: JQuery<Element>, position: number) {
226
+ constructor(node: Node, $element: JQuery<Element>, position: Position) {
221
227
  this.$element = $element;
222
228
 
223
229
  this.node = node;
224
230
  this.$ghost = jQuery(
225
231
  `<li class="jqtree_common jqtree-ghost"><span class="jqtree_common jqtree-circle"></span>
226
- <span class="jqtree_common jqtree-line"></span></li>`
232
+ <span class="jqtree_common jqtree-line"></span></li>`,
227
233
  );
228
234
 
229
235
  if (position === Position.After) {
@@ -252,7 +258,7 @@ class GhostDropHint implements DropHint {
252
258
  }
253
259
 
254
260
  public moveInsideOpenFolder(): void {
255
- const childElement = this.node.children[0].element;
261
+ const childElement = this.node.children[0]?.element;
256
262
 
257
263
  if (childElement) {
258
264
  jQuery(childElement).before(this.$ghost);
@@ -111,7 +111,7 @@ export default class SaveStateHandler {
111
111
  const state = this.getStateFromStorage();
112
112
 
113
113
  if (state && state.selected_node) {
114
- return state.selected_node[0];
114
+ return state.selected_node[0] || null;
115
115
  } else {
116
116
  return null;
117
117
  }
@@ -23,7 +23,7 @@ export default class ScrollHandler {
23
23
  public scrollToY(top: number): void {
24
24
  this.ensureInit();
25
25
 
26
- if (this.$scrollParent) {
26
+ if (this.$scrollParent && this.$scrollParent[0]) {
27
27
  this.$scrollParent[0].scrollTop = top;
28
28
  } else {
29
29
  const offset = this.treeWidget.$el.offset();
@@ -121,7 +121,7 @@ export default class ScrollHandler {
121
121
  if (
122
122
  $scrollParent &&
123
123
  $scrollParent.length &&
124
- $scrollParent[0].tagName !== "HTML"
124
+ $scrollParent[0]?.tagName !== "HTML"
125
125
  ) {
126
126
  this.$scrollParent = $scrollParent;
127
127
 
@@ -223,6 +223,10 @@ export default class ScrollHandler {
223
223
 
224
224
  const scrollParent = $scrollParent[0];
225
225
 
226
+ if (!scrollParent) {
227
+ return;
228
+ }
229
+
226
230
  const canScrollRight =
227
231
  scrollParent.scrollLeft + scrollParent.clientWidth <
228
232
  scrollParent.scrollWidth;
@@ -16,7 +16,7 @@ export default class SelectNodeHandler {
16
16
  const selectedNodes = this.getSelectedNodes();
17
17
 
18
18
  if (selectedNodes.length) {
19
- return selectedNodes[0];
19
+ return selectedNodes[0] || false;
20
20
  } else {
21
21
  return false;
22
22
  }
@@ -94,6 +94,8 @@ const register = (widgetClass: unknown, widgetName: string): void => {
94
94
  } else {
95
95
  return callFunction(this, functionName, args);
96
96
  }
97
+ } else {
98
+ return undefined;
97
99
  }
98
100
  };
99
101
  };
@@ -3,10 +3,12 @@
3
3
  "extends": ["plugin:jest/all", "plugin:testing-library/dom"],
4
4
  "rules": {
5
5
  "jest/consistent-test-it": "off",
6
- "jest/prefer-expect-assertions": "off",
6
+ "jest/max-expects": ["off"],
7
7
  "jest/no-duplicate-hooks": "off",
8
8
  "jest/no-hooks": "off",
9
9
  "jest/no-identical-title": "off",
10
+ "jest/no-standalone-expect": "off",
11
+ "jest/prefer-expect-assertions": "off",
10
12
  "jest/prefer-strict-equal": "off",
11
13
  "jest/require-hook": "off",
12
14
  "jest/require-top-level-describe": "off"
@@ -0,0 +1,25 @@
1
+ import { axe, toHaveNoViolations } from "jest-axe";
2
+ import "../../tree.jquery";
3
+ import exampleData from "../support/exampleData";
4
+
5
+ expect.extend(toHaveNoViolations);
6
+
7
+ beforeEach(() => {
8
+ $("body").append('<div id="tree1"></div>');
9
+ });
10
+
11
+ afterEach(() => {
12
+ const $tree = $("#tree1");
13
+ $tree.tree("destroy");
14
+ $tree.remove();
15
+ });
16
+
17
+ it("has an accessible ui", async () => {
18
+ const $tree = $("#tree1");
19
+ $tree.tree({
20
+ data: exampleData,
21
+ });
22
+ const element = $tree.get()[0] as HTMLElement;
23
+
24
+ await expect(axe(element)).resolves.toHaveNoViolations();
25
+ });
@@ -1,6 +1,7 @@
1
1
  import getGiven from "givens";
2
2
  import { rest } from "msw";
3
3
  import { setupServer } from "msw/node";
4
+ import { waitFor } from "@testing-library/dom";
4
5
  import "../../tree.jquery";
5
6
  import exampleData from "../support/exampleData";
6
7
  import { titleSpan } from "../support/testUtil";
@@ -41,17 +42,15 @@ describe("tree.click", () => {
41
42
  given.$tree.tree({ data: exampleData });
42
43
  });
43
44
 
44
- it("fires tree.click", () =>
45
- new Promise<void>((done) => {
46
- given.$tree.on("tree.click", (e: unknown) => {
47
- const treeClickEvent = e as ClickNodeEvent;
45
+ it("fires tree.click", () => {
46
+ const onClick = jest.fn();
47
+ given.$tree.on("tree.click", onClick);
48
48
 
49
- expect(treeClickEvent.node).toBe(given.node1);
50
- done();
51
- });
52
-
53
- given.titleSpan.trigger("click");
54
- }));
49
+ given.titleSpan.trigger("click");
50
+ expect(onClick).toHaveBeenCalledWith(
51
+ expect.objectContaining({ node: given.node1 })
52
+ );
53
+ });
55
54
  });
56
55
 
57
56
  describe("tree.contextmenu", () => {
@@ -70,17 +69,15 @@ describe("tree.contextmenu", () => {
70
69
  given.$tree.tree({ data: exampleData });
71
70
  });
72
71
 
73
- it("fires tree.contextmenu", () =>
74
- new Promise<void>((done) => {
75
- given.$tree.on("tree.contextmenu", (e: unknown) => {
76
- const treeClickEvent = e as ClickNodeEvent;
72
+ it("fires tree.contextmenu", () => {
73
+ const onContextMenu = jest.fn();
74
+ given.$tree.on("tree.contextmenu", onContextMenu);
77
75
 
78
- expect(treeClickEvent.node).toBe(given.node1);
79
- done();
80
- });
81
-
82
- given.titleSpan.contextmenu();
83
- }));
76
+ given.titleSpan.trigger("contextmenu");
77
+ expect(onContextMenu).toHaveBeenCalledWith(
78
+ expect.objectContaining({ node: given.node1 })
79
+ );
80
+ });
84
81
  });
85
82
 
86
83
  describe("tree.dblclick", () => {
@@ -99,17 +96,15 @@ describe("tree.dblclick", () => {
99
96
  given.$tree.tree({ data: exampleData });
100
97
  });
101
98
 
102
- it("fires tree.dblclick", () =>
103
- new Promise<void>((done) => {
104
- given.$tree.on("tree.dblclick", (e: unknown) => {
105
- const treeClickEvent = e as ClickNodeEvent;
99
+ it("fires tree.dblclick", () => {
100
+ const onDoubleClick = jest.fn();
101
+ given.$tree.on("tree.dblclick", onDoubleClick);
106
102
 
107
- expect(treeClickEvent.node).toBe(given.node1);
108
- done();
109
- });
110
-
111
- given.titleSpan.trigger("dblclick");
112
- }));
103
+ given.titleSpan.trigger("dblclick");
104
+ expect(onDoubleClick).toHaveBeenCalledWith(
105
+ expect.objectContaining({ node: given.node1 })
106
+ );
107
+ });
113
108
  });
114
109
 
115
110
  describe("tree.init", () => {
@@ -120,22 +115,17 @@ describe("tree.init", () => {
120
115
  given("$tree", () => $("#tree1"));
121
116
 
122
117
  context("with json data", () => {
123
- it("is called", () =>
124
- new Promise<void>((done) => {
125
- given.$tree.on("tree.init", () => {
126
- expect(
127
- given.$tree.tree("getNodeByName", "node2")
128
- ).toMatchObject({
129
- id: 124,
130
- name: "node2",
131
- });
132
- done();
133
- });
134
-
135
- given.$tree.tree({
136
- data: exampleData,
137
- });
138
- }));
118
+ it("is called", () => {
119
+ const onInit = jest.fn();
120
+ given.$tree.on("tree.init", onInit);
121
+
122
+ given.$tree.tree({
123
+ data: exampleData,
124
+ });
125
+
126
+ // eslint-disable-next-line jest/prefer-called-with
127
+ expect(onInit).toHaveBeenCalled();
128
+ });
139
129
  });
140
130
 
141
131
  context("with data loaded from an url", () => {
@@ -147,20 +137,17 @@ describe("tree.init", () => {
147
137
  );
148
138
  });
149
139
 
150
- it("is called", () =>
151
- new Promise<void>((done) => {
152
- given.$tree.on("tree.init", () => {
153
- expect(
154
- given.$tree.tree("getNodeByName", "node2")
155
- ).toMatchObject({
156
- id: 124,
157
- name: "node2",
158
- });
159
- done();
160
- });
161
-
162
- given.$tree.tree({ dataUrl: "/tree/" });
163
- }));
140
+ it("is called", async () => {
141
+ const onInit = jest.fn();
142
+ given.$tree.on("tree.init", onInit);
143
+
144
+ given.$tree.tree({ dataUrl: "/tree/" });
145
+
146
+ await waitFor(() => {
147
+ // eslint-disable-next-line jest/prefer-called-with
148
+ expect(onInit).toHaveBeenCalled();
149
+ });
150
+ });
164
151
  });
165
152
  });
166
153
 
@@ -172,16 +159,15 @@ describe("tree.load_data", () => {
172
159
  given("$tree", () => $("#tree1"));
173
160
 
174
161
  context("when the tree is initialized with data", () => {
175
- it("fires tree.load_data", () =>
176
- new Promise<void>((resolve) => {
177
- given.$tree.on("tree.load_data", (e: any) => {
178
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
179
- expect(e.tree_data).toEqual(exampleData);
180
- resolve();
181
- });
182
-
183
- given.$tree.tree({ data: exampleData });
184
- }));
162
+ it("fires tree.load_data", () => {
163
+ const onLoadData = jest.fn();
164
+ given.$tree.on("tree.load_data", onLoadData);
165
+
166
+ given.$tree.tree({ data: exampleData });
167
+ expect(onLoadData).toHaveBeenCalledWith(
168
+ expect.objectContaining({ tree_data: exampleData })
169
+ );
170
+ });
185
171
  });
186
172
  });
187
173
 
@@ -203,35 +189,35 @@ describe("tree.select", () => {
203
189
  });
204
190
  });
205
191
 
206
- it("fires tree.click", () =>
207
- new Promise<void>((done) => {
208
- given.$tree.on("tree.select", (e: unknown) => {
209
- const treeClickEvent = e as ClickNodeEvent;
210
-
211
- expect(treeClickEvent.node).toBe(given.node1);
212
- expect(treeClickEvent.deselected_node).toBeNull();
213
- done();
214
- });
215
-
216
- given.titleSpan.trigger("click");
217
- }));
192
+ it("fires tree.select", () => {
193
+ const onSelect = jest.fn();
194
+ given.$tree.on("tree.select", onSelect);
195
+
196
+ given.titleSpan.trigger("click");
197
+ expect(onSelect).toHaveBeenCalledWith(
198
+ expect.objectContaining({
199
+ node: given.node1,
200
+ deselected_node: null,
201
+ })
202
+ );
203
+ });
218
204
 
219
205
  context("when the node was selected", () => {
220
206
  beforeEach(() => {
221
207
  given.$tree.tree("selectNode", given.node1);
222
208
  });
223
209
 
224
- it("fires tree.select with node is null", () =>
225
- new Promise<void>((done) => {
226
- given.$tree.on("tree.select", (e: unknown) => {
227
- const treeClickEvent = e as ClickNodeEvent;
228
-
229
- expect(treeClickEvent.node).toBeNull();
230
- expect(treeClickEvent.previous_node).toBe(given.node1);
231
- done();
232
- });
210
+ it("fires tree.select with node is null", () => {
211
+ const onSelect = jest.fn();
212
+ given.$tree.on("tree.select", onSelect);
233
213
 
234
- given.titleSpan.trigger("click");
235
- }));
214
+ given.titleSpan.trigger("click");
215
+ expect(onSelect).toHaveBeenCalledWith(
216
+ expect.objectContaining({
217
+ node: null,
218
+ previous_node: given.node1,
219
+ })
220
+ );
221
+ });
236
222
  });
237
223
  });
@@ -984,7 +984,7 @@ describe("refresh", () => {
984
984
 
985
985
  it("rerenders the tree", () => {
986
986
  const tree = given.$tree.tree("getTree");
987
- tree.children[0].name = "node1a";
987
+ (tree.children[0] as INode).name = "node1a";
988
988
 
989
989
  expect(given.$tree).toHaveTreeStructure([
990
990
  expect.objectContaining({ name: "node1" }),