jqtree 1.7.5 → 1.8.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 (119) hide show
  1. package/.eslintrc +13 -3
  2. package/.github/workflows/ci.yml +6 -6
  3. package/.github/workflows/codeql-analysis.yml +4 -4
  4. package/.github/workflows/size.yml +3 -3
  5. package/.github/workflows/static.yml +1 -1
  6. package/bower.json +1 -1
  7. package/config/babel.config.json +1 -1
  8. package/config/jest.config.js +4 -0
  9. package/config/jest.polyfills.js +14 -0
  10. package/config/production +2 -0
  11. package/devserver/devserver_scroll.js +8 -0
  12. package/devserver/test_index.html +9 -0
  13. package/devserver/test_scroll.html +28 -0
  14. package/devserver/test_scroll_container.html +39 -0
  15. package/docs/.ruby-version +1 -1
  16. package/docs/_config.yml +1 -1
  17. package/docs/_entries/general/changelog.md +11 -0
  18. package/docs/_entries/multiple_selection/get-selected-nodes.md +1 -1
  19. package/docs/_entries/node/getnextnode.md +3 -6
  20. package/docs/_entries/node/getnextsibling.md +1 -1
  21. package/docs/_entries/node/getnextvisiblenode.md +8 -5
  22. package/docs/_entries/node/getpreviousnode.md +12 -0
  23. package/docs/_entries/node/getprevioussibling.md +1 -1
  24. package/docs/_entries/node/getpreviousvisiblenode.md +6 -5
  25. package/package.json +35 -29
  26. package/src/dataLoader.ts +57 -34
  27. package/src/dragAndDropHandler/dragElement.ts +54 -0
  28. package/src/dragAndDropHandler/generateHitAreas.ts +176 -0
  29. package/src/dragAndDropHandler/index.ts +454 -0
  30. package/src/dragAndDropHandler/iterateVisibleNodes.ts +91 -0
  31. package/src/dragAndDropHandler/types.ts +13 -0
  32. package/src/elementsRenderer.ts +75 -40
  33. package/src/jqtreeMethodTypes.ts +40 -0
  34. package/src/jqtreeOptions.ts +43 -25
  35. package/src/keyHandler.ts +59 -30
  36. package/src/mouseHandler.ts +385 -0
  37. package/src/mouseUtils.ts +23 -0
  38. package/src/node.ts +1 -29
  39. package/src/nodeElement/borderDropHint.ts +32 -0
  40. package/src/nodeElement/folderElement.ts +133 -0
  41. package/src/nodeElement/ghostDropHint.ts +69 -0
  42. package/src/nodeElement/index.ts +102 -0
  43. package/src/playwright/coverage.ts +4 -7
  44. package/src/playwright/playwright.test.ts +150 -53
  45. package/src/playwright/testUtils.ts +28 -5
  46. package/src/position.ts +28 -0
  47. package/src/saveStateHandler.ts +75 -26
  48. package/src/scrollHandler/containerScrollParent.ts +13 -23
  49. package/src/scrollHandler/createScrollParent.ts +22 -22
  50. package/src/scrollHandler/documentScrollParent.ts +16 -13
  51. package/src/scrollHandler.ts +13 -15
  52. package/src/selectNodeHandler.ts +10 -16
  53. package/src/test/jqTree/events.test.ts +97 -30
  54. package/src/test/jqTree/keyboard.test.ts +18 -23
  55. package/src/test/jqTree/loadOnDemand.test.ts +22 -15
  56. package/src/test/jqTree/methods.test.ts +40 -14
  57. package/src/test/jqTree/mouse.test.ts +82 -0
  58. package/src/test/jqTree/options.test.ts +24 -12
  59. package/src/test/node.test.ts +3 -2
  60. package/src/test/{nodeUtil.test.ts → position.test.ts} +1 -1
  61. package/src/tree.jquery.ts +314 -208
  62. package/src/util.ts +12 -0
  63. package/src/version.ts +1 -1
  64. package/tree.jquery.debug.js +2594 -3419
  65. package/tree.jquery.debug.js.map +1 -1
  66. package/tree.jquery.js +3 -3
  67. package/tree.jquery.js.map +1 -1
  68. package/tsconfig.json +5 -3
  69. package/docs/_entries/functions/get-selected-nodes.md +0 -10
  70. package/lib/dataLoader.js +0 -123
  71. package/lib/dragAndDropHandler.js +0 -588
  72. package/lib/elementsRenderer.js +0 -267
  73. package/lib/jqtreeOptions.js +0 -1
  74. package/lib/keyHandler.js +0 -111
  75. package/lib/mouse.widget.js +0 -255
  76. package/lib/node.js +0 -708
  77. package/lib/nodeElement.js +0 -274
  78. package/lib/nodeUtils.js +0 -10
  79. package/lib/playwright/coverage.js +0 -99
  80. package/lib/playwright/playwright.test.js +0 -606
  81. package/lib/playwright/testUtils.js +0 -210
  82. package/lib/saveStateHandler.js +0 -277
  83. package/lib/scrollHandler/containerScrollParent.js +0 -160
  84. package/lib/scrollHandler/createScrollParent.js +0 -57
  85. package/lib/scrollHandler/documentScrollParent.js +0 -169
  86. package/lib/scrollHandler/scrollParent.js +0 -58
  87. package/lib/scrollHandler/types.js +0 -1
  88. package/lib/scrollHandler.js +0 -71
  89. package/lib/selectNodeHandler.js +0 -128
  90. package/lib/simple.widget.js +0 -158
  91. package/lib/test/global.d.js +0 -3
  92. package/lib/test/jqTree/accessibility.test.js +0 -37
  93. package/lib/test/jqTree/create.test.js +0 -48
  94. package/lib/test/jqTree/events.test.js +0 -210
  95. package/lib/test/jqTree/keyboard.test.js +0 -225
  96. package/lib/test/jqTree/loadOnDemand.test.js +0 -218
  97. package/lib/test/jqTree/methods.test.js +0 -1348
  98. package/lib/test/jqTree/options.test.js +0 -548
  99. package/lib/test/jqTree/scrollHandler/containerScrollParent.test.js +0 -94
  100. package/lib/test/node.test.js +0 -1202
  101. package/lib/test/nodeUtil.test.js +0 -27
  102. package/lib/test/nodeUtils.test.js +0 -20
  103. package/lib/test/support/exampleData.js +0 -35
  104. package/lib/test/support/jqTreeMatchers.js +0 -70
  105. package/lib/test/support/matchers.d.js +0 -1
  106. package/lib/test/support/setupTests.js +0 -7
  107. package/lib/test/support/testUtil.js +0 -29
  108. package/lib/test/support/treeStructure.js +0 -38
  109. package/lib/test/util.test.js +0 -26
  110. package/lib/tree.jquery.d.js +0 -1
  111. package/lib/tree.jquery.js +0 -1105
  112. package/lib/types.js +0 -1
  113. package/lib/typings.d.js +0 -2
  114. package/lib/util.js +0 -15
  115. package/lib/version.js +0 -8
  116. package/src/dragAndDropHandler.ts +0 -713
  117. package/src/mouse.widget.ts +0 -266
  118. package/src/nodeElement.ts +0 -272
  119. package/src/types.ts +0 -19
@@ -1,31 +1,24 @@
1
1
  import getGiven from "givens";
2
- import { rest } from "msw";
2
+ import { http, HttpResponse } from "msw";
3
3
  import { setupServer } from "msw/node";
4
4
  import { waitFor } from "@testing-library/dom";
5
+ import { userEvent } from "@testing-library/user-event";
5
6
  import "../../tree.jquery";
6
7
  import exampleData from "../support/exampleData";
7
8
  import { titleSpan } from "../support/testUtil";
8
9
 
9
10
  const context = describe;
10
11
 
11
- const server = setupServer();
12
-
13
- beforeAll(() => server.listen());
14
-
15
12
  beforeEach(() => {
16
13
  $("body").append('<div id="tree1"></div>');
17
14
  });
18
15
 
19
16
  afterEach(() => {
20
- server.resetHandlers();
21
-
22
17
  const $tree = $("#tree1");
23
18
  $tree.tree("destroy");
24
19
  $tree.remove();
25
20
  });
26
21
 
27
- afterAll(() => server.close());
28
-
29
22
  describe("tree.click", () => {
30
23
  interface Vars {
31
24
  node1: INode;
@@ -42,13 +35,13 @@ describe("tree.click", () => {
42
35
  given.$tree.tree({ data: exampleData });
43
36
  });
44
37
 
45
- it("fires tree.click", () => {
38
+ it("fires tree.click", async () => {
46
39
  const onClick = jest.fn();
47
40
  given.$tree.on("tree.click", onClick);
48
41
 
49
- given.titleSpan.trigger("click");
42
+ await userEvent.click(given.titleSpan.get(0) as HTMLElement);
50
43
  expect(onClick).toHaveBeenCalledWith(
51
- expect.objectContaining({ node: given.node1 })
44
+ expect.objectContaining({ node: given.node1 }),
52
45
  );
53
46
  });
54
47
  });
@@ -69,13 +62,16 @@ describe("tree.contextmenu", () => {
69
62
  given.$tree.tree({ data: exampleData });
70
63
  });
71
64
 
72
- it("fires tree.contextmenu", () => {
65
+ it("fires tree.contextmenu", async () => {
73
66
  const onContextMenu = jest.fn();
74
67
  given.$tree.on("tree.contextmenu", onContextMenu);
75
68
 
76
- given.titleSpan.trigger("contextmenu");
69
+ await userEvent.pointer({
70
+ target: given.titleSpan.get(0) as HTMLElement,
71
+ keys: "[MouseRight]",
72
+ });
77
73
  expect(onContextMenu).toHaveBeenCalledWith(
78
- expect.objectContaining({ node: given.node1 })
74
+ expect.objectContaining({ node: given.node1 }),
79
75
  );
80
76
  });
81
77
  });
@@ -96,13 +92,13 @@ describe("tree.dblclick", () => {
96
92
  given.$tree.tree({ data: exampleData });
97
93
  });
98
94
 
99
- it("fires tree.dblclick", () => {
95
+ it("fires tree.dblclick", async () => {
100
96
  const onDoubleClick = jest.fn();
101
97
  given.$tree.on("tree.dblclick", onDoubleClick);
102
98
 
103
- given.titleSpan.trigger("dblclick");
99
+ await userEvent.dblClick(given.titleSpan.get(0) as HTMLElement);
104
100
  expect(onDoubleClick).toHaveBeenCalledWith(
105
- expect.objectContaining({ node: given.node1 })
101
+ expect.objectContaining({ node: given.node1 }),
106
102
  );
107
103
  });
108
104
  });
@@ -129,12 +125,15 @@ describe("tree.init", () => {
129
125
  });
130
126
 
131
127
  context("with data loaded from an url", () => {
128
+ const server = setupServer(
129
+ http.get("/tree/", () => HttpResponse.json(exampleData)),
130
+ );
132
131
  beforeEach(() => {
133
- server.use(
134
- rest.get("/tree/", (_request, response, ctx) =>
135
- response(ctx.status(200), ctx.json(exampleData))
136
- )
137
- );
132
+ server.listen();
133
+ });
134
+
135
+ afterAll(() => {
136
+ server.close();
138
137
  });
139
138
 
140
139
  it("is called", async () => {
@@ -165,7 +164,7 @@ describe("tree.load_data", () => {
165
164
 
166
165
  given.$tree.tree({ data: exampleData });
167
166
  expect(onLoadData).toHaveBeenCalledWith(
168
- expect.objectContaining({ tree_data: exampleData })
167
+ expect.objectContaining({ tree_data: exampleData }),
169
168
  );
170
169
  });
171
170
  });
@@ -189,16 +188,16 @@ describe("tree.select", () => {
189
188
  });
190
189
  });
191
190
 
192
- it("fires tree.select", () => {
191
+ it("fires tree.select", async () => {
193
192
  const onSelect = jest.fn();
194
193
  given.$tree.on("tree.select", onSelect);
195
194
 
196
- given.titleSpan.trigger("click");
195
+ await userEvent.click(given.titleSpan.get(0) as HTMLElement);
197
196
  expect(onSelect).toHaveBeenCalledWith(
198
197
  expect.objectContaining({
199
198
  node: given.node1,
200
199
  deselected_node: null,
201
- })
200
+ }),
202
201
  );
203
202
  });
204
203
 
@@ -207,17 +206,85 @@ describe("tree.select", () => {
207
206
  given.$tree.tree("selectNode", given.node1);
208
207
  });
209
208
 
210
- it("fires tree.select with node is null", () => {
209
+ it("fires tree.select with node is null", async () => {
211
210
  const onSelect = jest.fn();
212
211
  given.$tree.on("tree.select", onSelect);
213
212
 
214
- given.titleSpan.trigger("click");
213
+ await userEvent.click(given.titleSpan.get(0) as HTMLElement);
215
214
  expect(onSelect).toHaveBeenCalledWith(
216
215
  expect.objectContaining({
217
216
  node: null,
218
217
  previous_node: given.node1,
219
- })
218
+ }),
219
+ );
220
+ });
221
+ });
222
+ });
223
+
224
+ describe("tree.loading_data", () => {
225
+ const server = setupServer(
226
+ http.get("/tree/", () => HttpResponse.json(exampleData)),
227
+ );
228
+ beforeEach(() => {
229
+ server.listen();
230
+ });
231
+
232
+ afterAll(() => {
233
+ server.close();
234
+ });
235
+
236
+ it("fires tree.loading_data when the data is loading from an url", async () => {
237
+ const $tree = $("#tree1");
238
+
239
+ const onLoading = jest.fn();
240
+ $tree.on("tree.loading_data", onLoading);
241
+
242
+ $tree.tree({ dataUrl: "/tree/" });
243
+
244
+ await waitFor(() => {
245
+ expect(onLoading).toHaveBeenCalledWith(
246
+ expect.objectContaining({
247
+ isLoading: true,
248
+ node: null,
249
+ }),
220
250
  );
221
251
  });
252
+
253
+ await waitFor(() => {
254
+ expect(onLoading).toHaveBeenCalledWith(
255
+ expect.objectContaining({
256
+ isLoading: false,
257
+ node: null,
258
+ }),
259
+ );
260
+ });
261
+ });
262
+ });
263
+
264
+ describe("onLoading", () => {
265
+ const server = setupServer(
266
+ http.get("/tree/", () => HttpResponse.json(exampleData)),
267
+ );
268
+ beforeEach(() => {
269
+ server.listen();
270
+ });
271
+
272
+ afterAll(() => {
273
+ server.close();
274
+ });
275
+
276
+ it("calls onLoading", async () => {
277
+ const $tree = $("#tree1");
278
+ const onLoading = jest.fn();
279
+
280
+ $tree.tree({ dataUrl: "/tree/", onLoading });
281
+
282
+ await waitFor(() => {
283
+ expect(onLoading).toHaveBeenCalledWith(false, null, $tree);
284
+ });
285
+
286
+ await waitFor(() => {
287
+ expect(onLoading).toHaveBeenCalledWith(false, null, $tree);
288
+ });
222
289
  });
223
290
  });
@@ -1,4 +1,5 @@
1
1
  import getGiven from "givens";
2
+ import { userEvent } from "@testing-library/user-event";
2
3
  import "../../tree.jquery";
3
4
  import exampleData from "../support/exampleData";
4
5
 
@@ -18,22 +19,16 @@ describe("keyboard support", () => {
18
19
  interface Vars {
19
20
  autoOpen: boolean;
20
21
  initialSelectedNode: INode | null;
21
- pressedKey: number;
22
+ pressedKey: string;
22
23
  $tree: JQuery<HTMLElement>;
23
24
  }
24
25
 
25
- const KEY_DOWN = 40;
26
- const KEY_LEFT = 37;
27
- const KEY_RIGHT = 39;
28
- const KEY_UP = 38;
29
- const KEY_PAGE_UP = 33;
30
-
31
26
  const given = getGiven<Vars>();
32
27
  given("autoOpen", () => false);
33
28
  given("initialSelectedNode", () => null);
34
29
  given("$tree", () => $("#tree1"));
35
30
 
36
- beforeEach(() => {
31
+ beforeEach(async () => {
37
32
  given.$tree.tree({
38
33
  animationSpeed: 0,
39
34
  autoOpen: given.autoOpen,
@@ -44,15 +39,15 @@ describe("keyboard support", () => {
44
39
  given.$tree.tree("selectNode", given.initialSelectedNode);
45
40
  }
46
41
 
47
- given.$tree.trigger($.Event("keydown", { which: given.pressedKey }));
42
+ await userEvent.keyboard(`{${given.pressedKey}}`);
48
43
  });
49
44
 
50
45
  context("with key down", () => {
51
- given("pressedKey", () => KEY_DOWN);
46
+ given("pressedKey", () => "ArrowDown");
52
47
 
53
48
  context("when a node is selected", () => {
54
49
  given("initialSelectedNode", () =>
55
- given.$tree.tree("getNodeByNameMustExist", "node1")
50
+ given.$tree.tree("getNodeByNameMustExist", "node1"),
56
51
  );
57
52
 
58
53
  it("selects the next node", () => {
@@ -71,7 +66,7 @@ describe("keyboard support", () => {
71
66
 
72
67
  context("when the last node is selected", () => {
73
68
  given("initialSelectedNode", () =>
74
- given.$tree.tree("getNodeByNameMustExist", "node2")
69
+ given.$tree.tree("getNodeByNameMustExist", "node2"),
75
70
  );
76
71
 
77
72
  it("keeps the node selected", () => {
@@ -83,11 +78,11 @@ describe("keyboard support", () => {
83
78
  });
84
79
 
85
80
  context("with key up", () => {
86
- given("pressedKey", () => KEY_UP);
81
+ given("pressedKey", () => "ArrowUp");
87
82
 
88
83
  context("when a node is selected", () => {
89
84
  given("initialSelectedNode", () =>
90
- given.$tree.tree("getNodeByNameMustExist", "node2")
85
+ given.$tree.tree("getNodeByNameMustExist", "node2"),
91
86
  );
92
87
 
93
88
  it("selects the next node", () => {
@@ -106,11 +101,11 @@ describe("keyboard support", () => {
106
101
  });
107
102
 
108
103
  context("with key right", () => {
109
- given("pressedKey", () => KEY_RIGHT);
104
+ given("pressedKey", () => "ArrowRight");
110
105
 
111
106
  context("when a closed folder is selected", () => {
112
107
  given("initialSelectedNode", () =>
113
- given.$tree.tree("getNodeByNameMustExist", "node1")
108
+ given.$tree.tree("getNodeByNameMustExist", "node1"),
114
109
  );
115
110
 
116
111
  it("opens the folder", () => {
@@ -132,7 +127,7 @@ describe("keyboard support", () => {
132
127
  context("when an open folder is selected", () => {
133
128
  given("autoOpen", () => true);
134
129
  given("initialSelectedNode", () =>
135
- given.$tree.tree("getNodeByNameMustExist", "node1")
130
+ given.$tree.tree("getNodeByNameMustExist", "node1"),
136
131
  );
137
132
 
138
133
  it("selects the first child", () => {
@@ -168,7 +163,7 @@ describe("keyboard support", () => {
168
163
 
169
164
  context("when a child is selected", () => {
170
165
  given("initialSelectedNode", () =>
171
- given.$tree.tree("getNodeByNameMustExist", "child1")
166
+ given.$tree.tree("getNodeByNameMustExist", "child1"),
172
167
  );
173
168
 
174
169
  it("does nothing", () => {
@@ -179,11 +174,11 @@ describe("keyboard support", () => {
179
174
  });
180
175
  });
181
176
  context("with key left", () => {
182
- given("pressedKey", () => KEY_LEFT);
177
+ given("pressedKey", () => "ArrowLeft");
183
178
 
184
179
  context("when a closed folder is selected", () => {
185
180
  given("initialSelectedNode", () =>
186
- given.$tree.tree("getNodeByNameMustExist", "node3")
181
+ given.$tree.tree("getNodeByNameMustExist", "node3"),
187
182
  );
188
183
 
189
184
  it("selects the previous node", () => {
@@ -210,7 +205,7 @@ describe("keyboard support", () => {
210
205
  context("when an open folder is selected", () => {
211
206
  given("autoOpen", () => true);
212
207
  given("initialSelectedNode", () =>
213
- given.$tree.tree("getNodeByNameMustExist", "node2")
208
+ given.$tree.tree("getNodeByNameMustExist", "node2"),
214
209
  );
215
210
 
216
211
  it("closes the folder", () => {
@@ -237,10 +232,10 @@ describe("keyboard support", () => {
237
232
  });
238
233
 
239
234
  context("with page up key", () => {
240
- given("pressedKey", () => KEY_PAGE_UP);
235
+ given("pressedKey", () => "PageUp");
241
236
 
242
237
  given("initialSelectedNode", () =>
243
- given.$tree.tree("getNodeByNameMustExist", "child1")
238
+ given.$tree.tree("getNodeByNameMustExist", "child1"),
244
239
  );
245
240
 
246
241
  it("does nothing", () => {
@@ -1,6 +1,7 @@
1
1
  import getGiven from "givens";
2
2
  import { screen } from "@testing-library/dom";
3
- import { rest } from "msw";
3
+ import { userEvent } from "@testing-library/user-event";
4
+ import { http, HttpResponse } from "msw";
4
5
  import { setupServer } from "msw/node";
5
6
  import "../../tree.jquery";
6
7
  import { togglerLink } from "../support/testUtil";
@@ -47,16 +48,16 @@ context("when a node has load_on_demand in the data", () => {
47
48
 
48
49
  beforeEach(() => {
49
50
  server.use(
50
- rest.get("/tree/", (request, response, ctx) => {
51
- const parentId = request.url.searchParams.get("node");
51
+ http.get("/tree/", ({ request }) => {
52
+ const url = new URL(request.url);
53
+ const parentId = url.searchParams.get("node");
52
54
 
53
55
  if (parentId === "1") {
54
- return response(
55
- ctx.status(200),
56
- ctx.json([{ id: 2, name: "loaded-on-demand" }]),
57
- );
56
+ return HttpResponse.json([
57
+ { id: 2, name: "loaded-on-demand" },
58
+ ]);
58
59
  } else {
59
- return response(ctx.status(400));
60
+ return new HttpResponse(null, { status: 400 });
60
61
  }
61
62
  }),
62
63
  );
@@ -91,7 +92,8 @@ context("when a node has load_on_demand in the data", () => {
91
92
  );
92
93
 
93
94
  it("loads the subtree", async () => {
94
- togglerLink(given.node.element).trigger("click");
95
+ const toggler = togglerLink(given.node.element);
96
+ await userEvent.click(toggler.get(0) as HTMLElement);
95
97
 
96
98
  await screen.findByText("loaded-on-demand");
97
99
 
@@ -106,20 +108,21 @@ context("when a node has load_on_demand in the data", () => {
106
108
  ]);
107
109
  });
108
110
 
109
- context("when the node is selected and has the focus", () => {
111
+ context("when the node is selected", () => {
110
112
  beforeEach(() => {
111
113
  given.$tree.tree("selectNode", given.node);
112
114
  });
113
115
 
114
- it("keeps the node selected and focused", async () => {
116
+ it("keeps the node selected", async () => {
115
117
  expect(given.node.element).toBeSelected();
116
118
  expect(given.node.element).toBeFocused();
117
119
 
118
- togglerLink(given.node.element).trigger("click");
120
+ const toggler = togglerLink(given.node.element);
121
+ await userEvent.click(toggler.get(0) as HTMLElement);
122
+
119
123
  await screen.findByText("loaded-on-demand");
120
124
 
121
125
  expect(given.node.element).toBeSelected();
122
- expect(given.node.element).toBeFocused();
123
126
  });
124
127
  });
125
128
 
@@ -127,7 +130,9 @@ context("when a node has load_on_demand in the data", () => {
127
130
  it("doesn't select the node", async () => {
128
131
  expect(given.node.element).not.toBeSelected();
129
132
 
130
- togglerLink(given.node.element).trigger("click");
133
+ const toggler = togglerLink(given.node.element);
134
+ await userEvent.click(toggler.get(0) as HTMLElement);
135
+
131
136
  await screen.findByText("loaded-on-demand");
132
137
 
133
138
  expect(given.node.element).not.toBeSelected();
@@ -144,7 +149,9 @@ context("when a node has load_on_demand in the data", () => {
144
149
  expect(given.node.element).toBeSelected();
145
150
  expect(given.node.element).not.toBeFocused();
146
151
 
147
- togglerLink(given.node.element).trigger("click");
152
+ const toggler = togglerLink(given.node.element);
153
+ await userEvent.click(toggler.get(0) as HTMLElement);
154
+
148
155
  await screen.findByText("loaded-on-demand");
149
156
 
150
157
  expect(given.node.element).toBeSelected();
@@ -1,6 +1,7 @@
1
1
  import getGiven from "givens";
2
2
  import { screen, waitFor } from "@testing-library/dom";
3
- import { rest } from "msw";
3
+ import { http, HttpResponse } from "msw";
4
+ import { userEvent } from "@testing-library/user-event";
4
5
  import { setupServer } from "msw/node";
5
6
  import "../../tree.jquery";
6
7
  import exampleData from "../support/exampleData";
@@ -134,7 +135,7 @@ describe("addToSelection", () => {
134
135
  given("child1", () => given.$tree.tree("getNodeByNameMustExist", "child1"));
135
136
  given("child2", () => given.$tree.tree("getNodeByNameMustExist", "child2"));
136
137
 
137
- beforeEach(() => {
138
+ it("selects the nodes", () => {
138
139
  given.$tree.tree({
139
140
  autoOpen: true,
140
141
  data: exampleData,
@@ -142,15 +143,21 @@ describe("addToSelection", () => {
142
143
 
143
144
  given.$tree.tree("addToSelection", given.child1);
144
145
  given.$tree.tree("addToSelection", given.child2);
145
- });
146
146
 
147
- it("selects the nodes", () => {
148
147
  expect(given.$tree.tree("getSelectedNodes")).toEqual(
149
148
  expect.arrayContaining([given.child1, given.child2]),
150
149
  );
151
150
  });
152
151
 
153
152
  it("renders the nodes correctly", () => {
153
+ given.$tree.tree({
154
+ autoOpen: true,
155
+ data: exampleData,
156
+ });
157
+
158
+ given.$tree.tree("addToSelection", given.child1);
159
+ given.$tree.tree("addToSelection", given.child2);
160
+
154
161
  expect(given.$tree).toHaveTreeStructure([
155
162
  expect.objectContaining({
156
163
  name: "node1",
@@ -172,6 +179,20 @@ describe("addToSelection", () => {
172
179
  }),
173
180
  ]);
174
181
  });
182
+
183
+ it("opens the parent node when it's closed", () => {
184
+ given.$tree.tree({
185
+ autoOpen: false,
186
+ data: exampleData,
187
+ });
188
+
189
+ const node1 = given.$tree.tree("getNodeByNameMustExist", "node1");
190
+ expect(node1.is_open).toBeFalsy();
191
+
192
+ given.$tree.tree("addToSelection", given.child1);
193
+
194
+ expect(node1.is_open).toBe(true);
195
+ });
175
196
  });
176
197
 
177
198
  describe("appendNode", () => {
@@ -749,9 +770,7 @@ describe("loadDataFromUrl", () => {
749
770
 
750
771
  beforeEach(() => {
751
772
  server.use(
752
- rest.get("/tree/", (_request, response, ctx) =>
753
- response(ctx.status(200), ctx.json(given.serverData)),
754
- ),
773
+ http.get("/tree/", () => HttpResponse.json(given.serverData)),
755
774
  );
756
775
 
757
776
  given.$tree.tree({ data: given.initialData });
@@ -1011,11 +1030,7 @@ describe("reload", () => {
1011
1030
  given("$tree", () => $("#tree1"));
1012
1031
 
1013
1032
  beforeEach(async () => {
1014
- server.use(
1015
- rest.get("/tree2/", (_request, response, ctx) =>
1016
- response(ctx.status(200), ctx.json(exampleData)),
1017
- ),
1018
- );
1033
+ server.use(http.get("/tree2/", () => HttpResponse.json(exampleData)));
1019
1034
 
1020
1035
  given.$tree.tree({ dataUrl: "/tree2/" });
1021
1036
  await screen.findByText("node1");
@@ -1207,6 +1222,15 @@ describe("selectNode", () => {
1207
1222
  expect(given.$tree.tree("getSelectedNode")).toBeFalse();
1208
1223
  });
1209
1224
  });
1225
+
1226
+ it("opens the parent node when it's closed", () => {
1227
+ expect(given.node1.is_open).toBeFalsy();
1228
+
1229
+ const child1 = given.$tree.tree("getNodeByNameMustExist", "child1");
1230
+ given.$tree.tree("selectNode", child1);
1231
+
1232
+ expect(given.node1.is_open).toBe(true);
1233
+ });
1210
1234
  });
1211
1235
 
1212
1236
  describe("setOption", () => {
@@ -1226,9 +1250,11 @@ describe("setOption", () => {
1226
1250
  given("node1", () => given.$tree.tree("getNodeByNameMustExist", "node1"));
1227
1251
  given("$tree", () => $("#tree1"));
1228
1252
 
1229
- it("sets an option", () => {
1253
+ it("sets an option", async () => {
1230
1254
  given.$tree.tree("setOption", "selectable", true);
1231
- titleSpan(given.node1.element).trigger("click");
1255
+ await userEvent.click(
1256
+ titleSpan(given.node1.element).get(0) as HTMLElement,
1257
+ );
1232
1258
  expect(given.$tree.tree("getSelectedNode")).toMatchObject({
1233
1259
  name: "node1",
1234
1260
  });
@@ -0,0 +1,82 @@
1
+ import "../../tree.jquery";
2
+ import { userEvent } from "@testing-library/user-event";
3
+ import exampleData from "../support/exampleData";
4
+ import { titleSpan, togglerLink } from "../support/testUtil";
5
+
6
+ beforeEach(() => {
7
+ $("body").append('<div id="tree1"></div>');
8
+ });
9
+
10
+ afterEach(() => {
11
+ const $tree = $("#tree1");
12
+ $tree.tree("destroy");
13
+ $tree.remove();
14
+ });
15
+
16
+ it("selects a node and sets the focus when it is clicked", async () => {
17
+ const $tree = $("#tree1");
18
+ $tree.tree({ data: exampleData });
19
+
20
+ const node = $tree.tree("getNodeByNameMustExist", "node1");
21
+ expect(node.element).not.toBeSelected();
22
+ expect(node.element).not.toBeFocused();
23
+
24
+ await userEvent.click(titleSpan(node.element).get(0) as HTMLElement);
25
+
26
+ expect(node.element).toBeSelected();
27
+ });
28
+
29
+ it("deselects when a selected node is clicked", async () => {
30
+ const $tree = $("#tree1");
31
+ $tree.tree({ data: exampleData });
32
+
33
+ const node = $tree.tree("getNodeByNameMustExist", "node1");
34
+ $tree.tree("selectNode", node);
35
+
36
+ expect(node.element).toBeSelected();
37
+
38
+ await userEvent.click(titleSpan(node.element).get(0) as HTMLElement);
39
+
40
+ expect(node.element).not.toBeSelected();
41
+ });
42
+
43
+ it("opens a node when the toggle button is clicked", async () => {
44
+ const $tree = $("#tree1");
45
+ $tree.tree({ data: exampleData });
46
+
47
+ const node = $tree.tree("getNodeByNameMustExist", "node1");
48
+ expect(node.element).not.toBeOpen();
49
+
50
+ await userEvent.click(togglerLink(node.element).get(0) as HTMLElement);
51
+
52
+ expect(node.element).toBeOpen();
53
+ });
54
+
55
+ it("doesn't select a node when it is opened", async () => {
56
+ const $tree = $("#tree1");
57
+ $tree.tree({ data: exampleData });
58
+
59
+ const node = $tree.tree("getNodeByNameMustExist", "node1");
60
+ expect(node.element).not.toBeSelected();
61
+ expect(node.element).not.toBeOpen();
62
+
63
+ await userEvent.click(togglerLink(node.element).get(0) as HTMLElement);
64
+
65
+ expect(node.element).not.toBeSelected();
66
+ expect(node.element).toBeOpen();
67
+ });
68
+
69
+ it("keeps it selected when a selected node is opened", async () => {
70
+ const $tree = $("#tree1");
71
+ $tree.tree({ data: exampleData });
72
+
73
+ const node = $tree.tree("getNodeByNameMustExist", "node1");
74
+ $tree.tree("selectNode", node);
75
+ expect(node.element).toBeSelected();
76
+ expect(node.element).not.toBeOpen();
77
+
78
+ await userEvent.click(togglerLink(node.element).get(0) as HTMLElement);
79
+
80
+ expect(node.element).toBeSelected();
81
+ expect(node.element).toBeOpen();
82
+ });