box-ui-elements 23.4.0-beta.30 → 23.4.0-beta.32

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 (77) hide show
  1. package/dist/explorer.css +1 -1
  2. package/dist/explorer.js +1 -1
  3. package/dist/openwith.js +1 -1
  4. package/dist/picker.js +1 -1
  5. package/dist/preview.css +1 -1
  6. package/dist/preview.js +1 -1
  7. package/dist/sharing.js +1 -1
  8. package/dist/sidebar.css +1 -1
  9. package/dist/sidebar.js +1 -1
  10. package/dist/uploader.js +1 -1
  11. package/es/common/types/metadata.js.flow +6 -0
  12. package/es/common/types/metadata.js.map +1 -1
  13. package/es/elements/content-sidebar/SidebarNav.js +14 -3
  14. package/es/elements/content-sidebar/SidebarNav.js.flow +23 -3
  15. package/es/elements/content-sidebar/SidebarNav.js.map +1 -1
  16. package/es/elements/content-sidebar/SidebarNavTablist.js +58 -17
  17. package/es/elements/content-sidebar/SidebarNavTablist.js.flow +80 -21
  18. package/es/elements/content-sidebar/SidebarNavTablist.js.map +1 -1
  19. package/es/features/metadata-instance-editor/CascadePolicy.js +53 -23
  20. package/es/features/metadata-instance-editor/CascadePolicy.js.flow +69 -27
  21. package/es/features/metadata-instance-editor/CascadePolicy.js.map +1 -1
  22. package/es/features/metadata-instance-editor/Instance.js +26 -4
  23. package/es/features/metadata-instance-editor/Instance.js.flow +33 -4
  24. package/es/features/metadata-instance-editor/Instance.js.map +1 -1
  25. package/es/features/metadata-instance-editor/constants.js +4 -1
  26. package/es/features/metadata-instance-editor/constants.js.flow +10 -1
  27. package/es/features/metadata-instance-editor/constants.js.map +1 -1
  28. package/es/features/metadata-instance-editor/messages.js +16 -0
  29. package/es/features/metadata-instance-editor/messages.js.flow +21 -0
  30. package/es/features/metadata-instance-editor/messages.js.map +1 -1
  31. package/es/features/metadata-instance-editor/stories/tests/CascadePolicy-visual.stories.js +32 -0
  32. package/es/features/metadata-instance-editor/stories/tests/CascadePolicy-visual.stories.js.flow +36 -0
  33. package/es/features/metadata-instance-editor/stories/tests/CascadePolicy-visual.stories.js.map +1 -0
  34. package/i18n/bn-IN.js +4 -0
  35. package/i18n/da-DK.js +4 -0
  36. package/i18n/de-DE.js +4 -0
  37. package/i18n/en-AU.js +4 -0
  38. package/i18n/en-CA.js +4 -0
  39. package/i18n/en-GB.js +4 -0
  40. package/i18n/en-US.js +4 -0
  41. package/i18n/en-US.properties +8 -0
  42. package/i18n/en-x-pseudo.js +4 -0
  43. package/i18n/es-419.js +4 -0
  44. package/i18n/es-ES.js +4 -0
  45. package/i18n/fi-FI.js +4 -0
  46. package/i18n/fr-CA.js +4 -0
  47. package/i18n/fr-FR.js +4 -0
  48. package/i18n/hi-IN.js +4 -0
  49. package/i18n/it-IT.js +4 -0
  50. package/i18n/ja-JP.js +4 -0
  51. package/i18n/ko-KR.js +4 -0
  52. package/i18n/nb-NO.js +4 -0
  53. package/i18n/nl-NL.js +4 -0
  54. package/i18n/pl-PL.js +4 -0
  55. package/i18n/pt-BR.js +4 -0
  56. package/i18n/ru-RU.js +4 -0
  57. package/i18n/sv-SE.js +4 -0
  58. package/i18n/tr-TR.js +4 -0
  59. package/i18n/zh-CN.js +4 -0
  60. package/i18n/zh-TW.js +4 -0
  61. package/package.json +7 -7
  62. package/src/common/types/metadata.js +6 -0
  63. package/src/elements/content-sidebar/SidebarNav.js +23 -3
  64. package/src/elements/content-sidebar/SidebarNavTablist.js +80 -21
  65. package/src/elements/content-sidebar/__tests__/SidebarNav.test.js +99 -147
  66. package/src/elements/content-sidebar/__tests__/SidebarNavTablist.test.js +189 -42
  67. package/src/features/metadata-instance-editor/CascadePolicy.js +69 -27
  68. package/src/features/metadata-instance-editor/Instance.js +33 -4
  69. package/src/features/metadata-instance-editor/__tests__/CascadePolicy.test.js +70 -63
  70. package/src/features/metadata-instance-editor/__tests__/Instance.test.js +34 -19
  71. package/src/features/metadata-instance-editor/__tests__/Instances.test.js +15 -10
  72. package/src/features/metadata-instance-editor/__tests__/MetadataInstanceEditor.test.js +53 -10
  73. package/src/features/metadata-instance-editor/__tests__/__snapshots__/Instance.test.js.snap +2 -1
  74. package/src/features/metadata-instance-editor/constants.js +10 -1
  75. package/src/features/metadata-instance-editor/messages.js +21 -0
  76. package/src/features/metadata-instance-editor/stories/tests/CascadePolicy-visual.stories.js +36 -0
  77. package/src/features/metadata-instance-editor/__tests__/__snapshots__/CascadePolicy.test.js.snap +0 -108
@@ -1,22 +1,11 @@
1
1
  import * as React from 'react';
2
2
  import { MemoryRouter } from 'react-router-dom';
3
- import userEvent from '@testing-library/user-event';
4
- import { mount } from 'enzyme';
5
- import { BoxAiLogo } from '@box/blueprint-web-assets/icons/Logo';
6
3
  import { usePromptFocus } from '@box/box-ai-content-answers';
7
- import AdditionalTabPlaceholder from '../additional-tabs/AdditionalTabPlaceholder';
8
- import AdditionalTabs from '../additional-tabs';
9
- import AdditionalTabsLoading from '../additional-tabs/AdditionalTabsLoading';
4
+
10
5
  import FeatureProvider from '../../common/feature-checking/FeatureProvider';
11
- import DocGenIcon from '../../../icon/fill/DocGenIcon';
12
- import IconChatRound from '../../../icons/general/IconChatRound';
13
- import IconDocInfo from '../../../icons/general/IconDocInfo';
14
- import IconMagicWand from '../../../icons/general/IconMagicWand';
15
- import IconMetadataThick from '../../../icons/general/IconMetadataThick';
16
6
  import SidebarNav from '../SidebarNav';
17
- import SidebarNavButton from '../SidebarNavButton';
18
- import SidebarNavSignButton from '../SidebarNavSignButton';
19
- import { render, screen } from '../../../test-utils/testing-library';
7
+
8
+ import { render, screen, userEvent } from '../../../test-utils/testing-library';
20
9
 
21
10
  jest.mock('@box/box-ai-content-answers');
22
11
 
@@ -24,88 +13,52 @@ describe('elements/content-sidebar/SidebarNav', () => {
24
13
  const focusBoxAISidebarPromptMock = jest.fn();
25
14
 
26
15
  beforeEach(() => {
16
+ jest.clearAllMocks();
27
17
  usePromptFocus.mockReturnValue({
28
18
  focusPrompt: focusBoxAISidebarPromptMock,
29
19
  });
30
20
  });
31
21
 
32
- const getWrapper = (props = {}, active = '', features = {}) =>
33
- mount(
34
- <MemoryRouter initialEntries={[`/${active}`]}>
22
+ const renderSidebarNav = ({ path = '/', props = {}, features = {} } = {}) => {
23
+ return render(
24
+ <MemoryRouter initialEntries={[path]}>
35
25
  <FeatureProvider features={features}>
36
26
  <SidebarNav {...props} />
37
27
  </FeatureProvider>
38
28
  </MemoryRouter>,
39
- )
40
- .find('SidebarNav')
41
- .at(1);
42
-
43
- const getSidebarNav = ({ path = '/', props, features }) => (
44
- <MemoryRouter initialEntries={[path]}>
45
- <FeatureProvider features={features}>
46
- <SidebarNav {...props} />
47
- </FeatureProvider>
48
- </MemoryRouter>
49
- );
50
-
51
- test('should render skills tab', () => {
52
- const props = {
53
- hasSkills: true,
29
+ );
30
+ };
31
+
32
+ describe('individual tab rendering', () => {
33
+ const TABS_CONFIG = {
34
+ skills: { testId: 'sidebarskills', propName: 'hasSkills' },
35
+ details: { testId: 'sidebardetails', propName: 'hasDetails' },
36
+ activity: { testId: 'sidebaractivity', propName: 'hasActivity' },
37
+ metadata: { testId: 'sidebarmetadata', propName: 'hasMetadata' },
38
+ boxai: { testId: 'sidebarboxai', propName: 'hasBoxAI' },
39
+ docgen: { testId: 'sidebardocgen', propName: 'hasDocGen' },
54
40
  };
55
- const wrapper = getWrapper(props);
56
- expect(wrapper.find(BoxAiLogo)).toHaveLength(0);
57
- expect(wrapper.find(IconMagicWand)).toHaveLength(1);
58
- expect(wrapper.find(IconMetadataThick)).toHaveLength(0);
59
- expect(wrapper.find(IconDocInfo)).toHaveLength(0);
60
- expect(wrapper.find(IconChatRound)).toHaveLength(0);
61
- });
62
41
 
63
- test('should render details tab', () => {
64
- const props = {
65
- hasDetails: true,
66
- };
67
- const wrapper = getWrapper(props);
68
- expect(wrapper.find(BoxAiLogo)).toHaveLength(0);
69
- expect(wrapper.find(IconMagicWand)).toHaveLength(0);
70
- expect(wrapper.find(IconMetadataThick)).toHaveLength(0);
71
- expect(wrapper.find(IconDocInfo)).toHaveLength(1);
72
- expect(wrapper.find(IconChatRound)).toHaveLength(0);
73
- });
42
+ const tabNames = Object.keys(TABS_CONFIG);
74
43
 
75
- test('should render activity tab', () => {
76
- const props = {
77
- hasActivity: true,
78
- };
79
- const wrapper = getWrapper(props);
80
- expect(wrapper.find(BoxAiLogo)).toHaveLength(0);
81
- expect(wrapper.find(IconMagicWand)).toHaveLength(0);
82
- expect(wrapper.find(IconMetadataThick)).toHaveLength(0);
83
- expect(wrapper.find(IconDocInfo)).toHaveLength(0);
84
- expect(wrapper.find(IconChatRound)).toHaveLength(1);
85
- });
44
+ test.each(tabNames)('should render %s tab', tabName => {
45
+ const { testId, propName } = TABS_CONFIG[tabName];
86
46
 
87
- test('should render metadata tab', () => {
88
- const props = {
89
- hasMetadata: true,
90
- };
91
- const wrapper = getWrapper(props);
92
- expect(wrapper.find(BoxAiLogo)).toHaveLength(0);
93
- expect(wrapper.find(IconMagicWand)).toHaveLength(0);
94
- expect(wrapper.find(IconMetadataThick)).toHaveLength(1);
95
- expect(wrapper.find(IconDocInfo)).toHaveLength(0);
96
- expect(wrapper.find(IconChatRound)).toHaveLength(0);
97
- });
47
+ renderSidebarNav({
48
+ props: {
49
+ [propName]: true,
50
+ },
51
+ });
98
52
 
99
- test('should render box ai tab', () => {
100
- const props = {
101
- hasBoxAI: true,
102
- };
103
- const wrapper = getWrapper(props);
104
- expect(wrapper.find(BoxAiLogo)).toHaveLength(1);
105
- expect(wrapper.find(IconMagicWand)).toHaveLength(0);
106
- expect(wrapper.find(IconMetadataThick)).toHaveLength(0);
107
- expect(wrapper.find(IconDocInfo)).toHaveLength(0);
108
- expect(wrapper.find(IconChatRound)).toHaveLength(0);
53
+ expect(screen.getByTestId(testId)).toBeInTheDocument();
54
+
55
+ tabNames
56
+ .filter(name => name !== tabName)
57
+ .forEach(otherTabName => {
58
+ const otherTab = TABS_CONFIG[otherTabName];
59
+ expect(screen.queryByTestId(otherTab.testId)).not.toBeInTheDocument();
60
+ });
61
+ });
109
62
  });
110
63
 
111
64
  describe('should render box ai tab with correct disabled state and tooltip', () => {
@@ -116,16 +69,16 @@ describe('elements/content-sidebar/SidebarNav', () => {
116
69
  `(
117
70
  'given feature boxai.sidebar.showOnlyNavButton = true and boxai.sidebar.disabledTooltip = $disabledTooltip, should render box ai tab with disabled state and tooltip = $expectedTooltip',
118
71
  async ({ disabledTooltip, expectedTooltip }) => {
119
- render(
120
- getSidebarNav({
121
- features: { boxai: { sidebar: { disabledTooltip, showOnlyNavButton: true } } },
122
- props: { hasBoxAI: true },
123
- }),
124
- );
72
+ const user = userEvent();
73
+
74
+ renderSidebarNav({
75
+ features: { boxai: { sidebar: { disabledTooltip, showOnlyNavButton: true } } },
76
+ props: { hasBoxAI: true },
77
+ });
125
78
 
126
79
  const button = screen.getByTestId('sidebarboxai');
127
80
 
128
- await userEvent.hover(button);
81
+ await user.hover(button);
129
82
 
130
83
  expect(button).toHaveAttribute('aria-disabled', 'true');
131
84
  expect(screen.getByText(expectedTooltip)).toBeInTheDocument();
@@ -133,16 +86,16 @@ describe('elements/content-sidebar/SidebarNav', () => {
133
86
  );
134
87
 
135
88
  test('given feature boxai.sidebar.showOnlyNavButton = false, should render box ai tab with default tooltip', async () => {
136
- render(
137
- getSidebarNav({
138
- features: { boxai: { sidebar: { showOnlyNavButton: false } } },
139
- props: { hasBoxAI: true },
140
- }),
141
- );
89
+ const user = userEvent();
90
+
91
+ renderSidebarNav({
92
+ features: { boxai: { sidebar: { showOnlyNavButton: false } } },
93
+ props: { hasBoxAI: true },
94
+ });
142
95
 
143
96
  const button = screen.getByTestId('sidebarboxai');
144
97
 
145
- await userEvent.hover(button);
98
+ await user.hover(button);
146
99
 
147
100
  expect(button).not.toHaveAttribute('aria-disabled');
148
101
  expect(screen.getByText('Box AI')).toBeInTheDocument();
@@ -150,22 +103,22 @@ describe('elements/content-sidebar/SidebarNav', () => {
150
103
  });
151
104
 
152
105
  test('should call focusBoxAISidebarPrompt when clicked on Box AI Tab', async () => {
153
- render(
154
- getSidebarNav({
155
- features: {
156
- boxai: {
157
- sidebar: {
158
- showOnlyNavButton: false,
159
- },
106
+ const user = userEvent();
107
+
108
+ renderSidebarNav({
109
+ features: {
110
+ boxai: {
111
+ sidebar: {
112
+ showOnlyNavButton: false,
160
113
  },
161
114
  },
162
- props: { hasBoxAI: true },
163
- }),
164
- );
115
+ },
116
+ props: { hasBoxAI: true },
117
+ });
165
118
 
166
119
  const button = screen.getByTestId('sidebarboxai');
167
120
 
168
- await userEvent.click(button);
121
+ await user.click(button);
169
122
 
170
123
  expect(usePromptFocus).toHaveBeenCalledTimes(1);
171
124
  expect(usePromptFocus).toHaveBeenCalledWith('.be.bcs');
@@ -175,53 +128,52 @@ describe('elements/content-sidebar/SidebarNav', () => {
175
128
  });
176
129
 
177
130
  test('should have multiple tabs', () => {
178
- const props = {
179
- hasActivity: true,
180
- hasBoxAI: true,
181
- hasMetadata: true,
182
- hasSkills: true,
183
- };
184
- const wrapper = getWrapper(props, 'activity');
185
- expect(wrapper.find(IconMagicWand)).toHaveLength(1);
186
- expect(wrapper.find(IconMetadataThick)).toHaveLength(1);
187
- expect(wrapper.find(IconDocInfo)).toHaveLength(0);
188
- expect(wrapper.find(IconChatRound)).toHaveLength(1);
189
- expect(wrapper.find(BoxAiLogo)).toHaveLength(1);
190
- expect(wrapper.find(SidebarNavButton)).toHaveLength(4);
131
+ renderSidebarNav({
132
+ path: '/activity',
133
+ props: {
134
+ hasActivity: true,
135
+ hasBoxAI: true,
136
+ hasMetadata: true,
137
+ hasSkills: true,
138
+ },
139
+ });
140
+
141
+ expect(screen.getByTestId('sidebaractivity')).toBeInTheDocument();
142
+ expect(screen.getByTestId('sidebarboxai')).toBeInTheDocument();
143
+ expect(screen.getByTestId('sidebarmetadata')).toBeInTheDocument();
144
+ expect(screen.getByTestId('sidebarskills')).toBeInTheDocument();
145
+
146
+ expect(screen.queryByTestId('sidebardetails')).not.toBeInTheDocument();
147
+
148
+ const navButtons = screen.getAllByRole('tab');
149
+ expect(navButtons).toHaveLength(4);
191
150
  });
192
151
 
193
152
  test('should render the additional tabs loading state', () => {
194
- const props = {
195
- additionalTabs: [],
196
- hasAdditionalTabs: true,
197
- };
198
- const wrapper = getWrapper(props);
199
- expect(wrapper.find(AdditionalTabs)).toHaveLength(1);
200
- expect(wrapper.find(AdditionalTabsLoading)).toHaveLength(1);
201
- expect(wrapper.find(AdditionalTabPlaceholder)).toHaveLength(5);
153
+ renderSidebarNav({
154
+ props: {
155
+ additionalTabs: [],
156
+ hasAdditionalTabs: true,
157
+ },
158
+ });
159
+
160
+ expect(screen.getByTestId('additional-tabs-overflow')).toBeInTheDocument();
161
+
162
+ const placeholders = screen.getAllByTestId('additionaltabplaceholder');
163
+ expect(placeholders).toHaveLength(5);
202
164
  });
203
165
 
204
166
  test('should render the Box Sign entry point if its feature is enabled', () => {
205
- const props = {
206
- signSidebarProps: {
207
- enabled: true,
208
- onClick: () => {},
167
+ renderSidebarNav({
168
+ props: {
169
+ signSidebarProps: {
170
+ enabled: true,
171
+ onClick: () => {},
172
+ },
209
173
  },
210
- };
211
- const wrapper = getWrapper(props);
174
+ });
212
175
 
213
- expect(wrapper.exists(SidebarNavSignButton)).toBe(true);
214
- });
215
- test('should render docgen tab', () => {
216
- const props = {
217
- hasDocGen: true,
218
- };
219
- const wrapper = getWrapper(props);
220
- expect(wrapper.find(IconMagicWand)).toHaveLength(0);
221
- expect(wrapper.find(IconMetadataThick)).toHaveLength(0);
222
- expect(wrapper.find(IconDocInfo)).toHaveLength(0);
223
- expect(wrapper.find(IconChatRound)).toHaveLength(0);
224
- expect(wrapper.find(BoxAiLogo)).toHaveLength(0);
225
- expect(wrapper.find(DocGenIcon)).toHaveLength(1);
176
+ const boxSignSection = screen.getByRole('button', { name: /sign/i });
177
+ expect(boxSignSection).toBeInTheDocument();
226
178
  });
227
179
  });
@@ -1,5 +1,6 @@
1
1
  import * as React from 'react';
2
- import { createMemoryHistory } from 'history';
2
+ import { MemoryRouter, useHistory } from 'react-router-dom';
3
+ import { render, screen, userEvent } from '../../../test-utils/testing-library';
3
4
  import SidebarNavTablist from '../SidebarNavTablist';
4
5
  import {
5
6
  SIDEBAR_VIEW_SKILLS,
@@ -9,59 +10,205 @@ import {
9
10
  KEYS,
10
11
  } from '../../../constants';
11
12
 
12
- jest.mock('react-router-dom', () => ({
13
- ...jest.requireActual('react-router-dom'),
14
- withRouter: Component => Component,
15
- }));
13
+ const MockTabComponent = React.forwardRef(
14
+ (
15
+ {
16
+ sidebarView,
17
+ elementId,
18
+ internalSidebarNavigation,
19
+ internalSidebarNavigationHandler,
20
+ isOpen,
21
+ onNavigate,
22
+ routerDisabled,
23
+ ...otherProps
24
+ },
25
+ ref,
26
+ ) => (
27
+ <button ref={ref} data-testid={`tab-${sidebarView}`} {...otherProps}>
28
+ {sidebarView}
29
+ </button>
30
+ ),
31
+ );
16
32
 
17
33
  describe('elements/content-sidebar/SidebarNavTablist', () => {
18
- test('should correctly render children', () => {
19
- const MockChildren = () => <div />;
34
+ const viewList = [SIDEBAR_VIEW_ACTIVITY, SIDEBAR_VIEW_DETAILS, SIDEBAR_VIEW_SKILLS, SIDEBAR_VIEW_METADATA];
35
+ let testHistory;
36
+
37
+ beforeEach(() => {
38
+ jest.clearAllMocks();
39
+ });
20
40
 
21
- const wrapper = shallow(
22
- <SidebarNavTablist>
23
- <MockChildren />
24
- </SidebarNavTablist>,
41
+ const renderSidebarNavTablist = ({
42
+ path = '/',
43
+ props = {},
44
+ children = [<MockTabComponent key="test" sidebarView="test" />],
45
+ } = {}) => {
46
+ let historyRef;
47
+
48
+ const HistoryCapture = () => {
49
+ const history = useHistory();
50
+ historyRef = history;
51
+ return null;
52
+ };
53
+
54
+ const result = render(
55
+ <MemoryRouter initialEntries={[path]}>
56
+ <HistoryCapture />
57
+ <SidebarNavTablist {...props}>{children}</SidebarNavTablist>
58
+ </MemoryRouter>,
25
59
  );
26
60
 
27
- expect(wrapper.type()).toEqual('div');
28
- expect(wrapper.hasClass('bcs-SidebarNav-main')).toBe(true);
29
- expect(wrapper.exists(MockChildren)).toBe(true);
30
- });
61
+ testHistory = historyRef;
62
+ return result;
63
+ };
31
64
 
32
- describe('handleKeyDown', () => {
33
- const viewList = [SIDEBAR_VIEW_ACTIVITY, SIDEBAR_VIEW_DETAILS, SIDEBAR_VIEW_SKILLS, SIDEBAR_VIEW_METADATA];
65
+ test('should correctly render children', () => {
66
+ renderSidebarNavTablist({
67
+ props: { routerDisabled: false },
68
+ children: [<MockTabComponent key="test" sidebarView="test" />],
69
+ });
34
70
 
71
+ expect(screen.getByRole('tablist')).toBeInTheDocument();
72
+ expect(screen.getByTestId('tab-test')).toBeInTheDocument();
73
+ });
74
+
75
+ describe('handleKeyDown with router', () => {
35
76
  test.each`
36
- key | route
37
- ${KEYS.arrowUp} | ${SIDEBAR_VIEW_ACTIVITY}
38
- ${KEYS.arrowDown} | ${SIDEBAR_VIEW_SKILLS}
39
- ${KEYS.arrowRight} | ${SIDEBAR_VIEW_DETAILS}
40
- `('should navigate to right sidebar panels when a user presses different arrow keys', ({ key, route }) => {
41
- const history = createMemoryHistory({
42
- initialEntries: [`/${SIDEBAR_VIEW_DETAILS}`],
77
+ key | expectedPath
78
+ ${KEYS.arrowUp} | ${`/${SIDEBAR_VIEW_ACTIVITY}`}
79
+ ${KEYS.arrowDown} | ${`/${SIDEBAR_VIEW_SKILLS}`}
80
+ `('should navigate to $expectedPath when user presses $key', async ({ key, expectedPath }) => {
81
+ const user = userEvent();
82
+ const children = viewList.map(view => <MockTabComponent sidebarView={view} key={view} />);
83
+
84
+ renderSidebarNavTablist({
85
+ path: `/${SIDEBAR_VIEW_DETAILS}`,
86
+ props: { routerDisabled: false },
87
+ children,
43
88
  });
44
89
 
45
- const wrapper = shallow(
46
- <SidebarNavTablist history={history}>
47
- {viewList.map(view => {
48
- return <div sidebarView={view} key={view} />;
49
- })}
50
- </SidebarNavTablist>,
51
- );
52
-
53
- const event = {
54
- key,
55
- preventDefault: jest.fn(),
56
- stopPropagation: jest.fn(),
90
+ const tablist = screen.getByRole('tablist');
91
+
92
+ await user.click(tablist);
93
+ await user.keyboard(`{${key}}`);
94
+
95
+ expect(testHistory.location.pathname).toBe(expectedPath);
96
+ });
97
+
98
+ test('should not navigate when user presses arrow right', async () => {
99
+ const user = userEvent();
100
+ const children = viewList.map(view => <MockTabComponent sidebarView={view} key={view} />);
101
+
102
+ renderSidebarNavTablist({
103
+ path: `/${SIDEBAR_VIEW_DETAILS}`,
104
+ props: { routerDisabled: false },
105
+ children,
106
+ });
107
+
108
+ const tablist = screen.getByRole('tablist');
109
+
110
+ await user.click(tablist);
111
+ await user.keyboard(`{${KEYS.arrowRight}}`);
112
+
113
+ expect(testHistory.location.pathname).toBe(`/${SIDEBAR_VIEW_DETAILS}`);
114
+ });
115
+ });
116
+
117
+ describe('handleKeyDown with routerDisabled', () => {
118
+ test.each`
119
+ key | expectedView
120
+ ${KEYS.arrowUp} | ${SIDEBAR_VIEW_ACTIVITY}
121
+ ${KEYS.arrowDown} | ${SIDEBAR_VIEW_SKILLS}
122
+ `(
123
+ 'should use internal navigation when routerDisabled=true and user presses $key',
124
+ async ({ key, expectedView }) => {
125
+ const user = userEvent();
126
+ const mockInternalSidebarNavigationHandler = jest.fn();
127
+ const internalSidebarNavigation = {
128
+ sidebar: SIDEBAR_VIEW_DETAILS,
129
+ };
130
+
131
+ const children = viewList.map(view => <MockTabComponent sidebarView={view} key={view} />);
132
+
133
+ renderSidebarNavTablist({
134
+ props: {
135
+ routerDisabled: true,
136
+ internalSidebarNavigation,
137
+ internalSidebarNavigationHandler: mockInternalSidebarNavigationHandler,
138
+ },
139
+ children,
140
+ });
141
+
142
+ const tablist = screen.getByRole('tablist');
143
+
144
+ await user.click(tablist);
145
+ await user.keyboard(`{${key}}`);
146
+
147
+ expect(mockInternalSidebarNavigationHandler).toHaveBeenCalledWith({
148
+ sidebar: expectedView,
149
+ });
150
+ },
151
+ );
152
+
153
+ test.each`
154
+ currentView | key | expectedView
155
+ ${SIDEBAR_VIEW_ACTIVITY} | ${KEYS.arrowUp} | ${SIDEBAR_VIEW_METADATA}
156
+ ${SIDEBAR_VIEW_METADATA} | ${KEYS.arrowDown} | ${SIDEBAR_VIEW_ACTIVITY}
157
+ `(
158
+ 'should wrap around when navigating beyond tabs range: from $currentView with $key goes to $expectedView',
159
+ async ({ currentView, key, expectedView }) => {
160
+ const user = userEvent();
161
+ const mockInternalSidebarNavigationHandler = jest.fn();
162
+ const internalSidebarNavigation = {
163
+ sidebar: currentView,
164
+ };
165
+
166
+ const children = viewList.map(view => <MockTabComponent sidebarView={view} key={view} />);
167
+
168
+ renderSidebarNavTablist({
169
+ props: {
170
+ routerDisabled: true,
171
+ internalSidebarNavigation,
172
+ internalSidebarNavigationHandler: mockInternalSidebarNavigationHandler,
173
+ },
174
+ children,
175
+ });
176
+
177
+ const tablist = screen.getByRole('tablist');
178
+
179
+ await user.click(tablist);
180
+ await user.keyboard(`{${key}}`);
181
+
182
+ expect(mockInternalSidebarNavigationHandler).toHaveBeenCalledWith({
183
+ sidebar: expectedView,
184
+ });
185
+ },
186
+ );
187
+
188
+ test('should not call internal navigation handler when user presses arrow right', async () => {
189
+ const user = userEvent();
190
+ const mockInternalSidebarNavigationHandler = jest.fn();
191
+ const internalSidebarNavigation = {
192
+ sidebar: SIDEBAR_VIEW_DETAILS,
57
193
  };
58
- wrapper.props().onKeyDown(event);
59
194
 
60
- if (key === KEYS.arrowUp || key === KEYS.arrowDown) {
61
- expect(event.preventDefault).toBeCalled();
62
- expect(event.stopPropagation).toBeCalled();
63
- }
64
- expect(history.location.pathname).toBe(`/${route}`);
195
+ const children = viewList.map(view => <MockTabComponent sidebarView={view} key={view} />);
196
+
197
+ renderSidebarNavTablist({
198
+ props: {
199
+ routerDisabled: true,
200
+ internalSidebarNavigation,
201
+ internalSidebarNavigationHandler: mockInternalSidebarNavigationHandler,
202
+ },
203
+ children,
204
+ });
205
+
206
+ const tablist = screen.getByRole('tablist');
207
+
208
+ await user.click(tablist);
209
+ await user.keyboard(`{${KEYS.arrowRight}}`);
210
+
211
+ expect(mockInternalSidebarNavigationHandler).not.toHaveBeenCalled();
65
212
  });
66
213
  });
67
214
  });