jqtree 1.6.2 → 1.6.3

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 (247) hide show
  1. package/.eslintrc +3 -12
  2. package/.github/workflows/ci.yml +48 -23
  3. package/.github/workflows/codeql-analysis.yml +9 -5
  4. package/.prettier +3 -0
  5. package/README.md +11 -8
  6. package/bower.json +1 -1
  7. package/{.postcssrc → config/.postcssrc} +0 -0
  8. package/{babel.config.json → config/babel.config.json} +0 -0
  9. package/{babel.coverage.config.json → config/babel.coverage.config.json} +0 -0
  10. package/{jest-jsdom.config.js → config/jest.config.js} +8 -3
  11. package/config/playwright.config.js +18 -0
  12. package/config/production +4 -0
  13. package/{rollup.config.js → config/rollup.config.js} +3 -3
  14. package/{jqtree.postcss → css/jqtree.postcss} +0 -0
  15. package/devserver/index.html +1 -9
  16. package/docs/Gemfile +2 -0
  17. package/docs/Gemfile.lock +263 -0
  18. package/{_config.yml → docs/_config.yml} +8 -1
  19. package/{_entries → docs/_entries}/01_general.md +0 -0
  20. package/{_entries → docs/_entries}/02_introduction.md +0 -0
  21. package/{_entries → docs/_entries}/03_features.md +1 -1
  22. package/{_entries → docs/_entries}/04_demo.html +1 -7
  23. package/{_entries → docs/_entries}/05_requirements.md +0 -0
  24. package/{_entries → docs/_entries}/06_downloads.md +0 -0
  25. package/{_entries → docs/_entries}/07_tutorial.md +0 -0
  26. package/{_entries → docs/_entries}/08_examples.md +0 -0
  27. package/{_entries → docs/_entries}/09_usecases.md +0 -0
  28. package/{_entries → docs/_entries}/10_changelog.md +4 -0
  29. package/{_entries → docs/_entries}/11_options.md +0 -0
  30. package/{_entries → docs/_entries}/12_animationspeed.md +0 -0
  31. package/{_entries → docs/_entries}/13_autoescape.md +0 -0
  32. package/{_entries → docs/_entries}/14_autoopen.md +0 -0
  33. package/{_entries → docs/_entries}/15_buttonleft.md +0 -0
  34. package/{_entries → docs/_entries}/16_closedicon.md +0 -0
  35. package/{_entries → docs/_entries}/17_data.md +0 -0
  36. package/{_entries → docs/_entries}/18_datafilter.md +0 -0
  37. package/{_entries → docs/_entries}/19_data-url.md +0 -0
  38. package/{_entries → docs/_entries}/20_draganddrop.md +0 -0
  39. package/{_entries → docs/_entries}/21_keyboardsupport.md +0 -0
  40. package/{_entries → docs/_entries}/22_oncanmove.md +0 -0
  41. package/{_entries → docs/_entries}/23_oncanmoveto.md +2 -2
  42. package/{_entries → docs/_entries}/24_oncanselectnode.md +0 -0
  43. package/{_entries → docs/_entries}/25_oncreateli.md +2 -2
  44. package/{_entries → docs/_entries}/26_ondragmove.md +0 -0
  45. package/{_entries → docs/_entries}/27_ondragstop.md +0 -0
  46. package/{_entries → docs/_entries}/28_onismovehandle.md +0 -0
  47. package/{_entries → docs/_entries}/29_onloadfailed.md +0 -0
  48. package/{_entries → docs/_entries}/30_onloading.md +2 -2
  49. package/{_entries → docs/_entries}/31_openedicon.md +0 -0
  50. package/{_entries → docs/_entries}/32_openfolderdelay.md +2 -0
  51. package/{_entries → docs/_entries}/33_rtl.md +0 -0
  52. package/{_entries → docs/_entries}/34_savestate.md +0 -0
  53. package/{_entries → docs/_entries}/35_selectable.md +0 -0
  54. package/{_entries → docs/_entries}/36_showemptyfolder.md +0 -0
  55. package/{_entries → docs/_entries}/37_slide.md +0 -0
  56. package/{_entries → docs/_entries}/38_start_dnd_delay.md +0 -0
  57. package/{_entries → docs/_entries}/39_tabindex.md +0 -0
  58. package/{_entries → docs/_entries}/40_usecontextmenu.md +0 -0
  59. package/{_entries → docs/_entries}/41_functions.md +0 -0
  60. package/{_entries → docs/_entries}/42_addparentnode.md +1 -1
  61. package/{_entries → docs/_entries}/43_addnodeafter.md +1 -1
  62. package/{_entries → docs/_entries}/44_addnodebefore.md +1 -1
  63. package/{_entries → docs/_entries}/45_appendnode.md +5 -5
  64. package/{_entries → docs/_entries}/46_closenode.md +0 -0
  65. package/{_entries → docs/_entries}/47_destroy.md +0 -0
  66. package/{_entries → docs/_entries}/48_getnodebycallback.md +0 -0
  67. package/{_entries → docs/_entries}/49_getnodebyid.md +0 -0
  68. package/{_entries → docs/_entries}/50_getnodebyhtmlelement.md +2 -2
  69. package/{_entries → docs/_entries}/51_getselectednode.md +0 -0
  70. package/{_entries → docs/_entries}/52_getstate.md +0 -0
  71. package/{_entries → docs/_entries}/53_gettree.md +1 -1
  72. package/{_entries → docs/_entries}/54_isdragging.md +1 -1
  73. package/{_entries → docs/_entries}/55_loaddata.md +3 -3
  74. package/{_entries → docs/_entries}/56_loaddatafromurl.md +4 -4
  75. package/{_entries → docs/_entries}/57_movedown.md +0 -0
  76. package/{_entries → docs/_entries}/58_movenode.md +3 -3
  77. package/{_entries → docs/_entries}/59_moveup.md +0 -0
  78. package/{_entries → docs/_entries}/60_opennode.md +3 -3
  79. package/docs/_entries/61_prependnode.md +21 -0
  80. package/{_entries → docs/_entries}/62_refresh.md +0 -0
  81. package/{_entries → docs/_entries}/63_reload.md +2 -2
  82. package/{_entries → docs/_entries}/64_removenode.md +0 -0
  83. package/{_entries → docs/_entries}/65_selectnode.md +0 -0
  84. package/{_entries → docs/_entries}/66_scrolltonode.md +0 -0
  85. package/{_entries → docs/_entries}/67_setoption.md +0 -0
  86. package/{_entries → docs/_entries}/68_setstate.md +0 -0
  87. package/{_entries → docs/_entries}/69_toggle.md +0 -0
  88. package/{_entries → docs/_entries}/70_tojson.md +0 -0
  89. package/{_entries → docs/_entries}/71_updatenode.md +1 -1
  90. package/{_entries → docs/_entries}/72_events.md +0 -0
  91. package/{_entries → docs/_entries}/73_tree-click.md +0 -0
  92. package/{_entries → docs/_entries}/74_tree-close.md +0 -0
  93. package/{_entries → docs/_entries}/75_tree-contextmenu.md +0 -0
  94. package/{_entries → docs/_entries}/76_tree-dblclick.md +0 -0
  95. package/{_entries → docs/_entries}/77_tree-init.md +0 -0
  96. package/{_entries → docs/_entries}/78_tree-load-data.md +0 -0
  97. package/{_entries → docs/_entries}/79_tree-loading-data.md +0 -0
  98. package/{_entries → docs/_entries}/80_tree-move.md +0 -0
  99. package/{_entries → docs/_entries}/81_tree-refresh.md +0 -0
  100. package/{_entries → docs/_entries}/82_tree-open.md +0 -0
  101. package/{_entries → docs/_entries}/83_tree-select.md +0 -0
  102. package/{_entries → docs/_entries}/84_multiple-selection.md +0 -0
  103. package/{_entries → docs/_entries}/85_add-to-selection.md +0 -0
  104. package/{_entries → docs/_entries}/86_get-selected-nodes.md +0 -0
  105. package/{_entries → docs/_entries}/87_is-node-selected.md +1 -1
  106. package/{_entries → docs/_entries}/88_remove-from-selection.md +0 -0
  107. package/{_entries → docs/_entries}/89_node-functions.md +0 -0
  108. package/{_entries → docs/_entries}/90_children.md +0 -0
  109. package/{_entries → docs/_entries}/91_getdata.md +2 -2
  110. package/{_entries → docs/_entries}/92_getlevel.md +0 -0
  111. package/{_entries → docs/_entries}/93_getnextnode.md +0 -0
  112. package/{_entries → docs/_entries}/94_getnextsibling.md +0 -0
  113. package/{_entries → docs/_entries}/95_getpreviousnode.md +0 -0
  114. package/{_entries → docs/_entries}/96_getprevioussibling.md +0 -0
  115. package/{_entries → docs/_entries}/97_parent.md +1 -1
  116. package/{_entries → docs/_entries}/insert.py +0 -0
  117. package/{_entries → docs/_entries}/renumber.py +0 -0
  118. package/{_examples → docs/_examples}/01_load_json_data.html +3 -5
  119. package/{_examples → docs/_examples}/02_load_json_data_from_server.html +3 -5
  120. package/{_examples → docs/_examples}/03_drag_and_drop.html +3 -5
  121. package/{_examples → docs/_examples}/04_save_state.html +3 -5
  122. package/{_examples → docs/_examples}/05_load_on_demand.html +3 -5
  123. package/{_examples → docs/_examples}/06_autoescape.html +3 -5
  124. package/{_examples → docs/_examples}/07_autoscroll.html +3 -5
  125. package/{_examples → docs/_examples}/08_multiple_select.html +3 -5
  126. package/{_examples → docs/_examples}/09_custom_html.html +3 -5
  127. package/{_examples → docs/_examples}/10_icon_buttons.html +3 -5
  128. package/{_examples → docs/_examples}/11_right-to-left.html +3 -5
  129. package/{_examples → docs/_examples}/12_button_on_right.html +3 -5
  130. package/docs/_examples/13_drag_outside.html +48 -0
  131. package/{_examples → docs/_examples}/14_filter.html +7 -9
  132. package/docs/_layouts/example.html +7 -0
  133. package/{_layouts/base.html → docs/_layouts/page.html} +4 -11
  134. package/docs/documentation.css +3 -0
  135. package/docs/index.html +65 -0
  136. package/docs/jqtree.css +189 -0
  137. package/docs/package.json +22 -0
  138. package/docs/pnpm-lock.yaml +768 -0
  139. package/docs/postcss.config.js +7 -0
  140. package/{static → docs/static}/bower.json +0 -1
  141. package/{static → docs/static}/bower_components/fontawesome/css/all.min.css +0 -0
  142. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-brands-400.eot +0 -0
  143. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-brands-400.svg +0 -0
  144. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-brands-400.ttf +0 -0
  145. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-brands-400.woff +0 -0
  146. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-brands-400.woff2 +0 -0
  147. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-regular-400.eot +0 -0
  148. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-regular-400.svg +0 -0
  149. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-regular-400.ttf +0 -0
  150. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-regular-400.woff +0 -0
  151. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-regular-400.woff2 +0 -0
  152. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-solid-900.eot +0 -0
  153. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-solid-900.svg +0 -0
  154. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-solid-900.ttf +0 -0
  155. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-solid-900.woff +0 -0
  156. package/{static → docs/static}/bower_components/fontawesome/webfonts/fa-solid-900.woff2 +0 -0
  157. package/{static → docs/static}/bower_components/jquery/dist/jquery.js +0 -0
  158. package/{static → docs/static}/bower_components/jquery/dist/jquery.min.js +0 -0
  159. package/{static → docs/static}/bower_components/jquery-mockjax/dist/jquery.mockjax.js +0 -0
  160. package/docs/static/documentation.css +1313 -0
  161. package/docs/static/documentation.js +26 -0
  162. package/{static → docs/static}/example.css +5 -37
  163. package/{static → docs/static}/example.postcss +5 -35
  164. package/{static → docs/static}/example_data.js +0 -0
  165. package/{static → docs/static}/examples/autoescape.js +0 -0
  166. package/{static → docs/static}/examples/autoscroll.js +0 -0
  167. package/{static → docs/static}/examples/button-on-right.js +0 -0
  168. package/{static → docs/static}/examples/custom_html.js +5 -9
  169. package/{static → docs/static}/examples/drag-outside.js +0 -0
  170. package/{static → docs/static}/examples/drag_and_drop.js +0 -0
  171. package/{static → docs/static}/examples/filter.js +2 -2
  172. package/{static → docs/static}/examples/icon_buttons.js +0 -0
  173. package/{static → docs/static}/examples/load_json_data.js +0 -0
  174. package/{static → docs/static}/examples/load_json_data_from_server.js +0 -0
  175. package/{static → docs/static}/examples/load_on_demand.js +0 -0
  176. package/{static → docs/static}/examples/multiple_select.js +0 -0
  177. package/{static → docs/static}/examples/right-to-left.js +0 -0
  178. package/{static → docs/static}/examples/save_state.js +0 -0
  179. package/{static → docs/static}/monokai.css +0 -0
  180. package/{static → docs/static}/spinner.gif +0 -0
  181. package/docs/tailwind.config.js +16 -0
  182. package/docs/tree.jquery.js +21 -0
  183. package/lib/dragAndDropHandler.js +8 -4
  184. package/lib/mouse.widget.js +3 -3
  185. package/lib/nodeElement.js +3 -3
  186. package/lib/playwright/coverage.js +140 -0
  187. package/lib/playwright/playwright.test.js +293 -201
  188. package/lib/playwright/testUtils.js +267 -0
  189. package/lib/test/jqTree/events.test.js +10 -9
  190. package/lib/test/jqTree/loadOnDemand.test.js +26 -21
  191. package/lib/test/jqTree/methods.test.js +84 -64
  192. package/lib/test/jqTree/options.test.js +41 -29
  193. package/lib/tree.jquery.js +4 -4
  194. package/package.json +48 -49
  195. package/src/dragAndDropHandler.ts +8 -4
  196. package/src/jqtreeOptions.ts +1 -1
  197. package/src/playwright/.eslintrc +2 -2
  198. package/src/playwright/coverage.ts +41 -0
  199. package/src/playwright/playwright.test.ts +50 -52
  200. package/src/playwright/playwright.test.ts-snapshots/with-dragAndDrop-moves-a-node-1-Chromium-darwin.png +0 -0
  201. package/src/playwright/playwright.test.ts-snapshots/with-dragAndDrop-moves-a-node-1-Chromium-linux.png +0 -0
  202. package/src/playwright/playwright.test.ts-snapshots/without-dragAndDrop-displays-a-tree-1-Chromium-darwin.png +0 -0
  203. package/src/playwright/playwright.test.ts-snapshots/without-dragAndDrop-displays-a-tree-1-Chromium-linux.png +0 -0
  204. package/src/playwright/playwright.test.ts-snapshots/without-dragAndDrop-selects-a-node-1-Chromium-darwin.png +0 -0
  205. package/src/playwright/playwright.test.ts-snapshots/without-dragAndDrop-selects-a-node-1-Chromium-linux.png +0 -0
  206. package/src/playwright/testUtils.ts +122 -0
  207. package/src/test/.eslintrc +13 -3
  208. package/src/test/jqTree/events.test.ts +10 -9
  209. package/src/test/jqTree/loadOnDemand.test.ts +10 -10
  210. package/src/test/jqTree/methods.test.ts +37 -45
  211. package/src/test/jqTree/options.test.ts +26 -28
  212. package/src/tree.jquery.d.ts +1 -1
  213. package/tree.jquery.debug.js +17 -14
  214. package/tree.jquery.debug.js.map +1 -1
  215. package/tree.jquery.js +3 -3
  216. package/tree.jquery.js.map +1 -1
  217. package/_entries/61_prependnode.md +0 -21
  218. package/_examples/13_drag_outside.html +0 -26
  219. package/_layouts/frontpage.html +0 -20
  220. package/_layouts/page.html +0 -7
  221. package/index.html +0 -48
  222. package/jest-browser.config.js +0 -15
  223. package/jest-playwright.config.js +0 -21
  224. package/jest.config.js +0 -8
  225. package/lib/playwright/testUtil.js +0 -459
  226. package/lib/playwright/visualRegression.js +0 -193
  227. package/production +0 -5
  228. package/src/playwright/screenshots/displays_a_tree_Desktop.png +0 -0
  229. package/src/playwright/screenshots/displays_a_tree_iPhone 6.png +0 -0
  230. package/src/playwright/screenshots/moves_a_node_Desktop.png +0 -0
  231. package/src/playwright/screenshots/moves_a_node_iPhone 6.png +0 -0
  232. package/src/playwright/screenshots/opens_a_node_Desktop.png +0 -0
  233. package/src/playwright/screenshots/opens_a_node_iPhone 6.png +0 -0
  234. package/src/playwright/screenshots/selects_a_node_Desktop.png +0 -0
  235. package/src/playwright/screenshots/selects_a_node_iPhone 6.png +0 -0
  236. package/src/playwright/testUtil.ts +0 -170
  237. package/src/playwright/visualRegression.ts +0 -88
  238. package/static/bower_components/bootstrap/dist/css/bootstrap-theme.min.css +0 -6
  239. package/static/bower_components/bootstrap/dist/css/bootstrap.min.css +0 -6
  240. package/static/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot +0 -0
  241. package/static/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.svg +0 -288
  242. package/static/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf +0 -0
  243. package/static/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff +0 -0
  244. package/static/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2 +0 -0
  245. package/static/bower_components/bootstrap/dist/js/bootstrap.min.js +0 -6
  246. package/static/documentation.css +0 -171
  247. package/static/documentation.js +0 -48
@@ -0,0 +1,41 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import crypto from "crypto";
4
+ import { BrowserContext } from "@playwright/test";
5
+
6
+ const istanbulCLIOutput = path.join(process.cwd(), ".nyc_output");
7
+
8
+ const generateUUID = () => crypto.randomBytes(16).toString("hex");
9
+
10
+ export const initCoverage = async (context: BrowserContext) => {
11
+ await fs.promises.mkdir(istanbulCLIOutput, { recursive: true });
12
+
13
+ await context.exposeFunction(
14
+ "collectIstanbulCoverage",
15
+ (coverageJSON: string) => {
16
+ if (!coverageJSON) {
17
+ console.log("No coverage");
18
+ } else {
19
+ const filename = path.join(
20
+ istanbulCLIOutput,
21
+ `playwright_coverage_${generateUUID()}.json`
22
+ );
23
+ console.log(`Writing coverage to ${filename}`);
24
+ fs.writeFileSync(filename, coverageJSON);
25
+ }
26
+ }
27
+ );
28
+ };
29
+
30
+ export const saveCoverage = async (context: BrowserContext) => {
31
+ for (const page of context.pages()) {
32
+ await page.evaluate(() => {
33
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
34
+ const anyWindow = window as any;
35
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
36
+ const coverageData = anyWindow.__coverage__;
37
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
38
+ anyWindow.collectIstanbulCoverage(JSON.stringify(coverageData));
39
+ });
40
+ }
41
+ };
@@ -1,37 +1,27 @@
1
- /// <reference types="jest-playwright-preset" />
2
- /// <reference types="expect-playwright" />
3
-
4
- import getGiven from "givens";
1
+ import { test, expect, Page } from "@playwright/test";
5
2
  import {
6
3
  dragAndDrop,
7
- expectToBeClosed,
8
- expectToBeOpen,
9
- expectToBeSelected,
10
4
  findNodeElement,
11
5
  getTreeStructure,
12
- openNode,
13
6
  selectNode,
14
- } from "./testUtil";
15
- import { matchScreenshot } from "./visualRegression";
7
+ } from "./testUtils";
8
+ import { initCoverage, saveCoverage } from "./coverage";
16
9
 
17
- interface Vars {
10
+ interface InitPageParameters {
11
+ baseURL?: string;
18
12
  dragAndDrop: boolean;
13
+ page: Page;
19
14
  }
20
15
 
21
- const given = getGiven<Vars>();
22
- given("dragAndDrop", () => false);
23
-
24
- beforeEach(async () => {
25
- await jestPlaywright.resetPage();
16
+ const initPage = async ({ baseURL, dragAndDrop, page }: InitPageParameters) => {
17
+ if (!baseURL) {
18
+ throw new Error("Missing baseURL");
19
+ }
26
20
 
27
- await page.goto("http://localhost:8080/test_index.html");
21
+ await page.goto(`${baseURL}/test_index.html`);
28
22
  await page.waitForLoadState("domcontentloaded");
29
23
 
30
- // Fix error on iphone6 device when collecting coverage
31
- await page.evaluate(() => {
32
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
33
- (window as any)["reportCodeCoverage"] = () => null;
34
- });
24
+ page.on("console", (msg) => console.log(`console: ${msg.text()}`));
35
25
 
36
26
  await page.evaluate(`
37
27
  const $tree = jQuery("#tree1");
@@ -40,51 +30,58 @@ beforeEach(async () => {
40
30
  animationSpeed: 0,
41
31
  autoOpen: 0,
42
32
  data: ExampleData.exampleData,
43
- dragAndDrop: ${given.dragAndDrop},
33
+ dragAndDrop: ${dragAndDrop},
44
34
  startDndDelay: 100,
45
35
  });
46
36
  `);
47
- });
48
37
 
49
- afterEach(async () => {
50
- await jestPlaywright.saveCoverage(page);
51
- });
38
+ await page.evaluate(`
39
+ console.log(window.__coverage__ ? 'Coverage enabled' : 'Coverage not enabled');
40
+ `);
41
+ };
52
42
 
53
- it("displays a tree", async () => {
54
- await expect(page).toMatchText(/.*Saurischia.*/);
55
- await expect(page).toMatchText(/.*Ornithischians.*/);
56
- await expect(page).toMatchText(/.*Coelophysoids.*/);
43
+ test.beforeEach(async ({ context }) => {
44
+ await initCoverage(context);
45
+ });
57
46
 
58
- await matchScreenshot("displays_a_tree");
47
+ test.afterEach(async ({ context }) => {
48
+ await saveCoverage(context);
59
49
  });
60
50
 
61
- it("selects a node", async () => {
62
- await expect(page).toMatchText(/.*Saurischia.*/);
63
- const saurischia = await findNodeElement("Saurischia");
64
- await selectNode(saurischia);
65
- await expectToBeSelected(saurischia);
51
+ test.describe("without dragAndDrop", () => {
52
+ test.beforeEach(async ({ baseURL, page }) => {
53
+ await initPage({ baseURL, page, dragAndDrop: false });
54
+ });
66
55
 
67
- await matchScreenshot("selects_a_node");
68
- });
56
+ test("displays a tree", async ({ page }) => {
57
+ await expect(page.locator("body")).toHaveText(/.*Saurischia.*/);
58
+ await expect(page.locator("body")).toHaveText(/.*Ornithischians.*/);
59
+ await expect(page.locator("body")).toHaveText(/.*Coelophysoids.*/);
69
60
 
70
- it("opens a node", async () => {
71
- await expect(page).toMatchText(/.*Saurischia.*/);
61
+ const screenshot = await page.screenshot();
62
+ expect(screenshot).toMatchSnapshot();
63
+ });
72
64
 
73
- const theropods = await findNodeElement("Theropods");
74
- await expectToBeClosed(theropods);
75
- await openNode(theropods);
76
- await expectToBeOpen(theropods);
65
+ test("selects a node", async ({ page }) => {
66
+ await expect(page.locator("body")).toHaveText(/.*Saurischia.*/);
77
67
 
78
- await matchScreenshot("opens_a_node");
68
+ const saurischia = await findNodeElement(page, "Saurischia");
69
+ await selectNode(saurischia);
70
+
71
+ const screenshot = await page.screenshot();
72
+ expect(screenshot).toMatchSnapshot();
73
+ });
79
74
  });
80
75
 
81
- describe("dragAndDrop", () => {
82
- given("dragAndDrop", () => true);
76
+ test.describe("with dragAndDrop", () => {
77
+ test.beforeEach(async ({ baseURL, page }) => {
78
+ await initPage({ baseURL, page, dragAndDrop: true });
79
+ });
83
80
 
84
- it("moves a node", async () => {
85
- await dragAndDrop("Herrerasaurians", "Ornithischians");
81
+ test("moves a node", async ({ page }) => {
82
+ await dragAndDrop(page, "Herrerasaurians", "Ornithischians");
86
83
 
87
- const structure = await getTreeStructure();
84
+ const structure = await getTreeStructure(page);
88
85
 
89
86
  expect(structure).toEqual([
90
87
  expect.objectContaining({
@@ -109,6 +106,7 @@ describe("dragAndDrop", () => {
109
106
  }),
110
107
  ]);
111
108
 
112
- await matchScreenshot("moves_a_node");
109
+ const screenshot = await page.screenshot();
110
+ expect(screenshot).toMatchSnapshot();
113
111
  });
114
112
  });
@@ -0,0 +1,122 @@
1
+ import { Page, ElementHandle } from "@playwright/test";
2
+
3
+ const locateTitle = (page: Page, title: string) =>
4
+ page.locator(".jqtree-title", {
5
+ hasText: title,
6
+ });
7
+
8
+ export const findNodeElement = async (page: Page, title: string) => {
9
+ const titleElement = await locateTitle(page, title).elementHandle();
10
+
11
+ if (!titleElement) {
12
+ throw new Error(`Title element not found: ${title}`);
13
+ }
14
+
15
+ const nodeElement = await titleElement.evaluateHandle((el) => {
16
+ const li = el.closest("li");
17
+
18
+ if (!li) {
19
+ throw Error("Node element not found");
20
+ }
21
+
22
+ return li;
23
+ });
24
+
25
+ return nodeElement;
26
+ };
27
+
28
+ export const selectNode = async (nodeElement: ElementHandle) => {
29
+ const titleHandle = await nodeElement.$(".jqtree-title");
30
+
31
+ if (!titleHandle) {
32
+ throw new Error("Could not select: title element not found");
33
+ }
34
+
35
+ await titleHandle.click();
36
+ };
37
+
38
+ const getRect = async (elementHandle: ElementHandle<HTMLElement>) => {
39
+ const boundingBox = await elementHandle.boundingBox();
40
+
41
+ if (!boundingBox) {
42
+ throw "No bounding box";
43
+ }
44
+
45
+ return boundingBox;
46
+ };
47
+
48
+ export const getTreeStructure = async (page: Page) => {
49
+ const structure = await page.evaluate<string>(`
50
+ ;
51
+ function getTreeNode($li) {
52
+ const $div = $li.children("div.jqtree-element");
53
+ const $span = $div.children("span.jqtree-title");
54
+ const name = $span.text();
55
+ const selected = $li.hasClass("jqtree-selected");
56
+
57
+ if ($li.hasClass("jqtree-folder")) {
58
+ const $ul = $li.children("ul.jqtree_common");
59
+
60
+ return {
61
+ nodeType: "folder",
62
+ children: getChildren($ul),
63
+ name,
64
+ open: !$li.hasClass("jqtree-closed"),
65
+ selected,
66
+ };
67
+ } else {
68
+ return {
69
+ nodeType: "child",
70
+ name,
71
+ selected,
72
+ };
73
+ }
74
+ }
75
+
76
+ function getChildren($ul) {
77
+ return $ul
78
+ .children("li.jqtree_common")
79
+ .map((_, li) => {
80
+ return getTreeNode(jQuery(li));
81
+ })
82
+ .get();
83
+ }
84
+
85
+ JSON.stringify(window.getChildren(jQuery("ul.jqtree-tree")));
86
+ `);
87
+
88
+ return JSON.parse(structure) as JQTreeMatchers.TreeStructure;
89
+ };
90
+
91
+ const getNodeRect = async (page: Page, title: string) => {
92
+ const titleElement = await locateTitle(page, title).elementHandle();
93
+
94
+ if (!titleElement) {
95
+ throw Error("Element not found");
96
+ }
97
+
98
+ const rect = await getRect(titleElement as ElementHandle<HTMLElement>);
99
+ return rect;
100
+ };
101
+
102
+ export const dragAndDrop = async (
103
+ page: Page,
104
+ from: string,
105
+ to: string
106
+ ): Promise<void> => {
107
+ const fromRect = await getNodeRect(page, from);
108
+ const toRect = await getNodeRect(page, to);
109
+
110
+ await page.mouse.move(
111
+ fromRect.x + fromRect.width / 2,
112
+ fromRect.y + fromRect.height / 2
113
+ );
114
+ await page.mouse.down();
115
+ // eslint-disable-next-line playwright/no-wait-for-timeout
116
+ await page.waitForTimeout(200);
117
+ await page.mouse.move(
118
+ toRect.x + toRect.width / 2,
119
+ toRect.y + toRect.height / 2
120
+ );
121
+ await page.mouse.up();
122
+ };
@@ -1,4 +1,14 @@
1
1
  {
2
- "plugins": ["testing-library"],
3
- "extends": ["plugin:testing-library/dom"]
4
- }
2
+ "plugins": ["jest", "testing-library"],
3
+ "extends": ["plugin:jest/all", "plugin:testing-library/dom"],
4
+ "rules": {
5
+ "jest/consistent-test-it": "off",
6
+ "jest/prefer-expect-assertions": "off",
7
+ "jest/no-duplicate-hooks": "off",
8
+ "jest/no-hooks": "off",
9
+ "jest/no-identical-title": "off",
10
+ "jest/prefer-strict-equal": "off",
11
+ "jest/require-hook": "off",
12
+ "jest/require-top-level-describe": "off"
13
+ }
14
+ }
@@ -7,16 +7,24 @@ import { titleSpan } from "../support/testUtil";
7
7
 
8
8
  const context = describe;
9
9
 
10
+ const server = setupServer();
11
+
12
+ beforeAll(() => server.listen());
13
+
10
14
  beforeEach(() => {
11
15
  $("body").append('<div id="tree1"></div>');
12
16
  });
13
17
 
14
18
  afterEach(() => {
19
+ server.resetHandlers();
20
+
15
21
  const $tree = $("#tree1");
16
22
  $tree.tree("destroy");
17
23
  $tree.remove();
18
24
  });
19
25
 
26
+ afterAll(() => server.close());
27
+
20
28
  describe("tree.click", () => {
21
29
  interface Vars {
22
30
  node1: INode;
@@ -131,19 +139,12 @@ describe("tree.init", () => {
131
139
  });
132
140
 
133
141
  context("with data loaded from an url", () => {
134
- let server: ReturnType<typeof setupServer> | null = null;
135
-
136
- beforeAll(() => {
137
- server = setupServer(
142
+ beforeEach(() => {
143
+ server.use(
138
144
  rest.get("/tree/", (_request, response, ctx) =>
139
145
  response(ctx.status(200), ctx.json(exampleData))
140
146
  )
141
147
  );
142
- server.listen();
143
- });
144
-
145
- afterAll(() => {
146
- server?.close();
147
148
  });
148
149
 
149
150
  it("is called", () =>
@@ -7,17 +7,25 @@ import { togglerLink } from "../support/testUtil";
7
7
 
8
8
  const context = describe;
9
9
 
10
+ const server = setupServer();
11
+
12
+ beforeAll(() => server.listen());
13
+
10
14
  beforeEach(() => {
11
15
  $("body").append('<div id="tree1"></div>');
12
16
  });
13
17
 
14
18
  afterEach(() => {
19
+ server.resetHandlers();
20
+
15
21
  const $tree = $("#tree1");
16
22
  $tree.tree("destroy");
17
23
  $tree.remove();
18
24
  localStorage.clear();
19
25
  });
20
26
 
27
+ afterAll(() => server.close());
28
+
21
29
  context("when a node has load_on_demand in the data", () => {
22
30
  interface Vars {
23
31
  autoOpen: boolean;
@@ -37,10 +45,8 @@ context("when a node has load_on_demand in the data", () => {
37
45
  },
38
46
  ];
39
47
 
40
- let server: ReturnType<typeof setupServer> | null = null;
41
-
42
- beforeAll(() => {
43
- server = setupServer(
48
+ beforeEach(() => {
49
+ server.use(
44
50
  rest.get("/tree/", (request, response, ctx) => {
45
51
  const parentId = request.url.searchParams.get("node");
46
52
 
@@ -54,12 +60,6 @@ context("when a node has load_on_demand in the data", () => {
54
60
  }
55
61
  })
56
62
  );
57
-
58
- server.listen();
59
- });
60
-
61
- afterAll(() => {
62
- server?.close();
63
63
  });
64
64
 
65
65
  beforeEach(() => {
@@ -1,5 +1,5 @@
1
1
  import getGiven from "givens";
2
- import { screen } from "@testing-library/dom";
2
+ import { screen, waitFor } from "@testing-library/dom";
3
3
  import { rest } from "msw";
4
4
  import { setupServer } from "msw/node";
5
5
  import "../../tree.jquery";
@@ -9,17 +9,25 @@ import __version__ from "../../version";
9
9
 
10
10
  const context = describe;
11
11
 
12
+ const server = setupServer();
13
+
14
+ beforeAll(() => server.listen());
15
+
12
16
  beforeEach(() => {
13
17
  $("body").append('<div id="tree1"></div>');
14
18
  });
15
19
 
16
20
  afterEach(() => {
21
+ server.resetHandlers();
22
+
17
23
  const $tree = $("#tree1");
18
24
  $tree.tree("destroy");
19
25
  $tree.remove();
20
26
  localStorage.clear();
21
27
  });
22
28
 
29
+ afterAll(() => server.close());
30
+
23
31
  describe("addNodeAfter", () => {
24
32
  interface Vars {
25
33
  node: INode;
@@ -739,22 +747,13 @@ describe("loadDataFromUrl", () => {
739
747
  given("serverData", () => exampleData);
740
748
  given("$tree", () => $("#tree1"));
741
749
 
742
- let server: ReturnType<typeof setupServer> | null = null;
743
-
744
- beforeAll(() => {
745
- server = setupServer(
746
- rest.get("/tree/", (_request, response, ctx) => {
747
- return response(ctx.status(200), ctx.json(given.serverData));
748
- })
750
+ beforeEach(() => {
751
+ server.use(
752
+ rest.get("/tree/", (_request, response, ctx) =>
753
+ response(ctx.status(200), ctx.json(given.serverData))
754
+ )
749
755
  );
750
- server.listen();
751
- });
752
-
753
- afterAll(() => {
754
- server?.close();
755
- });
756
756
 
757
- beforeEach(() => {
758
757
  given.$tree.tree({ data: given.initialData });
759
758
  });
760
759
 
@@ -909,12 +908,15 @@ describe("openNode", () => {
909
908
  });
910
909
 
911
910
  context("with onFinished parameter", () => {
912
- it("calls the function", () =>
913
- new Promise((resolve) =>
914
- given.$tree.tree("openNode", given.node1, (node) =>
915
- resolve(expect(node).toBe(given.node1))
916
- )
917
- ));
911
+ it("calls the function", async () => {
912
+ const onFinished = jest.fn();
913
+
914
+ given.$tree.tree("openNode", given.node1, onFinished);
915
+
916
+ await waitFor(() => {
917
+ expect(onFinished).toHaveBeenCalledWith(given.node1);
918
+ });
919
+ });
918
920
  });
919
921
  });
920
922
 
@@ -1008,23 +1010,14 @@ describe("reload", () => {
1008
1010
  given("node1", () => given.$tree.tree("getNodeByNameMustExist", "node1"));
1009
1011
  given("$tree", () => $("#tree1"));
1010
1012
 
1011
- let server: ReturnType<typeof setupServer> | null = null;
1012
-
1013
- beforeAll(() => {
1014
- server = setupServer(
1015
- rest.get("/tree/", (_request, response, ctx) =>
1013
+ beforeEach(async () => {
1014
+ server.use(
1015
+ rest.get("/tree2/", (_request, response, ctx) =>
1016
1016
  response(ctx.status(200), ctx.json(exampleData))
1017
1017
  )
1018
1018
  );
1019
- server.listen();
1020
- });
1021
-
1022
- afterAll(() => {
1023
- server?.close();
1024
- });
1025
1019
 
1026
- beforeEach(async () => {
1027
- given.$tree.tree({ dataUrl: "/tree/" });
1020
+ given.$tree.tree({ dataUrl: "/tree2/" });
1028
1021
  await screen.findByText("node1");
1029
1022
 
1030
1023
  given.$tree.tree("removeNode", given.node1);
@@ -1045,19 +1038,18 @@ describe("reload", () => {
1045
1038
  });
1046
1039
 
1047
1040
  context("with a onFinished parameter", () => {
1048
- it("calls onFinished", () =>
1049
- new Promise<void>((resolve) => {
1050
- const handleFinished = () => {
1051
- expect(given.$tree).toHaveTreeStructure([
1052
- expect.objectContaining({ name: "node1" }),
1053
- expect.objectContaining({ name: "node2" }),
1054
- ]);
1041
+ it("calls onFinished", async () => {
1042
+ const handleFinished = jest.fn();
1043
+
1044
+ given.$tree.tree("reload", handleFinished);
1055
1045
 
1056
- resolve();
1057
- };
1046
+ await waitFor(() => expect(handleFinished).toHaveBeenCalledWith());
1058
1047
 
1059
- given.$tree.tree("reload", handleFinished);
1060
- }));
1048
+ expect(given.$tree).toHaveTreeStructure([
1049
+ expect.objectContaining({ name: "node1" }),
1050
+ expect.objectContaining({ name: "node2" }),
1051
+ ]);
1052
+ });
1061
1053
  });
1062
1054
  });
1063
1055