@dhis2-ui/transfer 10.16.2 → 10.16.3-alpha.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 (109) hide show
  1. package/package.json +10 -9
  2. package/src/__e2e__/add_remove-highlighted-options.e2e.stories.js +30 -0
  3. package/src/__e2e__/common/options.js +90 -0
  4. package/src/__e2e__/common/stateful-decorator.js +33 -0
  5. package/src/__e2e__/common.js +0 -0
  6. package/src/__e2e__/disabled-transfer-buttons.e2e.stories.js +49 -0
  7. package/src/__e2e__/disabled-transfer-options.e2e.stories.js +21 -0
  8. package/src/__e2e__/display-order.e2e.stories.js +24 -0
  9. package/src/__e2e__/filter-options-list.e2e.stories.js +87 -0
  10. package/src/__e2e__/highlight-range-of-options.e2e.stories.js +52 -0
  11. package/src/__e2e__/loading_lists.e2e.stories.js +26 -0
  12. package/src/__e2e__/notify_at_end_of_list.e2e.stories.js +116 -0
  13. package/src/__e2e__/reorder-with-buttons.e2e.stories.js +35 -0
  14. package/src/__e2e__/set_unset-highlighted-option.e2e.stories.js +30 -0
  15. package/src/__e2e__/transferring-items.e2e.stories.js +27 -0
  16. package/src/__tests__/common.test.js +131 -0
  17. package/src/__tests__/helper/add-all-selectable-source-options.test.js +46 -0
  18. package/src/__tests__/helper/add-individual-source-options.test.js +80 -0
  19. package/src/__tests__/helper/default-filter-callback.test.js +45 -0
  20. package/src/__tests__/helper/is-reorder-down-disabled.test.js +96 -0
  21. package/src/__tests__/helper/is-reorder-up-disabled.test.js +96 -0
  22. package/src/__tests__/helper/move-highlighted-picked-option-down.test.js +111 -0
  23. package/src/__tests__/helper/move-highlighted-picked-option-to-bottom.test.js +101 -0
  24. package/src/__tests__/helper/move-highlighted-picked-option-to-top.test.js +101 -0
  25. package/src/__tests__/helper/move-highlighted-picked-option-up.test.js +111 -0
  26. package/src/__tests__/helper/remove-all-picked-options.test.js +29 -0
  27. package/src/__tests__/helper/remove-individual-picked-options.test.js +38 -0
  28. package/src/__tests__/helper/use-highlighted-option/create-toggle-highlighted-option.test.js +104 -0
  29. package/src/__tests__/helper/use-highlighted-option/toggle-add.test.js +84 -0
  30. package/src/__tests__/helper/use-highlighted-option/toggle-range.test.js +150 -0
  31. package/src/__tests__/helper/use-highlighted-option/toggle-replace.test.js +39 -0
  32. package/src/__tests__/helper/use-highlighted-option.test.js +41 -0
  33. package/src/__tests__/reordering-actions.test.js +165 -0
  34. package/src/__tests__/transfer.test.js +137 -0
  35. package/src/actions.js +33 -0
  36. package/src/add-all.js +27 -0
  37. package/src/add-individual.js +27 -0
  38. package/src/common/find-option-index.js +9 -0
  39. package/src/common/get-mode-by-modifier-key.js +35 -0
  40. package/src/common/index.js +5 -0
  41. package/src/common/is-option.js +7 -0
  42. package/src/common/modes.js +11 -0
  43. package/src/common/remove-option.js +19 -0
  44. package/src/common/toggle-value.js +18 -0
  45. package/src/container.js +23 -0
  46. package/src/end-intersection-detector.js +37 -0
  47. package/src/features/add_remove-highlighted-options/index.js +92 -0
  48. package/src/features/add_remove-highlighted-options.feature +41 -0
  49. package/src/features/common/index.js +8 -0
  50. package/src/features/disabled-transfer-buttons/index.js +118 -0
  51. package/src/features/disabled-transfer-buttons.feature +46 -0
  52. package/src/features/disabled-transfer-options/index.js +182 -0
  53. package/src/features/disabled-transfer-options.feature +42 -0
  54. package/src/features/display-order/index.js +205 -0
  55. package/src/features/display-order.feature +30 -0
  56. package/src/features/filter-options-list/index.js +133 -0
  57. package/src/features/filter-options-list.feature +40 -0
  58. package/src/features/highlight-range-of-options/index.js +336 -0
  59. package/src/features/highlight-range-of-options.feature +70 -0
  60. package/src/features/loading_lists/index.js +43 -0
  61. package/src/features/loading_lists.feature +19 -0
  62. package/src/features/notify_at_end_of_list/index.js +125 -0
  63. package/src/features/notify_at_end_of_list.feature +64 -0
  64. package/src/features/reorder-with-buttons/index.js +181 -0
  65. package/src/features/reorder-with-buttons.feature +138 -0
  66. package/src/features/set_unset-highlighted-option/index.js +121 -0
  67. package/src/features/set_unset-highlighted-option.feature +42 -0
  68. package/src/features/transferring-items/index.js +375 -0
  69. package/src/features/transferring-items.feature +44 -0
  70. package/src/filter.js +38 -0
  71. package/src/icons.js +194 -0
  72. package/src/index.js +2 -0
  73. package/src/left-footer.js +22 -0
  74. package/src/left-header.js +22 -0
  75. package/src/left-side.js +34 -0
  76. package/src/locales/en/translations.json +7 -0
  77. package/src/locales/index.js +16 -0
  78. package/src/options-container.js +127 -0
  79. package/src/remove-all.js +27 -0
  80. package/src/remove-individual.js +27 -0
  81. package/src/reordering-actions.js +136 -0
  82. package/src/right-footer.js +22 -0
  83. package/src/right-header.js +22 -0
  84. package/src/right-side.js +33 -0
  85. package/src/transfer/add-all-selectable-source-options.js +37 -0
  86. package/src/transfer/add-individual-source-options.js +61 -0
  87. package/src/transfer/create-double-click-handlers.js +36 -0
  88. package/src/transfer/default-filter-callback.js +17 -0
  89. package/src/transfer/get-highlighted-picked-indices.js +26 -0
  90. package/src/transfer/get-option-click-handlers.js +19 -0
  91. package/src/transfer/index.js +17 -0
  92. package/src/transfer/is-reorder-down-disabled.js +34 -0
  93. package/src/transfer/is-reorder-up-disabled.js +30 -0
  94. package/src/transfer/move-highlighted-picked-option-down.js +54 -0
  95. package/src/transfer/move-highlighted-picked-option-to-bottom.js +44 -0
  96. package/src/transfer/move-highlighted-picked-option-to-top.js +38 -0
  97. package/src/transfer/move-highlighted-picked-option-up.js +47 -0
  98. package/src/transfer/remove-all-picked-options.js +13 -0
  99. package/src/transfer/remove-individual-picked-options.js +49 -0
  100. package/src/transfer/use-filter.js +17 -0
  101. package/src/transfer/use-highlighted-options/create-toggle-highlighted-option.js +64 -0
  102. package/src/transfer/use-highlighted-options/toggle-add.js +20 -0
  103. package/src/transfer/use-highlighted-options/toggle-range.js +61 -0
  104. package/src/transfer/use-highlighted-options/toggle-replace.js +26 -0
  105. package/src/transfer/use-highlighted-options.js +34 -0
  106. package/src/transfer/use-options-key-monitor.js +41 -0
  107. package/src/transfer-option.js +91 -0
  108. package/src/transfer.js +539 -0
  109. package/src/transfer.prod.stories.js +621 -0
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Click modes when clicking on an option with/without
3
+ * a modifier key (ctrl, alt, cmd, shift)
4
+ */
5
+
6
+ // no or multiple modifier keys
7
+ export const REPLACE_MODE = 'REPLACE_MODE'
8
+ // add/remove options from selection
9
+ export const ADD_MODE = 'ADD_MODE'
10
+ // create selection range
11
+ export const RANGE_MODE = 'RANGE_MODE'
@@ -0,0 +1,19 @@
1
+ import { findOptionIndex } from './find-option-index.js'
2
+
3
+ /**
4
+ * @param {Object[]} options
5
+ * @param {Object} option
6
+ * @returns {Object}
7
+ */
8
+ export const removeOption = (options, option) => {
9
+ const index = findOptionIndex(options, option)
10
+
11
+ if (index === -1) {
12
+ return options
13
+ }
14
+ if (index === 0) {
15
+ return options.slice(1)
16
+ }
17
+
18
+ return [...options.slice(0, index), ...options.slice(index + 1)]
19
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @param {string[]} values
3
+ * @param {string} value
4
+ * @returns {string[]}
5
+ */
6
+ export const toggleValue = (values, value) => {
7
+ const index = values.indexOf(value)
8
+
9
+ if (index === -1) {
10
+ return [...values, value]
11
+ } else if (index === 0) {
12
+ values.slice(1)
13
+ }
14
+
15
+ const prevSlice = values.slice(0, index)
16
+ const nextSlice = values.slice(index + 1)
17
+ return [...prevSlice, ...nextSlice]
18
+ }
@@ -0,0 +1,23 @@
1
+ import PropTypes from 'prop-types'
2
+ import React from 'react'
3
+
4
+ export const Container = ({ children, dataTest, className, height }) => (
5
+ <div data-test={dataTest} className={className}>
6
+ {children}
7
+
8
+ <style jsx>{`
9
+ div {
10
+ display: flex;
11
+ width: 100%;
12
+ height: ${height};
13
+ }
14
+ `}</style>
15
+ </div>
16
+ )
17
+
18
+ Container.propTypes = {
19
+ height: PropTypes.string.isRequired,
20
+ children: PropTypes.node,
21
+ className: PropTypes.string,
22
+ dataTest: PropTypes.string,
23
+ }
@@ -0,0 +1,37 @@
1
+ import { IntersectionDetector } from '@dhis2-ui/intersection-detector'
2
+ import PropTypes from 'prop-types'
3
+ import React from 'react'
4
+
5
+ export const INTERSECTION_DETECTOR_HEIGHT = 50
6
+
7
+ export const EndIntersectionDetector = ({
8
+ rootRef,
9
+ onEndReached,
10
+ dataTest,
11
+ }) => (
12
+ <div data-test={dataTest}>
13
+ <IntersectionDetector
14
+ rootRef={rootRef}
15
+ onChange={({ isIntersecting }) => isIntersecting && onEndReached()}
16
+ />
17
+
18
+ <style jsx>{`
19
+ div {
20
+ width: 100%;
21
+ height: ${INTERSECTION_DETECTOR_HEIGHT}px;
22
+ position: absolute;
23
+ z-index: -1;
24
+ bottom: 0;
25
+ inset-inline-start: 0;
26
+ }
27
+ `}</style>
28
+ </div>
29
+ )
30
+
31
+ EndIntersectionDetector.propTypes = {
32
+ rootRef: PropTypes.shape({
33
+ current: PropTypes.instanceOf(HTMLElement),
34
+ }).isRequired,
35
+ onEndReached: PropTypes.func.isRequired,
36
+ dataTest: PropTypes.string,
37
+ }
@@ -0,0 +1,92 @@
1
+ import { Given, When, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('the option list has two or more items', () => {
4
+ cy.visitStory('Transfer add & remove highlighted options', 'Has Options')
5
+ cy.get('{transfer-sourceoptions}').as('list')
6
+ })
7
+
8
+ Given('the selected list has two or more items', () => {
9
+ cy.visitStory('Transfer add & remove highlighted options', 'Has Selected')
10
+ cy.get('{transfer-pickedoptions}').as('list')
11
+ })
12
+
13
+ Given('some items are highlighted', () => {
14
+ cy.get('@list')
15
+ .find('{transferoption}')
16
+ .then(($options) => {
17
+ const multipleOptions = $options.filter((index) => index < 3)
18
+ return cy.wrap(multipleOptions)
19
+ })
20
+ .as('highlightedMultipleOptions')
21
+ .each(($option) => cy.wrap($option).clickWith('ctrl'))
22
+ })
23
+
24
+ When(
25
+ 'the user clicks multiple items with {string} which are not highlighted',
26
+ (modifierKey) => {
27
+ cy.get('@list')
28
+ .find('{transferoption}')
29
+ .then(($options) => {
30
+ const multipleOptions = $options.filter((index) => index < 3)
31
+ return cy.wrap(multipleOptions)
32
+ })
33
+ .as('multipleOptions')
34
+ .each(($option) =>
35
+ cy
36
+ .wrap($option)
37
+ .clickWith(modifierKey === 'cmd' ? 'meta' : modifierKey)
38
+ )
39
+ }
40
+ )
41
+
42
+ When(
43
+ 'the user clicks on one item with {string} which is highlighted',
44
+ (modifierKey) => {
45
+ cy.get('@highlightedMultipleOptions')
46
+ .first()
47
+ .clickWith(modifierKey === 'cmd' ? 'meta' : modifierKey)
48
+ .as('clickedOption')
49
+ cy.get('@highlightedMultipleOptions')
50
+ .filter((index) => index !== 0)
51
+ .as('remainingHighlightedOptions')
52
+ }
53
+ )
54
+
55
+ When(
56
+ 'the user clicks on one item without a modifier key which is highlighted',
57
+ () => {
58
+ cy.get('@highlightedMultipleOptions')
59
+ .first()
60
+ .click()
61
+ .as('clickedOption')
62
+ cy.get('@highlightedMultipleOptions')
63
+ .filter((index) => index !== 0)
64
+ .as('remainingHighlightedOptions')
65
+ }
66
+ )
67
+
68
+ Then('all of the clicked items should be highlighted', () => {
69
+ cy.get('@multipleOptions').each(($option) => {
70
+ expect($option).to.have.class('highlighted')
71
+ })
72
+ })
73
+
74
+ Then('the clicked item should not be highlighted', () => {
75
+ cy.get('@clickedOption').should('not.have.class', 'highlighted')
76
+ })
77
+
78
+ Then('the other previously highlighted items should remain highlighted', () => {
79
+ cy.get('@remainingHighlightedOptions').each(($option) => {
80
+ expect($option).to.have.class('highlighted')
81
+ })
82
+ })
83
+
84
+ Then('the clicked option is highlighted', () => {
85
+ cy.get('@clickedOption').should('have.class', 'highlighted')
86
+ })
87
+
88
+ Then('the other previously highlighted items should not be highlighted', () => {
89
+ cy.get('@remainingHighlightedOptions').each(($option) => {
90
+ expect($option).to.not.have.class('highlighted')
91
+ })
92
+ })
@@ -0,0 +1,41 @@
1
+ Feature: Add/Remove options to/from the highlighted options
2
+
3
+ Scenario Outline: Highlight multiple items using CMD/CTRL+click
4
+ Given the <type> list has two or more items
5
+ When the user clicks multiple items with "<metaKey>" which are not highlighted
6
+ Then all of the clicked items should be highlighted
7
+
8
+ Examples:
9
+ | type | metaKey |
10
+ | option | cmd |
11
+ | option | ctrl |
12
+ | selected | cmd |
13
+ | selected | ctrl |
14
+
15
+ Scenario Outline: Unhighlight items using CMD/CTRL+click
16
+ Given the <type> list has two or more items
17
+ And some items are highlighted
18
+ When the user clicks on one item with "<metaKey>" which is highlighted
19
+ Then the clicked item should not be highlighted
20
+ And the other previously highlighted items should remain highlighted
21
+
22
+ Examples:
23
+ | type | metaKey |
24
+ | option | cmd |
25
+ | option | ctrl |
26
+ | selected | cmd |
27
+ | selected | ctrl |
28
+
29
+ Scenario Outline: A user clicks a highlighted option without a modifier key when multiple options are highlighted
30
+ Given the <type> list has two or more items
31
+ And some items are highlighted
32
+ When the user clicks on one item without a modifier key which is highlighted
33
+ Then the clicked option is highlighted
34
+ And the other previously highlighted items should not be highlighted
35
+
36
+ Examples:
37
+ | type | metaKey |
38
+ | option | cmd |
39
+ | option | ctrl |
40
+ | selected | cmd |
41
+ | selected | ctrl |
@@ -0,0 +1,8 @@
1
+ export const extractOptionFromElement = (element) => {
2
+ const $element = Cypress.$(element)
3
+
4
+ return {
5
+ label: $element.text(),
6
+ value: $element.data('value'),
7
+ }
8
+ }
@@ -0,0 +1,118 @@
1
+ import { Given, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('the options list has items', () => {
4
+ cy.visitStory('Transfer Disabled Transfer Buttons', 'Has Options')
5
+ })
6
+
7
+ Given('the selected list has items', () => {
8
+ cy.visitStory('Transfer Disabled Transfer Buttons', 'Some Options Selected')
9
+ })
10
+
11
+ Given('the transfer does not have any options', () => {
12
+ cy.visitStory('Transfer Disabled Transfer Buttons', 'No Options')
13
+ })
14
+
15
+ Given('all options have been selected', () => {
16
+ cy.visitStory('Transfer Disabled Transfer Buttons', 'All Options Selected')
17
+ })
18
+
19
+ Given('the selected list does not have items', () => {
20
+ cy.visitStory('Transfer Disabled Transfer Buttons', 'Has Options')
21
+ })
22
+
23
+ Given('no option items are highlighted', () => {
24
+ cy.get(
25
+ '[data-test="dhis2-uicore-transfer-sourceoptions"] [data-test="dhis2-uicore-transferoption"]'
26
+ ).each(($option) =>
27
+ cy.wrap($option).should('not.have.class', 'highlighted')
28
+ )
29
+ })
30
+
31
+ Given('some option items are highlighted', () => {
32
+ cy.get(
33
+ '[data-test="dhis2-uicore-transfer-sourceoptions"] [data-test="dhis2-uicore-transferoption"]'
34
+ )
35
+ .first()
36
+ .click()
37
+ })
38
+
39
+ Given('no selected items are highlighted', () => {
40
+ cy.get(
41
+ '[data-test="dhis2-uicore-transfer-pickedoptions"] [data-test="dhis2-uicore-transferoption"]'
42
+ ).each(($option) =>
43
+ cy.wrap($option).should('not.have.class', 'highlighted')
44
+ )
45
+ })
46
+
47
+ Given('some selected items are highlighted', () => {
48
+ cy.get(
49
+ '[data-test="dhis2-uicore-transfer-pickedoptions"] [data-test="dhis2-uicore-transferoption"]'
50
+ )
51
+ .first()
52
+ .click()
53
+ })
54
+
55
+ Given('a source list that has only disabled options', () => {
56
+ cy.visitStory(
57
+ 'Transfer Disabled Transfer Buttons',
58
+ 'Only Disabled Source Options'
59
+ )
60
+ })
61
+
62
+ Then("the 'move to picked list' button should be disabled", () => {
63
+ cy.get(
64
+ '[data-test="dhis2-uicore-transfer-actions-addindividual"][disabled]'
65
+ ).should('exist')
66
+ })
67
+
68
+ Then("the 'move to picked list' button should be enabled", () => {
69
+ cy.get('[data-test="dhis2-uicore-transfer-actions-addindividual"]').should(
70
+ 'exist'
71
+ )
72
+ cy.get(
73
+ '[data-test="dhis2-uicore-transfer-actions-addindividual"][disabled]'
74
+ ).should('not.exist')
75
+ })
76
+
77
+ Then("the 'move to source list' button should be disabled", () => {
78
+ cy.get(
79
+ '[data-test="dhis2-uicore-transfer-actions-removeindividual"][disabled]'
80
+ ).should('exist')
81
+ })
82
+
83
+ Then("the 'move to source list' button should be enabled", () => {
84
+ cy.get(
85
+ '[data-test="dhis2-uicore-transfer-actions-removeindividual"]'
86
+ ).should('exist')
87
+ cy.get(
88
+ '[data-test="dhis2-uicore-transfer-actions-removeindividual"][disabled]'
89
+ ).should('not.exist')
90
+ })
91
+
92
+ Then("the 'move all to picked list' button should be disabled", () => {
93
+ cy.get(
94
+ '[data-test="dhis2-uicore-transfer-actions-addall"][disabled]'
95
+ ).should('exist')
96
+ })
97
+
98
+ Then("the 'move all to picked list' button should be enabled", () => {
99
+ cy.get('[data-test="dhis2-uicore-transfer-actions-addall"]').should('exist')
100
+ cy.get(
101
+ '[data-test="dhis2-uicore-transfer-actions-addall"][disabled]'
102
+ ).should('not.exist')
103
+ })
104
+
105
+ Then("the 'move all to source list' button should be disabled", () => {
106
+ cy.get(
107
+ '[data-test="dhis2-uicore-transfer-actions-removeall"][disabled]'
108
+ ).should('exist')
109
+ })
110
+
111
+ Then("the 'move all to source list' button should be enabled", () => {
112
+ cy.get('[data-test="dhis2-uicore-transfer-actions-removeall"]').should(
113
+ 'exist'
114
+ )
115
+ cy.get(
116
+ '[data-test="dhis2-uicore-transfer-actions-removeall"][disabled]'
117
+ ).should('not.exist')
118
+ })
@@ -0,0 +1,46 @@
1
+ @component-transfer @button-states
2
+ Feature: Disable transfer buttons when actions are not possible
3
+
4
+ Scenario: None of the selectable options are highlighted
5
+ Given the options list has items
6
+ And no option items are highlighted
7
+ Then the 'move to picked list' button should be disabled
8
+
9
+ Scenario: Some of the selectable options are highlighted
10
+ Given the options list has items
11
+ And some option items are highlighted
12
+ Then the 'move to picked list' button should be enabled
13
+
14
+ Scenario: None of the selected options are highlighted
15
+ Given the selected list has items
16
+ And no selected items are highlighted
17
+ Then the 'move to source list' button should be disabled
18
+
19
+ Scenario: Some of the selected options are highlighted
20
+ Given the selected list has items
21
+ And some selected items are highlighted
22
+ Then the 'move to source list' button should be enabled
23
+
24
+ Scenario: The transfer does not have any options at all
25
+ Given the transfer does not have any options
26
+ Then the 'move all to picked list' button should be disabled
27
+
28
+ Scenario: All options are on the selected side
29
+ Given all options have been selected
30
+ Then the 'move all to picked list' button should be disabled
31
+
32
+ Scenario: Some items in options list
33
+ Given the options list has items
34
+ Then the 'move all to picked list' button should be enabled
35
+
36
+ Scenario: No items in selected list
37
+ Given the selected list does not have items
38
+ Then the 'move all to source list' button should be disabled
39
+
40
+ Scenario: Some items in selected list
41
+ Given the selected list has items
42
+ Then the 'move all to source list' button should be enabled
43
+
44
+ Scenario: Only disabled options in source list
45
+ Given a source list that has only disabled options
46
+ Then the 'move all to picked list' button should be disabled
@@ -0,0 +1,182 @@
1
+ import { Given, When, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+ import { extractOptionFromElement } from '../common/index.js'
3
+
4
+ const enabledSourceOptionSelector =
5
+ '{transfer-sourceoptions} {transferoption}:not(.disabled)'
6
+
7
+ const disabledSourceOptionSelector =
8
+ '{transfer-sourceoptions} {transferoption}.disabled'
9
+
10
+ Given('a source list that contains a disabled option', () => {
11
+ cy.visitStory('Disabled Source Options', 'One Disabled')
12
+ cy.get(disabledSourceOptionSelector)
13
+ .first()
14
+ .as('disabledSourceOption')
15
+ .should('exist')
16
+ })
17
+
18
+ Given(
19
+ 'a source list that contains at least one disabled option and at least one enabled option',
20
+ () => {
21
+ cy.visitStory('Disabled Source Options', 'One Disabled')
22
+ cy.get(disabledSourceOptionSelector)
23
+ .first()
24
+ .as('disabledSourceOption')
25
+ .should('exist')
26
+ cy.get(enabledSourceOptionSelector)
27
+ .as('enabledSourceOptions')
28
+ .should('exist')
29
+ }
30
+ )
31
+
32
+ Given(
33
+ 'a source list that contains at least one disabled option and at least one enabled highlighted option',
34
+ () => {
35
+ cy.visitStory('Disabled Source Options', 'One Disabled')
36
+ cy.get(disabledSourceOptionSelector)
37
+ .first()
38
+ .as('disabledSourceOption')
39
+ .should('exist')
40
+ cy.get(enabledSourceOptionSelector)
41
+ .invoke('slice', 0, 2)
42
+ .as('enabledHighlightedSourceOptions')
43
+ .each(($option) => cy.wrap($option).click())
44
+ .should('have.class', 'highlighted')
45
+ }
46
+ )
47
+
48
+ Given(
49
+ 'a source list that contains at least one disabled option and several enabled options',
50
+ () => {
51
+ cy.visitStory('Disabled Source Options', 'One Disabled')
52
+ cy.get(disabledSourceOptionSelector)
53
+ .first()
54
+ .as('disabledSourceOption')
55
+ .should('exist')
56
+ cy.get(enabledSourceOptionSelector)
57
+ .as('enabledSourceOptions')
58
+ .should('have.length.of.at.least', 2)
59
+ }
60
+ )
61
+
62
+ When('the user clicks a disabled option', () => {
63
+ cy.get(disabledSourceOptionSelector).click().as('clickedDisabledOption')
64
+ })
65
+
66
+ When('the user double clicks a disabled option', () => {
67
+ cy.get(disabledSourceOptionSelector)
68
+ .dblclick()
69
+ .as('doubleClickedDisabledOption')
70
+ })
71
+
72
+ When("the user clicks the 'move all to picked list' button", () => {
73
+ cy.get('{transfer-actions-addall}').click()
74
+ })
75
+
76
+ When('the user clicks the disabled item with {string}', (type) => {
77
+ cy.get(disabledSourceOptionSelector)
78
+ .clickWith(type)
79
+ .as('clickedWithModifierDisabledOption')
80
+ })
81
+
82
+ When('the user SHIFT+clicks the disabled item', () => {
83
+ cy.get(disabledSourceOptionSelector)
84
+ .clickWith('shift')
85
+ .as('clickedWithShiftDisabledOption')
86
+ })
87
+
88
+ When('the user clicks an enabled option', () => {
89
+ cy.get(enabledSourceOptionSelector)
90
+ .first()
91
+ .click()
92
+ .as('clickedEnabledOption')
93
+ })
94
+
95
+ When(
96
+ 'SHIFT+clicks another enabled option, including a disabled item in the range of options',
97
+ () => {
98
+ cy.get(disabledSourceOptionSelector)
99
+ .next()
100
+ .clickWith('shift')
101
+ .as('clickedWithShiftEnabledOption')
102
+ }
103
+ )
104
+
105
+ Then('the disabled option is not highlighted', () => {
106
+ cy.get('@disabledSourceOption').should('not.have.class', 'highlighted')
107
+ })
108
+
109
+ Then('the disabled option is not transferred to the picked list', () => {
110
+ // if the aliased element still exists, it hasn't been removed
111
+ // from the source list. Transferring does not need to be tested
112
+ // here as that's covered by another test
113
+ cy.get('@disabledSourceOption').should('exist')
114
+ })
115
+
116
+ Then('the disabled options are not transferred to the picked list', () => {
117
+ // if the aliased element still exists, it hasn't been removed
118
+ // from the source list. Transferring does not need to be tested
119
+ // here as that's covered by another test
120
+ cy.get('@disabledSourceOption').should('exist')
121
+ })
122
+
123
+ Then('the enabled options are transferred to the picked list', () => {
124
+ // if the aliased elements don't exist, it hasn't been removed
125
+ // from the source list. Transferring does not need to be tested
126
+ // here as that's covered by another test
127
+ cy.get('@enabledSourceOptions').should('not.exist')
128
+ })
129
+
130
+ Then('the previously highlighted items are still highlighted', () => {
131
+ cy.get('@enabledHighlightedSourceOptions').should(
132
+ 'have.class',
133
+ 'highlighted'
134
+ )
135
+ })
136
+
137
+ Then('only the previously highlighted items are highlighted', () => {
138
+ cy.get('@enabledHighlightedSourceOptions').should(
139
+ 'have.class',
140
+ 'highlighted'
141
+ )
142
+
143
+ cy.all(
144
+ () => cy.get('{transfer-sourceoptions} {transferoption}'),
145
+ () => cy.get('@enabledHighlightedSourceOptions')
146
+ ).should(([$sourceOptions, $previouslyHighlightedOptions]) => {
147
+ const previouslyHighlightedOptions = $previouslyHighlightedOptions
148
+ .toArray()
149
+ .map(extractOptionFromElement)
150
+
151
+ const $notHighlightedSourceOptions = $sourceOptions.filter(
152
+ (_index, sourceOptionEl) => {
153
+ const label = sourceOptionEl.innerText
154
+ const value = sourceOptionEl.dataset.value
155
+ !previouslyHighlightedOptions.find(
156
+ (option) => value === option.value && label === option.label
157
+ )
158
+ }
159
+ )
160
+
161
+ $notHighlightedSourceOptions.each((_index, option) => {
162
+ cy.wrap(option).should('not.have.class', 'highlighted')
163
+ })
164
+ })
165
+ })
166
+
167
+ Then('the enabled options in the range are highlighted', () => {
168
+ cy.all(
169
+ () => cy.get('{transfer-sourceoptions} {transferoption}'),
170
+ () => cy.get('@clickedEnabledOption'),
171
+ () => cy.get('@clickedWithShiftEnabledOption')
172
+ ).should(
173
+ ([$all, $clickedEnabledOption, $clickedWithShiftEnabledOption]) => {
174
+ const from = $clickedEnabledOption.index()
175
+ const to = $clickedWithShiftEnabledOption.index()
176
+ const $allInRange = $all.slice(from, to + 1)
177
+ const $allInRangeEnabled = $allInRange.filter(':not(.disabled)')
178
+
179
+ expect($allInRangeEnabled).to.have.class('highlighted')
180
+ }
181
+ )
182
+ })
@@ -0,0 +1,42 @@
1
+ @component-transfer @disabled-options
2
+ Feature: Options can be disabled
3
+
4
+ Scenario: The user clicks a disabled option
5
+ Given a source list that contains a disabled option
6
+ When the user clicks a disabled option
7
+ Then the disabled option is not highlighted
8
+
9
+ Scenario: The user double clicks a disabled option
10
+ Given a source list that contains a disabled option
11
+ When the user double clicks a disabled option
12
+ Then the disabled option is not transferred to the picked list
13
+
14
+ Scenario: The user clicks the 'move all to picked list' button with disabled options in the source list
15
+ Given a source list that contains at least one disabled option and at least one enabled option
16
+ When the user clicks the 'move all to picked list' button
17
+ Then the disabled options are not transferred to the picked list
18
+ And the enabled options are transferred to the picked list
19
+
20
+ Scenario Outline: The user CMD/CTRL+clicks a disabled item with other items highlighted
21
+ Given a source list that contains at least one disabled option and at least one enabled highlighted option
22
+ When the user clicks the disabled item with "<type>"
23
+ Then the disabled option is not highlighted
24
+ And the previously highlighted items are still highlighted
25
+
26
+ Examples:
27
+ | type |
28
+ | ctrl |
29
+ | cmd |
30
+
31
+ Scenario: The user SHIFT+clicks a disabled item with other items highlighted
32
+ Given a source list that contains at least one disabled option and at least one enabled highlighted option
33
+ When the user SHIFT+clicks the disabled item
34
+ Then the disabled option is not highlighted
35
+ And only the previously highlighted items are highlighted
36
+
37
+ Scenario: The user SHIFT+clicks to select a range of options that include a disabled option
38
+ Given a source list that contains at least one disabled option and several enabled options
39
+ When the user clicks an enabled option
40
+ And SHIFT+clicks another enabled option, including a disabled item in the range of options
41
+ Then the enabled options in the range are highlighted
42
+ And the disabled option is not highlighted