diff --git a/tests/menu-button-actions-active-descendant/data/assertions.csv b/tests/menu-button-actions-active-descendant/data/assertions.csv
new file mode 100644
index 000000000..2a1b356da
--- /dev/null
+++ b/tests/menu-button-actions-active-descendant/data/assertions.csv
@@ -0,0 +1,15 @@
+assertionId,priority,assertionStatement,assertionPhrase,refIds
+nameActions,1,"Name of the menu button, 'Actions', is conveyed","convey name of the menu button, 'Actions'",button
+nameMenuActions,3,"Name of the menu, 'Actions', is conveyed","convey name of the menu, 'Actions'",menu aria-labelledby
+nameFocusedItemAction1,1,"Name of the focused item, 'Action 1', is conveyed","convey name of the focused item, 'Action 1'",aria-activedescendant
+nameFocusedItemAction2,1,"Name of the focused item, 'Action 2', is conveyed","convey name of the focused item, 'Action 2'",aria-activedescendant
+nameFocusedItemAction4,1,"Name of the focused item, 'Action 4', is conveyed","convey name of the focused item, 'Action 4'",aria-activedescendant
+numberItemsMenu4,2,"Number of items in the menu,'(4', is conveyed","convey number of items in the menu, '4'",aria-setsize
+roleFocusedItemMenuItem,2,"Role of the focused item, 'menu item', is conveyed","convey role of the focused item, 'menu item'",menuitem
+roleMenu,3,Role 'menu' is conveyed,convey role 'menu',menu
+roleMenuButton,1,Role 'menu button' is conveyed,convey role 'menu button',button aria-haspopup
+stateCollapsed,1,State 'collapsed' is conveyed,convey state 'collapsed',aria-expanded
+interactionModeEnabled,2,Screen reader switched from reading mode to interaction mode|{screenReader} switched from {readingMode} to {interactionMode},switch from reading mode to interaction mode|switch from {readingMode} to {interactionMode},
+positionFocusedItemMenu1,2,"Position of the focused item in the menu, '1', is conveyed","convey position of the focused item in the menu, '1'",aria-posinset aria-activedescendant
+positionFocusedItemMenu2,2,"Position of the focused item in the menu, '2', is conveyed","convey position of the focused item in the menu, '2'",aria-posinset aria-activedescendant
+positionFocusedItemMenu4,2,"Position of the focused item in the menu, '4', is conveyed","convey position of the focused item in the menu, '4'",aria-posinset aria-activedescendant
diff --git a/tests/menu-button-actions-active-descendant/data/commands.csv b/tests/menu-button-actions-active-descendant/data/commands.csv
deleted file mode 100644
index 888bd5281..000000000
--- a/tests/menu-button-actions-active-descendant/data/commands.csv
+++ /dev/null
@@ -1,42 +0,0 @@
-testId,task,mode,at,commandA,commandB,commandC,commandD,commandE,commandF
-1,navigate forwards to menu button,reading,JAWS,B,F,TAB,DOWN,,
-1,navigate forwards to menu button,reading,NVDA,B,F,TAB,DOWN,,
-2,navigate backwards to menu button,reading,JAWS,SHIFT_B,SHIFT_F,SHIFT_TAB,UP,,
-2,navigate backwards to menu button,reading,NVDA,SHIFT_B,SHIFT_F,SHIFT_TAB,UP,,
-3,navigate forwards to menu button,interaction,JAWS,TAB,,,,,
-3,navigate forwards to menu button,interaction,NVDA,TAB,,,,,
-4,navigate backwards to menu button,interaction,JAWS,SHIFT_TAB,,,,,
-4,navigate backwards to menu button,interaction,NVDA,SHIFT_TAB,,,,,
-5,navigate forwards to menu button,interaction,voiceover_macos,TAB,CTRL_OPT_RIGHT,CTRL_OPT_CMD_J,,,
-6,navigate backwards to menu button,interaction,voiceover_macos,SHIFT_TAB,CTRL_OPT_LEFT,SHIFT_CTRL_OPT_CMD_J,,,
-7,read information about menu button,reading,JAWS,INS_TAB,INS_UP,,,,
-7,read information about menu button,reading,NVDA,INS_TAB,INS_UP,,,,
-8,read information about menu button,interaction,JAWS,INS_TAB,INS_UP,,,,
-8,read information about menu button,interaction,NVDA,INS_TAB,INS_UP,,,,
-9,read information about menu button,interaction,voiceover_macos,CTRL_OPT_F3,CTRL_OPT_F4,,,,
-10,open menu,reading,JAWS,SPACE,ENTER,,,,
-10,open menu,reading,NVDA,SPACE,ENTER,,,,
-11,open menu,interaction,JAWS,SPACE,ENTER,DOWN,,,
-11,open menu,interaction,NVDA,SPACE,ENTER,DOWN,,,
-12,open menu,interaction,voiceover_macos,CTRL_OPT_SPACE,SPACE,ENTER,DOWN,,
-13,open menu to last item,interaction,JAWS,UP,,,,,
-13,open menu to last item,interaction,NVDA,UP,,,,,
-14,open menu to last item,interaction,voiceover_macos,UP,,,,,
-15,read information about menu item,interaction,JAWS,INS_TAB,INS_UP,,,,
-15,read information about menu item,interaction,NVDA,INS_TAB,INS_UP,,,,
-16,read information about menu item,interaction,voiceover_macos,CTRL_OPT_F3,CTRL_OPT_F4,,,,
-17,navigate to first item in menu,interaction,JAWS,HOME,DOWN,,,,
-17,navigate to first item in menu,interaction,NVDA,HOME,DOWN,,,,
-18,navigate to first item in menu,interaction,voiceover_macos,HOME,DOWN,,,,
-19,navigate to last item in menu,interaction,JAWS,END,UP,,,,
-19,navigate to last item in menu,interaction,NVDA,END,UP,,,,
-20,navigate to last item in menu,interaction,voiceover_macos,END,UP,,,,
-21,navigate to item in menu by typing character,interaction,JAWS,A,,,,,
-21,navigate to item in menu by typing character,interaction,NVDA,A,,,,,
-22,navigate to item in menu by typing character,interaction,voiceover_macos,A,,,,,
-23,activate menu item,interaction,JAWS,ENTER,,,,,
-23,activate menu item,interaction,NVDA,ENTER,,,,,
-24,activate menu item,interaction,voiceover_macos,CTRL_OPT_SPACE,ENTER,,,,
-25,close menu,interaction,JAWS,ESC,,,,,
-25,close menu,interaction,NVDA,ESC,,,,,
-26,close menu,interaction,voiceover_macos,ESC,,,,,
diff --git a/tests/menu-button-actions-active-descendant/data/jaws-commands.csv b/tests/menu-button-actions-active-descendant/data/jaws-commands.csv
new file mode 100644
index 000000000..bef2cb964
--- /dev/null
+++ b/tests/menu-button-actions-active-descendant/data/jaws-commands.csv
@@ -0,0 +1,32 @@
+testId,command,settings,assertionExceptions,presentationNumber
+navForwardsToMenuButton,b,virtualCursor,,1
+navForwardsToMenuButton,f,virtualCursor,,1.1
+navForwardsToMenuButton,tab,virtualCursor,2:interactionModeEnabled,1.2
+navForwardsToMenuButton,down,virtualCursor,,1.3
+navBackToMenuButton,shift+b,virtualCursor,,2
+navBackToMenuButton,shift+f,virtualCursor,,2.1
+navBackToMenuButton,shift+tab,virtualCursor,2:interactionModeEnabled,2.2
+navBackToMenuButton,up,virtualCursor,,2.3
+navForwardsToMenuButton,tab,pcCursor,,3
+navBackToMenuButton,shift+tab,pcCursor,,4
+reqInfoAboutMenuButton,ins+tab,virtualCursor,,7
+reqInfoAboutMenuButton,ins+up,virtualCursor,,7.1
+reqInfoAboutMenuButton,ins+tab,pcCursor,,8
+reqInfoAboutMenuButton,ins+up,pcCursor,,8.1
+openMenu,space,virtualCursor,2:interactionModeEnabled,10
+openMenu,enter,virtualCursor,2:interactionModeEnabled,10.1
+openMenu,space,pcCursor,,11
+openMenu,enter,pcCursor,,11.1
+openMenu,down,pcCursor,,11.2
+openMenuToLastItem,up,pcCursor,,13
+reqInfoAboutMenuItem,ins+tab,virtualCursor,,15
+reqInfoAboutMenuItem,ins+up,virtualCursor,,15.1
+reqInfoAboutMenuItem,ins+tab,pcCursor,,15.2
+reqInfoAboutMenuItem,ins+up,pcCursor,,15.3
+navToFirstItemMenu,home,pcCursor,,17
+navToFirstItemMenu,down,pcCursor,,17.1
+navToLastItemMenu,end,pcCursor,,19
+navToLastItemMenu,up,pcCursor,,19.1
+navToItemMenuByTypingCharacter,a,pcCursor,,21
+activateMenuItem,enter,pcCursor,,23
+closeMenu,esc,pcCursor,,25
diff --git a/tests/menu-button-actions-active-descendant/data/nvda-commands.csv b/tests/menu-button-actions-active-descendant/data/nvda-commands.csv
new file mode 100644
index 000000000..995a4431c
--- /dev/null
+++ b/tests/menu-button-actions-active-descendant/data/nvda-commands.csv
@@ -0,0 +1,32 @@
+testId,command,settings,assertionExceptions,presentationNumber
+navForwardsToMenuButton,b,browseMode,,1
+navForwardsToMenuButton,f,browseMode,,1.1
+navForwardsToMenuButton,tab,browseMode,2:interactionModeEnabled,1.2
+navForwardsToMenuButton,down,browseMode,,1.3
+navBackToMenuButton,shift+b,browseMode,,2
+navBackToMenuButton,shift+f,browseMode,,2.1
+navBackToMenuButton,shift+tab,browseMode,2:interactionModeEnabled,2.2
+navBackToMenuButton,up,browseMode,,2.3
+navForwardsToMenuButton,tab,focusMode,,3
+navBackToMenuButton,shift+tab,focusMode,,4
+reqInfoAboutMenuButton,ins+tab,browseMode,,7
+reqInfoAboutMenuButton,ins+up,browseMode,,7.1
+reqInfoAboutMenuButton,ins+tab,focusMode,,8
+reqInfoAboutMenuButton,ins+up,focusMode,,8.1
+openMenu,space,browseMode,2:interactionModeEnabled,10
+openMenu,enter,browseMode,2:interactionModeEnabled,10.1
+openMenu,space,focusMode,,11
+openMenu,enter,focusMode,,11.1
+openMenu,down,focusMode,,11.2
+openMenuToLastItem,up,focusMode,,13
+reqInfoAboutMenuItem,ins+tab,browseMode,,15
+reqInfoAboutMenuItem,ins+up,browseMode,,15.1
+reqInfoAboutMenuItem,ins+tab,focusMode,,15.2
+reqInfoAboutMenuItem,ins+up,focusMode,,15.3
+navToFirstItemMenu,home,focusMode,,17
+navToFirstItemMenu,down,focusMode,,17.1
+navToLastItemMenu,end,focusMode,,19
+navToLastItemMenu,up,focusMode,,19.1
+navToItemMenuByTypingCharacter,a,focusMode,,21
+activateMenuItem,enter,focusMode,,23
+closeMenu,esc,focusMode,,25
diff --git a/tests/menu-button-actions-active-descendant/data/references.csv b/tests/menu-button-actions-active-descendant/data/references.csv
index c34bf8d85..937d3520d 100644
--- a/tests/menu-button-actions-active-descendant/data/references.csv
+++ b/tests/menu-button-actions-active-descendant/data/references.csv
@@ -1,14 +1,17 @@
-refId,value
-author,Isabel Del Castillo
-authorEmail,isa.delcastillo5@gmail.com
-title,Action Menu Button Example Using aria-activedescendant
-reference,reference/2021-1-14_171136/menu-button-actions-active-descendant.html
-designPattern,https://w3c.github.io/aria-practices/#menubutton
-example,https://w3c.github.io/aria-practices/examples/menu-button/menu-button-actions-active-descendant.html
-menu,https://w3c.github.io/aria/#menu
-menuitem,https://w3c.github.io/aria/#menuitem
-aria-haspopup,https://w3c.github.io/aria/#aria-haspopup
-aria-controls,https://w3c.github.io/aria/#aria-controls
-aria-activedescendant,https://w3c.github.io/aria/#aria-activedescendant
-aria-labelledby,https://w3c.github.io/aria/#aria-labelledby
-aria-expanded,https://w3c.github.io/aria/#aria-expanded
+refId,type,value,linkText
+author,metadata,Isabel Del Castillo,
+authorEmail,metadata,isa.delcastillo5@gmail.com,
+title,metadata,Action Menu Button Example Using aria-activedescendant,
+reference,metadata,reference/2024-7-21_174946/menu-button-actions-active-descendant.html,Test Case Page for Action Menu Button Example Using aria-activedescendant
+designPattern,metadata,https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/,APG Pattern: Menu Button
+example,metadata,https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/examples/menu-button-actions-active-descendant/,APG Example: Actions Menu Button Using aria-activedescendant
+menu,aria,menu,menu
+menuitem,aria,menuitem,menuitem
+aria-haspopup,aria,aria-haspopup,aria-haspopup
+aria-controls,aria,aria-controls,aria-controls
+aria-activedescendant,aria,aria-activedescendant,aria-activedescendant
+aria-labelledby,aria,aria-labelledby,aria-labelledby
+aria-expanded,aria,aria-expanded,aria-expanded
+aria-posinset,aria,aria-posinset,aria-posinset
+aria-setsize,aria,aria-setsize,aria-setsize
+button,htmlAam,button,button
diff --git a/tests/menu-button-actions-active-descendant/data/scripts.csv b/tests/menu-button-actions-active-descendant/data/scripts.csv
new file mode 100644
index 000000000..25e1351da
--- /dev/null
+++ b/tests/menu-button-actions-active-descendant/data/scripts.csv
@@ -0,0 +1,6 @@
+setupScript,setupScriptDescription
+openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'"
+openMenuAndSetFocusToLastItem,"opens the menu, and sets focus on 'Action 4'"
+setFocusAfterMenuButton,sets focus on a link after the menu button
+setFocusBeforeMenuButton,sets focus on a link before the menu button
+setFocusOnMenuButton,sets focus on the menu button
diff --git a/tests/menu-button-actions-active-descendant/data/tests.csv b/tests/menu-button-actions-active-descendant/data/tests.csv
index 8033c0a56..4204d1a26 100644
--- a/tests/menu-button-actions-active-descendant/data/tests.csv
+++ b/tests/menu-button-actions-active-descendant/data/tests.csv
@@ -1,27 +1,12 @@
-testId,title,appliesTo,mode,task,setupScript,setupScriptDescription,refs,instructions,assertion1,assertion2,assertion3,assertion4,assertion5,assertion6,assertion7
-1,Navigate forwards to a menu button in reading mode,"JAWS,NVDA",reading,navigate forwards to menu button,setFocusBeforeMenuButton,sets focus on a link before the menu button,aria-haspopup,Navigate to the menu button.,Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,,
-2,Navigate backwards to a menu button in reading mode,"JAWS,NVDA",reading,navigate backwards to menu button,setFocusAfterMenuButton,sets focus on a link after the menu button,aria-haspopup,Navigate to the menu button.,Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,,
-3,Navigate forwards to a menu button in interaction mode,"JAWS,NVDA",interaction,navigate forwards to menu button,setFocusBeforeMenuButton,sets focus on a link before the menu button,aria-haspopup,Navigate to the menu button.,Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,,
-4,Navigate backwards to a menu button in interaction mode,"JAWS,NVDA",interaction,navigate backwards to menu button,setFocusAfterMenuButton,sets focus on a link after the menu button,aria-haspopup,Navigate to the menu button.,Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,,
-5,Navigate forwards to a menu button,voiceover_macos,interaction,navigate forwards to menu button,setFocusBeforeMenuButton,sets focus on a link before the menu button,aria-haspopup,Navigate to the menu button.,Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,,
-6,Navigate backwards to a menu button,voiceover_macos,interaction,navigate backwards to menu button,setFocusAfterMenuButton,sets focus on a link after the menu button,aria-haspopup,Navigate to the menu button.,Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,,
-7,Read information about a menu button in reading mode,"JAWS,NVDA",reading,read information about menu button,setFocusOnMenuButton,sets focus on the menu button,aria-haspopup,"With the reading cursor on the 'Actions' menu button, read information about the menu button.",Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,,
-8,Read information about a menu button in interaction mode,"JAWS,NVDA",interaction,read information about menu button,setFocusOnMenuButton,sets focus on the menu button,aria-haspopup,"With focus on the 'Actions' menu button, read information about the menu button.",Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,,
-9,Read information about a menu button,voiceover_macos,interaction,read information about menu button,setFocusOnMenuButton,sets focus on the menu button,aria-haspopup,"With focus on the 'Actions' menu button, read information about the menu button.",Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,,
-10,Open a menu in reading mode,"JAWS,NVDA",reading,open menu,setFocusOnMenuButton,sets focus on the menu button,menu aria-labelledby menuitem aria-activedescendant,"With the reading cursor on the 'Actions' menu button, open the menu.",Role 'menu' is conveyed,Name 'Actions' is conveyed,"2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 1', is conveyed",Position of the focused item in the menu (1) is conveyed,Number of items in the menu (4) is conveyed,
-11,Open a menu in interaction mode,"JAWS,NVDA",interaction,open menu,setFocusOnMenuButton,sets focus on the menu button,menu aria-labelledby menuitem aria-activedescendant,"With focus on the 'Actions' menu button, open the menu.",Role 'menu' is conveyed,Name 'Actions' is conveyed,"2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 1', is conveyed",Position of the focused item in the menu (1) is conveyed,Number of items in the menu (4) is conveyed,
-12,Open a menu,voiceover_macos,interaction,Open menu,setFocusOnMenuButton,sets focus on the menu button,menu aria-labelledby menuitem,"With focus on the 'Actions' menu button, open the menu.",Role 'menu' is conveyed,Name 'Actions' is conveyed,"2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 1', is conveyed",Position of the focused item in the menu (1) is conveyed,Number of items in the menu (4) is conveyed,
-13,Open a menu to the last item in interaction mode,"JAWS,NVDA",interaction,Open menu to last item,setFocusOnMenuButton,sets focus on the menu button,menu aria-labelledby menuitem aria-activedescendant,"With focus on the 'Actions' menu button, open the menu.",Role 'menu' is conveyed,Name 'Actions' is conveyed,"2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 4', is conveyed",Position of the focused item in the menu (4) is conveyed,Number of items in the menu (4) is conveyed,
-14,Open a menu to the last item,voiceover_macos,interaction,Open menu to last item,setFocusOnMenuButton,sets focus on the menu button,menu aria-labelledby menuitem aria-activedescendant,"With focus on the 'Actions' menu button, open the menu.",Role 'menu' is conveyed,Name 'Actions' is conveyed,"2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 4', is conveyed",Position of the focused item in the menu (4) is conveyed,Number of items in the menu (4) is conveyed,
-15,Read information about a menu item in interaction mode,"JAWS,NVDA",interaction,Read information about menu item,openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'",menuitem aria-activedescendant,"With focus on the 'Action 1' menu item, read information about the menu item.","Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 1', is conveyed",Position of the focused item in the menu (1) is conveyed,Number of items in the menu (4) is conveyed,,,
-16,Read information about a menu item,voiceover_macos,interaction,Read information about menu item,openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'",menuitem aria-activedescendant,"With focus on the 'Action 1' menu item, read information about the menu item.","Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 1', is conveyed",Position of the focused item in the menu (1) is conveyed,Number of items in the menu (4) is conveyed,,,
-17,Navigate to the first item in a menu in interaction mode,"JAWS,NVDA",interaction,navigate to first item in menu,openMenuAndSetFocusToLastItem,"opens the menu, and sets focus on 'Action 4'",menuitem aria-activedescendant,"With focus on the 'Action 4' menu item, navigate to the first menu item.","2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 1', is conveyed",Position of the focused item in the menu (1) is conveyed,Number of items in the menu (4) is conveyed,,,
-18,Navigate to the first item in a menu,voiceover_macos,interaction,navigate to first item in menu,openMenuAndSetFocusToLastItem,"opens the menu, and sets focus on 'Action 4'",menuitem aria-activedescendant,"With focus on the 'Action 4' menu item, navigate to the first menu item.","2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 1', is conveyed",Position of the focused item in the menu (1) is conveyed,Number of items in the menu (4) is conveyed,,,
-19,Navigate to the last item in a menu in interaction mode,"JAWS,NVDA",interaction,navigate to last item in menu,openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'",menuitem aria-activedescendant,"With focus on the 'Action 1' menu item, navigate to the last menu item.","2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 4', is conveyed",Position of the focused item in the menu (4) is conveyed,Number of items in the menu (4) is conveyed,,,
-20,Navigate to the last item in a menu,voiceover_macos,interaction,navigate to last item in menu,openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'",menuitem aria-activedescendant,"With focus on the 'Action 1' menu item, navigate to the last menu item.","2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 4', is conveyed",Position of the focused item in the menu (4) is conveyed,Number of items in the menu (4) is conveyed,,,
-21,Navigate to an item in a menu by typing a character in interaction mode,"JAWS,NVDA",interaction,navigate to item in menu by typing character,openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'",menuitem aria-activedescendant,"With focus on the 'Action 1' menu item, type a character to navigate to a different menu item.","2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 2', is conveyed",Position of the focused item in the menu (2) is conveyed,Number of items in the menu (4) is conveyed,,,
-22,Navigate to an item in a menu by typing a character,voiceover_macos,interaction,navigate to item in menu by typing character,openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'",menuitem aria-activedescendant,"With focus on the 'Action 1' menu item, type a character to navigate to a different menu item.","2:Role of the focused item, 'menu item', is conveyed","Name of the focused item, 'Action 2', is conveyed",Position of the focused item in the menu (2) is conveyed,Number of items in the menu (4) is conveyed,,,
-23,Activate a menu item in interaction mode,"JAWS,NVDA",interaction,activate menu item,openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'",aria-haspopup,"With focus on the 'Action 1' menu item, activate the menu item.",Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,,
-24,Activate a menu item,voiceover_macos,interaction,activate menu item,openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'",aria-haspopup,"With focus on the 'Action 1' menu item, activate the menu item.",Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,,
-25,Close a menu in interaction mode,"JAWS,NVDA",interaction,close menu,openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'",aria-haspopup,"With focus on the 'Action 1' menu item, close the menu.",Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,,
-26,Close a menu,voiceover_macos,interaction,close menu,openMenuAndSetFocusToFirstItem,"opens the menu, and sets focus on 'Action 1'",aria-haspopup,"With focus on the 'Action 1' menu item, close the menu.",Role 'menu button' is conveyed,Name 'Actions' is conveyed,,,,,
+testId,title,presentationNumber,setupScript,instructions,assertions
+navForwardsToMenuButton,Navigate forwards to a menu button,5,setFocusBeforeMenuButton,"Starting at the 'Navigate forwards from here' link,, navigate to the menu button.",nameActions roleMenuButton stateCollapsed 0:interactionModeEnabled
+navBackToMenuButton,Navigate backwards to a menu button,6,setFocusAfterMenuButton,"Starting at the 'Navigate backwards from here' link,, navigate to the menu button.",nameActions roleMenuButton stateCollapsed 0:interactionModeEnabled
+reqInfoAboutMenuButton,Request information about a menu button,9,setFocusOnMenuButton,"Starting at the 'Actions' menu button, read information about the menu button.",nameActions roleMenuButton stateCollapsed
+openMenu,Open a menu,12,setFocusOnMenuButton,"Starting at the 'Actions' menu button, open the menu.",nameFocusedItemAction1 roleFocusedItemMenuItem positionFocusedItemMenu1 numberItemsMenu4 nameMenuActions roleMenu 0:interactionModeEnabled
+openMenuToLastItem,Open a menu to the last item,14,setFocusOnMenuButton,"Starting at the 'Actions' menu button, open the menu.",nameFocusedItemAction4 roleFocusedItemMenuItem positionFocusedItemMenu4 numberItemsMenu4 nameMenuActions roleMenu
+reqInfoAboutMenuItem,Request information about a menu item,16,openMenuAndSetFocusToFirstItem,"Starting at the 'Action 1' menu item, read information about the menu item.",nameFocusedItemAction1 roleFocusedItemMenuItem positionFocusedItemMenu1 numberItemsMenu4 nameMenuActions roleMenu
+navToFirstItemMenu,Navigate to the first item in a menu,18,openMenuAndSetFocusToLastItem,"Starting at the 'Action 4' menu item, navigate to the first menu item.",nameFocusedItemAction1 roleFocusedItemMenuItem positionFocusedItemMenu1 numberItemsMenu4
+navToLastItemMenu,Navigate to the last item in a menu,20,openMenuAndSetFocusToFirstItem,"Starting at the 'Action 1' menu item, navigate to the last menu item.",nameFocusedItemAction4 roleFocusedItemMenuItem positionFocusedItemMenu4 numberItemsMenu4
+navToItemMenuByTypingCharacter,Navigate to an item in a menu by typing a character,22,openMenuAndSetFocusToFirstItem,"Starting at the 'Action 1' menu item, type a character to navigate to a different menu item.",nameFocusedItemAction2 roleFocusedItemMenuItem positionFocusedItemMenu2 numberItemsMenu4
+activateMenuItem,Activate a menu item,24,openMenuAndSetFocusToFirstItem,"Starting at the 'Action 1' menu item, activate the menu item.",nameActions roleMenuButton stateCollapsed
+closeMenu,Close a menu,26,openMenuAndSetFocusToFirstItem,"Starting at the 'Action 1' menu item, close the menu.",nameActions roleMenuButton stateCollapsed
diff --git a/tests/menu-button-actions-active-descendant/data/voiceover_macos-commands.csv b/tests/menu-button-actions-active-descendant/data/voiceover_macos-commands.csv
new file mode 100644
index 000000000..0afa44aef
--- /dev/null
+++ b/tests/menu-button-actions-active-descendant/data/voiceover_macos-commands.csv
@@ -0,0 +1,24 @@
+testId,command,settings,assertionExceptions,presentationNumber
+navForwardsToMenuButton,tab,,,5.0
+navForwardsToMenuButton,ctrl+opt+right,,,5.1
+navForwardsToMenuButton,j,quickNavOn,,5.2
+navBackToMenuButton,shift+tab,,,6.0
+navBackToMenuButton,ctrl+opt+left,,,6.1
+navBackToMenuButton,j,quickNavOn,,6.2
+reqInfoAboutMenuButton,ctrl+opt+f3,,,9.0
+reqInfoAboutMenuButton,ctrl+opt+f4,,,9.1
+openMenu,ctrl+opt+space,,,12.0
+openMenu,space,,,12.1
+openMenu,enter,,,12.2
+openMenu,down,quickNavOff,,12.3
+openMenuToLastItem,up,quickNavOff,,14.0
+reqInfoAboutMenuItem,ctrl+opt+f3,,,16.0
+reqInfoAboutMenuItem,ctrl+opt+f4,,,16.1
+navToFirstItemMenu,home,,,18.0
+navToFirstItemMenu,down,quickNavOff,,18.1
+navToLastItemMenu,end,,,20.0
+navToLastItemMenu,up,quickNavOff,,20.1
+navToItemMenuByTypingCharacter,a,,,22.0
+activateMenuItem,ctrl+opt+space,,,24.0
+activateMenuItem,enter,,,24.1
+closeMenu,esc,,,26.0
diff --git a/tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/menu-button-actions-active-descendant.html b/tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/menu-button-actions-active-descendant.html
deleted file mode 100644
index 1fb1900c9..000000000
--- a/tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/menu-button-actions-active-descendant.html
+++ /dev/null
@@ -1,57 +0,0 @@
-
-
-
- Actions Menu Button Example Using aria-activedescendant
-
-
-
-
-
-
-
-
Actions Menu Button Example Using aria-activedescendant
-
- This example demonstrates how the
- menu button design pattern
- can be used to create a button that opens an actions menu.
- In this example, choosing an action from the menu will cause the chosen action to be displayed in the Last Action edit box.
-
-
-
-
-
-
diff --git a/tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/css/menu-button-actions.css b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/css/menu-button-actions.css
similarity index 97%
rename from tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/css/menu-button-actions.css
rename to tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/css/menu-button-actions.css
index 391043fa3..ec0375f1f 100644
--- a/tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/css/menu-button-actions.css
+++ b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/css/menu-button-actions.css
@@ -45,8 +45,8 @@
.menu-button-actions button svg.down {
padding-left: 0.125em;
- fill: currentColor;
- stroke: currentColor;
+ fill: currentcolor;
+ stroke: currentcolor;
}
.menu-button-actions button[aria-expanded="true"] svg.down {
diff --git a/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/css/menu-button-links.css b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/css/menu-button-links.css
new file mode 100644
index 000000000..6ab2b3680
--- /dev/null
+++ b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/css/menu-button-links.css
@@ -0,0 +1,78 @@
+.menu-button-links {
+ margin: 0;
+ font-size: 110%;
+}
+
+.menu-button-links button {
+ margin: 0;
+ padding: 6px;
+ display: inline-block;
+ position: relative;
+ background-color: #034575;
+ border: 1px solid #034575;
+ font-size: 0.9em;
+ color: white;
+ border-radius: 5px;
+}
+
+.menu-button-links [role="menu"] {
+ margin: 0;
+ padding: 7px 4px;
+ list-style: none;
+ display: none;
+ position: absolute;
+ border: 2px solid #034575;
+ border-radius: 5px;
+ background-color: #eee;
+}
+
+.menu-button-links [role="menuitem"],
+.menu-button-links [role="separator"] {
+ margin: 0;
+ padding: 6px;
+ display: block;
+ width: 24em;
+ background-color: #eee;
+ border: none;
+ color: black;
+ border-radius: 5px;
+}
+
+.menu-button-links [role="separator"] {
+ padding-top: 3px;
+ background-image: url("../images/separator.svg");
+ background-position: center;
+ background-repeat: repeat-x;
+}
+
+.menu-button-links button svg.down {
+ padding-left: 0.125em;
+ fill: currentcolor;
+ stroke: currentcolor;
+}
+
+.menu-button-links button[aria-expanded="true"] svg.down {
+ transform: rotate(180deg);
+}
+
+/* focus styling */
+
+.menu-button-links button:hover,
+.menu-button-links button:focus,
+.menu-button-links button[aria-expanded="true"] {
+ padding: 4px;
+ border: 3px solid #034575;
+ background: #eee;
+ color: #222;
+ outline: none;
+ margin: 0;
+}
+
+.menu-button-links [role="menuitem"]:focus {
+ padding: 4px;
+ border: 2px solid #034575;
+ background: #034575;
+ color: #fff;
+ outline: none;
+ margin: 0;
+}
diff --git a/tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/js/menu-button-actions-active-descendant.js b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/js/menu-button-actions-active-descendant.js
similarity index 98%
rename from tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/js/menu-button-actions-active-descendant.js
rename to tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/js/menu-button-actions-active-descendant.js
index 685e270ef..5783b2d84 100644
--- a/tests/menu-button-actions-active-descendant/reference/2021-1-14_171136/js/menu-button-actions-active-descendant.js
+++ b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/js/menu-button-actions-active-descendant.js
@@ -162,9 +162,9 @@ class MenuButtonActionsActiveDescendant {
closePopup() {
if (this.isOpen()) {
- this.buttonNode.removeAttribute('aria-expanded');
+ this.buttonNode.setAttribute('aria-expanded', 'false');
this.menuNode.setAttribute('aria-activedescendant', '');
- for (var i = 0; i < this.menuitemNodes.length; i++) {
+ for (let i = 0; i < this.menuitemNodes.length; i++) {
this.menuitemNodes[i].classList.remove('focus');
}
this.menuNode.style.display = 'none';
diff --git a/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/js/menu-button-actions.js b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/js/menu-button-actions.js
new file mode 100644
index 000000000..cd69d5621
--- /dev/null
+++ b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/js/menu-button-actions.js
@@ -0,0 +1,346 @@
+/*
+ * This content is licensed according to the W3C Software License at
+ * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * File: menu-button-actions.js
+ *
+ * Desc: Creates a menu button that opens a menu of actions
+ */
+
+'use strict';
+
+class MenuButtonActions {
+ constructor(domNode, performMenuAction) {
+ this.domNode = domNode;
+ this.performMenuAction = performMenuAction;
+ this.buttonNode = domNode.querySelector('button');
+ this.menuNode = domNode.querySelector('[role="menu"]');
+ this.menuitemNodes = [];
+ this.firstMenuitem = false;
+ this.lastMenuitem = false;
+ this.firstChars = [];
+
+ this.buttonNode.addEventListener(
+ 'keydown',
+ this.onButtonKeydown.bind(this)
+ );
+ this.buttonNode.addEventListener('click', this.onButtonClick.bind(this));
+
+ var nodes = domNode.querySelectorAll('[role="menuitem"]');
+
+ for (var i = 0; i < nodes.length; i++) {
+ var menuitem = nodes[i];
+ this.menuitemNodes.push(menuitem);
+ menuitem.tabIndex = -1;
+ this.firstChars.push(menuitem.textContent.trim()[0].toLowerCase());
+
+ menuitem.addEventListener('keydown', this.onMenuitemKeydown.bind(this));
+
+ menuitem.addEventListener('click', this.onMenuitemClick.bind(this));
+
+ menuitem.addEventListener(
+ 'mouseover',
+ this.onMenuitemMouseover.bind(this)
+ );
+
+ if (!this.firstMenuitem) {
+ this.firstMenuitem = menuitem;
+ }
+ this.lastMenuitem = menuitem;
+ }
+
+ domNode.addEventListener('focusin', this.onFocusin.bind(this));
+ domNode.addEventListener('focusout', this.onFocusout.bind(this));
+
+ window.addEventListener(
+ 'mousedown',
+ this.onBackgroundMousedown.bind(this),
+ true
+ );
+ }
+
+ setFocusToMenuitem(newMenuitem) {
+ this.menuitemNodes.forEach(function (item) {
+ if (item === newMenuitem) {
+ item.tabIndex = 0;
+ newMenuitem.focus();
+ } else {
+ item.tabIndex = -1;
+ }
+ });
+ }
+
+ setFocusToFirstMenuitem() {
+ this.setFocusToMenuitem(this.firstMenuitem);
+ }
+
+ setFocusToLastMenuitem() {
+ this.setFocusToMenuitem(this.lastMenuitem);
+ }
+
+ setFocusToPreviousMenuitem(currentMenuitem) {
+ var newMenuitem, index;
+
+ if (currentMenuitem === this.firstMenuitem) {
+ newMenuitem = this.lastMenuitem;
+ } else {
+ index = this.menuitemNodes.indexOf(currentMenuitem);
+ newMenuitem = this.menuitemNodes[index - 1];
+ }
+
+ this.setFocusToMenuitem(newMenuitem);
+
+ return newMenuitem;
+ }
+
+ setFocusToNextMenuitem(currentMenuitem) {
+ var newMenuitem, index;
+
+ if (currentMenuitem === this.lastMenuitem) {
+ newMenuitem = this.firstMenuitem;
+ } else {
+ index = this.menuitemNodes.indexOf(currentMenuitem);
+ newMenuitem = this.menuitemNodes[index + 1];
+ }
+ this.setFocusToMenuitem(newMenuitem);
+
+ return newMenuitem;
+ }
+
+ setFocusByFirstCharacter(currentMenuitem, char) {
+ var start, index;
+
+ if (char.length > 1) {
+ return;
+ }
+
+ char = char.toLowerCase();
+
+ // Get start index for search based on position of currentItem
+ start = this.menuitemNodes.indexOf(currentMenuitem) + 1;
+ if (start >= this.menuitemNodes.length) {
+ start = 0;
+ }
+
+ // Check remaining slots in the menu
+ index = this.firstChars.indexOf(char, start);
+
+ // If not found in remaining slots, check from beginning
+ if (index === -1) {
+ index = this.firstChars.indexOf(char, 0);
+ }
+
+ // If match was found...
+ if (index > -1) {
+ this.setFocusToMenuitem(this.menuitemNodes[index]);
+ }
+ }
+
+ // Utilities
+
+ getIndexFirstChars(startIndex, char) {
+ for (var i = startIndex; i < this.firstChars.length; i++) {
+ if (char === this.firstChars[i]) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ // Popup menu methods
+
+ openPopup() {
+ this.menuNode.style.display = 'block';
+ this.buttonNode.setAttribute('aria-expanded', 'true');
+ }
+
+ closePopup() {
+ if (this.isOpen()) {
+ this.buttonNode.setAttribute('aria-expanded', 'false');
+ this.menuNode.style.display = 'none';
+ }
+ }
+
+ isOpen() {
+ return this.buttonNode.getAttribute('aria-expanded') === 'true';
+ }
+
+ // Menu event handlers
+
+ onFocusin() {
+ this.domNode.classList.add('focus');
+ }
+
+ onFocusout() {
+ this.domNode.classList.remove('focus');
+ }
+
+ onButtonKeydown(event) {
+ var key = event.key,
+ flag = false;
+
+ switch (key) {
+ case ' ':
+ case 'Enter':
+ case 'ArrowDown':
+ case 'Down':
+ this.openPopup();
+ this.setFocusToFirstMenuitem();
+ flag = true;
+ break;
+
+ case 'Esc':
+ case 'Escape':
+ this.closePopup();
+ flag = true;
+ break;
+
+ case 'Up':
+ case 'ArrowUp':
+ this.openPopup();
+ this.setFocusToLastMenuitem();
+ flag = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (flag) {
+ event.stopPropagation();
+ event.preventDefault();
+ }
+ }
+
+ onButtonClick(event) {
+ if (this.isOpen()) {
+ this.closePopup();
+ this.buttonNode.focus();
+ } else {
+ this.openPopup();
+ this.setFocusToFirstMenuitem();
+ }
+
+ event.stopPropagation();
+ event.preventDefault();
+ }
+
+ onMenuitemKeydown(event) {
+ var tgt = event.currentTarget,
+ key = event.key,
+ flag = false;
+
+ function isPrintableCharacter(str) {
+ return str.length === 1 && str.match(/\S/);
+ }
+
+ if (event.ctrlKey || event.altKey || event.metaKey) {
+ return;
+ }
+
+ if (event.shiftKey) {
+ if (isPrintableCharacter(key)) {
+ this.setFocusByFirstCharacter(tgt, key);
+ flag = true;
+ }
+
+ if (event.key === 'Tab') {
+ this.buttonNode.focus();
+ this.closePopup();
+ flag = true;
+ }
+ } else {
+ switch (key) {
+ case ' ':
+ case 'Enter':
+ this.closePopup();
+ this.performMenuAction(tgt);
+ this.buttonNode.focus();
+ flag = true;
+ break;
+
+ case 'Esc':
+ case 'Escape':
+ this.closePopup();
+ this.buttonNode.focus();
+ flag = true;
+ break;
+
+ case 'Up':
+ case 'ArrowUp':
+ this.setFocusToPreviousMenuitem(tgt);
+ flag = true;
+ break;
+
+ case 'ArrowDown':
+ case 'Down':
+ this.setFocusToNextMenuitem(tgt);
+ flag = true;
+ break;
+
+ case 'Home':
+ case 'PageUp':
+ this.setFocusToFirstMenuitem();
+ flag = true;
+ break;
+
+ case 'End':
+ case 'PageDown':
+ this.setFocusToLastMenuitem();
+ flag = true;
+ break;
+
+ case 'Tab':
+ this.closePopup();
+ break;
+
+ default:
+ if (isPrintableCharacter(key)) {
+ this.setFocusByFirstCharacter(tgt, key);
+ flag = true;
+ }
+ break;
+ }
+ }
+
+ if (flag) {
+ event.stopPropagation();
+ event.preventDefault();
+ }
+ }
+
+ onMenuitemClick(event) {
+ var tgt = event.currentTarget;
+ this.closePopup();
+ this.buttonNode.focus();
+ this.performMenuAction(tgt);
+ }
+
+ onMenuitemMouseover(event) {
+ var tgt = event.currentTarget;
+ tgt.focus();
+ }
+
+ onBackgroundMousedown(event) {
+ if (!this.domNode.contains(event.target)) {
+ if (this.isOpen()) {
+ this.closePopup();
+ this.buttonNode.focus();
+ }
+ }
+ }
+}
+
+// Initialize menu buttons
+window.addEventListener('load', function () {
+ document.getElementById('action_output').value = 'none';
+
+ function performMenuAction(node) {
+ document.getElementById('action_output').value = node.textContent.trim();
+ }
+
+ var menuButtons = document.querySelectorAll('.menu-button-actions');
+ for (var i = 0; i < menuButtons.length; i++) {
+ new MenuButtonActions(menuButtons[i], performMenuAction);
+ }
+});
diff --git a/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/js/menu-button-links.js b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/js/menu-button-links.js
new file mode 100644
index 000000000..757aac226
--- /dev/null
+++ b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/js/menu-button-links.js
@@ -0,0 +1,328 @@
+/*
+ * This content is licensed according to the W3C Software License at
+ * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
+ *
+ * File: menu-button-links.js
+ *
+ * Desc: Creates a menu button that opens a menu of links
+ */
+
+'use strict';
+
+class MenuButtonLinks {
+ constructor(domNode) {
+ this.domNode = domNode;
+ this.buttonNode = domNode.querySelector('button');
+ this.menuNode = domNode.querySelector('[role="menu"]');
+ this.menuitemNodes = [];
+ this.firstMenuitem = false;
+ this.lastMenuitem = false;
+ this.firstChars = [];
+
+ this.buttonNode.addEventListener(
+ 'keydown',
+ this.onButtonKeydown.bind(this)
+ );
+ this.buttonNode.addEventListener('click', this.onButtonClick.bind(this));
+
+ var nodes = domNode.querySelectorAll('[role="menuitem"]');
+
+ for (var i = 0; i < nodes.length; i++) {
+ var menuitem = nodes[i];
+ this.menuitemNodes.push(menuitem);
+ menuitem.tabIndex = -1;
+ this.firstChars.push(menuitem.textContent.trim()[0].toLowerCase());
+
+ menuitem.addEventListener('keydown', this.onMenuitemKeydown.bind(this));
+
+ menuitem.addEventListener(
+ 'mouseover',
+ this.onMenuitemMouseover.bind(this)
+ );
+
+ if (!this.firstMenuitem) {
+ this.firstMenuitem = menuitem;
+ }
+ this.lastMenuitem = menuitem;
+ }
+
+ domNode.addEventListener('focusin', this.onFocusin.bind(this));
+ domNode.addEventListener('focusout', this.onFocusout.bind(this));
+
+ window.addEventListener(
+ 'mousedown',
+ this.onBackgroundMousedown.bind(this),
+ true
+ );
+ }
+
+ setFocusToMenuitem(newMenuitem) {
+ this.menuitemNodes.forEach(function (item) {
+ if (item === newMenuitem) {
+ item.tabIndex = 0;
+ newMenuitem.focus();
+ } else {
+ item.tabIndex = -1;
+ }
+ });
+ }
+
+ setFocusToFirstMenuitem() {
+ this.setFocusToMenuitem(this.firstMenuitem);
+ }
+
+ setFocusToLastMenuitem() {
+ this.setFocusToMenuitem(this.lastMenuitem);
+ }
+
+ setFocusToPreviousMenuitem(currentMenuitem) {
+ var newMenuitem, index;
+
+ if (currentMenuitem === this.firstMenuitem) {
+ newMenuitem = this.lastMenuitem;
+ } else {
+ index = this.menuitemNodes.indexOf(currentMenuitem);
+ newMenuitem = this.menuitemNodes[index - 1];
+ }
+
+ this.setFocusToMenuitem(newMenuitem);
+
+ return newMenuitem;
+ }
+
+ setFocusToNextMenuitem(currentMenuitem) {
+ var newMenuitem, index;
+
+ if (currentMenuitem === this.lastMenuitem) {
+ newMenuitem = this.firstMenuitem;
+ } else {
+ index = this.menuitemNodes.indexOf(currentMenuitem);
+ newMenuitem = this.menuitemNodes[index + 1];
+ }
+ this.setFocusToMenuitem(newMenuitem);
+
+ return newMenuitem;
+ }
+
+ setFocusByFirstCharacter(currentMenuitem, char) {
+ var start, index;
+
+ if (char.length > 1) {
+ return;
+ }
+
+ char = char.toLowerCase();
+
+ // Get start index for search based on position of currentItem
+ start = this.menuitemNodes.indexOf(currentMenuitem) + 1;
+ if (start >= this.menuitemNodes.length) {
+ start = 0;
+ }
+
+ // Check remaining slots in the menu
+ index = this.firstChars.indexOf(char, start);
+
+ // If not found in remaining slots, check from beginning
+ if (index === -1) {
+ index = this.firstChars.indexOf(char, 0);
+ }
+
+ // If match was found...
+ if (index > -1) {
+ this.setFocusToMenuitem(this.menuitemNodes[index]);
+ }
+ }
+
+ // Utilities
+
+ getIndexFirstChars(startIndex, char) {
+ for (var i = startIndex; i < this.firstChars.length; i++) {
+ if (char === this.firstChars[i]) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ // Popup menu methods
+
+ openPopup() {
+ this.menuNode.style.display = 'block';
+ this.buttonNode.setAttribute('aria-expanded', 'true');
+ }
+
+ closePopup() {
+ if (this.isOpen()) {
+ this.buttonNode.setAttribute('aria-expanded', 'false');
+ this.menuNode.style.display = 'none';
+ }
+ }
+
+ isOpen() {
+ return this.buttonNode.getAttribute('aria-expanded') === 'true';
+ }
+
+ // Menu event handlers
+
+ onFocusin() {
+ this.domNode.classList.add('focus');
+ }
+
+ onFocusout() {
+ this.domNode.classList.remove('focus');
+ }
+
+ onButtonKeydown(event) {
+ var key = event.key,
+ flag = false;
+
+ switch (key) {
+ case ' ':
+ case 'Enter':
+ case 'ArrowDown':
+ case 'Down':
+ this.openPopup();
+ this.setFocusToFirstMenuitem();
+ flag = true;
+ break;
+
+ case 'Esc':
+ case 'Escape':
+ this.closePopup();
+ this.buttonNode.focus();
+ flag = true;
+ break;
+
+ case 'Up':
+ case 'ArrowUp':
+ this.openPopup();
+ this.setFocusToLastMenuitem();
+ flag = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (flag) {
+ event.stopPropagation();
+ event.preventDefault();
+ }
+ }
+
+ onButtonClick(event) {
+ if (this.isOpen()) {
+ this.closePopup();
+ this.buttonNode.focus();
+ } else {
+ this.openPopup();
+ this.setFocusToFirstMenuitem();
+ }
+
+ event.stopPropagation();
+ event.preventDefault();
+ }
+
+ onMenuitemKeydown(event) {
+ var tgt = event.currentTarget,
+ key = event.key,
+ flag = false;
+
+ function isPrintableCharacter(str) {
+ return str.length === 1 && str.match(/\S/);
+ }
+
+ if (event.ctrlKey || event.altKey || event.metaKey) {
+ return;
+ }
+
+ if (event.shiftKey) {
+ if (isPrintableCharacter(key)) {
+ this.setFocusByFirstCharacter(tgt, key);
+ flag = true;
+ }
+
+ if (event.key === 'Tab') {
+ this.buttonNode.focus();
+ this.closePopup();
+ flag = true;
+ }
+ } else {
+ switch (key) {
+ case ' ':
+ window.location.href = tgt.href;
+ break;
+
+ case 'Esc':
+ case 'Escape':
+ this.closePopup();
+ this.buttonNode.focus();
+ flag = true;
+ break;
+
+ case 'Up':
+ case 'ArrowUp':
+ this.setFocusToPreviousMenuitem(tgt);
+ flag = true;
+ break;
+
+ case 'ArrowDown':
+ case 'Down':
+ this.setFocusToNextMenuitem(tgt);
+ flag = true;
+ break;
+
+ case 'Home':
+ case 'PageUp':
+ this.setFocusToFirstMenuitem();
+ flag = true;
+ break;
+
+ case 'End':
+ case 'PageDown':
+ this.setFocusToLastMenuitem();
+ flag = true;
+ break;
+
+ case 'Tab':
+ this.closePopup();
+ break;
+
+ default:
+ if (isPrintableCharacter(key)) {
+ this.setFocusByFirstCharacter(tgt, key);
+ flag = true;
+ }
+ break;
+ }
+ }
+
+ if (flag) {
+ event.stopPropagation();
+ event.preventDefault();
+ }
+ }
+
+ onMenuitemMouseover(event) {
+ var tgt = event.currentTarget;
+ tgt.focus();
+ }
+
+ onBackgroundMousedown(event) {
+ if (!this.domNode.contains(event.target)) {
+ if (this.isOpen()) {
+ this.closePopup();
+ this.buttonNode.focus();
+ }
+ }
+ }
+}
+
+// Initialize menu buttons
+
+window.addEventListener('load', function () {
+ var menuButtons = document.querySelectorAll('.menu-button-links');
+ for (let i = 0; i < menuButtons.length; i++) {
+ new MenuButtonLinks(menuButtons[i]);
+ }
+});
diff --git a/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/menu-button-actions-active-descendant.html b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/menu-button-actions-active-descendant.html
new file mode 100644
index 000000000..a203fc37f
--- /dev/null
+++ b/tests/menu-button-actions-active-descendant/reference/2024-7-21_174946/menu-button-actions-active-descendant.html
@@ -0,0 +1,61 @@
+
+
+
+
+
+ Actions Menu Button Example Using aria-activedescendant
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Actions Menu Button Example Using aria-activedescendant
+
+
+
+ This example demonstrates how the Menu Button Pattern can be used to create a button that opens an actions menu.
+ In this example, choosing an action from the menu will cause the chosen action to be displayed in the Last Action edit box.
+