@wordpress/block-library 8.3.2 → 8.4.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 (193) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/button/edit.js +3 -1
  3. package/build/button/edit.js.map +1 -1
  4. package/build/button/index.js +17 -6
  5. package/build/button/index.js.map +1 -1
  6. package/build/cover/edit/index.js +3 -2
  7. package/build/cover/edit/index.js.map +1 -1
  8. package/build/file/index.js +10 -1
  9. package/build/file/index.js.map +1 -1
  10. package/build/image/image.js +21 -15
  11. package/build/image/image.js.map +1 -1
  12. package/build/latest-comments/edit.js +6 -2
  13. package/build/latest-comments/edit.js.map +1 -1
  14. package/build/latest-comments/index.js +13 -0
  15. package/build/latest-comments/index.js.map +1 -1
  16. package/build/navigation/edit/index.js +2 -28
  17. package/build/navigation/edit/index.js.map +1 -1
  18. package/build/navigation/edit/menu-inspector-controls.js +5 -6
  19. package/build/navigation/edit/menu-inspector-controls.js.map +1 -1
  20. package/build/navigation/edit/navigation-menu-selector.js +14 -11
  21. package/build/navigation/edit/navigation-menu-selector.js.map +1 -1
  22. package/build/navigation/edit/unsaved-inner-blocks.js +4 -5
  23. package/build/navigation/edit/unsaved-inner-blocks.js.map +1 -1
  24. package/build/navigation/edit/use-create-navigation-menu.js +11 -2
  25. package/build/navigation/edit/use-create-navigation-menu.js.map +1 -1
  26. package/build/navigation/use-navigation-menu.js +1 -1
  27. package/build/navigation/use-navigation-menu.js.map +1 -1
  28. package/build/navigation-link/edit.js +4 -0
  29. package/build/navigation-link/edit.js.map +1 -1
  30. package/build/navigation-link/link-ui.js +1 -0
  31. package/build/navigation-link/link-ui.js.map +1 -1
  32. package/build/navigation-submenu/edit.js +4 -0
  33. package/build/navigation-submenu/edit.js.map +1 -1
  34. package/build/page-list/edit.js +5 -4
  35. package/build/page-list/edit.js.map +1 -1
  36. package/build/page-list/use-convert-to-navigation-links.js +61 -5
  37. package/build/page-list/use-convert-to-navigation-links.js.map +1 -1
  38. package/build/post-excerpt/edit.js +49 -3
  39. package/build/post-excerpt/edit.js.map +1 -1
  40. package/build/post-excerpt/index.js +4 -0
  41. package/build/post-excerpt/index.js.map +1 -1
  42. package/build/post-featured-image/dimension-controls.js +52 -1
  43. package/build/post-featured-image/dimension-controls.js.map +1 -1
  44. package/build/post-featured-image/edit.js +9 -4
  45. package/build/post-featured-image/edit.js.map +1 -1
  46. package/build/post-featured-image/index.js +3 -0
  47. package/build/post-featured-image/index.js.map +1 -1
  48. package/build/{experiments.js → private-apis.js} +3 -3
  49. package/build/private-apis.js.map +1 -0
  50. package/build/site-logo/edit.js +7 -11
  51. package/build/site-logo/edit.js.map +1 -1
  52. package/build/table/edit.js +3 -3
  53. package/build/table/edit.js.map +1 -1
  54. package/build/table-of-contents/utils.js +1 -1
  55. package/build/table-of-contents/utils.js.map +1 -1
  56. package/build/verse/index.js +6 -0
  57. package/build/verse/index.js.map +1 -1
  58. package/build-module/button/edit.js +2 -1
  59. package/build-module/button/edit.js.map +1 -1
  60. package/build-module/button/index.js +17 -6
  61. package/build-module/button/index.js.map +1 -1
  62. package/build-module/cover/edit/index.js +3 -2
  63. package/build-module/cover/edit/index.js.map +1 -1
  64. package/build-module/file/index.js +10 -1
  65. package/build-module/file/index.js.map +1 -1
  66. package/build-module/image/image.js +21 -15
  67. package/build-module/image/image.js.map +1 -1
  68. package/build-module/latest-comments/edit.js +6 -2
  69. package/build-module/latest-comments/edit.js.map +1 -1
  70. package/build-module/latest-comments/index.js +13 -0
  71. package/build-module/latest-comments/index.js.map +1 -1
  72. package/build-module/navigation/edit/index.js +3 -29
  73. package/build-module/navigation/edit/index.js.map +1 -1
  74. package/build-module/navigation/edit/menu-inspector-controls.js +5 -5
  75. package/build-module/navigation/edit/menu-inspector-controls.js.map +1 -1
  76. package/build-module/navigation/edit/navigation-menu-selector.js +14 -10
  77. package/build-module/navigation/edit/navigation-menu-selector.js.map +1 -1
  78. package/build-module/navigation/edit/unsaved-inner-blocks.js +4 -5
  79. package/build-module/navigation/edit/unsaved-inner-blocks.js.map +1 -1
  80. package/build-module/navigation/edit/use-create-navigation-menu.js +11 -2
  81. package/build-module/navigation/edit/use-create-navigation-menu.js.map +1 -1
  82. package/build-module/navigation/use-navigation-menu.js +1 -1
  83. package/build-module/navigation/use-navigation-menu.js.map +1 -1
  84. package/build-module/navigation-link/edit.js +4 -0
  85. package/build-module/navigation-link/edit.js.map +1 -1
  86. package/build-module/navigation-link/link-ui.js +1 -0
  87. package/build-module/navigation-link/link-ui.js.map +1 -1
  88. package/build-module/navigation-submenu/edit.js +4 -0
  89. package/build-module/navigation-submenu/edit.js.map +1 -1
  90. package/build-module/page-list/edit.js +5 -4
  91. package/build-module/page-list/edit.js.map +1 -1
  92. package/build-module/page-list/use-convert-to-navigation-links.js +61 -5
  93. package/build-module/page-list/use-convert-to-navigation-links.js.map +1 -1
  94. package/build-module/post-excerpt/edit.js +52 -5
  95. package/build-module/post-excerpt/edit.js.map +1 -1
  96. package/build-module/post-excerpt/index.js +4 -0
  97. package/build-module/post-excerpt/index.js.map +1 -1
  98. package/build-module/post-featured-image/dimension-controls.js +52 -1
  99. package/build-module/post-featured-image/dimension-controls.js.map +1 -1
  100. package/build-module/post-featured-image/edit.js +9 -4
  101. package/build-module/post-featured-image/edit.js.map +1 -1
  102. package/build-module/post-featured-image/index.js +3 -0
  103. package/build-module/post-featured-image/index.js.map +1 -1
  104. package/build-module/{experiments.js → private-apis.js} +2 -2
  105. package/build-module/private-apis.js.map +1 -0
  106. package/build-module/site-logo/edit.js +7 -11
  107. package/build-module/site-logo/edit.js.map +1 -1
  108. package/build-module/table/edit.js +3 -3
  109. package/build-module/table/edit.js.map +1 -1
  110. package/build-module/table-of-contents/utils.js +1 -1
  111. package/build-module/table-of-contents/utils.js.map +1 -1
  112. package/build-module/verse/index.js +6 -0
  113. package/build-module/verse/index.js.map +1 -1
  114. package/build-style/avatar/style-rtl.css +3 -0
  115. package/build-style/avatar/style.css +3 -0
  116. package/build-style/button/editor-rtl.css +31 -0
  117. package/build-style/button/editor.css +31 -0
  118. package/build-style/button/style-rtl.css +31 -0
  119. package/build-style/button/style.css +31 -0
  120. package/build-style/classic-rtl.css +5 -0
  121. package/build-style/classic.css +5 -0
  122. package/build-style/editor-rtl.css +36 -1
  123. package/build-style/editor.css +36 -1
  124. package/build-style/file/style-rtl.css +1 -0
  125. package/build-style/file/style.css +1 -0
  126. package/build-style/image/editor-rtl.css +1 -0
  127. package/build-style/image/editor.css +1 -0
  128. package/build-style/image/style-rtl.css +6 -2
  129. package/build-style/image/style.css +6 -0
  130. package/build-style/latest-comments/style-rtl.css +18 -5
  131. package/build-style/latest-comments/style.css +18 -5
  132. package/build-style/quote/style-rtl.css +5 -5
  133. package/build-style/quote/style.css +5 -5
  134. package/build-style/style-rtl.css +64 -12
  135. package/build-style/style.css +64 -10
  136. package/build-types/table-of-contents/utils.d.ts +1 -1
  137. package/package.json +30 -30
  138. package/src/avatar/index.php +67 -63
  139. package/src/avatar/style.scss +3 -0
  140. package/src/button/block.json +17 -6
  141. package/src/button/edit.js +2 -1
  142. package/src/button/editor.scss +36 -0
  143. package/src/button/style.scss +37 -1
  144. package/src/classic.scss +5 -0
  145. package/src/cover/edit/index.js +4 -1
  146. package/src/editor.scss +5 -0
  147. package/src/file/block.json +10 -1
  148. package/src/file/style.scss +1 -0
  149. package/src/image/editor.scss +1 -0
  150. package/src/image/image.js +32 -27
  151. package/src/image/style.scss +13 -0
  152. package/src/latest-comments/block.json +13 -0
  153. package/src/latest-comments/edit.js +9 -2
  154. package/src/latest-comments/style.scss +25 -7
  155. package/src/navigation/edit/index.js +1 -30
  156. package/src/navigation/edit/menu-inspector-controls.js +3 -4
  157. package/src/navigation/edit/navigation-menu-selector.js +12 -26
  158. package/src/navigation/edit/test/navigation-menu-selector.js +638 -0
  159. package/src/navigation/edit/unsaved-inner-blocks.js +29 -36
  160. package/src/navigation/edit/use-create-navigation-menu.js +13 -1
  161. package/src/navigation/index.php +8 -6
  162. package/src/navigation/use-navigation-menu.js +1 -1
  163. package/src/navigation-link/edit.js +3 -0
  164. package/src/navigation-link/link-ui.js +1 -0
  165. package/src/navigation-submenu/edit.js +3 -0
  166. package/src/page-list/edit.js +6 -5
  167. package/src/page-list/index.php +4 -4
  168. package/src/page-list/test/convert-to-links-modal.js +134 -0
  169. package/src/page-list/use-convert-to-navigation-links.js +64 -4
  170. package/src/post-excerpt/block.json +4 -0
  171. package/src/post-excerpt/edit.js +72 -7
  172. package/src/post-excerpt/index.php +29 -5
  173. package/src/post-featured-image/block.json +3 -0
  174. package/src/post-featured-image/dimension-controls.js +64 -2
  175. package/src/post-featured-image/edit.js +18 -6
  176. package/src/post-featured-image/index.php +25 -9
  177. package/src/post-title/index.php +3 -3
  178. package/src/{experiments.js → private-apis.js} +1 -1
  179. package/src/quote/style.scss +2 -2
  180. package/src/site-logo/edit.js +3 -6
  181. package/src/table/edit.js +3 -3
  182. package/src/table-of-contents/utils.ts +1 -1
  183. package/src/template-part/index.php +1 -1
  184. package/src/verse/block.json +6 -0
  185. package/tsconfig.json +24 -1
  186. package/tsconfig.tsbuildinfo +1 -1
  187. package/build/experiments.js.map +0 -1
  188. package/build/navigation/leaf-more-menu.js +0 -95
  189. package/build/navigation/leaf-more-menu.js.map +0 -1
  190. package/build-module/experiments.js.map +0 -1
  191. package/build-module/navigation/leaf-more-menu.js +0 -76
  192. package/build-module/navigation/leaf-more-menu.js.map +0 -1
  193. package/src/navigation/leaf-more-menu.js +0 -93
@@ -0,0 +1,638 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { render, screen } from '@testing-library/react';
5
+ import userEvent from '@testing-library/user-event';
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import NavigationMenuSelector from '../navigation-menu-selector';
11
+ import useNavigationMenu from '../../use-navigation-menu';
12
+ import useNavigationEntities from '../../use-navigation-entities';
13
+
14
+ jest.mock( '../../use-navigation-menu', () => {
15
+ // This allows us to tweak the returned value on each test.
16
+ const mock = jest.fn();
17
+ return mock;
18
+ } );
19
+
20
+ jest.mock( '../../use-navigation-entities', () => {
21
+ // This allows us to tweak the returned value on each test.
22
+ const mock = jest.fn();
23
+ return mock;
24
+ } );
25
+
26
+ useNavigationEntities.mockReturnValue( {
27
+ menus: [],
28
+ } );
29
+
30
+ const navigationMenu1 = {
31
+ id: 1,
32
+ title: {
33
+ rendered: 'Menu 1',
34
+ },
35
+ status: 'publish',
36
+ };
37
+ const navigationMenu2 = {
38
+ id: 2,
39
+ title: {
40
+ rendered: 'Menu 2',
41
+ },
42
+ status: 'publish',
43
+ };
44
+ const navigationMenu3 = {
45
+ id: 3,
46
+ title: {
47
+ rendered: 'Menu 3',
48
+ },
49
+ status: 'publish',
50
+ };
51
+
52
+ const navigationMenusFixture = [
53
+ navigationMenu1,
54
+ navigationMenu2,
55
+ navigationMenu3,
56
+ ];
57
+
58
+ const classicMenusFixture = [
59
+ {
60
+ id: 1,
61
+ name: 'Classic Menu 1',
62
+ },
63
+ {
64
+ id: 2,
65
+ name: 'Classic Menu 2',
66
+ },
67
+ {
68
+ id: 3,
69
+ name: 'Classic Menu 3',
70
+ },
71
+ ];
72
+
73
+ describe( 'NavigationMenuSelector', () => {
74
+ describe( 'Toggle', () => {
75
+ it( 'should show dropdown toggle with loading message when menus have not resolved', async () => {
76
+ useNavigationMenu.mockReturnValue( {
77
+ navigationMenus: [],
78
+ isResolvingNavigationMenus: true,
79
+ hasResolvedNavigationMenus: false,
80
+ canSwitchNavigationMenu: true,
81
+ } );
82
+
83
+ render( <NavigationMenuSelector /> );
84
+
85
+ expect(
86
+ screen.getByRole( 'button', {
87
+ name: /Loading/,
88
+ } )
89
+ ).toBeInTheDocument();
90
+ } );
91
+
92
+ it( 'should show correct dropdown toggle prompt to choose a menu when navigation menus have resolved', async () => {
93
+ useNavigationMenu.mockReturnValue( {
94
+ navigationMenus: [],
95
+ hasResolvedNavigationMenus: true,
96
+ canUserCreateNavigationMenu: true,
97
+ canSwitchNavigationMenu: true,
98
+ } );
99
+
100
+ render( <NavigationMenuSelector /> );
101
+
102
+ expect(
103
+ screen.getByRole( 'button', {
104
+ name: 'Choose or create a Navigation menu',
105
+ } )
106
+ ).toBeInTheDocument();
107
+ } );
108
+ } );
109
+
110
+ describe( 'Dropdown', () => {
111
+ it( 'should show in loading state with no options when menus have not resolved and user cannot create menus', async () => {
112
+ const user = userEvent.setup();
113
+
114
+ useNavigationMenu.mockReturnValue( {
115
+ navigationMenus: [],
116
+ isResolvingNavigationMenus: true,
117
+ hasResolvedNavigationMenus: false,
118
+ canUserCreateNavigationMenu: false,
119
+ canSwitchNavigationMenu: true,
120
+ } );
121
+
122
+ render( <NavigationMenuSelector /> );
123
+
124
+ const toggleButton = screen.getByRole( 'button' );
125
+ await user.click( toggleButton );
126
+
127
+ expect(
128
+ screen.getByRole( 'menu', {
129
+ name: /Loading/,
130
+ } )
131
+ ).toBeInTheDocument();
132
+
133
+ // Check that all the option groups are *not* present.
134
+ const menusGroup = screen.queryByRole( 'group', { name: 'Menus' } );
135
+ expect( menusGroup ).not.toBeInTheDocument();
136
+
137
+ const classicMenusGroup = screen.queryByRole( 'group', {
138
+ name: 'Import Classic Menus',
139
+ } );
140
+ expect( classicMenusGroup ).not.toBeInTheDocument();
141
+
142
+ const toolsGroup = screen.queryByRole( 'group', {
143
+ name: 'Tools',
144
+ } );
145
+ expect( toolsGroup ).not.toBeInTheDocument();
146
+ } );
147
+
148
+ describe( 'Creating new menus', () => {
149
+ it( 'should show option to create a menu when no menus exist but user can create menus', async () => {
150
+ const user = userEvent.setup();
151
+
152
+ useNavigationMenu.mockReturnValue( {
153
+ navigationMenus: [],
154
+ hasResolvedNavigationMenus: true,
155
+ canUserCreateNavigationMenu: true,
156
+ canSwitchNavigationMenu: true,
157
+ } );
158
+
159
+ render( <NavigationMenuSelector /> );
160
+
161
+ const toggleButton = screen.getByRole( 'button', {
162
+ name: 'Choose or create a Navigation menu',
163
+ } );
164
+
165
+ await user.click( toggleButton );
166
+
167
+ const menuPopover = screen.getByRole( 'menu' );
168
+
169
+ expect( menuPopover ).toHaveAttribute(
170
+ 'aria-label',
171
+ expect.stringContaining(
172
+ 'Choose or create a Navigation menu'
173
+ )
174
+ );
175
+
176
+ // Check that all the option groups are *not* present.
177
+ const menusGroup = screen.queryByRole( 'group', {
178
+ name: 'Menus',
179
+ } );
180
+ expect( menusGroup ).not.toBeInTheDocument();
181
+
182
+ const classicMenusGroup = screen.queryByRole( 'group', {
183
+ name: 'Import Classic Menus',
184
+ } );
185
+ expect( classicMenusGroup ).not.toBeInTheDocument();
186
+
187
+ // Check the Tools Group and Create Menu Button are present.
188
+ const toolsGroup = screen.queryByRole( 'group', {
189
+ name: 'Tools',
190
+ } );
191
+ expect( toolsGroup ).toBeInTheDocument();
192
+
193
+ const createMenuButton = screen.getByRole( 'menuitem', {
194
+ name: 'Create new menu',
195
+ } );
196
+
197
+ expect( createMenuButton ).toBeInTheDocument();
198
+ } );
199
+
200
+ it( 'should not show option to create a menu when user does not have permission to create menus', async () => {
201
+ const user = userEvent.setup();
202
+
203
+ useNavigationMenu.mockReturnValue( {
204
+ navigationMenus: [],
205
+ hasResolvedNavigationMenus: true,
206
+ canUserCreateNavigationMenu: false,
207
+ canSwitchNavigationMenu: true,
208
+ } );
209
+
210
+ render( <NavigationMenuSelector /> );
211
+
212
+ const toggleButton = screen.getByRole( 'button' );
213
+ await user.click( toggleButton );
214
+
215
+ // Check the Tools Group and Create Menu Button are present.
216
+ const toolsGroup = screen.queryByRole( 'group', {
217
+ name: 'Tools',
218
+ } );
219
+ expect( toolsGroup ).not.toBeInTheDocument();
220
+ } );
221
+
222
+ it( 'should call handler callback and close popover when create menu button is clicked', async () => {
223
+ const user = userEvent.setup();
224
+ const handler = jest.fn();
225
+
226
+ useNavigationMenu.mockReturnValue( {
227
+ navigationMenus: [],
228
+ hasResolvedNavigationMenus: true,
229
+ canUserCreateNavigationMenu: true,
230
+ canSwitchNavigationMenu: true,
231
+ } );
232
+
233
+ render( <NavigationMenuSelector onCreateNew={ handler } /> );
234
+
235
+ const toggleButton = screen.getByRole( 'button' );
236
+ await user.click( toggleButton );
237
+
238
+ const createMenuButton = screen.getByRole( 'menuitem', {
239
+ name: 'Create new menu',
240
+ } );
241
+
242
+ await user.click( createMenuButton );
243
+
244
+ expect( handler ).toHaveBeenCalled();
245
+
246
+ expect( screen.queryByRole( 'menu' ) ).not.toBeInTheDocument();
247
+ } );
248
+
249
+ it( 'should handle disabled state of the create menu button during the creation process', async () => {
250
+ const user = userEvent.setup();
251
+ const handler = jest.fn();
252
+
253
+ useNavigationMenu.mockReturnValue( {
254
+ navigationMenus: [],
255
+ hasResolvedNavigationMenus: true,
256
+ canUserCreateNavigationMenu: true,
257
+ canSwitchNavigationMenu: true,
258
+ } );
259
+
260
+ const { rerender } = render(
261
+ <NavigationMenuSelector onCreateNew={ handler } />
262
+ );
263
+
264
+ const toggleButton = screen.getByRole( 'button' );
265
+
266
+ await user.click( toggleButton );
267
+
268
+ await user.click(
269
+ screen.getByRole( 'menuitem', {
270
+ name: 'Create new menu',
271
+ } )
272
+ );
273
+
274
+ // Re-open the dropdown (it's closed when the "Create menu" button is clicked).
275
+ await user.click( toggleButton );
276
+
277
+ // Check the dropdown is open again.
278
+ expect( screen.getByRole( 'menu' ) ).toBeInTheDocument();
279
+
280
+ // Check the "Create menu" button is disabled.
281
+ expect(
282
+ screen.queryByRole( 'menuitem', {
283
+ name: 'Create new menu',
284
+ } )
285
+ ).toBeDisabled();
286
+
287
+ // Simulate the menu being created and component being re-rendered.
288
+ rerender(
289
+ <NavigationMenuSelector
290
+ onCreateNew={ handler }
291
+ createNavigationMenuIsSuccess={ true }
292
+ />
293
+ );
294
+
295
+ // Check the button is enabled again.
296
+ expect(
297
+ screen.queryByRole( 'menuitem', {
298
+ name: 'Create new menu',
299
+ } )
300
+ ).toBeEnabled();
301
+ } );
302
+ } );
303
+
304
+ describe( 'Navigation menus', () => {
305
+ it( 'should not show a list of menus when menus exist but user does not have permission to switch menus', async () => {
306
+ const user = userEvent.setup();
307
+
308
+ useNavigationMenu.mockReturnValue( {
309
+ navigationMenus: navigationMenusFixture,
310
+ hasResolvedNavigationMenus: true,
311
+ canUserCreateNavigationMenu: true,
312
+ canSwitchNavigationMenu: false,
313
+ } );
314
+
315
+ render( <NavigationMenuSelector /> );
316
+
317
+ const toggleButton = screen.getByRole( 'button' );
318
+ await user.click( toggleButton );
319
+
320
+ const menusGroup = screen.queryByRole( 'group', {
321
+ name: 'Menus',
322
+ } );
323
+ expect( menusGroup ).not.toBeInTheDocument();
324
+ } );
325
+
326
+ it( 'should show a list of menus when menus exist', async () => {
327
+ const user = userEvent.setup();
328
+
329
+ useNavigationMenu.mockReturnValue( {
330
+ navigationMenus: navigationMenusFixture,
331
+ hasResolvedNavigationMenus: true,
332
+ canUserCreateNavigationMenu: false,
333
+ canSwitchNavigationMenu: true,
334
+ } );
335
+
336
+ render( <NavigationMenuSelector /> );
337
+
338
+ const toggleButton = screen.getByRole( 'button' );
339
+ await user.click( toggleButton );
340
+
341
+ const menusGroup = screen.queryByRole( 'group', {
342
+ name: 'Menus',
343
+ } );
344
+ expect( menusGroup ).toBeInTheDocument();
345
+
346
+ navigationMenusFixture.forEach( ( item ) => {
347
+ const menuItem = screen.queryByRole( 'menuitemradio', {
348
+ name: item?.title?.rendered,
349
+ } );
350
+ expect( menuItem ).toBeInTheDocument();
351
+ } );
352
+ } );
353
+
354
+ it( 'should render fallback title when menu has no title', async () => {
355
+ const user = userEvent.setup();
356
+
357
+ const menusWithNoTitle = [
358
+ {
359
+ id: 1,
360
+ status: 'publish',
361
+ },
362
+ {
363
+ id: 2,
364
+ status: 'publish',
365
+ },
366
+ ];
367
+
368
+ useNavigationMenu.mockReturnValue( {
369
+ navigationMenus: menusWithNoTitle,
370
+ hasResolvedNavigationMenus: true,
371
+ canUserCreateNavigationMenu: true,
372
+ canSwitchNavigationMenu: true,
373
+ } );
374
+
375
+ render( <NavigationMenuSelector /> );
376
+
377
+ const toggleButton = screen.getByRole( 'button' );
378
+ await user.click( toggleButton );
379
+
380
+ const menusGroup = screen.queryByRole( 'group', {
381
+ name: 'Menus',
382
+ } );
383
+ expect( menusGroup ).toBeInTheDocument();
384
+
385
+ // Check for sequentially named fallback titles.
386
+ expect(
387
+ screen.getByRole( 'menuitemradio', {
388
+ name: '(no title 1)',
389
+ } )
390
+ ).toBeInTheDocument();
391
+
392
+ expect(
393
+ screen.getByRole( 'menuitemradio', {
394
+ name: '(no title 2)',
395
+ } )
396
+ ).toBeInTheDocument();
397
+ } );
398
+
399
+ it( 'should pre-select the correct menu in the menu list if a menu ID is passed', async () => {
400
+ const user = userEvent.setup();
401
+
402
+ useNavigationMenu.mockReturnValue( {
403
+ navigationMenus: navigationMenusFixture,
404
+ hasResolvedNavigationMenus: true,
405
+ canUserCreateNavigationMenu: true,
406
+ canSwitchNavigationMenu: true,
407
+ } );
408
+
409
+ render(
410
+ <NavigationMenuSelector
411
+ currentMenuId={ navigationMenusFixture[ 0 ].id }
412
+ />
413
+ );
414
+
415
+ const toggleButton = screen.getByRole( 'button' );
416
+ await user.click( toggleButton );
417
+
418
+ const menuItem = screen.getByRole( 'menuitemradio', {
419
+ name: navigationMenusFixture[ 0 ].title.rendered,
420
+ } );
421
+
422
+ expect( menuItem ).toBeChecked();
423
+ } );
424
+
425
+ it( 'should call the handler when the navigation menu is selected and disable all options during the import/creation process', async () => {
426
+ const user = userEvent.setup();
427
+
428
+ const handler = jest.fn();
429
+
430
+ useNavigationMenu.mockReturnValue( {
431
+ navigationMenus: navigationMenusFixture,
432
+ hasResolvedNavigationMenus: true,
433
+ canUserCreateNavigationMenu: true,
434
+ canSwitchNavigationMenu: true,
435
+ } );
436
+
437
+ const { rerender } = render(
438
+ <NavigationMenuSelector
439
+ onSelectNavigationMenu={ handler }
440
+ />
441
+ );
442
+ const toggleButton = screen.getByRole( 'button' );
443
+
444
+ await user.click( toggleButton );
445
+
446
+ await user.click(
447
+ screen.getByRole( 'menuitemradio', {
448
+ name: navigationMenusFixture[ 0 ].title.rendered,
449
+ } )
450
+ );
451
+
452
+ expect( handler ).toHaveBeenCalledWith(
453
+ navigationMenusFixture[ 0 ].id
454
+ );
455
+
456
+ // Check the dropdown has been closed.
457
+ expect( screen.queryByRole( 'menu' ) ).not.toBeInTheDocument();
458
+
459
+ // Re-open the dropdown
460
+ await user.click( screen.getByRole( 'button' ) );
461
+
462
+ // Check the dropdown is again open and is in the "loading" state.
463
+ expect(
464
+ screen.getByRole( 'menu', {
465
+ name: /Loading/,
466
+ } )
467
+ ).toBeInTheDocument();
468
+
469
+ // // Check all menu items are present but disabled.
470
+ screen.getAllByRole( 'menuitem' ).forEach( ( item ) => {
471
+ // // Check all menu items are present but disabled.
472
+ expect( item ).toBeDisabled();
473
+ } );
474
+
475
+ // // Simulate the menu being created and component being re-rendered.
476
+ rerender(
477
+ <NavigationMenuSelector
478
+ createNavigationMenuIsSuccess={ true } // classic menu import creates a Navigation menu.
479
+ />
480
+ );
481
+
482
+ // Todo: fix bug where aria label is not updated.
483
+ // expect(
484
+ // screen.getByRole( 'menu', {
485
+ // name: `You are currently editing ${ navigationMenusFixture[ 0 ].title.rendered }`,
486
+ // } )
487
+ // ).toBeInTheDocument();
488
+
489
+ // Check all menu items are re-enabled.
490
+ screen.getAllByRole( 'menuitem' ).forEach( ( item ) => {
491
+ // // Check all menu items are present but disabled.
492
+ expect( item ).toBeEnabled();
493
+ } );
494
+ } );
495
+ } );
496
+
497
+ describe( 'Classic menus', () => {
498
+ it( 'should not show classic menus if there are no classic menus', async () => {
499
+ const user = userEvent.setup();
500
+
501
+ useNavigationEntities.mockReturnValue( {
502
+ menus: [],
503
+ } );
504
+
505
+ render( <NavigationMenuSelector /> );
506
+
507
+ const toggleButton = screen.getByRole( 'button' );
508
+ await user.click( toggleButton );
509
+
510
+ const classicMenusGroup = screen.queryByRole( 'group', {
511
+ name: 'Import Classic Menus',
512
+ } );
513
+ expect( classicMenusGroup ).not.toBeInTheDocument();
514
+ } );
515
+
516
+ it( 'should not show classic menus if there are classic menus but the user does not have permission to create menus', async () => {
517
+ const user = userEvent.setup();
518
+
519
+ useNavigationMenu.mockReturnValue( {
520
+ canUserCreateNavigationMenu: false,
521
+ } );
522
+
523
+ useNavigationEntities.mockReturnValue( {
524
+ menus: classicMenusFixture,
525
+ } );
526
+
527
+ render( <NavigationMenuSelector /> );
528
+
529
+ const toggleButton = screen.getByRole( 'button' );
530
+ await user.click( toggleButton );
531
+
532
+ const classicMenusGroup = screen.queryByRole( 'group', {
533
+ name: 'Import Classic Menus',
534
+ } );
535
+ expect( classicMenusGroup ).not.toBeInTheDocument();
536
+ } );
537
+
538
+ it( 'should show classic menus if there are classic menus and the user has permission to create menus', async () => {
539
+ const user = userEvent.setup();
540
+
541
+ useNavigationMenu.mockReturnValue( {
542
+ canUserCreateNavigationMenu: true,
543
+ } );
544
+
545
+ useNavigationEntities.mockReturnValue( {
546
+ menus: classicMenusFixture,
547
+ } );
548
+
549
+ render( <NavigationMenuSelector /> );
550
+
551
+ const toggleButton = screen.getByRole( 'button' );
552
+ await user.click( toggleButton );
553
+
554
+ const classicMenusGroup = screen.queryByRole( 'group', {
555
+ name: 'Import Classic Menus',
556
+ } );
557
+
558
+ expect( classicMenusGroup ).toBeInTheDocument();
559
+
560
+ // Check for classic menuitems
561
+ classicMenusFixture.forEach( ( item ) => {
562
+ const menuItem = screen.getByRole( 'menuitem', {
563
+ name: `Create from '${ item.name }'`,
564
+ } );
565
+ expect( menuItem ).toBeInTheDocument();
566
+ } );
567
+ } );
568
+
569
+ it( 'should call the handler when the classic menu item is selected and disable all options during the import/creation process', async () => {
570
+ const user = userEvent.setup();
571
+ const handler = jest.fn();
572
+
573
+ useNavigationMenu.mockReturnValue( {
574
+ canUserCreateNavigationMenu: true,
575
+ } );
576
+
577
+ useNavigationEntities.mockReturnValue( {
578
+ menus: classicMenusFixture,
579
+ } );
580
+
581
+ const { rerender } = render(
582
+ <NavigationMenuSelector onSelectClassicMenu={ handler } />
583
+ );
584
+
585
+ const toggleButton = screen.getByRole( 'button' );
586
+
587
+ await user.click( toggleButton );
588
+
589
+ await user.click(
590
+ screen.getByRole( 'menuitem', {
591
+ name: `Create from '${ classicMenusFixture[ 0 ].name }'`,
592
+ } )
593
+ );
594
+
595
+ expect( handler ).toHaveBeenCalled();
596
+
597
+ // Check the dropdown has been closed.
598
+ expect( screen.queryByRole( 'menu' ) ).not.toBeInTheDocument();
599
+
600
+ // // Re-open the dropdown (it's closed when the "Create menu" button is clicked).
601
+ await user.click( screen.getByRole( 'button' ) );
602
+
603
+ // Check the dropdown is open and is in the "loading" state.
604
+ expect(
605
+ screen.getByRole( 'menu', {
606
+ name: /Loading/,
607
+ } )
608
+ ).toBeInTheDocument();
609
+
610
+ // Check all menu items are present but disabled.
611
+ screen.getAllByRole( 'menuitem' ).forEach( ( item ) => {
612
+ // // Check all menu items are present but disabled.
613
+ expect( item ).toBeDisabled();
614
+ } );
615
+
616
+ // Simulate the menu being created and component being re-rendered.
617
+ rerender(
618
+ <NavigationMenuSelector
619
+ createNavigationMenuIsSuccess={ true } // classic menu import creates a Navigation menu.
620
+ />
621
+ );
622
+
623
+ // Todo: fix bug where aria label is not updated.
624
+ // expect(
625
+ // screen.getByRole( 'menu', {
626
+ // name: `You are currently editing ${ classicMenusFixture[ 0 ].name }`,
627
+ // } )
628
+ // ).toBeInTheDocument();
629
+
630
+ // Check all menu items are re-enabled.
631
+ screen.getAllByRole( 'menuitem' ).forEach( ( item ) => {
632
+ // // Check all menu items are present but disabled.
633
+ expect( item ).toBeEnabled();
634
+ } );
635
+ } );
636
+ } );
637
+ } );
638
+ } );