@dhis2-ui/organisation-unit-tree 10.16.2 → 10.16.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 (142) hide show
  1. package/package.json +8 -7
  2. package/src/__e2e__/children_as_child_nodes.js +23 -0
  3. package/src/__e2e__/common.js +70 -0
  4. package/src/__e2e__/controlled_expanded.js +89 -0
  5. package/src/__e2e__/displaying_loading_error.js +45 -0
  6. package/src/__e2e__/expanded.js +42 -0
  7. package/src/__e2e__/force_reload.js +66 -0
  8. package/src/__e2e__/get-organisation-unit-data.js +119 -0
  9. package/src/__e2e__/highlight.js +23 -0
  10. package/src/__e2e__/loading_state.js +37 -0
  11. package/src/__e2e__/multi_selection.js +24 -0
  12. package/src/__e2e__/namespace.js +1 -0
  13. package/src/__e2e__/no_selection.js +32 -0
  14. package/src/__e2e__/path_based_filtering.js +49 -0
  15. package/src/__e2e__/single_selection.js +46 -0
  16. package/src/__e2e__/sub_unit_as_root.js +28 -0
  17. package/src/__e2e__/tree_api.js +55 -0
  18. package/src/__stories__/collapsed.js +11 -0
  19. package/src/__stories__/custom-expanded-imperative-open.js +181 -0
  20. package/src/__stories__/custom-node-label.js +19 -0
  21. package/src/__stories__/development-stories.js +86 -0
  22. package/src/__stories__/expanded.js +12 -0
  23. package/src/__stories__/filtered-root.js +15 -0
  24. package/src/__stories__/filtered.js +13 -0
  25. package/src/__stories__/force-reload-all.js +46 -0
  26. package/src/__stories__/force-reload-one-unit.js +36 -0
  27. package/src/__stories__/highlighted.js +13 -0
  28. package/src/__stories__/indeterminate.js +13 -0
  29. package/src/__stories__/loading-error-grandchild.js +39 -0
  30. package/src/__stories__/loading.js +27 -0
  31. package/src/__stories__/multiple-roots.js +20 -0
  32. package/src/__stories__/no-selection.js +16 -0
  33. package/src/__stories__/replace-roots.js +28 -0
  34. package/src/__stories__/root-error.js +36 -0
  35. package/src/__stories__/root-loading.js +34 -0
  36. package/src/__stories__/rtl.js +14 -0
  37. package/src/__stories__/selected-multiple.js +18 -0
  38. package/src/__stories__/shared.js +192 -0
  39. package/src/__stories__/single-selection.js +16 -0
  40. package/src/features/children_as_child_nodes/index.js +29 -0
  41. package/src/features/children_as_child_nodes.feature +6 -0
  42. package/src/features/controlled_expanded/index.js +86 -0
  43. package/src/features/controlled_expanded.feature +11 -0
  44. package/src/features/displaying_loading_error/index.js +46 -0
  45. package/src/features/displaying_loading_error.feature +24 -0
  46. package/src/features/expanded/index.js +87 -0
  47. package/src/features/expanded.feature +27 -0
  48. package/src/features/force_reload/index.js +36 -0
  49. package/src/features/force_reload.feature +7 -0
  50. package/src/features/highlight/index.js +9 -0
  51. package/src/features/highlight.feature +5 -0
  52. package/src/features/loading_state/index.js +26 -0
  53. package/src/features/loading_state.feature +7 -0
  54. package/src/features/multi_selection/index.js +94 -0
  55. package/src/features/multi_selection.feature +31 -0
  56. package/src/features/no_selection/index.js +41 -0
  57. package/src/features/no_selection.feature +13 -0
  58. package/src/features/path_based_filtering/index.js +97 -0
  59. package/src/features/path_based_filtering.feature +24 -0
  60. package/src/features/single_selection/index.js +41 -0
  61. package/src/features/single_selection.feature +20 -0
  62. package/src/features/sub_unit_as_root/index.js +83 -0
  63. package/src/features/sub_unit_as_root.feature +34 -0
  64. package/src/features/tree_api/index.js +121 -0
  65. package/src/features/tree_api.feature +37 -0
  66. package/src/get-all-expanded-paths/get-all-expanded-paths.js +32 -0
  67. package/src/get-all-expanded-paths/get-all-expanded-paths.test.js +22 -0
  68. package/src/get-all-expanded-paths/index.js +1 -0
  69. package/src/helpers/index.js +3 -0
  70. package/src/helpers/is-path-included.js +15 -0
  71. package/src/helpers/left-trim-to-root-id.js +3 -0
  72. package/src/helpers/sort-node-children-alphabetically.js +5 -0
  73. package/src/index.js +6 -0
  74. package/src/locales/ar/translations.json +5 -0
  75. package/src/locales/cs/translations.json +5 -0
  76. package/src/locales/en/translations.json +5 -0
  77. package/src/locales/es/translations.json +5 -0
  78. package/src/locales/es_419/translations.json +5 -0
  79. package/src/locales/fr/translations.json +5 -0
  80. package/src/locales/index.js +50 -0
  81. package/src/locales/lo/translations.json +5 -0
  82. package/src/locales/nb/translations.json +5 -0
  83. package/src/locales/nl/translations.json +5 -0
  84. package/src/locales/pt/translations.json +5 -0
  85. package/src/locales/ru/translations.json +5 -0
  86. package/src/locales/uk/translations.json +5 -0
  87. package/src/locales/uz_Latn/translations.json +5 -0
  88. package/src/locales/uz_UZ_Cyrl/translations.json +5 -0
  89. package/src/locales/uz_UZ_Latn/translations.json +5 -0
  90. package/src/locales/vi/translations.json +5 -0
  91. package/src/locales/zh/translations.json +5 -0
  92. package/src/locales/zh_CN/translations.json +5 -0
  93. package/src/organisation-unit-node/compute-child-nodes.js +27 -0
  94. package/src/organisation-unit-node/compute-child-nodes.test.js +85 -0
  95. package/src/organisation-unit-node/error-message.js +23 -0
  96. package/src/organisation-unit-node/has-descendant-selected-paths.js +15 -0
  97. package/src/organisation-unit-node/has-descendant-selected-paths.test.js +30 -0
  98. package/src/organisation-unit-node/index.js +1 -0
  99. package/src/organisation-unit-node/label/disabled-selection-label.js +26 -0
  100. package/src/organisation-unit-node/label/icon-empty.js +31 -0
  101. package/src/organisation-unit-node/label/icon-folder-closed.js +38 -0
  102. package/src/organisation-unit-node/label/icon-folder-open.js +49 -0
  103. package/src/organisation-unit-node/label/icon-single.js +41 -0
  104. package/src/organisation-unit-node/label/icon.js +35 -0
  105. package/src/organisation-unit-node/label/iconized-checkbox.js +67 -0
  106. package/src/organisation-unit-node/label/index.js +1 -0
  107. package/src/organisation-unit-node/label/label-container.js +36 -0
  108. package/src/organisation-unit-node/label/label.js +146 -0
  109. package/src/organisation-unit-node/label/single-selection-label.js +60 -0
  110. package/src/organisation-unit-node/loading-spinner.js +22 -0
  111. package/src/organisation-unit-node/organisation-unit-node-children.js +123 -0
  112. package/src/organisation-unit-node/organisation-unit-node.js +190 -0
  113. package/src/organisation-unit-node/use-open-state.js +37 -0
  114. package/src/organisation-unit-node/use-open-state.test.js +111 -0
  115. package/src/organisation-unit-node/use-org-children.js +63 -0
  116. package/src/organisation-unit-node/use-org-children.test.js +314 -0
  117. package/src/organisation-unit-node/use-org-data/index.js +1 -0
  118. package/src/organisation-unit-node/use-org-data/use-org-data.js +40 -0
  119. package/src/organisation-unit-node/use-org-data/use-org-data.test.js +137 -0
  120. package/src/organisation-unit-tree/default-render-node-label/default-render-node-label.js +1 -0
  121. package/src/organisation-unit-tree/default-render-node-label/index.js +1 -0
  122. package/src/organisation-unit-tree/filter-root-ids.js +9 -0
  123. package/src/organisation-unit-tree/index.js +3 -0
  124. package/src/organisation-unit-tree/organisation-unit-tree-root-error.js +20 -0
  125. package/src/organisation-unit-tree/organisation-unit-tree-root-loading.js +22 -0
  126. package/src/organisation-unit-tree/organisation-unit-tree.js +253 -0
  127. package/src/organisation-unit-tree/organisation-unit-tree.test.js +77 -0
  128. package/src/organisation-unit-tree/use-expanded/create-expand-handlers.js +45 -0
  129. package/src/organisation-unit-tree/use-expanded/create-expand-handlers.test.js +54 -0
  130. package/src/organisation-unit-tree/use-expanded/index.js +1 -0
  131. package/src/organisation-unit-tree/use-expanded/use-expanded.js +42 -0
  132. package/src/organisation-unit-tree/use-expanded/use-expanded.test.js +73 -0
  133. package/src/organisation-unit-tree/use-force-reload.js +22 -0
  134. package/src/organisation-unit-tree/use-force-reload.test.js +43 -0
  135. package/src/organisation-unit-tree/use-root-org-data/index.js +1 -0
  136. package/src/organisation-unit-tree/use-root-org-data/patch-missing-display-name.js +20 -0
  137. package/src/organisation-unit-tree/use-root-org-data/patch-missing-display-name.test.js +24 -0
  138. package/src/organisation-unit-tree/use-root-org-data/use-root-org-data.js +60 -0
  139. package/src/organisation-unit-tree/use-root-org-data/use-root-org-unit.test.js +184 -0
  140. package/src/organisation-unit-tree.e2e.stories.js +28 -0
  141. package/src/organisation-unit-tree.prod.stories.js +70 -0
  142. package/src/prop-types.js +33 -0
@@ -0,0 +1,27 @@
1
+ Feature: Nodes can be expanded
2
+
3
+ Scenario: No initially expanded paths are provided
4
+ Given a OrganisationUnitTree with children and no paths in the initiallyExpanded prop is rendered
5
+ Then the root unit is closed
6
+
7
+ # The given step is really long.. but I don't know how to split it while
8
+ # being able to test/prepare that with cypress
9
+ Scenario: The first unit on the second level is provided as initially expanded path
10
+ Given a OrganisationUnitTree with children and the path of the first unit on the second level in the initiallyExpanded prop is rendered
11
+ Then the root unit is opened
12
+
13
+ # For info what a "sub", "main" and "root" unit is, see
14
+ # "sub_unit_as_root.feature"
15
+ Scenario: A sub org unit gets expanded within the main org unit tree
16
+ Given both a sub org unit with children and a main org unit are root org units
17
+ And the root main org unit is expanded
18
+ When the user expands the sub org unit within the main org unit tree
19
+ Then the root sub org unit should not expand
20
+
21
+ # For info what a "sub", "main" and "root" unit is, see
22
+ # "sub_unit_as_root.feature"
23
+ Scenario: A root sub org unit gets expanded which is also in the main org unit tree
24
+ Given both a sub org unit with children and a main org unit are root org units
25
+ And the root main org unit is expanded
26
+ When the user expands the root sub org unit
27
+ Then the sub org unit within the main org unit tree should not expand
@@ -0,0 +1,36 @@
1
+ import { Given, When, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('a OrganisationUnitTree with three levels is rendered', () => {
4
+ cy.visitStory('OrganisationUnitTree', 'Force reloading')
5
+ })
6
+
7
+ Given('the two parent levels are opened', () => {
8
+ cy.getOrgUnitByLabel('Org Unit 1').as('rootNode').openOrgUnitNode()
9
+
10
+ cy.getOrgUnitByLabel('Org Unit 2').openOrgUnitNode()
11
+
12
+ cy.get('@rootNode')
13
+ .find(
14
+ '[data-test="dhis2-uiwidgets-orgunittree-node"] [data-test="dhis2-uiwidgets-orgunittree-node"]'
15
+ )
16
+ .should('exist')
17
+ })
18
+
19
+ When(
20
+ 'the tree is being force reloaded and the loading process has finished',
21
+ () => {
22
+ cy.get('[data-test="reload-all"]').click()
23
+ }
24
+ )
25
+
26
+ Then('all three levels are visible again', () => {
27
+ cy.get('@rootNode')
28
+ .find('[data-test="dhis2-uiwidgets-orgunittree-node"]')
29
+ .should('exist')
30
+
31
+ cy.get('@rootNode')
32
+ .find(
33
+ '[data-test="dhis2-uiwidgets-orgunittree-node"] [data-test="dhis2-uiwidgets-orgunittree-node"]'
34
+ )
35
+ .should('exist')
36
+ })
@@ -0,0 +1,7 @@
1
+ Feature: The whole organisation unit tree can be reloaded
2
+
3
+ Scenario: The whole tree is reloaded while being opened
4
+ Given a OrganisationUnitTree with three levels is rendered
5
+ And the two parent levels are opened
6
+ When the tree is being force reloaded and the loading process has finished
7
+ Then all three levels are visible again
@@ -0,0 +1,9 @@
1
+ import { Given, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('a OrganisationUnitTree with a highlighted root unit is rendered', () => {
4
+ cy.visitStory('OrganisationUnitTree', 'Root highlighted')
5
+ })
6
+
7
+ Then('root unit has the highlighted styles', () => {
8
+ cy.getOrgUnitByLabel('Org Unit 1').find('.highlighted').should('exist')
9
+ })
@@ -0,0 +1,5 @@
1
+ Feature: Units can be highlighted
2
+
3
+ Scenario: The root unit is highlighted
4
+ Given a OrganisationUnitTree with a highlighted root unit is rendered
5
+ Then root unit has the highlighted styles
@@ -0,0 +1,26 @@
1
+ import { Given, When, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('a OrganisationUnitTree with two levels is rendered', () => {
4
+ cy.visitStory('OrganisationUnitTree', 'A 0000000001 loading')
5
+ })
6
+
7
+ Given('the root level is closed', () => {
8
+ cy.getOrgUnitByLabel('Org Unit 1').as('rootUnit').shouldBeAClosedNode()
9
+ })
10
+
11
+ When('the root level is opened', () => {
12
+ cy.get('@rootUnit').openOrgUnitNode()
13
+ })
14
+
15
+ Then(
16
+ 'there is a loading indicator rendered on the first child of the second level',
17
+ () => {
18
+ cy.getOrgUnitByLabel('Org Unit 2')
19
+ .find('[data-test="dhis2-uicore-circularloader"]')
20
+ .should('exist')
21
+
22
+ cy.getOrgUnitByLabel('Org Unit 2')
23
+ .find('[data-test="dhis2-uiwidgets-orgunittree-node-leaves"]:empty')
24
+ .should('exist')
25
+ }
26
+ )
@@ -0,0 +1,7 @@
1
+ Feature: When a unit is loading its children then there is a loading indicator
2
+
3
+ Scenario: The first second-level unit is loading its children
4
+ Given a OrganisationUnitTree with two levels is rendered
5
+ And the root level is closed
6
+ When the root level is opened
7
+ Then there is a loading indicator rendered on the first child of the second level
@@ -0,0 +1,94 @@
1
+ import { Given, When, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('an OrganisationUnitTree with two levels is rendered', () => {
4
+ cy.visitStory('OrganisationUnitTree', 'Multiple selection')
5
+ })
6
+
7
+ Given('no unit is selected', () => {
8
+ cy.window().should((win) => {
9
+ expect(win.selection).to.eql([])
10
+ })
11
+ })
12
+
13
+ Given('the root level unit is opened', () => {
14
+ cy.getOrgUnitByLabel('Org Unit 1').openOrgUnitNode(true)
15
+ })
16
+
17
+ Given('the first unit on the second level is selected', () => {
18
+ cy.getOrgUnitByLabel('Org Unit 2').toggleOrgUnitNodeSelection(true)
19
+ })
20
+
21
+ Given('the first unit on the second level unit is opened', () => {
22
+ cy.getOrgUnitByLabel('Org Unit 2').openOrgUnitNode(true)
23
+ })
24
+
25
+ Given('the second level has two units', () => {
26
+ cy.getOrgUnitByLabel('Org Unit 2')
27
+ .find('[data-test="dhis2-uiwidgets-orgunittree-node-leaves"]')
28
+ .first()
29
+ .children()
30
+ .filter((index, child) =>
31
+ Cypress.$(child).is(
32
+ '[data-test="dhis2-uiwidgets-orgunittree-node"]'
33
+ )
34
+ )
35
+ .should('have.length', 2)
36
+ })
37
+
38
+ When('the user selects a unit', () => {
39
+ cy.getOrgUnitByLabel('Org Unit 1').toggleOrgUnitNodeSelection(true)
40
+ })
41
+
42
+ When('the user selects the first unit on the second level', () => {
43
+ cy.getOrgUnitByLabel('Org Unit 2').toggleOrgUnitNodeSelection(true)
44
+ })
45
+
46
+ When('the user selects the root level', () => {
47
+ cy.getOrgUnitByLabel('Org Unit 1').toggleOrgUnitNodeSelection(true)
48
+ })
49
+
50
+ When('the user selects the second unit on the second level', () => {
51
+ cy.getOrgUnitByLabel('Org Unit 3').toggleOrgUnitNodeSelection(true)
52
+ })
53
+
54
+ Then('a unit is selected', () => {
55
+ cy.window().should((win) => {
56
+ expect(win.selection).to.eql(['/A0000000000'])
57
+ })
58
+ })
59
+
60
+ Then('the unit on the second level is selected', () => {
61
+ cy.window().should((win) => {
62
+ expect(win.selection).to.eql(['/A0000000000/A0000000001'])
63
+ })
64
+ })
65
+
66
+ Then('the unit on the first level is marked as selected intermediately', () => {
67
+ cy.getOrgUnitByLabel('Org Unit 1')
68
+ .find(
69
+ '[data-test="dhis2-uiwidgets-orgunittree-node-label"] [data-test="dhis2-uicore-checkbox"] input'
70
+ )
71
+ .should(($input) => {
72
+ expect($input[0].indeterminate).to.be.true
73
+ })
74
+ })
75
+
76
+ Then('the root unit is marked as selected', () => {
77
+ cy.window().should((win) => {
78
+ expect(win.selection.includes('/A0000000000')).to.be.true
79
+ })
80
+ })
81
+
82
+ Then('the first unit is selected', () => {
83
+ cy.window().should((win) => {
84
+ expect(win.selection.includes('/A0000000000/A0000000001')).to.be.true
85
+ expect(win.selection).to.have.length(2)
86
+ })
87
+ })
88
+
89
+ Then('the second unit is selected', () => {
90
+ cy.window().should((win) => {
91
+ expect(win.selection.includes('/A0000000000/A0000000002')).to.be.true
92
+ expect(win.selection).to.have.length(2)
93
+ })
94
+ })
@@ -0,0 +1,31 @@
1
+ Feature: When not limited any amount of units can be selected
2
+
3
+ Scenario: The user selects a unit when no other unit is selected
4
+ Given an OrganisationUnitTree with two levels is rendered
5
+ And no unit is selected
6
+ When the user selects a unit
7
+ Then a unit is selected
8
+
9
+ Scenario: The user selects a unit when a parent unit is not selected
10
+ Given an OrganisationUnitTree with two levels is rendered
11
+ And the root level unit is opened
12
+ When the user selects the first unit on the second level
13
+ Then the unit on the second level is selected
14
+ Then the unit on the first level is marked as selected intermediately
15
+
16
+ Scenario: The user selects a unit which is selected intermediately
17
+ Given an OrganisationUnitTree with two levels is rendered
18
+ And the root level unit is opened
19
+ And the first unit on the second level is selected
20
+ When the user selects the root level
21
+ Then the root unit is marked as selected
22
+
23
+ Scenario: The user selects a unit when another unit on the same level is selected
24
+ Given an OrganisationUnitTree with two levels is rendered
25
+ And the root level unit is opened
26
+ And the first unit on the second level unit is opened
27
+ And the second level has two units
28
+ And the first unit on the second level is selected
29
+ When the user selects the second unit on the second level
30
+ Then the first unit is selected
31
+ Then the second unit is selected
@@ -0,0 +1,41 @@
1
+ import { Given, When, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given(
4
+ 'a disabled, collapsed OrganisationUnitTree with two levels is rendered',
5
+ () => {
6
+ cy.visitStory('OrganisationUnitTree', 'No selection closed')
7
+ }
8
+ )
9
+
10
+ Given(
11
+ 'a disabled OrganisationUnitTree with two levels is rendered with the second level is expanded',
12
+ () => {
13
+ cy.visitStory('OrganisationUnitTree', 'No selection root opened')
14
+ }
15
+ )
16
+
17
+ When('the root node is clicked', () => {
18
+ cy.getOrgUnitByLabel('Org Unit 1')
19
+ .find('[data-test="dhis2-uiwidgets-orgunittree-node-label"]')
20
+ .first()
21
+ .trigger('click')
22
+ })
23
+
24
+ Then('the root node remains unselected', () => {
25
+ cy.getOrgUnitByLabel('Org Unit 1')
26
+ .find('[data-test="dhis2-uiwidgets-orgunittree-node-label"]')
27
+ .first()
28
+ .as('rootLabel')
29
+ .find('.checked')
30
+ .should('not.exist')
31
+
32
+ cy.get('@rootLabel').find('input').should('not.exist')
33
+ })
34
+
35
+ Then('the second level is expanded', () => {
36
+ cy.getOrgUnitByLabel('Org Unit 1').shouldBeAnOpenNode()
37
+ })
38
+
39
+ Then('the second level is collapsed', () => {
40
+ cy.getOrgUnitByLabel('Org Unit 1').shouldBeAClosedNode()
41
+ })
@@ -0,0 +1,13 @@
1
+ Feature: Selection can be disabled entirely in the OrganisationUnitTree
2
+
3
+ Scenario: The user clicks on a level of the disabled OrganisationUnitTree with the second level collapsed
4
+ Given a disabled, collapsed OrganisationUnitTree with two levels is rendered
5
+ When the root node is clicked
6
+ Then the root node remains unselected
7
+ But the second level is expanded
8
+
9
+ Scenario: The user clicks on a level of the disabled OrganisationUnitTree with the second level expanded
10
+ Given a disabled OrganisationUnitTree with two levels is rendered with the second level is expanded
11
+ When the root node is clicked
12
+ Then the root node remains unselected
13
+ But the second level is collapsed
@@ -0,0 +1,97 @@
1
+ import { Before, Given, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Before(() => {
4
+ cy.wrap([]).as('displayedUnits')
5
+ })
6
+
7
+ const addDisplayedUnit = (id) => {
8
+ cy.get('@displayedUnits').then((displayedUnits) => {
9
+ cy.wrap([...displayedUnits, id]).as('displayedUnits')
10
+ })
11
+ }
12
+
13
+ Given(
14
+ 'a unfiltered OrganisationUnitTree with a depth of 3 levels is rendered',
15
+ () => {
16
+ cy.visitStory('OrganisationUnitTree', 'Filtered by 3-level-path')
17
+ }
18
+ )
19
+
20
+ Given(
21
+ 'a filtered OrganisationUnitTree with a depth of 3 levels is rendered',
22
+ () => {
23
+ cy.visitStory(
24
+ 'OrganisationUnitTree',
25
+ 'Filtered by 3-level-path and 2-level-path'
26
+ )
27
+ }
28
+ )
29
+
30
+ /**
31
+ * left empty intentionally
32
+ * ========================
33
+ * Step is necessary to make the feature file understandable
34
+ * Required states are prepared by the story.
35
+ * There is no way to check if the given is true by checking the dom
36
+ * as this can only be verified by opening the org unit tree,
37
+ * which triggers the recursive loading strategy.
38
+ */
39
+ Given('the second level contains two nodes', () => {})
40
+ Given('all parent levels are open', () => {})
41
+ Given(
42
+ 'a filter containing the first child of the first second level is provided',
43
+ () => {}
44
+ )
45
+ Given('the second level nodes each have a child node', () => {})
46
+ Given(
47
+ 'a filter containing the first child of the second level is provided',
48
+ () => {}
49
+ )
50
+ Given(
51
+ 'a filter containing the second child of the first level is provided',
52
+ () => {}
53
+ )
54
+
55
+ Then('the root level is visible', () => {
56
+ cy.getOrgUnitByLabel('Org Unit 1').should('exist')
57
+
58
+ addDisplayedUnit('A0000000000')
59
+ })
60
+
61
+ Then('the first node on the second level is visible', () => {
62
+ cy.getOrgUnitByLabel('Org Unit 2').should('exist')
63
+
64
+ addDisplayedUnit('A0000000001')
65
+ })
66
+
67
+ Then(
68
+ 'the first child node of the first node on the second level is visible',
69
+ () => {
70
+ cy.getOrgUnitByLabel('Org Unit 4').should('exist')
71
+
72
+ addDisplayedUnit('A0000000003')
73
+ }
74
+ )
75
+
76
+ Then('the second node on the first level is visible', () => {
77
+ cy.getOrgUnitByLabel('Org Unit 3').should('exist')
78
+
79
+ addDisplayedUnit('A0000000002')
80
+ })
81
+
82
+ Then('all other nodes are not rendered', () => {
83
+ cy.get('@displayedUnits').then((displayedUnits) => {
84
+ cy.window().then((win) => {
85
+ const excludedUnitNumbers = win.allUnits
86
+ .filter((unit) => !displayedUnits.includes(unit))
87
+ .map((id) => parseInt(id.replace(/^.*(\d)$/, '$1'), 10) + 1)
88
+
89
+ excludedUnitNumbers.forEach((number) => {
90
+ const label = `Org Unit ${number}`
91
+ cy.get(
92
+ `[data-test="dhis2-uiwidgets-orgunittree-node-label"]:contains("${label}")`
93
+ ).should('not.exist')
94
+ })
95
+ })
96
+ })
97
+ })
@@ -0,0 +1,24 @@
1
+ Feature: The OrganisationUnitTree can be filtered by paths
2
+
3
+ Scenario: The org unit tree is filtered by a three-level-deep path
4
+ Given a unfiltered OrganisationUnitTree with a depth of 3 levels is rendered
5
+ And the second level contains two nodes
6
+ And all parent levels are open
7
+ And a filter containing the first child of the first second level is provided
8
+ Then the root level is visible
9
+ And the first node on the second level is visible
10
+ And the first child node of the first node on the second level is visible
11
+ And all other nodes are not rendered
12
+
13
+ Scenario: The org unit tree is filtered by a three-level- and a two-level-deep path
14
+ Given a filtered OrganisationUnitTree with a depth of 3 levels is rendered
15
+ And the second level contains two nodes
16
+ And the second level nodes each have a child node
17
+ And all parent levels are open
18
+ And a filter containing the first child of the second level is provided
19
+ And a filter containing the second child of the first level is provided
20
+ Then the root level is visible
21
+ And the first node on the second level is visible
22
+ And the first child node of the first node on the second level is visible
23
+ And the second node on the first level is visible
24
+ And all other nodes are not rendered
@@ -0,0 +1,41 @@
1
+ import { Given, When, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('an OrganisationUnitTree with two nodes is rendered', () => {
4
+ cy.visitStory('OrganisationUnitTree', 'Single selection')
5
+ })
6
+
7
+ Given('no unit has been selected', () => {
8
+ cy.get('.checked').should('not.exist')
9
+ })
10
+
11
+ Given('the first unit has been selected', () => {
12
+ cy.getOrgUnitByLabel('Org Unit 1').toggleOrgUnitNodeSelection(true, true)
13
+ })
14
+
15
+ When('the user selects the first unit', () => {
16
+ cy.getOrgUnitByLabel('Org Unit 1').toggleOrgUnitNodeSelection(true, true)
17
+ })
18
+
19
+ When('the user selects the second unit', () => {
20
+ cy.getOrgUnitByLabel('Org Unit 2').toggleOrgUnitNodeSelection(true, true)
21
+ })
22
+
23
+ When('the user deselects the first unit', () => {
24
+ cy.getOrgUnitByLabel('Org Unit 1').toggleOrgUnitNodeSelection(false, true)
25
+ })
26
+
27
+ Then('the first unit is selected', () => {
28
+ cy.getOrgUnitByLabel('Org Unit 1').shouldBeASelectedOrgUnitNode(true)
29
+ })
30
+
31
+ Then('the first unit is not selected', () => {
32
+ cy.getOrgUnitByLabel('Org Unit 1').shouldNotBeASelectedOrgUnitNode(true)
33
+ })
34
+
35
+ Then('the second unit is selected', () => {
36
+ cy.getOrgUnitByLabel('Org Unit 2').shouldBeASelectedOrgUnitNode(true)
37
+ })
38
+
39
+ Then('no unit is selected', () => {
40
+ cy.get('.checked').should('not.exist')
41
+ })
@@ -0,0 +1,20 @@
1
+ Feature: When specified only one unit can be selected
2
+
3
+ Scenario: The user selects a unit when no other unit is selected
4
+ Given an OrganisationUnitTree with two nodes is rendered
5
+ And no unit has been selected
6
+ When the user selects the first unit
7
+ Then the first unit is selected
8
+
9
+ Scenario: The user select a unit when another unit is selected
10
+ Given an OrganisationUnitTree with two nodes is rendered
11
+ And the first unit has been selected
12
+ When the user selects the second unit
13
+ Then the first unit is not selected
14
+ Then the second unit is selected
15
+
16
+ Scenario: The user deselects a unit
17
+ Given an OrganisationUnitTree with two nodes is rendered
18
+ And the first unit has been selected
19
+ When the user deselects the first unit
20
+ Then no unit is selected
@@ -0,0 +1,83 @@
1
+ import { Given, When, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ const rootOrgUnitLabelSelector = `
4
+ [data-test="dhis2-uiwidgets-orgunittree"]
5
+ > [data-test="dhis2-uiwidgets-orgunittree-node"]
6
+ > [data-test="dhis2-uiwidgets-orgunittree-node-content"]
7
+ > [data-test="dhis2-uiwidgets-orgunittree-node-label"]
8
+ label
9
+ `
10
+
11
+ Given('a sub org unit is a root org unit', () => {
12
+ cy.visitStory(
13
+ 'OrganisationUnitTree',
14
+ 'multiple root sub and one main org unit'
15
+ )
16
+ })
17
+
18
+ Given('both a sub org unit and a main org unit are root org units', () => {
19
+ cy.visitStory(
20
+ 'OrganisationUnitTree',
21
+ 'multiple root sub and one main org unit'
22
+ )
23
+ })
24
+
25
+ Given('multiple sub org units is a root org unit', () => {
26
+ cy.visitStory(
27
+ 'OrganisationUnitTree',
28
+ 'multiple root sub and one main org unit'
29
+ )
30
+ })
31
+
32
+ Given('the root sub org unit is a child of the root main org unit', () => {
33
+ cy.visitStory(
34
+ 'OrganisationUnitTree',
35
+ 'multiple root sub and one main org unit'
36
+ )
37
+ })
38
+
39
+ Given('the user provided one root sub org unit to the filter', () => {
40
+ cy.get('input[type="input"]').clear().type('/A0000000001')
41
+ })
42
+
43
+ Given('the user provided one non-root sub org unit to the filter', () => {
44
+ cy.get('input[type="input"]').clear().type('/A0000000000/A0000000006')
45
+ })
46
+
47
+ When('the user selects sub org unit in the main org unit tree', () => {
48
+ cy.contains('label', 'Org Unit 1').click()
49
+ cy.get('[data-test="dhis2-uiwidgets-orgunittree-node-content"]')
50
+ .contains('label', 'Org Unit 2')
51
+ .click()
52
+ })
53
+
54
+ When('the user selects the root sub org unit', () => {
55
+ cy.contains(rootOrgUnitLabelSelector, 'Org Unit 2').click()
56
+ })
57
+
58
+ Then(
59
+ 'all root sub org units but the filtered sub org unit should be hidden',
60
+ () => {
61
+ cy.contains(rootOrgUnitLabelSelector, 'Org Unit 2').should('exist')
62
+ cy.contains(rootOrgUnitLabelSelector, 'Org Unit 1').should('not.exist')
63
+ cy.contains(rootOrgUnitLabelSelector, 'Org Unit 3').should('not.exist')
64
+ }
65
+ )
66
+
67
+ Then('the root main org unit should be marked as indeterminate', () => {
68
+ cy.contains(rootOrgUnitLabelSelector, 'Org Unit 1')
69
+ .find('> .icon svg')
70
+ .should('have.class', 'indeterminate')
71
+ })
72
+
73
+ Then('the root sub org unit should be selected', () => {
74
+ cy.contains(rootOrgUnitLabelSelector, 'Org Unit 2')
75
+ .find('> .icon svg')
76
+ .should('have.class', 'checked')
77
+ })
78
+
79
+ Then('only the root main org units should be visible', () => {
80
+ cy.contains(rootOrgUnitLabelSelector, 'Org Unit 1').should('exist')
81
+ cy.contains(rootOrgUnitLabelSelector, 'Org Unit 2').should('not.exist')
82
+ cy.contains(rootOrgUnitLabelSelector, 'Org Unit 3').should('not.exist')
83
+ })
@@ -0,0 +1,34 @@
1
+ Feature: Sub-org units can be a root org unit
2
+
3
+ Main org unit : is an actual root org unit in the configured hierarchy
4
+ Sub org unit : is an org unit which is inside the tree of a "main org unit"
5
+ Root org unit : refers to an org unit which is a root node in the component
6
+ ---
7
+ Org unit components can have multiple selections in all of the scenarios
8
+
9
+ Scenario: The user selects the root sub org unit
10
+ Given a sub org unit is a root org unit
11
+ When the user selects the root sub org unit
12
+ Then the root sub org unit should be selected
13
+
14
+ Scenario: The user selects the root sub org unit which is included in the tree of a root main org unit
15
+ Given both a sub org unit and a main org unit are root org units
16
+ And the root sub org unit is a child of the root main org unit
17
+ When the user selects the root sub org unit
18
+ Then the root main org unit should be marked as indeterminate
19
+
20
+ Scenario: The user selects the a child in the root main org unit which is also a root sub org unit
21
+ Given both a sub org unit and a main org unit are root org units
22
+ And the root sub org unit is a child of the root main org unit
23
+ When the user selects sub org unit in the main org unit tree
24
+ Then the root sub org unit should be selected
25
+
26
+ Scenario: The user filtered the tree by a root sub unit path
27
+ Given multiple sub org units is a root org unit
28
+ And the user provided one root sub org unit to the filter
29
+ Then all root sub org units but the filtered sub org unit should be hidden
30
+
31
+ Scenario: The user filtered the tree by a non-root sub unit path in the root main org unit
32
+ Given multiple sub org units is a root org unit
33
+ And the user provided one non-root sub org unit to the filter
34
+ Then only the root main org units should be visible