@@ -284,31 +284,36 @@ describe('MenuContainer', () => {
284284 } ) ;
285285
286286 describe ( 'navigational menu items (links)' , ( ) => {
287- it ( 'applies external anchor attributes, only if not disabled' , ( ) => {
287+ it ( 'applies href and external anchor attributes, only when not disabled' , ( ) => {
288288 const { getByTestId } = render (
289289 < TestMenu
290290 items = { [
291- { value : 'link-1' , href : '#1' , isExternal : true } ,
292- { value : 'link-2' , href : '#2' , isExternal : true , disabled : true }
291+ { value : 'link-1' , href : '#1' , external : true } ,
292+ { value : 'link-2' , href : '#2' , external : true , disabled : true }
293293 ] }
294294 />
295295 ) ;
296296 const menu = getByTestId ( 'menu' ) ;
297297
298+ expect ( menu . firstChild ) . toHaveAttribute ( 'href' , '#1' ) ;
298299 expect ( menu . firstChild ) . toHaveAttribute ( 'target' , '_blank' ) ;
299300 expect ( menu . firstChild ) . toHaveAttribute ( 'rel' , 'noopener noreferrer' ) ;
300301
302+ expect ( menu . childNodes [ 1 ] ) . not . toHaveAttribute ( 'href' ) ;
301303 expect ( menu . childNodes [ 1 ] ) . not . toHaveAttribute ( 'target' , '_blank' ) ;
302304 expect ( menu . childNodes [ 1 ] ) . not . toHaveAttribute ( 'rel' , 'noopener noreferrer' ) ;
303305 } ) ;
304306
305- it ( 'applies the correct aria-current attribute to active link' , async ( ) => {
307+ it ( 'tracks click events on links and alls the onChange function with the correct parameters' , async ( ) => {
308+ const onChangeSpy = jest . fn ( ) ;
309+
306310 const { getByTestId, getByText } = render (
307311 < TestMenu
308312 items = { [
309313 { value : 'link-1' , href : '#1' } ,
310314 { value : 'link-2' , href : '#2' }
311315 ] }
316+ onChange = { onChangeSpy }
312317 />
313318 ) ;
314319 const trigger = getByTestId ( 'trigger' ) ;
@@ -319,7 +324,51 @@ describe('MenuContainer', () => {
319324 await user . click ( link ) ;
320325 } ) ;
321326
322- expect ( link ) . toHaveAttribute ( 'aria-current' , 'page' ) ;
327+ expect ( onChangeSpy . mock . calls [ 2 ] [ 0 ] ) . toStrictEqual ( {
328+ type : 'menuItem:click' ,
329+ value : 'link-2' ,
330+ isExpanded : false ,
331+ selectedItems : [ ]
332+ } ) ;
333+
334+ expect ( link ) . not . toHaveAttribute ( 'aria-current' , 'page' ) ;
335+ } ) ;
336+
337+ it ( 'supports setting the selected link via item.selected and ignore link selection changes' , async ( ) => {
338+ const onChangeSpy = jest . fn ( ) ;
339+ const { getByTestId, getByText } = render (
340+ < TestMenu
341+ items = { [
342+ { value : 'link-1' , href : '#1' } ,
343+ { value : 'link-2' , href : '#2' , selected : true }
344+ ] }
345+ onChange = { onChangeSpy }
346+ />
347+ ) ;
348+ const trigger = getByTestId ( 'trigger' ) ;
349+ const secondLink = getByText ( 'link-2' ) ;
350+
351+ await waitFor ( async ( ) => {
352+ await user . click ( trigger ) ;
353+ } ) ;
354+
355+ expect ( secondLink ) . toHaveAttribute ( 'aria-current' , 'page' ) ;
356+
357+ const firstLink = getByText ( 'link-1' ) ;
358+
359+ await waitFor ( async ( ) => {
360+ await user . click ( trigger ) ;
361+ await user . click ( firstLink ) ;
362+ } ) ;
363+
364+ expect ( onChangeSpy . mock . calls [ 3 ] [ 0 ] ) . toStrictEqual ( {
365+ type : 'menuItem:click' ,
366+ value : 'link-1' ,
367+ isExpanded : false ,
368+ selectedItems : [ { href : '#2' , selected : true , value : 'link-2' } ]
369+ } ) ;
370+
371+ expect ( firstLink ) . not . toHaveAttribute ( 'aria-current' ) ;
323372 } ) ;
324373 } ) ;
325374
@@ -1297,7 +1346,7 @@ describe('MenuContainer', () => {
12971346 } ) ;
12981347
12991348 describe ( 'navigational menu items (links)' , ( ) => {
1300- it ( 'applies the correct aria-current attribute to selected link' , async ( ) => {
1349+ it ( 'applies the correct aria-current attribute to user- selected link' , async ( ) => {
13011350 const { getByTestId, getByText } = render (
13021351 < TestMenu
13031352 items = { [
@@ -1317,7 +1366,7 @@ describe('MenuContainer', () => {
13171366 expect ( link ) . toHaveAttribute ( 'aria-current' , 'page' ) ;
13181367 } ) ;
13191368
1320- it ( 'prevents default when clicking a selected link' , async ( ) => {
1369+ it ( 'prevents default only when clicking on user- selected link' , async ( ) => {
13211370 const { getByTestId, getByText } = render (
13221371 < TestMenu
13231372 items = { [
@@ -1328,18 +1377,31 @@ describe('MenuContainer', () => {
13281377 />
13291378 ) ;
13301379 const trigger = getByTestId ( 'trigger' ) ;
1331- const link = getByText ( 'link-2' ) ;
1380+ const firstLink = getByText ( 'link-1' ) ;
1381+ const secondLink = getByText ( 'link-2' ) ;
13321382
13331383 await waitFor ( async ( ) => {
13341384 await user . click ( trigger ) ;
1385+ await user . click ( firstLink ) ;
13351386 } ) ;
13361387
1337- const event = createEvent . click ( link ) ;
1338- event . preventDefault = jest . fn ( ) ;
1339- fireEvent ( link , event ) ;
1388+ expect ( firstLink ) . not . toHaveAttribute ( 'aria-current' ) ;
13401389
1341- expect ( event . preventDefault ) . toHaveBeenCalledTimes ( 1 ) ;
1342- expect ( link ) . toHaveAttribute ( 'aria-current' , 'page' ) ;
1390+ const firstLinkClickEvent = createEvent . click ( firstLink ) ;
1391+ firstLinkClickEvent . preventDefault = jest . fn ( ) ;
1392+ fireEvent ( firstLink , firstLinkClickEvent ) ;
1393+
1394+ // fire click event one more time to test behavior on previously clicked anchor
1395+ fireEvent ( firstLink , firstLinkClickEvent ) ;
1396+
1397+ expect ( firstLinkClickEvent . preventDefault ) . toHaveBeenCalledTimes ( 0 ) ;
1398+
1399+ const secondLinkClickEvent = createEvent . click ( secondLink ) ;
1400+ secondLinkClickEvent . preventDefault = jest . fn ( ) ;
1401+ fireEvent ( secondLink , secondLinkClickEvent ) ;
1402+
1403+ expect ( secondLinkClickEvent . preventDefault ) . toHaveBeenCalledTimes ( 1 ) ;
1404+ expect ( secondLink ) . toHaveAttribute ( 'aria-current' , 'page' ) ;
13431405 } ) ;
13441406 } ) ;
13451407 } ) ;
0 commit comments