@dhis2-ui/transfer 10.13.1 → 10.14.0

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 (53) hide show
  1. package/build/cjs/__e2e__/reorder-with-buttons.e2e.stories.js +15 -4
  2. package/build/cjs/__tests__/helper/default-filter-callback.test.js +6 -0
  3. package/build/cjs/__tests__/helper/is-reorder-down-disabled.test.js +50 -11
  4. package/build/cjs/__tests__/helper/is-reorder-up-disabled.test.js +50 -11
  5. package/build/cjs/__tests__/helper/move-highlighted-picked-option-down.test.js +65 -11
  6. package/build/cjs/__tests__/helper/move-highlighted-picked-option-to-bottom.test.js +85 -0
  7. package/build/cjs/__tests__/helper/move-highlighted-picked-option-to-top.test.js +85 -0
  8. package/build/cjs/__tests__/helper/move-highlighted-picked-option-up.test.js +65 -11
  9. package/build/cjs/__tests__/reordering-actions.test.js +104 -0
  10. package/build/cjs/features/reorder-with-buttons/index.js +70 -2
  11. package/build/cjs/features/reorder-with-buttons.feature +97 -5
  12. package/build/cjs/icons.js +53 -13
  13. package/build/cjs/locales/en/translations.json +7 -0
  14. package/build/cjs/locales/index.js +21 -0
  15. package/build/cjs/reordering-actions.js +93 -27
  16. package/build/cjs/transfer/default-filter-callback.js +17 -6
  17. package/build/cjs/transfer/get-highlighted-picked-indices.js +34 -0
  18. package/build/cjs/transfer/index.js +33 -0
  19. package/build/cjs/transfer/is-reorder-down-disabled.js +19 -8
  20. package/build/cjs/transfer/is-reorder-up-disabled.js +18 -8
  21. package/build/cjs/transfer/move-highlighted-picked-option-down.js +23 -6
  22. package/build/cjs/transfer/move-highlighted-picked-option-to-bottom.js +45 -0
  23. package/build/cjs/transfer/move-highlighted-picked-option-to-top.js +44 -0
  24. package/build/cjs/transfer/move-highlighted-picked-option-up.js +21 -6
  25. package/build/cjs/transfer.js +58 -6
  26. package/build/cjs/transfer.prod.stories.js +89 -19
  27. package/build/es/__e2e__/reorder-with-buttons.e2e.stories.js +14 -2
  28. package/build/es/__tests__/helper/default-filter-callback.test.js +6 -0
  29. package/build/es/__tests__/helper/is-reorder-down-disabled.test.js +50 -11
  30. package/build/es/__tests__/helper/is-reorder-up-disabled.test.js +50 -11
  31. package/build/es/__tests__/helper/move-highlighted-picked-option-down.test.js +65 -11
  32. package/build/es/__tests__/helper/move-highlighted-picked-option-to-bottom.test.js +83 -0
  33. package/build/es/__tests__/helper/move-highlighted-picked-option-to-top.test.js +83 -0
  34. package/build/es/__tests__/helper/move-highlighted-picked-option-up.test.js +65 -11
  35. package/build/es/__tests__/reordering-actions.test.js +101 -0
  36. package/build/es/features/reorder-with-buttons/index.js +70 -2
  37. package/build/es/features/reorder-with-buttons.feature +97 -5
  38. package/build/es/icons.js +51 -13
  39. package/build/es/locales/en/translations.json +7 -0
  40. package/build/es/locales/index.js +13 -0
  41. package/build/es/reordering-actions.js +94 -28
  42. package/build/es/transfer/default-filter-callback.js +17 -6
  43. package/build/es/transfer/get-highlighted-picked-indices.js +27 -0
  44. package/build/es/transfer/index.js +3 -0
  45. package/build/es/transfer/is-reorder-down-disabled.js +20 -8
  46. package/build/es/transfer/is-reorder-up-disabled.js +19 -8
  47. package/build/es/transfer/move-highlighted-picked-option-down.js +24 -6
  48. package/build/es/transfer/move-highlighted-picked-option-to-bottom.js +39 -0
  49. package/build/es/transfer/move-highlighted-picked-option-to-top.js +38 -0
  50. package/build/es/transfer/move-highlighted-picked-option-up.js +22 -6
  51. package/build/es/transfer.js +60 -8
  52. package/build/es/transfer.prod.stories.js +88 -18
  53. package/package.json +9 -7
@@ -37,4 +37,10 @@ describe('Transfer - defaultFilterCallback', () => {
37
37
  const actual = defaultFilterCallback(options, filter);
38
38
  expect(actual).toEqual(expected);
39
39
  });
40
+ it('should return all options when the filter is invalid regexp', () => {
41
+ const filter = '(';
42
+ const expected = options;
43
+ const actual = defaultFilterCallback(options, filter);
44
+ expect(actual).toEqual(expected);
45
+ });
40
46
  });
@@ -2,35 +2,74 @@ import { isReorderDownDisabled } from '../../transfer/is-reorder-down-disabled.j
2
2
  describe('Transfer - isReorderDownDisabled', () => {
3
3
  const selected = ['foo', 'bar', 'baz'];
4
4
  it('should return true when there are no highlighted picked options', () => {
5
- const highlightedPickedOptions = [];
6
5
  const actual = isReorderDownDisabled({
7
- highlightedPickedOptions,
6
+ highlightedPickedOptions: [],
8
7
  selected
9
8
  });
10
9
  expect(actual).toBe(true);
11
10
  });
12
- it('should return true when there are multiple highlighted picked options', () => {
13
- const highlightedPickedOptions = ['bar', 'foo'];
11
+ it('should return true if the last picked option is the only highlighted one', () => {
14
12
  const actual = isReorderDownDisabled({
15
- highlightedPickedOptions,
13
+ highlightedPickedOptions: ['baz'],
16
14
  selected
17
15
  });
18
16
  expect(actual).toBe(true);
19
17
  });
20
- it('should return true if the last picked option is highlighted', () => {
21
- const highlightedPickedOptions = ['baz'];
18
+ it('should return false when one picked option is highlighted which is not the last one', () => {
19
+ const actual = isReorderDownDisabled({
20
+ highlightedPickedOptions: ['bar'],
21
+ selected
22
+ });
23
+ expect(actual).toBe(false);
24
+ });
25
+ it('should return false for a contiguous multi-select not flush to the bottom', () => {
26
+ const actual = isReorderDownDisabled({
27
+ highlightedPickedOptions: ['foo', 'bar'],
28
+ selected
29
+ });
30
+ expect(actual).toBe(false);
31
+ });
32
+ it('should return true for a contiguous multi-select flush to the bottom', () => {
22
33
  const actual = isReorderDownDisabled({
23
- highlightedPickedOptions,
34
+ highlightedPickedOptions: ['bar', 'baz'],
24
35
  selected
25
36
  });
26
37
  expect(actual).toBe(true);
27
38
  });
28
- it('should return false when one picked option is highlighted which is not the last one', () => {
29
- const highlightedPickedOptions = ['bar'];
39
+ it('should return true when all items are highlighted', () => {
30
40
  const actual = isReorderDownDisabled({
31
- highlightedPickedOptions,
41
+ highlightedPickedOptions: ['foo', 'bar', 'baz'],
42
+ selected
43
+ });
44
+ expect(actual).toBe(true);
45
+ });
46
+ it('should return false for a non-contiguous selection containing the last item', () => {
47
+ const actual = isReorderDownDisabled({
48
+ highlightedPickedOptions: ['foo', 'baz'],
49
+ selected
50
+ });
51
+ expect(actual).toBe(false);
52
+ });
53
+ it('should ignore highlighted values that do not exist in selected', () => {
54
+ const actual = isReorderDownDisabled({
55
+ highlightedPickedOptions: ['ghost', 'foo'],
32
56
  selected
33
57
  });
34
58
  expect(actual).toBe(false);
35
59
  });
60
+ it('should return true when all highlighted values are missing from selected', () => {
61
+ const actual = isReorderDownDisabled({
62
+ highlightedPickedOptions: ['ghost'],
63
+ selected
64
+ });
65
+ expect(actual).toBe(true);
66
+ });
67
+ it('should return true when a filter is active on the picked side', () => {
68
+ const actual = isReorderDownDisabled({
69
+ highlightedPickedOptions: ['foo'],
70
+ selected,
71
+ filterActivePicked: true
72
+ });
73
+ expect(actual).toBe(true);
74
+ });
36
75
  });
@@ -2,35 +2,74 @@ import { isReorderUpDisabled } from '../../transfer/is-reorder-up-disabled.js';
2
2
  describe('Transfer - isReorderUpDisabled', () => {
3
3
  const selected = ['foo', 'bar', 'baz'];
4
4
  it('should return true when there are no highlighted picked options', () => {
5
- const highlightedPickedOptions = [];
6
5
  const actual = isReorderUpDisabled({
7
- highlightedPickedOptions,
6
+ highlightedPickedOptions: [],
8
7
  selected
9
8
  });
10
9
  expect(actual).toBe(true);
11
10
  });
12
- it('should return true when there are multiple highlighted picked options', () => {
13
- const highlightedPickedOptions = ['bar', 'baz'];
11
+ it('should return true if the first picked option is the only highlighted one', () => {
14
12
  const actual = isReorderUpDisabled({
15
- highlightedPickedOptions,
13
+ highlightedPickedOptions: ['foo'],
16
14
  selected
17
15
  });
18
16
  expect(actual).toBe(true);
19
17
  });
20
- it('should return true if the first picked option is highlighted', () => {
21
- const highlightedPickedOptions = ['foo'];
18
+ it('should return false when one picked option is highlighted which is not the first one', () => {
22
19
  const actual = isReorderUpDisabled({
23
- highlightedPickedOptions,
20
+ highlightedPickedOptions: ['baz'],
21
+ selected
22
+ });
23
+ expect(actual).toBe(false);
24
+ });
25
+ it('should return false for a contiguous multi-select not flush to the top', () => {
26
+ const actual = isReorderUpDisabled({
27
+ highlightedPickedOptions: ['bar', 'baz'],
28
+ selected
29
+ });
30
+ expect(actual).toBe(false);
31
+ });
32
+ it('should return true for a contiguous multi-select flush to the top', () => {
33
+ const actual = isReorderUpDisabled({
34
+ highlightedPickedOptions: ['foo', 'bar'],
35
+ selected
36
+ });
37
+ expect(actual).toBe(true);
38
+ });
39
+ it('should return true when all items are highlighted', () => {
40
+ const actual = isReorderUpDisabled({
41
+ highlightedPickedOptions: ['foo', 'bar', 'baz'],
24
42
  selected
25
43
  });
26
44
  expect(actual).toBe(true);
27
45
  });
28
- it('should return false when one picked option is highlighted which is not the last one', () => {
29
- const highlightedPickedOptions = ['baz'];
46
+ it('should return false for a non-contiguous selection containing the first item', () => {
30
47
  const actual = isReorderUpDisabled({
31
- highlightedPickedOptions,
48
+ highlightedPickedOptions: ['foo', 'baz'],
32
49
  selected
33
50
  });
34
51
  expect(actual).toBe(false);
35
52
  });
53
+ it('should ignore highlighted values that do not exist in selected', () => {
54
+ const actual = isReorderUpDisabled({
55
+ highlightedPickedOptions: ['ghost', 'baz'],
56
+ selected
57
+ });
58
+ expect(actual).toBe(false);
59
+ });
60
+ it('should return true when all highlighted values are missing from selected', () => {
61
+ const actual = isReorderUpDisabled({
62
+ highlightedPickedOptions: ['ghost'],
63
+ selected
64
+ });
65
+ expect(actual).toBe(true);
66
+ });
67
+ it('should return true when a filter is active on the picked side', () => {
68
+ const actual = isReorderUpDisabled({
69
+ highlightedPickedOptions: ['baz'],
70
+ selected,
71
+ filterActivePicked: true
72
+ });
73
+ expect(actual).toBe(true);
74
+ });
36
75
  });
@@ -1,15 +1,13 @@
1
1
  import { moveHighlightedPickedOptionDown } from '../../transfer/move-highlighted-picked-option-down.js';
2
2
  describe('Transfer - moveHighlightedPickedOptionDown', () => {
3
3
  const onChange = jest.fn();
4
- const selected = ['foo', 'bar', 'baz'];
5
4
  afterEach(() => {
6
5
  onChange.mockClear();
7
6
  });
8
- it('should move the highlighted option down', () => {
9
- const highlighted = ['bar'];
7
+ it('should move a single highlighted option down', () => {
10
8
  moveHighlightedPickedOptionDown({
11
- selected,
12
- highlightedPickedOptions: highlighted,
9
+ selected: ['foo', 'bar', 'baz'],
10
+ highlightedPickedOptions: ['bar'],
13
11
  onChange
14
12
  });
15
13
  expect(onChange).toHaveBeenCalledWith({
@@ -17,21 +15,77 @@ describe('Transfer - moveHighlightedPickedOptionDown', () => {
17
15
  });
18
16
  });
19
17
  it('should do nothing when trying to move down the last option', () => {
20
- const highlighted = ['baz'];
21
18
  moveHighlightedPickedOptionDown({
22
- selected,
23
- highlightedPickedOptions: highlighted,
19
+ selected: ['foo', 'bar', 'baz'],
20
+ highlightedPickedOptions: ['baz'],
24
21
  onChange
25
22
  });
26
23
  expect(onChange).toHaveBeenCalledTimes(0);
27
24
  });
28
25
  it('should do nothing when trying to move down a non-existing option', () => {
29
- const highlighted = ['foobar'];
30
26
  moveHighlightedPickedOptionDown({
31
- selected,
32
- highlightedPickedOptions: highlighted,
27
+ selected: ['foo', 'bar', 'baz'],
28
+ highlightedPickedOptions: ['ghost'],
33
29
  onChange
34
30
  });
35
31
  expect(onChange).toHaveBeenCalledTimes(0);
36
32
  });
33
+ it('should shift a contiguous block of highlighted options down as a group', () => {
34
+ moveHighlightedPickedOptionDown({
35
+ selected: ['a', 'b', 'c', 'd', 'e'],
36
+ highlightedPickedOptions: ['b', 'c'],
37
+ onChange
38
+ });
39
+ expect(onChange).toHaveBeenCalledWith({
40
+ selected: ['a', 'd', 'b', 'c', 'e']
41
+ });
42
+ });
43
+ it('should collapse and shift a non-contiguous selection down in one call', () => {
44
+ moveHighlightedPickedOptionDown({
45
+ selected: ['a', 'b', 'c', 'd', 'e'],
46
+ highlightedPickedOptions: ['b', 'd'],
47
+ onChange
48
+ });
49
+ expect(onChange).toHaveBeenCalledWith({
50
+ selected: ['a', 'c', 'e', 'b', 'd']
51
+ });
52
+ });
53
+ it('should preserve the relative order of highlighted items regardless of input order', () => {
54
+ moveHighlightedPickedOptionDown({
55
+ selected: ['a', 'b', 'c', 'd', 'e'],
56
+ highlightedPickedOptions: ['d', 'b'],
57
+ onChange
58
+ });
59
+ expect(onChange).toHaveBeenCalledWith({
60
+ selected: ['a', 'c', 'e', 'b', 'd']
61
+ });
62
+ });
63
+ it('should collapse a non-contiguous selection containing the last item without shifting past the end', () => {
64
+ moveHighlightedPickedOptionDown({
65
+ selected: ['a', 'b', 'c'],
66
+ highlightedPickedOptions: ['a', 'c'],
67
+ onChange
68
+ });
69
+ expect(onChange).toHaveBeenCalledWith({
70
+ selected: ['b', 'a', 'c']
71
+ });
72
+ });
73
+ it('should do nothing when the highlighted block is already flush to the bottom', () => {
74
+ moveHighlightedPickedOptionDown({
75
+ selected: ['a', 'b', 'c', 'd'],
76
+ highlightedPickedOptions: ['c', 'd'],
77
+ onChange
78
+ });
79
+ expect(onChange).toHaveBeenCalledTimes(0);
80
+ });
81
+ it('should ignore highlighted values that do not exist in selected', () => {
82
+ moveHighlightedPickedOptionDown({
83
+ selected: ['a', 'b', 'c'],
84
+ highlightedPickedOptions: ['ghost', 'a'],
85
+ onChange
86
+ });
87
+ expect(onChange).toHaveBeenCalledWith({
88
+ selected: ['b', 'a', 'c']
89
+ });
90
+ });
37
91
  });
@@ -0,0 +1,83 @@
1
+ import { moveHighlightedPickedOptionToBottom } from '../../transfer/move-highlighted-picked-option-to-bottom.js';
2
+ describe('Transfer - moveHighlightedPickedOptionToBottom', () => {
3
+ const onChange = jest.fn();
4
+ afterEach(() => {
5
+ onChange.mockClear();
6
+ });
7
+ it('should move a single highlighted option to the bottom', () => {
8
+ moveHighlightedPickedOptionToBottom({
9
+ selected: ['a', 'b', 'c', 'd'],
10
+ highlightedPickedOptions: ['b'],
11
+ onChange
12
+ });
13
+ expect(onChange).toHaveBeenCalledWith({
14
+ selected: ['a', 'c', 'd', 'b']
15
+ });
16
+ });
17
+ it('should move a contiguous block to the bottom as a group', () => {
18
+ moveHighlightedPickedOptionToBottom({
19
+ selected: ['a', 'b', 'c', 'd', 'e'],
20
+ highlightedPickedOptions: ['b', 'c'],
21
+ onChange
22
+ });
23
+ expect(onChange).toHaveBeenCalledWith({
24
+ selected: ['a', 'd', 'e', 'b', 'c']
25
+ });
26
+ });
27
+ it('should collapse a non-contiguous selection to the bottom preserving relative order', () => {
28
+ moveHighlightedPickedOptionToBottom({
29
+ selected: ['a', 'b', 'c', 'd', 'e'],
30
+ highlightedPickedOptions: ['b', 'd'],
31
+ onChange
32
+ });
33
+ expect(onChange).toHaveBeenCalledWith({
34
+ selected: ['a', 'c', 'e', 'b', 'd']
35
+ });
36
+ });
37
+ it('should preserve relative order regardless of highlight input order', () => {
38
+ moveHighlightedPickedOptionToBottom({
39
+ selected: ['a', 'b', 'c', 'd', 'e'],
40
+ highlightedPickedOptions: ['d', 'b'],
41
+ onChange
42
+ });
43
+ expect(onChange).toHaveBeenCalledWith({
44
+ selected: ['a', 'c', 'e', 'b', 'd']
45
+ });
46
+ });
47
+ it('should do nothing when the highlighted block is already flush to the bottom', () => {
48
+ moveHighlightedPickedOptionToBottom({
49
+ selected: ['a', 'b', 'c', 'd'],
50
+ highlightedPickedOptions: ['c', 'd'],
51
+ onChange
52
+ });
53
+ expect(onChange).toHaveBeenCalledTimes(0);
54
+ });
55
+ it('should still run when the selection includes the bottom item but has a gap', () => {
56
+ moveHighlightedPickedOptionToBottom({
57
+ selected: ['a', 'b', 'c', 'd'],
58
+ highlightedPickedOptions: ['b', 'd'],
59
+ onChange
60
+ });
61
+ expect(onChange).toHaveBeenCalledWith({
62
+ selected: ['a', 'c', 'b', 'd']
63
+ });
64
+ });
65
+ it('should do nothing when no highlighted options exist in selected', () => {
66
+ moveHighlightedPickedOptionToBottom({
67
+ selected: ['a', 'b', 'c'],
68
+ highlightedPickedOptions: ['ghost'],
69
+ onChange
70
+ });
71
+ expect(onChange).toHaveBeenCalledTimes(0);
72
+ });
73
+ it('should ignore highlighted values that do not exist in selected', () => {
74
+ moveHighlightedPickedOptionToBottom({
75
+ selected: ['a', 'b', 'c'],
76
+ highlightedPickedOptions: ['ghost', 'a'],
77
+ onChange
78
+ });
79
+ expect(onChange).toHaveBeenCalledWith({
80
+ selected: ['b', 'c', 'a']
81
+ });
82
+ });
83
+ });
@@ -0,0 +1,83 @@
1
+ import { moveHighlightedPickedOptionToTop } from '../../transfer/move-highlighted-picked-option-to-top.js';
2
+ describe('Transfer - moveHighlightedPickedOptionToTop', () => {
3
+ const onChange = jest.fn();
4
+ afterEach(() => {
5
+ onChange.mockClear();
6
+ });
7
+ it('should move a single highlighted option to the top', () => {
8
+ moveHighlightedPickedOptionToTop({
9
+ selected: ['a', 'b', 'c', 'd'],
10
+ highlightedPickedOptions: ['c'],
11
+ onChange
12
+ });
13
+ expect(onChange).toHaveBeenCalledWith({
14
+ selected: ['c', 'a', 'b', 'd']
15
+ });
16
+ });
17
+ it('should move a contiguous block to the top as a group', () => {
18
+ moveHighlightedPickedOptionToTop({
19
+ selected: ['a', 'b', 'c', 'd', 'e'],
20
+ highlightedPickedOptions: ['c', 'd'],
21
+ onChange
22
+ });
23
+ expect(onChange).toHaveBeenCalledWith({
24
+ selected: ['c', 'd', 'a', 'b', 'e']
25
+ });
26
+ });
27
+ it('should collapse a non-contiguous selection to the top preserving relative order', () => {
28
+ moveHighlightedPickedOptionToTop({
29
+ selected: ['a', 'b', 'c', 'd', 'e'],
30
+ highlightedPickedOptions: ['b', 'd'],
31
+ onChange
32
+ });
33
+ expect(onChange).toHaveBeenCalledWith({
34
+ selected: ['b', 'd', 'a', 'c', 'e']
35
+ });
36
+ });
37
+ it('should preserve relative order regardless of highlight input order', () => {
38
+ moveHighlightedPickedOptionToTop({
39
+ selected: ['a', 'b', 'c', 'd', 'e'],
40
+ highlightedPickedOptions: ['d', 'b'],
41
+ onChange
42
+ });
43
+ expect(onChange).toHaveBeenCalledWith({
44
+ selected: ['b', 'd', 'a', 'c', 'e']
45
+ });
46
+ });
47
+ it('should do nothing when the highlighted block is already flush to the top', () => {
48
+ moveHighlightedPickedOptionToTop({
49
+ selected: ['a', 'b', 'c', 'd'],
50
+ highlightedPickedOptions: ['a', 'b'],
51
+ onChange
52
+ });
53
+ expect(onChange).toHaveBeenCalledTimes(0);
54
+ });
55
+ it('should still run when the selection includes the top item but has a gap', () => {
56
+ moveHighlightedPickedOptionToTop({
57
+ selected: ['a', 'b', 'c', 'd'],
58
+ highlightedPickedOptions: ['a', 'c'],
59
+ onChange
60
+ });
61
+ expect(onChange).toHaveBeenCalledWith({
62
+ selected: ['a', 'c', 'b', 'd']
63
+ });
64
+ });
65
+ it('should do nothing when no highlighted options exist in selected', () => {
66
+ moveHighlightedPickedOptionToTop({
67
+ selected: ['a', 'b', 'c'],
68
+ highlightedPickedOptions: ['ghost'],
69
+ onChange
70
+ });
71
+ expect(onChange).toHaveBeenCalledTimes(0);
72
+ });
73
+ it('should ignore highlighted values that do not exist in selected', () => {
74
+ moveHighlightedPickedOptionToTop({
75
+ selected: ['a', 'b', 'c'],
76
+ highlightedPickedOptions: ['ghost', 'c'],
77
+ onChange
78
+ });
79
+ expect(onChange).toHaveBeenCalledWith({
80
+ selected: ['c', 'a', 'b']
81
+ });
82
+ });
83
+ });
@@ -1,15 +1,13 @@
1
1
  import { moveHighlightedPickedOptionUp } from '../../transfer/move-highlighted-picked-option-up.js';
2
2
  describe('Transfer - moveHighlightedPickedOptionUp', () => {
3
3
  const onChange = jest.fn();
4
- const selected = ['foo', 'bar', 'baz'];
5
4
  afterEach(() => {
6
5
  onChange.mockClear();
7
6
  });
8
- it('should move the highlighted option up', () => {
9
- const highlighted = ['bar'];
7
+ it('should move a single highlighted option up', () => {
10
8
  moveHighlightedPickedOptionUp({
11
- selected,
12
- highlightedPickedOptions: highlighted,
9
+ selected: ['foo', 'bar', 'baz'],
10
+ highlightedPickedOptions: ['bar'],
13
11
  onChange
14
12
  });
15
13
  expect(onChange).toHaveBeenCalledWith({
@@ -17,21 +15,77 @@ describe('Transfer - moveHighlightedPickedOptionUp', () => {
17
15
  });
18
16
  });
19
17
  it('should do nothing when trying to move up the first option', () => {
20
- const highlighted = ['foo'];
21
18
  moveHighlightedPickedOptionUp({
22
- selected,
23
- highlightedPickedOptions: highlighted,
19
+ selected: ['foo', 'bar', 'baz'],
20
+ highlightedPickedOptions: ['foo'],
24
21
  onChange
25
22
  });
26
23
  expect(onChange).toHaveBeenCalledTimes(0);
27
24
  });
28
25
  it('should do nothing when trying to move up a non-existing option', () => {
29
- const highlighted = ['foobar'];
30
26
  moveHighlightedPickedOptionUp({
31
- selected,
32
- highlightedPickedOptions: highlighted,
27
+ selected: ['foo', 'bar', 'baz'],
28
+ highlightedPickedOptions: ['ghost'],
33
29
  onChange
34
30
  });
35
31
  expect(onChange).toHaveBeenCalledTimes(0);
36
32
  });
33
+ it('should shift a contiguous block of highlighted options up as a group', () => {
34
+ moveHighlightedPickedOptionUp({
35
+ selected: ['a', 'b', 'c', 'd', 'e'],
36
+ highlightedPickedOptions: ['c', 'd'],
37
+ onChange
38
+ });
39
+ expect(onChange).toHaveBeenCalledWith({
40
+ selected: ['a', 'c', 'd', 'b', 'e']
41
+ });
42
+ });
43
+ it('should collapse and shift a non-contiguous selection up in one call', () => {
44
+ moveHighlightedPickedOptionUp({
45
+ selected: ['a', 'b', 'c', 'd', 'e'],
46
+ highlightedPickedOptions: ['b', 'd'],
47
+ onChange
48
+ });
49
+ expect(onChange).toHaveBeenCalledWith({
50
+ selected: ['b', 'd', 'a', 'c', 'e']
51
+ });
52
+ });
53
+ it('should preserve the relative order of highlighted items regardless of input order', () => {
54
+ moveHighlightedPickedOptionUp({
55
+ selected: ['a', 'b', 'c', 'd', 'e'],
56
+ highlightedPickedOptions: ['d', 'b'],
57
+ onChange
58
+ });
59
+ expect(onChange).toHaveBeenCalledWith({
60
+ selected: ['b', 'd', 'a', 'c', 'e']
61
+ });
62
+ });
63
+ it('should collapse a non-contiguous selection containing the first item without shifting past index 0', () => {
64
+ moveHighlightedPickedOptionUp({
65
+ selected: ['a', 'b', 'c'],
66
+ highlightedPickedOptions: ['a', 'c'],
67
+ onChange
68
+ });
69
+ expect(onChange).toHaveBeenCalledWith({
70
+ selected: ['a', 'c', 'b']
71
+ });
72
+ });
73
+ it('should do nothing when the highlighted block is already flush to the top', () => {
74
+ moveHighlightedPickedOptionUp({
75
+ selected: ['a', 'b', 'c', 'd'],
76
+ highlightedPickedOptions: ['a', 'b'],
77
+ onChange
78
+ });
79
+ expect(onChange).toHaveBeenCalledTimes(0);
80
+ });
81
+ it('should ignore highlighted values that do not exist in selected', () => {
82
+ moveHighlightedPickedOptionUp({
83
+ selected: ['a', 'b', 'c'],
84
+ highlightedPickedOptions: ['ghost', 'c'],
85
+ onChange
86
+ });
87
+ expect(onChange).toHaveBeenCalledWith({
88
+ selected: ['a', 'c', 'b']
89
+ });
90
+ });
37
91
  });
@@ -0,0 +1,101 @@
1
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2
+ import { mount } from 'enzyme';
3
+ import React from 'react';
4
+ import { ReorderingActions } from '../reordering-actions.js';
5
+ const findButton = (wrapper, dataTest) => wrapper.find(`button[data-test="${dataTest}"]`);
6
+ const allButtonHooks = dataTest => [`${dataTest}-buttonmovetotop`, `${dataTest}-buttonmoveup`, `${dataTest}-buttonmovedown`, `${dataTest}-buttonmovetobottom`];
7
+ describe('Transfer - ReorderingActions', () => {
8
+ const dataTest = 'test-reorderingactions';
9
+ const baseProps = {
10
+ dataTest,
11
+ onChangeUp: jest.fn(),
12
+ onChangeDown: jest.fn(),
13
+ onChangeToTop: jest.fn(),
14
+ onChangeToBottom: jest.fn()
15
+ };
16
+ afterEach(() => {
17
+ Object.values(baseProps).forEach(value => {
18
+ if (jest.isMockFunction(value)) {
19
+ value.mockClear();
20
+ }
21
+ });
22
+ });
23
+ it('renders all four reorder buttons', () => {
24
+ const wrapper = mount(/*#__PURE__*/React.createElement(ReorderingActions, baseProps));
25
+ expect(findButton(wrapper, `${dataTest}-buttonmovetotop`)).toHaveLength(1);
26
+ expect(findButton(wrapper, `${dataTest}-buttonmoveup`)).toHaveLength(1);
27
+ expect(findButton(wrapper, `${dataTest}-buttonmovedown`)).toHaveLength(1);
28
+ expect(findButton(wrapper, `${dataTest}-buttonmovetobottom`)).toHaveLength(1);
29
+ });
30
+ it('invokes the corresponding handler for each button', () => {
31
+ const wrapper = mount(/*#__PURE__*/React.createElement(ReorderingActions, baseProps));
32
+ findButton(wrapper, `${dataTest}-buttonmovetotop`).simulate('click');
33
+ expect(baseProps.onChangeToTop).toHaveBeenCalledTimes(1);
34
+ findButton(wrapper, `${dataTest}-buttonmoveup`).simulate('click');
35
+ expect(baseProps.onChangeUp).toHaveBeenCalledTimes(1);
36
+ findButton(wrapper, `${dataTest}-buttonmovedown`).simulate('click');
37
+ expect(baseProps.onChangeDown).toHaveBeenCalledTimes(1);
38
+ findButton(wrapper, `${dataTest}-buttonmovetobottom`).simulate('click');
39
+ expect(baseProps.onChangeToBottom).toHaveBeenCalledTimes(1);
40
+ });
41
+ it('does not cross-fire handlers when a single button is clicked', () => {
42
+ const wrapper = mount(/*#__PURE__*/React.createElement(ReorderingActions, baseProps));
43
+ findButton(wrapper, `${dataTest}-buttonmoveup`).simulate('click');
44
+ expect(baseProps.onChangeUp).toHaveBeenCalledTimes(1);
45
+ expect(baseProps.onChangeDown).not.toHaveBeenCalled();
46
+ expect(baseProps.onChangeToTop).not.toHaveBeenCalled();
47
+ expect(baseProps.onChangeToBottom).not.toHaveBeenCalled();
48
+ });
49
+ it('disables both up-side buttons when disabledUp is true', () => {
50
+ const wrapper = mount(/*#__PURE__*/React.createElement(ReorderingActions, _extends({}, baseProps, {
51
+ disabledUp: true
52
+ })));
53
+ expect(findButton(wrapper, `${dataTest}-buttonmovetotop`).prop('disabled')).toBe(true);
54
+ expect(findButton(wrapper, `${dataTest}-buttonmoveup`).prop('disabled')).toBe(true);
55
+ expect(findButton(wrapper, `${dataTest}-buttonmovedown`).prop('disabled')).toBeFalsy();
56
+ expect(findButton(wrapper, `${dataTest}-buttonmovetobottom`).prop('disabled')).toBeFalsy();
57
+ });
58
+ it('disables both down-side buttons when disabledDown is true', () => {
59
+ const wrapper = mount(/*#__PURE__*/React.createElement(ReorderingActions, _extends({}, baseProps, {
60
+ disabledDown: true
61
+ })));
62
+ expect(findButton(wrapper, `${dataTest}-buttonmovedown`).prop('disabled')).toBe(true);
63
+ expect(findButton(wrapper, `${dataTest}-buttonmovetobottom`).prop('disabled')).toBe(true);
64
+ expect(findButton(wrapper, `${dataTest}-buttonmoveup`).prop('disabled')).toBeFalsy();
65
+ expect(findButton(wrapper, `${dataTest}-buttonmovetotop`).prop('disabled')).toBeFalsy();
66
+ });
67
+ it('does not invoke handlers for disabled buttons', () => {
68
+ const wrapper = mount(/*#__PURE__*/React.createElement(ReorderingActions, _extends({}, baseProps, {
69
+ disabledUp: true,
70
+ disabledDown: true
71
+ })));
72
+ findButton(wrapper, `${dataTest}-buttonmovetotop`).simulate('click');
73
+ findButton(wrapper, `${dataTest}-buttonmoveup`).simulate('click');
74
+ findButton(wrapper, `${dataTest}-buttonmovedown`).simulate('click');
75
+ findButton(wrapper, `${dataTest}-buttonmovetobottom`).simulate('click');
76
+ expect(baseProps.onChangeToTop).not.toHaveBeenCalled();
77
+ expect(baseProps.onChangeUp).not.toHaveBeenCalled();
78
+ expect(baseProps.onChangeDown).not.toHaveBeenCalled();
79
+ expect(baseProps.onChangeToBottom).not.toHaveBeenCalled();
80
+ });
81
+ it('sets aria-label on every button', () => {
82
+ const wrapper = mount(/*#__PURE__*/React.createElement(ReorderingActions, baseProps));
83
+ const assertLabel = (hook, label) => {
84
+ expect(findButton(wrapper, hook).prop('aria-label')).toBe(label);
85
+ };
86
+ assertLabel(`${dataTest}-buttonmovetotop`, 'Move selected items to top');
87
+ assertLabel(`${dataTest}-buttonmoveup`, 'Move selected items up');
88
+ assertLabel(`${dataTest}-buttonmovedown`, 'Move selected items down');
89
+ assertLabel(`${dataTest}-buttonmovetobottom`, 'Move selected items to bottom');
90
+ });
91
+ it('still renders and wires up all four buttons when filterActive is true', () => {
92
+ const wrapper = mount(/*#__PURE__*/React.createElement(ReorderingActions, _extends({}, baseProps, {
93
+ filterActive: true
94
+ })));
95
+ allButtonHooks(dataTest).forEach(hook => {
96
+ expect(findButton(wrapper, hook)).toHaveLength(1);
97
+ });
98
+ findButton(wrapper, `${dataTest}-buttonmoveup`).simulate('click');
99
+ expect(baseProps.onChangeUp).toHaveBeenCalledTimes(1);
100
+ });
101
+ });