{"record":{"id":"fd5dac2a2037d5cd","repo":"angular/components","slug":"item-matching-json-stringify-itemfilter-does-n","errorCode":null,"errorMessage":"Item matching ${JSON.stringify(itemFilter)} does not have a submenu","messagePattern":"Item matching (.+?) does not have a submenu","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/material/menu/testing/menu-harness.ts","lineNumber":230,"sourceCode":"  }\n}\n\nexport async function clickItemImplementation(\n  items: MatMenuItemHarness[],\n  itemFilter: Omit<MenuItemHarnessFilters, 'ancestor'>,\n  subItemFilters: Omit<MenuItemHarnessFilters, 'ancestor'>[],\n): Promise<void> {\n  if (!items.length) {\n    throw Error(`Could not find item matching ${JSON.stringify(itemFilter)}`);\n  }\n\n  if (!subItemFilters.length) {\n    return await items[0].click();\n  }\n\n  const menu = await items[0].getSubmenu();\n  if (!menu) {\n    throw Error(`Item matching ${JSON.stringify(itemFilter)} does not have a submenu`);\n  }\n  return menu.clickItem(...(subItemFilters as [Omit<MenuItemHarnessFilters, 'ancestor'>]));\n}\n","sourceCodeStart":212,"sourceCodeEnd":234,"githubUrl":"https://github.com/angular/components/blob/0411926e7d8ae06b32236ec1048a888cfad5abf2/src/material/menu/testing/menu-harness.ts#L212-L234","documentation":"`clickItemImplementation` throws when the caller requested a nested click (subItemFilters provided) but the matched menu item has no submenu. `getSubmenu()` returned null, so descending into sub-items is impossible.","triggerScenarios":"`await menuHarness.clickItem({text: 'File'}, [{text: 'Open'}])` where the 'File' item was rendered without a `mat-menu` child (no `matMenuContent`/nested menu attached).","commonSituations":"A submenu was removed or renamed in the template but the test still navigates into it; the item is a leaf action (e.g. 'Close') mistakenly treated as a parent; lazy submenu content not rendered because the parent was not hovered.","solutions":["Remove the subItemFilters argument if the item is actually a leaf item","Verify the template attaches a nested menu (`<ng-template matMenuContent>` or nested `<mat-menu>`) to that item","Check the item text filter matches the item that truly has the submenu"],"exampleFix":"// before\nawait menuHarness.clickItem({text: 'Close'}, [{text: 'Now'}]);\n// after\nawait menuHarness.clickItem({text: 'Close'});","handlingStrategy":"validation","validationCode":"const item = (await menuHarness.getItems({text: 'File'}))[0];\nif (!item || !(await item.getSubmenu())) {\n  throw new Error('Item has no submenu; do not pass subItemFilters');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await menuHarness.clickItem({text: 'File'}, [{text: 'Open'}]);\n} catch (e) {\n  if (String(e?.message).includes('does not have a submenu')) {\n    fail(`'File' is a leaf item or submenu is not attached`);\n  }\n  throw e;\n}","preventionTips":["Only pass subItemFilters for items with nested menus","Keep template submenu structure in sync with tests","Hover parent items so lazy submenu content is attached before asserting"],"tags":["angular","material","testing","harness","submenu"],"backgroundTag":"harness-element-not-found","analyzedSha":"0411926e7d8ae06b32236ec1048a888cfad5abf2","analyzedAt":"2026-08-31T11:58:23.400Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}