Fix comment template NumpadEnter click under Vue 3

What does this MR do and why?

modalKeyboardNavigationMixin handles keyboard navigation in dropdown lists. Its onKeydown method selects the highlighted item by running event.target?.firstChild.click().

Under the Vue 3 compat build, the first DOM child of a dropdown item can be a comment node or a text node, not an element. Vue 3 does not collapse template whitespace around component default-slot fallback content the same way Vue 2 does.

Comment and text nodes have no click() method. The call throws a TypeError. The Numpad Enter key stops working.

This MR fixes the bug by changing firstChild to firstElementChild. This skips comment and text nodes and returns the first element, which is the item's button.

The same fix pattern was applied in merge request !251210 (merged), which fixed the identical bug in global_search.vue. This second occurrence was found while reviewing that MR.

The comment_templates_modal.vue component is the only live consumer of this mixin's onKeydown. The global_search.vue component also uses the mixin but defines its own onKeydown and getFocusableOptions, which fully shadow the mixin's versions.

How to set up and validate locally

  1. Run GDK with the Vue 3 build: set VUE_VERSION=3.
  2. Open a comment box.
  3. Click the "Insert comment template" icon.
  4. Use the arrow keys to highlight an item.
  5. Press the Numpad Enter key, not the regular Enter key.
  6. Confirm no console error appears and that the selected template is inserted.

Run the test under both Vue versions:

yarn jest spec/frontend/vue_shared/components/markdown/comment_templates_modal_spec.js
VUE_VERSION=3 yarn jest spec/frontend/vue_shared/components/markdown/comment_templates_modal_spec.js

The test mounts the real GlDisclosureDropdownGroup and GlDisclosureDropdownItem components from GitLab UI so the rendered DOM comes from the real Vue runtime. It dispatches a real bubbling keydown event with code NumpadEnter on a rendered dropdown item and asserts the component emits select with the template content. With the fix reverted, the test fails under VUE_VERSION=3 with a TypeError and passes under Vue 2, confirming the bug is Vue 3 only.

References

  • Same bug pattern as !251210 (merged) (fixed firstChild in global_search.vue; this occurrence was found while reviewing it)
Edited by Miguel Rincon

Merge request reports

Loading
Loading